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