From: Fred T. Hamster Date: Mon, 16 Mar 2026 19:07:20 +0000 (-0400) Subject: super achey breaky change -- switching to twofish X-Git-Url: https://feistymeow.org/gitweb/?a=commitdiff_plain;h=refs%2Fheads%2Fdev;p=feisty_meow.git super achey breaky change -- switching to twofish we've renamed blowfish crypto in honor of openssl breaking it for us, seemingly. and we're going to just drop in a replacement of twofish. however, right now, that's still in progress, so this code will not build yet. --- diff --git a/nucleus/library/crypto/blowfish_crypto.cpp b/nucleus/library/crypto/blowfish_crypto.cpp deleted file mode 100644 index 02ce5008..00000000 --- a/nucleus/library/crypto/blowfish_crypto.cpp +++ /dev/null @@ -1,371 +0,0 @@ -/* -* Name : blowfish encryption -* Author : Chris Koeritz -***** -* Copyright (c) 2005-$now By Author. This program is free software; you can -* redistribute it and/or modify it under the terms of the GNU General Public -* License as published by the Free Software Foundation; either version 2 of -* the License or (at your option) any later version. This is online at: -* http://www.fsf.org/copyleft/gpl.html -* Please send any updates to: fred@gruntose.com -*/ - -#include "blowfish_crypto.h" -#include "ssl_init.h" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -using namespace basis; -using namespace loggers; -using namespace mathematics; -using namespace structures; - -namespace crypto { - -////const int FUDGE = 128; - // extra space for the cipher's block size. blowfish is only 8 bytes for - // the cipher block size, but we ensure there will definitely be no - // problems. - -//#undef set_key - // get rid of a macro we don't want. - -//#define DEBUG_BLOWFISH - // uncomment for noisier version. -#undef ALWAYS_LOG -#define ALWAYS_LOG(t) CLASS_EMERGENCY_LOG(program_wide_logger::get(), t) -#ifdef DEBUG_BLOWFISH - #undef LOG - #define LOG(t) CLASS_EMERGENCY_LOG(program_wide_logger::get(), t) -#else - #undef LOG - #define LOG(t) -#endif - -// helpful macro for the error string of last failure. -//#define GET_SSL_ERROR() \ -// ERR_error_string(ERR_get_error(), NULL_POINTER) - -/* -#ifdef DEBUG_BLOWFISH - // this macro checks on the validity of the key sizes (in bits). - #define DISCUSS_KEY_SIZE(key_size) \ - if (key_size < minimum_key_size()) { \ - deadly_error(static_class_name(), func, \ - a_sprintf("key size (%d bits) is less than minimum key size %d.", \ - key_size, minimum_key_size())); \ - } \ - if (key_size > maximum_key_size()) { \ - deadly_error(static_class_name(), func, \ - a_sprintf("key size (%d bits) is greater than maximum key size %d.", \ - key_size, maximum_key_size())); \ - } - - // this macro checks that the key in the byte array has enough bytes for - // the key size bits. - #define DISCUSS_PROVIDED_KEY(key_size, key) \ - if (key.length() * BITS_PER_BYTE < key_size) { \ - deadly_error(static_class_name(), func, \ - a_sprintf("key array length (%d) is less than required by key size " \ - "(%d bits).", key.length(), key_size)); \ - } -#else - #define DISCUSS_PROVIDED_KEY(key_size, key) - #define DISCUSS_KEY_SIZE(key_size) -#endif -*/ - -blowfish_crypto::blowfish_crypto(int key_size) -: cryptical_envelopment(EVP_bf_cbc()) -///_key_size(key_size), -/// _key(new byte_array) -{ - set_key(key_size); -/* - FUNCDEF("ctor(int)"); - static_ssl_initializer(); - LOG("prior to key size discuss"); - DISCUSS_KEY_SIZE(key_size); - if (key_size < minimum_key_size()) - _key_size = minimum_key_size(); - if (key_size > maximum_key_size()) - _key_size = maximum_key_size(); - LOG("prior to generate key"); - generate_key(_key_size, *_key); - LOG("after generate key"); -*/ -} - -blowfish_crypto::blowfish_crypto(const byte_array &key, int key_size) -: cryptical_envelopment(EVP_bf_cbc()) -//: _key_size(key_size), -// _key(new byte_array(key)) -{ - set_key(key, key_size); -/* - FUNCDEF("ctor(byte_array,int)"); - static_ssl_initializer(); - // any problems with the key provided are horrid. they will yield a - // non-working blowfish object. - LOG("prior to key size discuss"); - DISCUSS_KEY_SIZE(key_size); - LOG("prior to provided key discuss"); - DISCUSS_PROVIDED_KEY(key_size, key); - LOG("prior to ssl static init"); - LOG("after ssl static init"); -*/ -} - -blowfish_crypto::blowfish_crypto(const blowfish_crypto &to_copy) -: root_object(), - cryptical_envelopment(*this) -/// _key_size(to_copy._key_size), -/// _key(new byte_array(*to_copy._key)) -{ -/// FUNCDEF("copy ctor"); -/// static_ssl_initializer(); -/// LOG("after ssl static init"); -} - -blowfish_crypto::~blowfish_crypto() -{ -/* - FUNCDEF("destructor"); - LOG("prior to key whack"); - WHACK(_key); - LOG("after key whack"); -*/ -} - -/* -int blowfish_crypto::key_size() const { return _key_size; } - -const byte_array &blowfish_crypto::get_key() const { return *_key; } - -int blowfish_crypto::minimum_key_size() { return 64; } - -int blowfish_crypto::maximum_key_size() { return 448; } -*/ - -blowfish_crypto &blowfish_crypto::operator = (const blowfish_crypto &to_copy) -{ - if (this == &to_copy) return *this; - *((cryptical_envelopment *)this) = *((cryptical_envelopment *)&to_copy); -//hmmm: is that the best way to do this? - -// _key_size = to_copy._key_size; -// *_key = *to_copy._key; - return *this; -} - -/* -bool blowfish_crypto::set_key(const byte_array &new_key, int key_size) -{ - FUNCDEF("set_key"); - if (!new_key.length()) return false; - DISCUSS_KEY_SIZE(key_size); - DISCUSS_PROVIDED_KEY(key_size, new_key); - if ( (key_size < minimum_key_size()) || (key_size > maximum_key_size()) ) - return false; - if (new_key.length() * BITS_PER_BYTE < key_size) return false; - _key_size = key_size; - *_key = new_key; - return true; -} - -void blowfish_crypto::generate_key(int size, byte_array &new_key) -{ - FUNCDEF("generate_key"); - static_ssl_initializer(); - DISCUSS_KEY_SIZE(size); - if (size < minimum_key_size()) - size = minimum_key_size(); - else if (size > maximum_key_size()) - size = maximum_key_size(); - int bytes = size / BITS_PER_BYTE; // calculate the number of bytes needed. - if (size % BITS_PER_BYTE) bytes++; // add one for non-integral portion. - new_key.reset(bytes); - for (int i = 0; i < bytes; i++) - new_key[i] = static_ssl_initializer().randomizer().inclusive(0, 255); -} - -SAFE_STATIC(mutex, __vector_init_lock, ) - -const byte_array &blowfish_crypto::init_vector() -{ - FUNCDEF("init_vector"); - static_ssl_initializer(); - auto_synchronizer locking(__vector_init_lock()); - static byte_array to_return(EVP_MAX_IV_LENGTH); - static bool initted = false; - if (!initted) { - LOG("actually doing init"); - for (int i = 0; i < to_return.length(); i++) - to_return[i] = abyte(214 - i); - initted = true; - LOG("finished init process"); - } - return to_return; -} - -bool blowfish_crypto::encrypt(const byte_array &source, - byte_array &target) const -{ - FUNCDEF("encrypt"); -ALWAYS_LOG(">>encrypt>>"); - target.reset(); - if (!_key->length() || !source.length()) return false; - bool to_return = true; - -LOG(a_sprintf(" encrypting %d bytes", source.length())); - - // initialize an encoding session. - EVP_CIPHER_CTX *session = EVP_CIPHER_CTX_new(); - EVP_CIPHER_CTX_init(session); - -//new rules! -//EVP_EncryptInit to set the cipher, but leave key and IV null and unset -//EVP_CIPHER_CTX_set_key_length and EVP_CTRL_AEAD_SET_IVLEN -//EVP_EncryptInit again. This time leave cipher null, because you've already set it, and set the key and IV. - - int initret = EVP_EncryptInit_ex(session, EVP_bf_cbc(), NULL_POINTER, NULL_POINTER, NULL_POINTER); - if (!initret) { - // zero means a failure of the initialization. - ALWAYS_LOG(a_sprintf("failure in calling EVP_EncryptInit_ex, with error %s", GET_SSL_ERROR())); - exit(1); - } - LOG(a_sprintf(" calling set key len with key size of %d", _key_size)); - // new fancy footwork needed to keep openssl from blowing up and claiming we didn't set the key. -//hmmm: check returns on these setters? - EVP_CIPHER_CTX_set_key_length(session, _key_size); - EVP_CIPHER_CTX_ctrl(session, EVP_CTRL_AEAD_SET_IVLEN, init_vector().length(), NULL); - // and round and round we go... - initret = EVP_EncryptInit_ex(session, NULL_POINTER, NULL_POINTER, _key->observe(), init_vector().observe()); - if (!initret) { - // zero means a failure of the initialization. - ALWAYS_LOG(a_sprintf("second phase failure in calling EVP_EncryptInit_ex, with error %s", GET_SSL_ERROR())); - exit(1); - } - - // allocate temporary space for encrypted data. - byte_array encoded(source.length() + FUDGE); - - // encrypt the entire source buffer. - int encoded_len = 0; - int enc_ret = EVP_EncryptUpdate(session, encoded.access(), &encoded_len, - source.observe(), source.length()); - if (enc_ret != 1) { - deadly_error(class_name(), func, a_sprintf("encryption failed, " - "result=%d with error=%s.", enc_ret, GET_SSL_ERROR())); - to_return = false; - } else { - // chop any extra space off. - LOG(a_sprintf(" chopping extra bytes %d to %d.", encoded_len, encoded.last())); - encoded.zap(encoded_len, encoded.last()); - target = encoded; - } - - // only add padding if we succeeded with the encryption. - if (enc_ret == 1) { - // finalize the encryption. - encoded.reset(FUDGE); // reinflate for padding. - int pad_len = 0; - enc_ret = EVP_EncryptFinal_ex(session, encoded.access(), &pad_len); - if (enc_ret != 1) { - deadly_error(class_name(), func, a_sprintf("finalizing encryption " - "failed, result=%d with error=%s.", enc_ret, GET_SSL_ERROR())); - to_return = false; - } else { - LOG(a_sprintf(" padding added %d bytes.", pad_len)); - encoded.zap(pad_len, encoded.last()); - target += encoded; - } - } - - EVP_CIPHER_CTX_cleanup(session); - EVP_CIPHER_CTX_free(session); -ALWAYS_LOG("<>decrypt>>"); - target.reset(); - if (!_key->length() || !source.length()) return false; - bool to_return = true; - EVP_CIPHER_CTX *session = EVP_CIPHER_CTX_new(); - EVP_CIPHER_CTX_init(session); - LOG(a_sprintf(" using key size with %d bits.", _key_size)); -///NOOOOOOO BITS_PER_BYTE * _key->length())); - int initret = EVP_DecryptInit_ex(session, EVP_bf_cbc(), NULL_POINTER, NULL_POINTER, NULL_POINTER); - if (!initret) { - // zero means a failure of the initialization. -//hmmm: below approach is called a deadly error. use that instead, throughout. - ALWAYS_LOG(a_sprintf("failure in calling EVP_DecryptInit_ex, with error %s", GET_SSL_ERROR())); - exit(1); - } - // more fancy fupwork. -//hmmm: check returns on these setters? - EVP_CIPHER_CTX_set_key_length(session, _key_size); - EVP_CIPHER_CTX_ctrl(session, EVP_CTRL_AEAD_SET_IVLEN, init_vector().length(), NULL); - initret = EVP_DecryptInit_ex(session, NULL_POINTER, NULL_POINTER, _key->observe(), init_vector().observe()); - if (!initret) { - // zero means a failure of the initialization. - ALWAYS_LOG(a_sprintf("second phase failure in calling EVP_DecryptInit_ex, with error %s", GET_SSL_ERROR())); - exit(1); - } - - // allocate enough space for decoded bytes. - byte_array decoded(source.length() + FUDGE); - - int decoded_len = 0; - int dec_ret = EVP_DecryptUpdate(session, decoded.access(), &decoded_len, - source.observe(), source.length()); - if (dec_ret != 1) { - deadly_error(class_name(), func, a_sprintf("decryption failed with error=%s", GET_SSL_ERROR())); - to_return = false; - } else { - LOG(a_sprintf(" first part decrypted size in bytes is %d.", decoded_len)); - decoded.zap(decoded_len, decoded.last()); - target = decoded; - } - - // only process padding if the first part of decryption succeeded. - if (dec_ret == 1) { - decoded.reset(FUDGE); // reinflate for padding. - int pad_len = 0; - dec_ret = EVP_DecryptFinal_ex(session, decoded.access(), &pad_len); - if (dec_ret != 1) { - deadly_error(class_name(), func, a_sprintf("finalizing decryption " - "failed, result=%d, padlen=%d, target had %d bytes, error=%s.", dec_ret, - pad_len, target.length(), GET_SSL_ERROR())); - to_return = false; - } else { - LOG(a_sprintf(" padding added %d bytes.", pad_len)); - decoded.zap(pad_len, decoded.last()); - target += decoded; - } - } - - EVP_CIPHER_CTX_cleanup(session); - EVP_CIPHER_CTX_free(session); -ALWAYS_LOG("< -#include - -#include "cryptical_envelopment.h" - -namespace crypto { - -//! Provides BlowFish encryption on byte_arrays using the OpenSSL package. - -class blowfish_crypto : public cryptical_envelopment -//: public virtual basis::root_object -{ -public: - blowfish_crypto(int key_size); - //!< this will create a new random key of the "key_size", in bits. - /*!< the valid sizes are from 64 bits to 448 bits (we are forcing a - higher minimum than the published algorithm because we have found smaller - keys to be unreliable during decryption. keys of 168 bits and larger - should be very secure. it is said that if a billion computers each tried - a billion keys a second, then a 168 bit key would take 10 * 10^24 years - to break (using brute force). this is essentially unbreakable since the - age of the universe is only 10 * 10^9 years so far. */ - - blowfish_crypto(const basis::byte_array &key, int key_size); - //!< uses a pre-existing "key". - - blowfish_crypto(const blowfish_crypto &to_copy); //!< copy constructor. - - virtual ~blowfish_crypto(); - - blowfish_crypto &operator = (const blowfish_crypto &to_copy); - - DEFINE_CLASS_NAME("blowfish_crypto"); - - // blowfish relevant values for appropriate key sizes. - virtual int minimum_key_size() const { return 32; } - virtual int maximum_key_size() const { return 448; } - -/// int key_size() const; // returns the size of our key, in bits. - -/// static int minimum_key_size(); -/// //!< returns the minimum key size (in bits) supported here. -/// static int maximum_key_size(); -/// //!< returns the maximum key size (in bits) supported here. - -/// const basis::byte_array &get_key() const; //!< returns our current key. - -/// bool set_key(const basis::byte_array &new_key, int key_size); - //!< sets the encryption key to "new_key". - -/// static void generate_key(int size, basis::byte_array &new_key); - //!< creates a "new_key" of the "size" (in bits) specified. - -/// bool encrypt(const basis::byte_array &source, basis::byte_array &target) const; - //!< encrypts the "source" array into the "target" array. - -/// bool decrypt(const basis::byte_array &source, basis::byte_array &target) const; - //!< decrypts the "target" array from the encrypted "source" array. - - // seldom-needed methods... - -/// static const basis::byte_array &init_vector(); - //!< returns the initialization vector that is used by this class. - /*!< decryption of chunks that were encrypted by this class will require - the same init vector as this function returns. this is mainly provided - for third-party applications that want to be able to decrypt interoperably - with this class. if you are creating such an application but for some - reason cannot run this class in order to invoke this method, the vector - is created by the algorithm in this class's implementation file - (currently named blowfish_crypto.cpp). */ - -private: -/// int _key_size; //!< number of bits in the key. -/// basis::byte_array *_key; //!< our secret key. -}; - -} //namespace. - -#endif - diff --git a/nucleus/library/crypto/borked_blowfish_crypto.cpp b/nucleus/library/crypto/borked_blowfish_crypto.cpp new file mode 100644 index 00000000..f912d847 --- /dev/null +++ b/nucleus/library/crypto/borked_blowfish_crypto.cpp @@ -0,0 +1,77 @@ +/* +* Name : borked_blowfish_crypto +* Author : Chris Koeritz +***** +* Copyright (c) 2005-$now By Author. This program is free software; you can +* redistribute it and/or modify it under the terms of the GNU General Public +* License as published by the Free Software Foundation; either version 2 of +* the License or (at your option) any later version. This is online at: +* http://www.fsf.org/copyleft/gpl.html +* Please send any updates to: fred@gruntose.com +*/ + +#include "borked_blowfish_crypto.h" +#include "ssl_init.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace basis; +using namespace loggers; +using namespace mathematics; +using namespace structures; + +namespace crypto { + +//#define DEBUG_BLOWFISH + // uncomment for noisier version. +#undef ALWAYS_LOG +#define ALWAYS_LOG(t) CLASS_EMERGENCY_LOG(program_wide_logger::get(), t) +#ifdef DEBUG_BLOWFISH + #undef LOG + #define LOG(t) CLASS_EMERGENCY_LOG(program_wide_logger::get(), t) +#else + #undef LOG + #define LOG(t) +#endif + +borked_blowfish_crypto::borked_blowfish_crypto(int key_size) +: cryptical_envelopment(EVP_bf_cbc()) +{ + set_key(key_size); +} + +borked_blowfish_crypto::borked_blowfish_crypto(const byte_array &key, int key_size) +: cryptical_envelopment(EVP_bf_cbc()) +{ + set_key(key, key_size); +} + +borked_blowfish_crypto::borked_blowfish_crypto(const borked_blowfish_crypto &to_copy) +: root_object(), + cryptical_envelopment(*this) +{ +} + +borked_blowfish_crypto::~borked_blowfish_crypto() +{ +} + +borked_blowfish_crypto &borked_blowfish_crypto::operator = (const borked_blowfish_crypto &to_copy) +{ + if (this == &to_copy) return *this; + *((cryptical_envelopment *)this) = *((cryptical_envelopment *)&to_copy); +//hmmm: is that the best way to do this? + return *this; +} + +} //namespace. + diff --git a/nucleus/library/crypto/borked_blowfish_crypto.h b/nucleus/library/crypto/borked_blowfish_crypto.h new file mode 100644 index 00000000..dfe0709d --- /dev/null +++ b/nucleus/library/crypto/borked_blowfish_crypto.h @@ -0,0 +1,64 @@ +#ifndef BLOWFISH_CRYPTO_CLASS +#define BLOWFISH_CRYPTO_CLASS + +/* +* Name : borked_blowfish_crypto +* Author : Chris Koeritz +* Purpose: provides BlowFish encryption on byte_arrays using the OpenSSL package. +**** +* Copyright (c) 2005-$now By Author. This program is free software; you can +* redistribute it and/or modify it under the terms of the GNU General Public +* License as published by the Free Software Foundation; either version 2 of +* the License or (at your option) any later version. This is online at: +* http://www.fsf.org/copyleft/gpl.html +* Please send any updates to: fred@gruntose.com +*/ + +/* + * NOTE: + * this class is currently failing with bad decrypt, which we actually blame the openssl + * libraries for. we have the same exact underlying usage of cryptical_envelopment class + * to drive the EVP functions for our twofish implementation, and it never has that issue. + * our blowfish implementation *used* to work fine, until openssl 3 or so. + */ + +#include +#include + +#include "cryptical_envelopment.h" + +namespace crypto { + +class borked_blowfish_crypto : public cryptical_envelopment +{ +public: + borked_blowfish_crypto(int key_size); + //!< this will create a new random key of the "key_size", in bits. + /*!< the valid sizes are from 64 bits to 448 bits (we are forcing a + higher minimum than the published algorithm because we have found smaller + keys to be unreliable during decryption. keys of 168 bits and larger + should be very secure. it is said that if a billion computers each tried + a billion keys a second, then a 168 bit key would take 10 * 10^24 years + to break (using brute force). this is essentially unbreakable since the + age of the universe is only 10 * 10^9 years so far. */ + + borked_blowfish_crypto(const basis::byte_array &key, int key_size); + //!< uses a pre-existing "key". + + borked_blowfish_crypto(const borked_blowfish_crypto &to_copy); //!< copy constructor. + + virtual ~borked_blowfish_crypto(); + + borked_blowfish_crypto &operator = (const borked_blowfish_crypto &to_copy); + + DEFINE_CLASS_NAME("borked_blowfish_crypto"); + + // blowfish relevant values for appropriate key sizes. + virtual int minimum_key_size() const { return 64; } // officially, this is 32. + virtual int maximum_key_size() const { return 448; } +}; + +} //namespace. + +#endif + diff --git a/nucleus/library/crypto/makefile b/nucleus/library/crypto/makefile index 4ba15f86..ec80a34f 100644 --- a/nucleus/library/crypto/makefile +++ b/nucleus/library/crypto/makefile @@ -4,7 +4,7 @@ include cpp/variables.def TYPE = library PROJECT = crypto -SOURCE = blowfish_crypto.cpp cryptical_envelopment.cpp old_school_rsa_crypto.cpp ssl_init.cpp twofish_crypto.cpp +SOURCE = borked_blowfish_crypto.cpp cryptical_envelopment.cpp old_school_rsa_crypto.cpp ssl_init.cpp twofish_crypto.cpp USE_SSL = t TARGETS = crypto.lib diff --git a/nucleus/library/crypto/twofish_crypto.cpp b/nucleus/library/crypto/twofish_crypto.cpp index ea9ad793..41bd802a 100644 --- a/nucleus/library/crypto/twofish_crypto.cpp +++ b/nucleus/library/crypto/twofish_crypto.cpp @@ -21,7 +21,6 @@ #include #include -//#include #include #include @@ -30,15 +29,16 @@ using namespace loggers; using namespace mathematics; using namespace structures; -namespace crypto { - -////const int FUDGE = 128; - // extra space for the cipher's block size. twofish is only 8 bytes for - // the cipher block size, but we ensure there will definitely be no - // problems. +/* + Q: is twofish truly requiring 128/192/256 key sizes only? + A: no, schneier says any key size up to 256 bits. + Q: can twofish really support *any* key length up to 256? + A: well, not in openssl. we are getting invalid key length complaints + with keys below 92 bits. this was calculated by testing for quite + a while with only those size keys, and 92 seems reliable as a minimum. +*/ -//#undef set_key - // get rid of a macro we don't want. +namespace crypto { //#define DEBUG_TWOFISH // uncomment for noisier version. @@ -52,321 +52,35 @@ namespace crypto { #define LOG(t) #endif -// helpful macro for the error string of last failure. -//#define GET_SSL_ERROR() \ -// ERR_error_string(ERR_get_error(), NULL_POINTER) - -/* -#ifdef DEBUG_TWOFISH - // this macro checks on the validity of the key sizes (in bits). - #define DISCUSS_KEY_SIZE(key_size) \ - if (key_size < minimum_key_size()) { \ - deadly_error(static_class_name(), func, \ - a_sprintf("key size (%d bits) is less than minimum key size %d.", \ - key_size, minimum_key_size())); \ - } \ - if (key_size > maximum_key_size()) { \ - deadly_error(static_class_name(), func, \ - a_sprintf("key size (%d bits) is greater than maximum key size %d.", \ - key_size, maximum_key_size())); \ - } - - // this macro checks that the key in the byte array has enough bytes for - // the key size bits. - #define DISCUSS_PROVIDED_KEY(key_size, key) \ - if (key.length() * BITS_PER_BYTE < key_size) { \ - deadly_error(static_class_name(), func, \ - a_sprintf("key array length (%d) is less than required by key size " \ - "(%d bits).", key.length(), key_size)); \ - } -#else - #define DISCUSS_PROVIDED_KEY(key_size, key) - #define DISCUSS_KEY_SIZE(key_size) -#endif -*/ - twofish_crypto::twofish_crypto(int key_size) : cryptical_envelopment(EVP_aes_256_cbc()) -///_key_size(key_size), -/// _key(new byte_array) { set_key(key_size); -/* - FUNCDEF("ctor(int)"); - static_ssl_initializer(); - LOG("prior to key size discuss"); - DISCUSS_KEY_SIZE(key_size); - if (key_size < minimum_key_size()) - _key_size = minimum_key_size(); - if (key_size > maximum_key_size()) - _key_size = maximum_key_size(); - LOG("prior to generate key"); - generate_key(_key_size, *_key); - LOG("after generate key"); -*/ } twofish_crypto::twofish_crypto(const byte_array &key, int key_size) : cryptical_envelopment(EVP_aes_256_cbc()) -//: _key_size(key_size), -// _key(new byte_array(key)) { set_key(key, key_size); -/* - FUNCDEF("ctor(byte_array,int)"); - static_ssl_initializer(); - // any problems with the key provided are horrid. they will yield a - // non-working twofish object. - LOG("prior to key size discuss"); - DISCUSS_KEY_SIZE(key_size); - LOG("prior to provided key discuss"); - DISCUSS_PROVIDED_KEY(key_size, key); - LOG("prior to ssl static init"); - LOG("after ssl static init"); -*/ } twofish_crypto::twofish_crypto(const twofish_crypto &to_copy) : root_object(), cryptical_envelopment(*this) -/// _key_size(to_copy._key_size), -/// _key(new byte_array(*to_copy._key)) { -/// FUNCDEF("copy ctor"); -/// static_ssl_initializer(); -/// LOG("after ssl static init"); } twofish_crypto::~twofish_crypto() { -/* - FUNCDEF("destructor"); - LOG("prior to key whack"); - WHACK(_key); - LOG("after key whack"); -*/ } -/* -int twofish_crypto::key_size() const { return _key_size; } - -const byte_array &twofish_crypto::get_key() const { return *_key; } - -int twofish_crypto::minimum_key_size() { return 64; } - -int twofish_crypto::maximum_key_size() { return 448; } -*/ - twofish_crypto &twofish_crypto::operator = (const twofish_crypto &to_copy) { if (this == &to_copy) return *this; *((cryptical_envelopment *)this) = *((cryptical_envelopment *)&to_copy); //hmmm: is that the best way to do this? - -// _key_size = to_copy._key_size; -// *_key = *to_copy._key; return *this; } -/* -bool twofish_crypto::set_key(const byte_array &new_key, int key_size) -{ - FUNCDEF("set_key"); - if (!new_key.length()) return false; - DISCUSS_KEY_SIZE(key_size); - DISCUSS_PROVIDED_KEY(key_size, new_key); - if ( (key_size < minimum_key_size()) || (key_size > maximum_key_size()) ) - return false; - if (new_key.length() * BITS_PER_BYTE < key_size) return false; - _key_size = key_size; - *_key = new_key; - return true; -} - -void twofish_crypto::generate_key(int size, byte_array &new_key) -{ - FUNCDEF("generate_key"); - static_ssl_initializer(); - DISCUSS_KEY_SIZE(size); - if (size < minimum_key_size()) - size = minimum_key_size(); - else if (size > maximum_key_size()) - size = maximum_key_size(); - int bytes = size / BITS_PER_BYTE; // calculate the number of bytes needed. - if (size % BITS_PER_BYTE) bytes++; // add one for non-integral portion. - new_key.reset(bytes); - for (int i = 0; i < bytes; i++) - new_key[i] = static_ssl_initializer().randomizer().inclusive(0, 255); -} - -SAFE_STATIC(mutex, __vector_init_lock, ) - -const byte_array &twofish_crypto::init_vector() -{ - FUNCDEF("init_vector"); - static_ssl_initializer(); - auto_synchronizer locking(__vector_init_lock()); - static byte_array to_return(EVP_MAX_IV_LENGTH); - static bool initted = false; - if (!initted) { - LOG("actually doing init"); - for (int i = 0; i < to_return.length(); i++) - to_return[i] = abyte(214 - i); - initted = true; - LOG("finished init process"); - } - return to_return; -} - -bool twofish_crypto::encrypt(const byte_array &source, - byte_array &target) const -{ - FUNCDEF("encrypt"); -ALWAYS_LOG(">>encrypt>>"); - target.reset(); - if (!_key->length() || !source.length()) return false; - bool to_return = true; - -LOG(a_sprintf(" encrypting %d bytes", source.length())); - - // initialize an encoding session. - EVP_CIPHER_CTX *session = EVP_CIPHER_CTX_new(); - EVP_CIPHER_CTX_init(session); - -//new rules! -//EVP_EncryptInit to set the cipher, but leave key and IV null and unset -//EVP_CIPHER_CTX_set_key_length and EVP_CTRL_AEAD_SET_IVLEN -//EVP_EncryptInit again. This time leave cipher null, because you've already set it, and set the key and IV. - - int initret = EVP_EncryptInit_ex(session, EVP_bf_cbc(), NULL_POINTER, NULL_POINTER, NULL_POINTER); - if (!initret) { - // zero means a failure of the initialization. - ALWAYS_LOG(a_sprintf("failure in calling EVP_EncryptInit_ex, with error %s", GET_SSL_ERROR())); - exit(1); - } - LOG(a_sprintf(" calling set key len with key size of %d", _key_size)); - // new fancy footwork needed to keep openssl from blowing up and claiming we didn't set the key. -//hmmm: check returns on these setters? - EVP_CIPHER_CTX_set_key_length(session, _key_size); - EVP_CIPHER_CTX_ctrl(session, EVP_CTRL_AEAD_SET_IVLEN, init_vector().length(), NULL); - // and round and round we go... - initret = EVP_EncryptInit_ex(session, NULL_POINTER, NULL_POINTER, _key->observe(), init_vector().observe()); - if (!initret) { - // zero means a failure of the initialization. - ALWAYS_LOG(a_sprintf("second phase failure in calling EVP_EncryptInit_ex, with error %s", GET_SSL_ERROR())); - exit(1); - } - - // allocate temporary space for encrypted data. - byte_array encoded(source.length() + FUDGE); - - // encrypt the entire source buffer. - int encoded_len = 0; - int enc_ret = EVP_EncryptUpdate(session, encoded.access(), &encoded_len, - source.observe(), source.length()); - if (enc_ret != 1) { - deadly_error(class_name(), func, a_sprintf("encryption failed, " - "result=%d with error=%s.", enc_ret, GET_SSL_ERROR())); - to_return = false; - } else { - // chop any extra space off. - LOG(a_sprintf(" chopping extra bytes %d to %d.", encoded_len, encoded.last())); - encoded.zap(encoded_len, encoded.last()); - target = encoded; - } - - // only add padding if we succeeded with the encryption. - if (enc_ret == 1) { - // finalize the encryption. - encoded.reset(FUDGE); // reinflate for padding. - int pad_len = 0; - enc_ret = EVP_EncryptFinal_ex(session, encoded.access(), &pad_len); - if (enc_ret != 1) { - deadly_error(class_name(), func, a_sprintf("finalizing encryption " - "failed, result=%d with error=%s.", enc_ret, GET_SSL_ERROR())); - to_return = false; - } else { - LOG(a_sprintf(" padding added %d bytes.", pad_len)); - encoded.zap(pad_len, encoded.last()); - target += encoded; - } - } - - EVP_CIPHER_CTX_cleanup(session); - EVP_CIPHER_CTX_free(session); -ALWAYS_LOG("<>decrypt>>"); - target.reset(); - if (!_key->length() || !source.length()) return false; - bool to_return = true; - EVP_CIPHER_CTX *session = EVP_CIPHER_CTX_new(); - EVP_CIPHER_CTX_init(session); - LOG(a_sprintf(" using key size with %d bits.", _key_size)); -///NOOOOOOO BITS_PER_BYTE * _key->length())); - int initret = EVP_DecryptInit_ex(session, EVP_bf_cbc(), NULL_POINTER, NULL_POINTER, NULL_POINTER); - if (!initret) { - // zero means a failure of the initialization. -//hmmm: below approach is called a deadly error. use that instead, throughout. - ALWAYS_LOG(a_sprintf("failure in calling EVP_DecryptInit_ex, with error %s", GET_SSL_ERROR())); - exit(1); - } - // more fancy fupwork. -//hmmm: check returns on these setters? - EVP_CIPHER_CTX_set_key_length(session, _key_size); - EVP_CIPHER_CTX_ctrl(session, EVP_CTRL_AEAD_SET_IVLEN, init_vector().length(), NULL); - initret = EVP_DecryptInit_ex(session, NULL_POINTER, NULL_POINTER, _key->observe(), init_vector().observe()); - if (!initret) { - // zero means a failure of the initialization. - ALWAYS_LOG(a_sprintf("second phase failure in calling EVP_DecryptInit_ex, with error %s", GET_SSL_ERROR())); - exit(1); - } - - // allocate enough space for decoded bytes. - byte_array decoded(source.length() + FUDGE); - - int decoded_len = 0; - int dec_ret = EVP_DecryptUpdate(session, decoded.access(), &decoded_len, - source.observe(), source.length()); - if (dec_ret != 1) { - deadly_error(class_name(), func, a_sprintf("decryption failed with error=%s", GET_SSL_ERROR())); - to_return = false; - } else { - LOG(a_sprintf(" first part decrypted size in bytes is %d.", decoded_len)); - decoded.zap(decoded_len, decoded.last()); - target = decoded; - } - - // only process padding if the first part of decryption succeeded. - if (dec_ret == 1) { - decoded.reset(FUDGE); // reinflate for padding. - int pad_len = 0; - dec_ret = EVP_DecryptFinal_ex(session, decoded.access(), &pad_len); - if (dec_ret != 1) { - deadly_error(class_name(), func, a_sprintf("finalizing decryption " - "failed, result=%d, padlen=%d, target had %d bytes, error=%s.", dec_ret, - pad_len, target.length(), GET_SSL_ERROR())); - to_return = false; - } else { - LOG(a_sprintf(" padding added %d bytes.", pad_len)); - decoded.zap(pad_len, decoded.last()); - target += decoded; - } - } - - EVP_CIPHER_CTX_cleanup(session); - EVP_CIPHER_CTX_free(session); -ALWAYS_LOG("< #include @@ -22,21 +21,14 @@ namespace crypto { -//! Provides TwoFish encryption on byte_arrays using the OpenSSL package. - class twofish_crypto : public cryptical_envelopment -//: public virtual basis::root_object { public: twofish_crypto(int key_size); //!< this will create a new random key of the "key_size", in bits. - /*!< the valid sizes are from 64 bits to 448 bits (we are forcing a - higher minimum than the published algorithm because we have found smaller - keys to be unreliable during decryption. keys of 168 bits and larger - should be very secure. it is said that if a billion computers each tried - a billion keys a second, then a 168 bit key would take 10 * 10^24 years - to break (using brute force). this is essentially unbreakable since the - age of the universe is only 10 * 10^9 years so far. */ + /*!< the valid sizes are from 128 bits to 256 bits. AES apparently only + requires that 128, 192 and 256 actually work, but the intervening key + sizes should be fine also. */ twofish_crypto(const basis::byte_array &key, int key_size); //!< uses a pre-existing "key". @@ -59,43 +51,6 @@ public: not the kind of deterministic behavior we might expect. */ virtual int maximum_key_size() const { return 256; } - -/// int key_size() const; // returns the size of our key, in bits. - -/// static int minimum_key_size(); -/// //!< returns the minimum key size (in bits) supported here. -/// static int maximum_key_size(); -/// //!< returns the maximum key size (in bits) supported here. - -/// const basis::byte_array &get_key() const; //!< returns our current key. - -/// bool set_key(const basis::byte_array &new_key, int key_size); - //!< sets the encryption key to "new_key". - -/// static void generate_key(int size, basis::byte_array &new_key); - //!< creates a "new_key" of the "size" (in bits) specified. - -/// bool encrypt(const basis::byte_array &source, basis::byte_array &target) const; - //!< encrypts the "source" array into the "target" array. - -/// bool decrypt(const basis::byte_array &source, basis::byte_array &target) const; - //!< decrypts the "target" array from the encrypted "source" array. - - // seldom-needed methods... - -/// static const basis::byte_array &init_vector(); - //!< returns the initialization vector that is used by this class. - /*!< decryption of chunks that were encrypted by this class will require - the same init vector as this function returns. this is mainly provided - for third-party applications that want to be able to decrypt interoperably - with this class. if you are creating such an application but for some - reason cannot run this class in order to invoke this method, the vector - is created by the algorithm in this class's implementation file - (currently named twofish_crypto.cpp). */ - -private: -/// int _key_size; //!< number of bits in the key. -/// basis::byte_array *_key; //!< our secret key. }; } //namespace. diff --git a/nucleus/library/tests_crypto/makefile b/nucleus/library/tests_crypto/makefile index 58b9ff7c..58b48471 100644 --- a/nucleus/library/tests_crypto/makefile +++ b/nucleus/library/tests_crypto/makefile @@ -2,7 +2,9 @@ include cpp/variables.def PROJECT = tests_crypto TYPE = test -TARGETS = test_blowfish_crypto.exe test_old_school_rsa_crypto.exe test_twofish_crypto.exe +TARGETS = test_blowfish_crypto.exe test_old_school_rsa_crypto.exe test_twofish_crypto.exe +# test_blowfish_crypto.exe -- currently blows up, which we think is an error in openssl, because the twofish crypto works perfectly using the same +# cryptical envelopment base. this is annoying, but we could stop using the legacy provider entirely if we didn't do blowfish any more. not yet. LOCAL_LIBS_USED = unit_test crypto application processes loggers configuration textual timely \ filesystem structures basis USE_SSL = t diff --git a/nucleus/library/tests_crypto/test_blowfish_crypto.cpp b/nucleus/library/tests_crypto/test_blowfish_crypto.cpp index 3baff5d7..4fa124ee 100644 --- a/nucleus/library/tests_crypto/test_blowfish_crypto.cpp +++ b/nucleus/library/tests_crypto/test_blowfish_crypto.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include @@ -57,9 +57,9 @@ const int ITERATIONS = 80; // number of test runs in our testing threads. const int MAX_STRING = 20000; // largest chunk that we'll try to encrypt. -// some constants snagged from older version of blowfish_crypto class... -const int blowfish_crypto_minimum_key_size_in_bits = 32; -const int blowfish_crypto_maximum_key_size_in_bits = 448; +// some constants snagged from older version of borked_blowfish_crypto class... +const int borked_blowfish_crypto_minimum_key_size_in_bits = 32; +const int borked_blowfish_crypto_maximum_key_size_in_bits = 448; ////////////// @@ -141,8 +141,8 @@ void blowfish_thread::perform_activity(void *) int left = ITERATIONS; while (left--) { time_stamp key_start; - blowfish_crypto bc(_parent.randomizer().inclusive(blowfish_crypto_minimum_key_size_in_bits, - blowfish_crypto_maximum_key_size_in_bits)); + borked_blowfish_crypto bc(_parent.randomizer().inclusive(borked_blowfish_crypto_minimum_key_size_in_bits, + borked_blowfish_crypto_maximum_key_size_in_bits)); #ifdef DEBUG_BLOWFISH LOG(a_sprintf("%d bit key has:", bc.key_size())); astring dumped_key = byte_formatter::text_dump(bc.get_key()); diff --git a/nucleus/library/tests_crypto/test_twofish_crypto.cpp b/nucleus/library/tests_crypto/test_twofish_crypto.cpp index 055eb65c..565b7cc7 100644 --- a/nucleus/library/tests_crypto/test_twofish_crypto.cpp +++ b/nucleus/library/tests_crypto/test_twofish_crypto.cpp @@ -46,19 +46,17 @@ using namespace unit_test; #define DEBUG_TWOFISH // uncomment for noisier run. -//const int TEST_RUNS_PER_KEY = 42; // encryption test cycles done on each key. -const int TEST_RUNS_PER_KEY = 420; // encryption test cycles done on each key. +const int TEST_RUNS_PER_KEY = 42; // encryption test cycles done on each key. const int THREAD_COUNT = 10; // number of threads testing twofish at once. -//const int ITERATIONS = 64; // number of test runs in our testing threads. -const int ITERATIONS = 4200; // number of test runs in our testing threads. +const int ITERATIONS = 64; // number of test runs in our testing threads. const int MAX_STRING = 64 * KILOBYTE; // largest chunk that we'll try to encrypt. // some constants snagged from older version of twofish_crypto class... -const int twofish_crypto_minimum_key_size_in_bits = 92; -const int twofish_crypto_maximum_key_size_in_bits = 256; +//const int twofish_crypto_minimum_key_size_in_bits = 92; +//const int twofish_crypto_maximum_key_size_in_bits = 256; /* Q: is twofish truly requiring 128/192/256 key sizes only? A: no, schneier says any key size up to 256 bits.