1 /*****************************************************************************\
3 * Name : blowfish encryption *
4 * Author : Chris Koeritz *
6 *******************************************************************************
7 * Copyright (c) 2005-$now By Author. This program is free software; you can *
8 * redistribute it and/or modify it under the terms of the GNU General Public *
9 * License as published by the Free Software Foundation; either version 2 of *
10 * the License or (at your option) any later version. This is online at: *
11 * http://www.fsf.org/copyleft/gpl.html *
12 * Please send any updates to: fred@gruntose.com *
13 \*****************************************************************************/
15 #include "blowfish_crypto.h"
18 #include <basis/astring.h>
19 #include <basis/functions.h>
20 #include <basis/mutex.h>
21 #include <loggers/critical_events.h>
22 #include <loggers/program_wide_logger.h>
23 #include <mathematics/chaos.h>
24 #include <structures/static_memory_gremlin.h>
26 #include <openssl/blowfish.h>
27 #include <openssl/evp.h>
29 using namespace basis;
30 using namespace loggers;
31 using namespace mathematics;
32 using namespace structures;
36 const int FUDGE = 128;
37 // extra space for the cipher's block size. blowfish is only 8 bytes for
38 // the cipher block size, but we ensure there will definitely be no
42 // get rid of a macro we don't want.
44 //#define DEBUG_BLOWFISH
45 // uncomment for noisier version.
49 #define LOG(t) CLASS_EMERGENCY_LOG(program_wide_logger::get(), t)
56 // this macro checks on the validity of the key sizes (in bits).
57 #define DISCUSS_KEY_SIZE(key_size) \
58 if (key_size < minimum_key_size()) { \
59 continuable_error(static_class_name(), func, \
60 a_sprintf("key size (%d bits) is less than minimum key size %d.", \
61 key_size, minimum_key_size())); \
63 if (key_size > maximum_key_size()) { \
64 continuable_error(static_class_name(), func, \
65 a_sprintf("key size (%d bits) is greater than maximum key size %d.", \
66 key_size, maximum_key_size())); \
69 // this macro checks that the key in the byte array has enough bytes for
71 #define DISCUSS_PROVIDED_KEY(key_size, key) \
72 if (key.length() * BITS_PER_BYTE < key_size) { \
73 continuable_error(static_class_name(), func, \
74 a_sprintf("key array length (%d) is less than required by key size " \
75 "(%d bits).", key.length(), key_size)); \
78 #define DISCUSS_PROVIDED_KEY(key_size, key)
79 #define DISCUSS_KEY_SIZE(key_size)
82 blowfish_crypto::blowfish_crypto(int key_size)
83 : _key_size(key_size),
87 static_ssl_initializer();
88 LOG("prior to key size discuss");
89 DISCUSS_KEY_SIZE(key_size);
90 if (key_size < minimum_key_size())
91 _key_size = minimum_key_size();
92 if (key_size > maximum_key_size())
93 _key_size = maximum_key_size();
94 LOG("prior to generate key");
95 generate_key(_key_size, *_key);
96 LOG("after generate key");
99 blowfish_crypto::blowfish_crypto(const byte_array &key, int key_size)
100 : _key_size(key_size),
101 _key(new byte_array(key))
103 FUNCDEF("ctor(byte_array,int)");
104 // any problems with the key provided are horrid. they will yield a
105 // non-working blowfish object.
106 LOG("prior to key size discuss");
107 DISCUSS_KEY_SIZE(key_size);
108 LOG("prior to provided key discuss");
109 DISCUSS_PROVIDED_KEY(key_size, key);
110 LOG("prior to ssl static init");
111 static_ssl_initializer();
112 LOG("after ssl static init");
115 blowfish_crypto::blowfish_crypto(const blowfish_crypto &to_copy)
117 _key_size(to_copy._key_size),
118 _key(new byte_array(*to_copy._key))
120 FUNCDEF("copy ctor");
121 static_ssl_initializer();
122 LOG("after ssl static init");
125 blowfish_crypto::~blowfish_crypto()
127 FUNCDEF("destructor");
128 LOG("prior to key whack");
130 LOG("after key whack");
133 int blowfish_crypto::key_size() const { return _key_size; }
135 const byte_array &blowfish_crypto::get_key() const { return *_key; }
137 int blowfish_crypto::minimum_key_size() { return 64; }
139 int blowfish_crypto::maximum_key_size() { return 448; }
141 blowfish_crypto &blowfish_crypto::operator = (const blowfish_crypto &to_copy)
143 if (this == &to_copy) return *this;
144 _key_size = to_copy._key_size;
145 *_key = *to_copy._key;
149 bool blowfish_crypto::set_key(const byte_array &new_key, int key_size)
152 if (!new_key.length()) return false;
153 DISCUSS_KEY_SIZE(key_size);
154 DISCUSS_PROVIDED_KEY(key_size, new_key);
155 if ( (key_size < minimum_key_size()) || (key_size > maximum_key_size()) )
157 if (new_key.length() * BITS_PER_BYTE < key_size) return false;
158 _key_size = key_size;
163 void blowfish_crypto::generate_key(int size, byte_array &new_key)
165 FUNCDEF("generate_key");
166 DISCUSS_KEY_SIZE(size);
167 if (size < minimum_key_size())
168 size = minimum_key_size();
169 else if (size > maximum_key_size())
170 size = maximum_key_size();
171 int bytes = size / BITS_PER_BYTE; // calculate the number of bytes needed.
172 if (size % BITS_PER_BYTE) bytes++; // add one for non-integral portion.
173 new_key.reset(bytes);
174 for (int i = 0; i < bytes; i++)
175 new_key[i] = static_ssl_initializer().randomizer().inclusive(0, 255);
178 SAFE_STATIC(mutex, __vector_init_lock, )
180 const byte_array &blowfish_crypto::init_vector()
182 FUNCDEF("init_vector");
183 auto_synchronizer locking(__vector_init_lock());
184 static byte_array to_return(EVP_MAX_IV_LENGTH);
185 static bool initted = false;
186 LOG("prior to initted check");
188 LOG("actually doing init");
189 for (int i = 0; i < EVP_MAX_IV_LENGTH; i++)
190 to_return[i] = 214 - i;
193 LOG("leaving init check");
197 bool blowfish_crypto::encrypt(const byte_array &source,
198 byte_array &target) const
202 if (!_key->length() || !source.length()) return false;
203 bool to_return = true;
205 // initialize an encoding session.
206 EVP_CIPHER_CTX *session = EVP_CIPHER_CTX_new();
208 EVP_CIPHER_CTX_init(session);
209 EVP_EncryptInit_ex(session, EVP_bf_cbc(), NULL_POINTER, _key->observe(),
210 init_vector().observe());
211 EVP_CIPHER_CTX_set_key_length(session, _key_size);
213 // allocate temporary space for encrypted data.
214 byte_array encoded(source.length() + FUDGE);
216 // encrypt the entire source buffer.
218 int enc_ret = EVP_EncryptUpdate(session, encoded.access(), &encoded_len,
219 source.observe(), source.length());
221 continuable_error(class_name(), func, a_sprintf("encryption failed, "
222 "result=%d.", enc_ret));
225 // chop any extra space off.
226 LOG(a_sprintf("chopping bytes %d to %d.\n", encoded_len, encoded.last()));
227 encoded.zap(encoded_len, encoded.last());
231 // only add padding if we succeeded with the encryption.
233 // finalize the encryption.
234 encoded.reset(FUDGE); // reinflate for padding.
236 enc_ret = EVP_EncryptFinal_ex(session, encoded.access(), &pad_len);
238 continuable_error(class_name(), func, a_sprintf("finalizing encryption "
239 "failed, result=%d.", enc_ret));
242 LOG(a_sprintf("padding added %d bytes.\n", pad_len));
243 encoded.zap(pad_len, encoded.last());
248 EVP_CIPHER_CTX_cleanup(session);
249 EVP_CIPHER_CTX_free(session);
253 bool blowfish_crypto::decrypt(const byte_array &source,
254 byte_array &target) const
258 if (!_key->length() || !source.length()) return false;
259 bool to_return = true;
260 EVP_CIPHER_CTX *session = EVP_CIPHER_CTX_new();
261 EVP_CIPHER_CTX_init(session);
262 LOG(a_sprintf("key size %d bits.\n", BITS_PER_BYTE * _key->length()));
263 EVP_DecryptInit_ex(session, EVP_bf_cbc(), NULL_POINTER, _key->observe(),
264 init_vector().observe());
265 EVP_CIPHER_CTX_set_key_length(session, _key_size);
267 // allocate enough space for decoded bytes.
268 byte_array decoded(source.length() + FUDGE);
271 int dec_ret = EVP_DecryptUpdate(session, decoded.access(), &decoded_len,
272 source.observe(), source.length());
274 continuable_error(class_name(), func, "decryption failed.");
277 LOG(a_sprintf(" decrypted size in bytes is %d.\n", decoded_len));
278 decoded.zap(decoded_len, decoded.last());
282 // only process padding if the first part of decryption succeeded.
284 decoded.reset(FUDGE); // reinflate for padding.
286 dec_ret = EVP_DecryptFinal_ex(session, decoded.access(), &pad_len);
287 LOG(a_sprintf("padding added %d bytes.\n", pad_len));
289 continuable_error(class_name(), func, a_sprintf("finalizing decryption "
290 "failed, result=%d, padlen=%d, target had %d bytes.", dec_ret,
291 pad_len, target.length()));
294 int dec_size = pad_len;
295 decoded.zap(dec_size, decoded.last());
300 EVP_CIPHER_CTX_cleanup(session);
301 EVP_CIPHER_CTX_free(session);