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
32namespace 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{
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 */
82MessageEncryptor::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 */
103void
104MessageEncryptor::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 */
122size_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 */
145void
146MessageEncryptor::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 */
156size_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
Base class for exceptions in Fawkes.
Definition: exception.h:36
Message encryption failed.
Definition: encrypt.h:33
MessageEncryptionException(const char *msg)
Constructor.
Definition: encrypt.cpp:44
size_t encrypt()
Encrypt.
Definition: encrypt.cpp:157
MessageEncryptor(const unsigned char *key, const unsigned char *iv)
Constructor.
Definition: encrypt.cpp:82
~MessageEncryptor()
Empty destructor.
Definition: encrypt.cpp:94
void set_plain_buffer(void *buffer, size_t buffer_length)
Set plain buffer.
Definition: encrypt.cpp:104
void set_crypt_buffer(void *buffer, size_t buffer_length)
Set crypted buffer.
Definition: encrypt.cpp:146
size_t recommended_crypt_buffer_size()
Get recommended crypted buffer size.
Definition: encrypt.cpp:123
Expected parameter is missing.
Definition: software.h:74
Fawkes library namespace.