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