00001 #ifndef BLOWFISH_CRYPTO_IMPLEMENTATION_FILE
00002 #define BLOWFISH_CRYPTO_IMPLEMENTATION_FILE
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "blowfish_crypto.h"
00019 #include "ssl_init.h"
00020
00021 #include <basis/byte_array.h>
00022 #include <basis/chaos.h>
00023 #include <basis/function.h>
00024 #include <basis/istring.h>
00025 #include <basis/log_base.h>
00026 #include <basis/mutex.h>
00027 #include <data_struct/static_memory_gremlin.h>
00028
00029 #include <openssl/blowfish.h>
00030 #include <openssl/evp.h>
00031
00032 const int FUDGE = 128;
00033
00034
00035
00036
00037 #undef set_key
00038
00039
00040 #undef LOG
00041 #define LOG(t) CLASS_EMERGENCY_LOG(program_wide_logger(), t)
00042
00043
00044
00045
00046 #ifdef DEBUG_BLOWFISH
00047
00048 #define DISCUSS_KEY_SIZE(key_size) \
00049 if (key_size < minimum_key_size()) { \
00050 continuable_error(static_class_name(), func, \
00051 isprintf("key size (%d bits) is less than minimum key size %d.", \
00052 key_size, minimum_key_size())); \
00053 } \
00054 if (key_size > maximum_key_size()) { \
00055 continuable_error(static_class_name(), func, \
00056 isprintf("key size (%d bits) is greater than maximum key size %d.", \
00057 key_size, maximum_key_size())); \
00058 }
00059
00060
00061
00062 #define DISCUSS_PROVIDED_KEY(key_size, key) \
00063 if (key.length() * BITS_PER_BYTE < key_size) { \
00064 continuable_error(static_class_name(), func, \
00065 isprintf("key array length (%d) is less than required by key size " \
00066 "(%d bits).", key.length(), key_size)); \
00067 }
00068 #else
00069 #define DISCUSS_PROVIDED_KEY(key_size, key)
00070 #define DISCUSS_KEY_SIZE(key_size)
00071 #endif
00072
00073 blowfish_crypto::blowfish_crypto(int key_size)
00074 : _key_size(key_size),
00075 _key(new byte_array)
00076 {
00077 FUNCDEF("constructor [int]");
00078 static_ssl_initializer();
00079 DISCUSS_KEY_SIZE(key_size);
00080 if (key_size < minimum_key_size())
00081 _key_size = minimum_key_size();
00082 if (key_size > maximum_key_size())
00083 _key_size = maximum_key_size();
00084 generate_key(_key_size, *_key);
00085 }
00086
00087 blowfish_crypto::blowfish_crypto(const byte_array &key, int key_size)
00088 : _key_size(key_size),
00089 _key(new byte_array(key))
00090 {
00091 FUNCDEF("constructor [byte_array/int]");
00092
00093
00094 DISCUSS_KEY_SIZE(key_size);
00095 DISCUSS_PROVIDED_KEY(key_size, key);
00096 static_ssl_initializer();
00097 }
00098
00099 blowfish_crypto::blowfish_crypto(const blowfish_crypto &to_copy)
00100 : object_base(),
00101 _key_size(to_copy._key_size),
00102 _key(new byte_array(*to_copy._key))
00103 { static_ssl_initializer(); }
00104
00105 blowfish_crypto::~blowfish_crypto()
00106 {
00107 WHACK(_key);
00108 }
00109
00110 int blowfish_crypto::key_size() const { return _key_size; }
00111
00112 const byte_array &blowfish_crypto::get_key() const { return *_key; }
00113
00114 int blowfish_crypto::minimum_key_size() { return 64; }
00115
00116 int blowfish_crypto::maximum_key_size() { return 448; }
00117
00118 blowfish_crypto &blowfish_crypto::operator = (const blowfish_crypto &to_copy)
00119 {
00120 if (this == &to_copy) return *this;
00121 _key_size = to_copy._key_size;
00122 *_key = *to_copy._key;
00123 return *this;
00124 }
00125
00126 bool blowfish_crypto::set_key(const byte_array &new_key, int key_size)
00127 {
00128 FUNCDEF("set_key");
00129 if (!new_key.length()) return false;
00130 DISCUSS_KEY_SIZE(key_size);
00131 DISCUSS_PROVIDED_KEY(key_size, new_key);
00132 if ( (key_size < minimum_key_size()) || (key_size > maximum_key_size()) )
00133 return false;
00134 if (new_key.length() * BITS_PER_BYTE < key_size) return false;
00135 _key_size = key_size;
00136 *_key = new_key;
00137 return true;
00138 }
00139
00140 void blowfish_crypto::generate_key(int size, byte_array &new_key)
00141 {
00142 FUNCDEF("generate_key");
00143 DISCUSS_KEY_SIZE(size);
00144 if (size < minimum_key_size())
00145 size = minimum_key_size();
00146 else if (size > maximum_key_size())
00147 size = maximum_key_size();
00148 int bytes = size / BITS_PER_BYTE;
00149 if (size % BITS_PER_BYTE) bytes++;
00150 new_key.reset(bytes);
00151 for (int i = 0; i < bytes; i++)
00152 new_key[i] = static_ssl_initializer().randomizer().inclusive(0, 255);
00153 }
00154
00155 SAFE_STATIC(mutex, __vector_init_lock, )
00156
00157 const byte_array &blowfish_crypto::init_vector()
00158 {
00159 auto_synchronizer locking(__vector_init_lock());
00160 static byte_array to_return(EVP_MAX_IV_LENGTH);
00161 static bool initted = false;
00162 if (!initted) {
00163 for (int i = 0; i < EVP_MAX_IV_LENGTH; i++)
00164 to_return[i] = 214 - i;
00165 initted = true;
00166 }
00167 return to_return;
00168 }
00169
00170 bool blowfish_crypto::encrypt(const byte_array &source,
00171 byte_array &target) const
00172 {
00173 FUNCDEF("encrypt");
00174 target.reset();
00175 if (!_key->length() || !source.length()) return false;
00176 bool to_return = true;
00177
00178
00179 EVP_CIPHER_CTX session;
00180 EVP_CIPHER_CTX_init(&session);
00181 EVP_EncryptInit_ex(&session, EVP_bf_cbc(), NIL, _key->observe(),
00182 init_vector().observe());
00183 EVP_CIPHER_CTX_set_key_length(&session, _key_size);
00184
00185
00186 byte_array encoded(source.length() + FUDGE);
00187
00188
00189 int encoded_len = 0;
00190 int enc_ret = EVP_EncryptUpdate(&session, encoded.access(), &encoded_len,
00191 source.observe(), source.length());
00192 if (enc_ret != 1) {
00193 continuable_error(class_name(), func, isprintf("encryption failed, "
00194 "result=%d.", enc_ret));
00195 to_return = false;
00196 } else {
00197
00198
00199 encoded.zap(encoded_len, encoded.last());
00200 target = encoded;
00201 }
00202
00203
00204 if (enc_ret == 1) {
00205
00206 encoded.reset(FUDGE);
00207 int pad_len = 0;
00208 enc_ret = EVP_EncryptFinal_ex(&session, encoded.access(), &pad_len);
00209 if (enc_ret != 1) {
00210 continuable_error(class_name(), func, isprintf("finalizing encryption "
00211 "failed, result=%d.", enc_ret));
00212 to_return = false;
00213 } else {
00214
00215 encoded.zap(pad_len, encoded.last());
00216 target += encoded;
00217 }
00218 }
00219
00220 EVP_CIPHER_CTX_cleanup(&session);
00221 return to_return;
00222 }
00223
00224 bool blowfish_crypto::decrypt(const byte_array &source,
00225 byte_array &target) const
00226 {
00227 FUNCDEF("decrypt");
00228 target.reset();
00229 if (!_key->length() || !source.length()) return false;
00230 bool to_return = true;
00231 EVP_CIPHER_CTX session;
00232 EVP_CIPHER_CTX_init(&session);
00233
00234 EVP_DecryptInit_ex(&session, EVP_bf_cbc(), NIL, _key->observe(),
00235 init_vector().observe());
00236 EVP_CIPHER_CTX_set_key_length(&session, _key_size);
00237
00238
00239 byte_array decoded(source.length() + FUDGE);
00240
00241 int decoded_len = 0;
00242 int dec_ret = EVP_DecryptUpdate(&session, decoded.access(), &decoded_len,
00243 source.observe(), source.length());
00244 if (dec_ret != 1) {
00245 continuable_error(class_name(), func, "decryption failed.");
00246 to_return = false;
00247 } else {
00248
00249 decoded.zap(decoded_len, decoded.last());
00250 target = decoded;
00251 }
00252
00253
00254 if (dec_ret == 1) {
00255 decoded.reset(FUDGE);
00256 int pad_len = 0;
00257 dec_ret = EVP_DecryptFinal_ex(&session, decoded.access(), &pad_len);
00258
00259 if (dec_ret != 1) {
00260 continuable_error(class_name(), func, isprintf("finalizing decryption "
00261 "failed, result=%d, padlen=%d, target had %d bytes.", dec_ret,
00262 pad_len, target.length()));
00263 to_return = false;
00264 } else {
00265 int dec_size = pad_len;
00266 decoded.zap(dec_size, decoded.last());
00267 target += decoded;
00268 }
00269 }
00270
00271 EVP_CIPHER_CTX_cleanup(&session);
00272 return to_return;
00273 }
00274
00275
00276 #endif //BLOWFISH_CRYPTO_IMPLEMENTATION_FILE
00277