Fawkes API  Fawkes Development Version
encrypt.cpp
1 
2 /***************************************************************************
3  * encrypt.cpp - Message encryption routine
4  *
5  * Created: Thu May 03 15:21:00 2007
6  * Copyright 2006-2014 Tim Niemueller [www.niemueller.de]
7  ****************************************************************************/
8 
9 /* This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version. A runtime exception applies to
13  * this software (see LICENSE.GPL_WRE file mentioned below for details).
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU Library General Public License for more details.
19  *
20  * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
21  */
22 
23 #include <netcomm/crypto/encrypt.h>
24 #include <core/exceptions/software.h>
25 
26 #ifdef HAVE_LIBCRYPTO
27 # include <openssl/evp.h>
28 #else
29 # include <cstring>
30 #endif
31 
32 namespace fawkes {
33 
34 /** @class MessageEncryptionException <netcomm/crypto/encrypt.h>
35  * Message encryption failed.
36  * This exception shall be thrown if there was a problem encrypting a
37  * world info message.
38  * @ingroup NetComm
39  */
40 
41 /** Constructor.
42  * @param msg message
43  */
45  : Exception(msg)
46 {
47 }
48 
49 
50 /** @class MessageEncryptor <netcomm/crypto/encrypt.h>
51  * Message encryptor.
52  * This class is used to encrypt world info message before they are sent
53  * over the network.
54  *
55  * The used encryption is AES (128 bit) with a supplied key and initialisation
56  * vector that both sides have to agree on.
57  * The encryption is used in the less safe Electronic Code Book (ECB) mode. It
58  * is prefered over Cipher Block Chaining (CBC) mode since we expect a very
59  * unreliable transport medium (wifi in a totally crowded and signal-hostile
60  * environment) where we could have severe packet loss. In CBC mode if you loose
61  * a single packet you can not only not decrypt this packet that you didn't get,
62  * but also not the directly following packages. In this case it can already
63  * cause severe problems if about half of the packes are lost.
64  *
65  * We are merely interested in some kind of child-proof blinds that is just used
66  * to make cheating too much work to be interesting. We actually don't care if
67  * someone can decrypt our traffic with enough time, we just don't want other
68  * teams to be able to decrypt our traffic during the game. Otherwise teams
69  * could cheat and just read the network messages to know where the opponents
70  * are instead of really detecting them using sensors.
71  *
72  * This implementation uses OpenSSL for the AES encryption (in fact it uses the
73  * accompanying libcrypto that comes with OpenSSL, not libopenssl itself). It is
74  * almost everywhere available and easy to use.
75  *
76  * @ingroup NetComm
77  * @author Tim Niemueller
78  */
79 
80 
81 /** Constructor.
82  * @param key encryption key
83  * @param iv initialisation vector
84  */
85 MessageEncryptor::MessageEncryptor(const unsigned char *key, const unsigned char *iv)
86 {
87  plain_buffer = NULL;
88  plain_buffer_length = 0;
89  crypt_buffer = NULL;
90  crypt_buffer_length = 0;
91 
92  this->key = key;
93  this->iv = iv;
94 }
95 
96 
97 /** Empty destructor. */
99 {
100 }
101 
102 
103 
104 
105 /** Set plain buffer.
106  * This set the source buffer that is encrypted.
107  * @param buffer plain buffer
108  * @param buffer_length plain buffer length
109  */
110 void
111 MessageEncryptor::set_plain_buffer(void *buffer, size_t buffer_length)
112 {
113  plain_buffer = buffer;
114  plain_buffer_length = buffer_length;
115 }
116 
117 
118 /** Get recommended crypted buffer size.
119  * The cryto text is in most cases longer than the plain text. This is because
120  * we use a block cipher. This block cipher encrypts block of certain sizes (in case
121  * of AES128 a block has a size of 16 bytes). If our data does not align to this block
122  * size padding at the end is required to fill up the last block to the requested
123  * size. Since this padding depends on the used cipher this convenience method
124  * is provided to get the recommended minimum size depending on the plain text
125  * buffer (that you have to set before you call this method.
126  * @return recommended minimum size of the crypted buffer
127  * @exception MissingParameterException thrown, if set_plain_buffer() has not
128  * been called or if the supplied buffer had zero size.
129  */
130 size_t
132 {
133  if ( plain_buffer_length == 0 ) {
134  throw MissingParameterException("plain buffer must be set and plain buffer size > 0");
135  }
136 
137 #ifdef HAVE_LIBCRYPTO
138  EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
139  EVP_EncryptInit(ctx, EVP_aes_128_ecb(), key, iv);
140  size_t rv = plain_buffer_length + EVP_CIPHER_CTX_block_size(ctx);
141  EVP_CIPHER_CTX_free(ctx);
142  return rv;
143 #else
144  return plain_buffer_length;
145 #endif
146 }
147 
148 
149 /** Set crypted buffer.
150  * This set the destination buffer to which the encrypted message is written.
151  * @param buffer crypted buffer
152  * @param buffer_length crypted buffer length
153  */
154 void
155 MessageEncryptor::set_crypt_buffer(void *buffer, size_t buffer_length)
156 {
157  crypt_buffer = buffer;
158  crypt_buffer_length = buffer_length;
159 }
160 
161 
162 /** Encrypt.
163  * Do the encryption.
164  * @return size of the crypted message in bytes
165  */
166 size_t
168 {
169  if ( (plain_buffer == NULL) || (plain_buffer_length == 0) ||
170  (crypt_buffer == NULL) || (crypt_buffer_length == 0) ) {
171  throw MissingParameterException("Buffer(s) not set for encryption");
172  }
173 
174 #ifdef HAVE_LIBCRYPTO
175  EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
176  if ( ! EVP_EncryptInit(ctx, EVP_aes_128_ecb(), key, iv) ) {
177  EVP_CIPHER_CTX_free(ctx);
178  throw MessageEncryptionException("Could not initialize cipher context");
179  }
180 
181 
182  int outl = crypt_buffer_length;
183  if ( ! EVP_EncryptUpdate(ctx,
184  (unsigned char *)crypt_buffer, &outl,
185  (unsigned char *)plain_buffer, plain_buffer_length) ) {
186  EVP_CIPHER_CTX_free(ctx);
187  throw MessageEncryptionException("EncryptUpdate failed");
188  }
189 
190  int plen = 0;
191  if ( ! EVP_EncryptFinal_ex(ctx, (unsigned char *)crypt_buffer + outl, &plen) ) {
192  EVP_CIPHER_CTX_free(ctx);
193  throw MessageEncryptionException("EncryptFinal failed");
194  }
195  outl += plen;
196 
197  EVP_CIPHER_CTX_free(ctx);
198  return outl;
199 #else
200  /* Plain text copy-through for debugging
201  memcpy(crypt_buffer, plain_buffer, plain_buffer_length);
202  return plain_buffer_length;
203  */
204  throw Exception("Encryption support not available");
205 #endif
206 }
207 
208 } // end namespace fawkes
size_t recommended_crypt_buffer_size()
Get recommended crypted buffer size.
Definition: encrypt.cpp:131
Fawkes library namespace.
Exception()
Constructor for subclasses.
Definition: exception.cpp:257
MessageEncryptor(const unsigned char *key, const unsigned char *iv)
Constructor.
Definition: encrypt.cpp:85
Base class for exceptions in Fawkes.
Definition: exception.h:36
void set_plain_buffer(void *buffer, size_t buffer_length)
Set plain buffer.
Definition: encrypt.cpp:111
size_t encrypt()
Encrypt.
Definition: encrypt.cpp:167
void set_crypt_buffer(void *buffer, size_t buffer_length)
Set crypted buffer.
Definition: encrypt.cpp:155
~MessageEncryptor()
Empty destructor.
Definition: encrypt.cpp:98
MessageEncryptionException(const char *msg)
Constructor.
Definition: encrypt.cpp:44
Expected parameter is missing.
Definition: software.h:76