Fawkes API
Fawkes Development Version
|
00001 00002 /*************************************************************************** 00003 * encrypt.cpp - WorldInfo encryptio routine 00004 * 00005 * Created: Thu May 03 15:21:00 2007 00006 * Copyright 2006-2007 Tim Niemueller [www.niemueller.de] 00007 * 00008 ****************************************************************************/ 00009 00010 /* This program is free software; you can redistribute it and/or modify 00011 * it under the terms of the GNU General Public License as published by 00012 * the Free Software Foundation; either version 2 of the License, or 00013 * (at your option) any later version. A runtime exception applies to 00014 * this software (see LICENSE.GPL_WRE file mentioned below for details). 00015 * 00016 * This program is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * GNU Library General Public License for more details. 00020 * 00021 * Read the full text in the LICENSE.GPL_WRE file in the doc directory. 00022 */ 00023 00024 #include <core/exceptions/software.h> 00025 #include <netcomm/worldinfo/encrypt.h> 00026 00027 #ifdef HAVE_LIBCRYPTO 00028 # include <openssl/evp.h> 00029 #else 00030 # include <cstring> 00031 #endif 00032 00033 namespace fawkes { 00034 00035 /** @class MessageEncryptionException <netcomm/worldinfo/encrypt.h> 00036 * Message encryption failed. 00037 * This exception shall be thrown if there was a problem encrypting a 00038 * world info message. 00039 * @ingroup NetComm 00040 */ 00041 00042 /** Constructor. 00043 * @param msg message 00044 */ 00045 MessageEncryptionException::MessageEncryptionException(const char *msg) 00046 : Exception(msg) 00047 { 00048 } 00049 00050 00051 /** @class WorldInfoMessageEncryptor <netcomm/worldinfo/encrypt.h> 00052 * WorldInfo message encryptor. 00053 * This class is used to encrypt world info message before they are sent 00054 * over the network. 00055 * 00056 * The used encryption is AES (128 bit) with a supplied key and initialisation 00057 * vector that both sides have to agree on. 00058 * The encryption is used in the less safe Electronic Code Book (ECB) mode. It 00059 * is prefered over Cipher Block Chaining (CBC) mode since we expect a very 00060 * unreliable transport medium (wifi in a totally crowded and signal-hostile 00061 * environment) where we could have severe packet loss. In CBC mode if you loose 00062 * a single packet you can not only not decrypt this packet that you didn't get, 00063 * but also not the directly following packages. In this case it can already 00064 * cause severe problems if about half of the packes are lost. 00065 * 00066 * We are merely interested in some kind of child-proof blinds that is just used 00067 * to make cheating too much work to be interesting. We actually don't care if 00068 * someone can decrypt our traffic with enough time, we just don't want other 00069 * teams to be able to decrypt our traffic during the game. Otherwise teams 00070 * could cheat and just read the network messages to know where the opponents 00071 * are instead of really detecting them using sensors. 00072 * 00073 * This implementation uses OpenSSL for the AES encryption (in fact it uses the 00074 * accompanying libcrypto that comes with OpenSSL, not libopenssl itself). It is 00075 * almost everywhere available and easy to use. 00076 * 00077 * @ingroup NetComm 00078 * @author Tim Niemueller 00079 */ 00080 00081 00082 /** Constructor. 00083 * @param key encryption key 00084 * @param iv initialisation vector 00085 */ 00086 WorldInfoMessageEncryptor::WorldInfoMessageEncryptor(const unsigned char *key, const unsigned char *iv) 00087 { 00088 plain_buffer = NULL; 00089 plain_buffer_length = 0; 00090 crypt_buffer = NULL; 00091 crypt_buffer_length = 0; 00092 00093 this->key = key; 00094 this->iv = iv; 00095 } 00096 00097 00098 /** Empty destructor. */ 00099 WorldInfoMessageEncryptor::~WorldInfoMessageEncryptor() 00100 { 00101 } 00102 00103 00104 00105 00106 /** Set plain buffer. 00107 * This set the source buffer that is encrypted. 00108 * @param buffer plain buffer 00109 * @param buffer_length plain buffer length 00110 */ 00111 void 00112 WorldInfoMessageEncryptor::set_plain_buffer(void *buffer, size_t buffer_length) 00113 { 00114 plain_buffer = buffer; 00115 plain_buffer_length = buffer_length; 00116 } 00117 00118 00119 /** Get recommended crypted buffer size. 00120 * The cryto text is in most cases longer than the plain text. This is because 00121 * we use a block cipher. This block cipher encrypts block of certain sizes (in case 00122 * of AES128 a block has a size of 16 bytes). If our data does not align to this block 00123 * size padding at the end is required to fill up the last block to the requested 00124 * size. Since this padding depends on the used cipher this convenience method 00125 * is provided to get the recommended minimum size depending on the plain text 00126 * buffer (that you have to set before you call this method. 00127 * @return recommended minimum size of the crypted buffer 00128 * @exception MissingParameterException thrown, if set_plain_buffer() has not 00129 * been called or if the supplied buffer had zero size. 00130 */ 00131 size_t 00132 WorldInfoMessageEncryptor::recommended_crypt_buffer_size() 00133 { 00134 if ( plain_buffer_length == 0 ) { 00135 throw MissingParameterException("plain buffer must be set and plain buffer size > 0"); 00136 } 00137 00138 #ifdef HAVE_LIBCRYPTO 00139 EVP_CIPHER_CTX ctx; 00140 EVP_EncryptInit(&ctx, EVP_aes_128_ecb(), key, iv); 00141 size_t rv = plain_buffer_length + EVP_CIPHER_CTX_block_size(&ctx); 00142 EVP_CIPHER_CTX_cleanup(&ctx); 00143 return rv; 00144 #else 00145 return plain_buffer_length; 00146 #endif 00147 } 00148 00149 00150 /** Set crypted buffer. 00151 * This set the destination buffer to which the encrypted message is written. 00152 * @param buffer crypted buffer 00153 * @param buffer_length crypted buffer length 00154 */ 00155 void 00156 WorldInfoMessageEncryptor::set_crypt_buffer(void *buffer, size_t buffer_length) 00157 { 00158 crypt_buffer = buffer; 00159 crypt_buffer_length = buffer_length; 00160 } 00161 00162 00163 /** Encrypt. 00164 * Do the encryption. 00165 * @return size of the crypted message in bytes 00166 */ 00167 size_t 00168 WorldInfoMessageEncryptor::encrypt() 00169 { 00170 if ( (plain_buffer == NULL) || (plain_buffer_length == 0) || 00171 (crypt_buffer == NULL) || (crypt_buffer_length == 0) ) { 00172 throw MissingParameterException("Buffer(s) not set for encryption"); 00173 } 00174 00175 #ifdef HAVE_LIBCRYPTO 00176 EVP_CIPHER_CTX ctx; 00177 if ( ! EVP_EncryptInit(&ctx, EVP_aes_128_ecb(), key, iv) ) { 00178 throw MessageEncryptionException("Could not initialize cipher context"); 00179 } 00180 00181 00182 int outl = crypt_buffer_length; 00183 if ( ! EVP_EncryptUpdate(&ctx, 00184 (unsigned char *)crypt_buffer, &outl, 00185 (unsigned char *)plain_buffer, plain_buffer_length) ) { 00186 throw MessageEncryptionException("EncryptUpdate failed"); 00187 } 00188 00189 int plen = 0; 00190 if ( ! EVP_EncryptFinal_ex(&ctx, (unsigned char *)crypt_buffer + outl, &plen) ) { 00191 throw MessageEncryptionException("EncryptFinal failed"); 00192 } 00193 outl += plen; 00194 00195 return outl; 00196 #else 00197 /* Plain text copy-through for debugging */ 00198 memcpy(crypt_buffer, plain_buffer, plain_buffer_length); 00199 return plain_buffer_length; 00200 #endif 00201 } 00202 00203 } // end namespace fawkes