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 <core/exceptions/software.h>
24 #include <netcomm/crypto/encrypt.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  */
44 MessageEncryptionException::MessageEncryptionException(const char *msg) : Exception(msg)
45 {
46 }
47 
48 /** @class MessageEncryptor <netcomm/crypto/encrypt.h>
49  * Message encryptor.
50  * This class is used to encrypt world info message before they are sent
51  * over the network.
52  *
53  * The used encryption is AES (128 bit) with a supplied key and initialisation
54  * vector that both sides have to agree on.
55  * The encryption is used in the less safe Electronic Code Book (ECB) mode. It
56  * is prefered over Cipher Block Chaining (CBC) mode since we expect a very
57  * unreliable transport medium (wifi in a totally crowded and signal-hostile
58  * environment) where we could have severe packet loss. In CBC mode if you loose
59  * a single packet you can not only not decrypt this packet that you didn't get,
60  * but also not the directly following packages. In this case it can already
61  * cause severe problems if about half of the packes are lost.
62  *
63  * We are merely interested in some kind of child-proof blinds that is just used
64  * to make cheating too much work to be interesting. We actually don't care if
65  * someone can decrypt our traffic with enough time, we just don't want other
66  * teams to be able to decrypt our traffic during the game. Otherwise teams
67  * could cheat and just read the network messages to know where the opponents
68  * are instead of really detecting them using sensors.
69  *
70  * This implementation uses OpenSSL for the AES encryption (in fact it uses the
71  * accompanying libcrypto that comes with OpenSSL, not libopenssl itself). It is
72  * almost everywhere available and easy to use.
73  *
74  * @ingroup NetComm
75  * @author Tim Niemueller
76  */
77 
78 /** Constructor.
79  * @param key encryption key
80  * @param iv initialisation vector
81  */
82 MessageEncryptor::MessageEncryptor(const unsigned char *key, const unsigned char *iv)
83 {
84  plain_buffer = NULL;
85  plain_buffer_length = 0;
86  crypt_buffer = NULL;
87  crypt_buffer_length = 0;
88 
89  this->key = key;
90  this->iv = iv;
91 }
92 
93 /** Empty destructor. */
95 {
96 }
97 
98 /** Set plain buffer.
99  * This set the source buffer that is encrypted.
100  * @param buffer plain buffer
101  * @param buffer_length plain buffer length
102  */
103 void
104 MessageEncryptor::set_plain_buffer(void *buffer, size_t buffer_length)
105 {
106  plain_buffer = buffer;
107  plain_buffer_length = buffer_length;
108 }
109 
110 /** Get recommended crypted buffer size.
111  * The cryto text is in most cases longer than the plain text. This is because
112  * we use a block cipher. This block cipher encrypts block of certain sizes (in case
113  * of AES128 a block has a size of 16 bytes). If our data does not align to this block
114  * size padding at the end is required to fill up the last block to the requested
115  * size. Since this padding depends on the used cipher this convenience method
116  * is provided to get the recommended minimum size depending on the plain text
117  * buffer (that you have to set before you call this method.
118  * @return recommended minimum size of the crypted buffer
119  * @exception MissingParameterException thrown, if set_plain_buffer() has not
120  * been called or if the supplied buffer had zero size.
121  */
122 size_t
124 {
125  if (plain_buffer_length == 0) {
126  throw MissingParameterException("plain buffer must be set and plain buffer size > 0");
127  }
128 
129 #ifdef HAVE_LIBCRYPTO
130  EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
131  EVP_EncryptInit(ctx, EVP_aes_128_ecb(), key, iv);
132  size_t rv = plain_buffer_length + EVP_CIPHER_CTX_block_size(ctx);
133  EVP_CIPHER_CTX_free(ctx);
134  return rv;
135 #else
136  return plain_buffer_length;
137 #endif
138 }
139 
140 /** Set crypted buffer.
141  * This set the destination buffer to which the encrypted message is written.
142  * @param buffer crypted buffer
143  * @param buffer_length crypted buffer length
144  */
145 void
146 MessageEncryptor::set_crypt_buffer(void *buffer, size_t buffer_length)
147 {
148  crypt_buffer = buffer;
149  crypt_buffer_length = buffer_length;
150 }
151 
152 /** Encrypt.
153  * Do the encryption.
154  * @return size of the crypted message in bytes
155  */
156 size_t
158 {
159  if ((plain_buffer == NULL) || (plain_buffer_length == 0) || (crypt_buffer == NULL)
160  || (crypt_buffer_length == 0)) {
161  throw MissingParameterException("Buffer(s) not set for encryption");
162  }
163 
164 #ifdef HAVE_LIBCRYPTO
165  EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
166  if (!EVP_EncryptInit(ctx, EVP_aes_128_ecb(), key, iv)) {
167  EVP_CIPHER_CTX_free(ctx);
168  throw MessageEncryptionException("Could not initialize cipher context");
169  }
170 
171  int outl = crypt_buffer_length;
172  if (!EVP_EncryptUpdate(ctx,
173  (unsigned char *)crypt_buffer,
174  &outl,
175  (unsigned char *)plain_buffer,
176  plain_buffer_length)) {
177  EVP_CIPHER_CTX_free(ctx);
178  throw MessageEncryptionException("EncryptUpdate failed");
179  }
180 
181  int plen = 0;
182  if (!EVP_EncryptFinal_ex(ctx, (unsigned char *)crypt_buffer + outl, &plen)) {
183  EVP_CIPHER_CTX_free(ctx);
184  throw MessageEncryptionException("EncryptFinal failed");
185  }
186  outl += plen;
187 
188  EVP_CIPHER_CTX_free(ctx);
189  return outl;
190 #else
191  /* Plain text copy-through for debugging
192  memcpy(crypt_buffer, plain_buffer, plain_buffer_length);
193  return plain_buffer_length;
194  */
195  throw Exception("Encryption support not available");
196 #endif
197 }
198 
199 } // end namespace fawkes
fawkes::MessageEncryptor::~MessageEncryptor
~MessageEncryptor()
Empty destructor.
Definition: encrypt.cpp:97
fawkes::MessageEncryptor::recommended_crypt_buffer_size
size_t recommended_crypt_buffer_size()
Get recommended crypted buffer size.
Definition: encrypt.cpp:126
fawkes::MessageEncryptor::set_crypt_buffer
void set_crypt_buffer(void *buffer, size_t buffer_length)
Set crypted buffer.
Definition: encrypt.cpp:149
fawkes::MessageEncryptionException::MessageEncryptionException
MessageEncryptionException(const char *msg)
Constructor.
Definition: encrypt.cpp:47
fawkes::MessageEncryptor::encrypt
size_t encrypt()
Encrypt.
Definition: encrypt.cpp:160
fawkes
fawkes::MissingParameterException
Definition: software.h:77
fawkes::MessageEncryptor::MessageEncryptor
MessageEncryptor(const unsigned char *key, const unsigned char *iv)
Constructor.
Definition: encrypt.cpp:85
fawkes::MessageEncryptor::set_plain_buffer
void set_plain_buffer(void *buffer, size_t buffer_length)
Set plain buffer.
Definition: encrypt.cpp:107
fawkes::MessageEncryptionException
Definition: encrypt.h:35