will not build quite yet, but nearly there...
-/*****************************************************************************\
-* *
-* 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 *
-\*****************************************************************************/
+/*
+* 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"
namespace crypto {
-const int FUDGE = 128;
+////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
+//#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
#endif
// helpful macro for the error string of last failure.
-#define GET_SSL_ERROR() \
- ERR_error_string(ERR_get_error(), NULL_POINTER)
+//#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) \
#define DISCUSS_PROVIDED_KEY(key_size, key)
#define DISCUSS_KEY_SIZE(key_size)
#endif
+*/
blowfish_crypto::blowfish_crypto(int key_size)
-: _key_size(key_size),
- _key(new byte_array)
+: cryptical_envelopment(key_size, EVP_bf_cbc())
+///_key_size(key_size),
+/// _key(new byte_array)
{
+/*
FUNCDEF("ctor(int)");
static_ssl_initializer();
LOG("prior to key size discuss");
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)
-: _key_size(key_size),
- _key(new byte_array(key))
+: cryptical_envelopment(key, key_size, EVP_bf_cbc())
+//: _key_size(key_size),
+// _key(new byte_array(key))
{
+/*
FUNCDEF("ctor(byte_array,int)");
static_ssl_initializer();
// any problems with the key provided are horrid. they will yield a
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(),
- _key_size(to_copy._key_size),
- _key(new byte_array(*to_copy._key))
+ 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");
+/// 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;
- _key_size = to_copy._key_size;
- *_key = *to_copy._key;
+ *((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");
ALWAYS_LOG("<<decrypt<<");
return to_return;
}
+*/
} //namespace.
#include <basis/byte_array.h>
#include <basis/contracts.h>
+#include "cryptical_envelopment.h"
+
namespace crypto {
//! Provides BlowFish encryption on byte_arrays using the OpenSSL package.
-class blowfish_crypto : public virtual basis::root_object
+class blowfish_crypto : public cryptical_envelopment
+//: public virtual basis::root_object
{
public:
blowfish_crypto(int key_size);
DEFINE_CLASS_NAME("blowfish_crypto");
- int key_size() const; // returns the size of our key, in bits.
+/// 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.
+/// 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.
+/// const basis::byte_array &get_key() const; //!< returns our current key.
- bool set_key(const basis::byte_array &new_key, int key_size);
+/// 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);
+/// 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;
+/// 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;
+/// 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();
+/// 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
(currently named blowfish_crypto.cpp). */
private:
- int _key_size; //!< number of bits in the key.
- basis::byte_array *_key; //!< our secret key.
+/// int _key_size; //!< number of bits in the key.
+/// basis::byte_array *_key; //!< our secret key.
};
} //namespace.
--- /dev/null
+/*****************************************************************************\
+* *
+* Name : cryptical_envelopment *
+* 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 "cryptical_envelopment.h"
+#include "ssl_init.h"
+
+#include <basis/astring.h>
+#include <basis/functions.h>
+#include <basis/mutex.h>
+#include <loggers/critical_events.h>
+#include <loggers/program_wide_logger.h>
+#include <mathematics/chaos.h>
+#include <structures/static_memory_gremlin.h>
+
+///#include <openssl/blowfish.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+
+using namespace basis;
+using namespace loggers;
+using namespace mathematics;
+using namespace structures;
+
+namespace crypto {
+
+const int FUDGE = 1024;
+ /* extra space for the cipher's block size. blowfish, e.g., is only 8 bytes for
+ the cipher block size, so we'd only ever need possibly 8 bytes padding?
+ */
+//hmmm: guarantee the fudge space is enough for other algorithms!
+
+//#undef set_key
+ // get rid of a macro we don't want.
+
+#define DEBUG_CRYPTICAL_ENVELOPMENT
+ // uncomment for noisier version.
+
+// our logging via LOG is disabled unless the debugging flag above is turned on.
+// but the ALWAYS_LOG macro is unfazed and will log regardless of the flag.
+#undef ALWAYS_LOG
+#define ALWAYS_LOG(t) CLASS_EMERGENCY_LOG(program_wide_logger::get(), t)
+#ifdef DEBUG_CRYPTICAL_ENVELOPMENT
+ #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_CRYPTICAL_ENVELOPMENT
+
+/// // 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
+
+cryptical_envelopment::cryptical_envelopment(int key_size, const EVP_CIPHER *cipher_type)
+: _key_size(key_size),
+ _key(new byte_array),
+ _cipher_type(cipher_type)
+{
+ 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");
+}
+
+cryptical_envelopment::cryptical_envelopment(const byte_array &key, int key_size, const EVP_CIPHER *cipher_type)
+: _key_size(key_size),
+ _key(new byte_array(key)),
+ _cipher_type(cipher_type)
+{
+ 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");
+}
+
+cryptical_envelopment::cryptical_envelopment(const cryptical_envelopment &to_copy)
+: root_object(),
+ _key_size(to_copy._key_size),
+ _key(new byte_array(*to_copy._key))
+{
+ FUNCDEF("copy ctor");
+ static_ssl_initializer();
+ LOG("after ssl static init");
+}
+
+cryptical_envelopment::~cryptical_envelopment()
+{
+ FUNCDEF("destructor");
+ LOG("prior to key whack");
+ WHACK(_key);
+ LOG("after key whack");
+}
+
+int cryptical_envelopment::key_size() const { return _key_size; }
+
+const byte_array &cryptical_envelopment::get_key() const { return *_key; }
+
+/////hmmm: these are not right for all encryption types.
+///int cryptical_envelopment::minimum_key_size() { return 64; }
+///
+///int cryptical_envelopment::maximum_key_size() { return 448; }
+
+cryptical_envelopment &cryptical_envelopment::operator = (const cryptical_envelopment &to_copy)
+{
+ if (this == &to_copy) return *this;
+ _key_size = to_copy._key_size;
+ *_key = *to_copy._key;
+ _cipher_type = to_copy._cipher_type;
+ return *this;
+}
+
+bool cryptical_envelopment::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 cryptical_envelopment::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);
+
+//hmmm: if we leave non-zero stuff in the last byte, that's not quite right!
+// also a question of endian-ness of where to zap those bits. argh!
+
+ // clear the bits that cannot be non-zero for a key whose bits are not evenly divisible by 8.
+
+}
+
+SAFE_STATIC(mutex, __vector_init_lock, )
+
+//hmmm: this seems like a bad security situation, because we are using a single process for
+// creating init vectors, so it's super easy to guess these (by reading the code, for
+// example). is this still secure, given that the keys are not known to an attacker?
+const byte_array &cryptical_envelopment::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 creating init_vector >>");
+//hmmm: we're okay with the wrap-around on the byte type (going negative) if the init vector length is longer than 214?
+ for (int i = 0; i < to_return.length(); i++)
+ to_return[i] = abyte(214 - i);
+ initted = true;
+ LOG("<< finished init_vector creation <<");
+ }
+ return to_return;
+}
+
+bool cryptical_envelopment::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, _cipher_type, NULL_POINTER, NULL_POINTER, NULL_POINTER);
+ if (!initret) {
+ // zero means a failure of the initialization.
+ deadly_error(class_name(), func, a_sprintf("failure in calling EVP_EncryptInit_ex, with error %s", GET_SSL_ERROR()));
+ }
+ 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.
+ deadly_error(class_name(), func, a_sprintf("second phase failure in calling EVP_EncryptInit_ex, with error %s", GET_SSL_ERROR()));
+ }
+
+ // 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(" encryption 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("<<encrypt<<");
+ return to_return;
+}
+
+bool cryptical_envelopment::decrypt(const byte_array &source,
+ byte_array &target) const
+{
+ FUNCDEF("decrypt");
+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));
+ int initret = EVP_DecryptInit_ex(session, _cipher_type, NULL_POINTER, NULL_POINTER, NULL_POINTER);
+ if (!initret) {
+ // zero means a failure of the initialization.
+ deadly_error(class_name(), func, a_sprintf("failure in calling EVP_DecryptInit_ex, with error %s", GET_SSL_ERROR()));
+ }
+ // 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.
+ deadly_error(class_name(), func, a_sprintf("second phase failure in calling EVP_DecryptInit_ex, with error %s", GET_SSL_ERROR()));
+ }
+
+ // 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(" decryption final had %d bytes padding.", pad_len));
+ decoded.zap(pad_len, decoded.last());
+ target += decoded;
+ }
+ }
+
+ EVP_CIPHER_CTX_cleanup(session);
+ EVP_CIPHER_CTX_free(session);
+ALWAYS_LOG("<<decrypt<<");
+ return to_return;
+}
+
+} //namespace.
+
+
--- /dev/null
+#ifndef CRYPTICAL_ENVELOPMENT_CLASS
+#define CRYPTICAL_ENVELOPMENT_CLASS
+
+/*
+* Name : cryptical_envelopment
+* Author : Chris Koeritz
+*
+* Purpose: Implements the majority of encryption processing using the
+* OpenSSL EVP methods, aka the digital envelope routines.
+*****
+* 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 <basis/byte_array.h>
+#include <basis/contracts.h>
+
+// forward.
+struct evp_cipher_st;
+typedef struct evp_cipher_st EVP_CIPHER;
+
+namespace crypto {
+
+class cryptical_envelopment : public virtual basis::root_object
+{
+public:
+ cryptical_envelopment(int key_size, const EVP_CIPHER *cipher_type);
+ //!< this will create a new random key of the "key_size", in bits.
+ /*!< the valid sizes for keys depend on the algorithm in question. */
+
+ cryptical_envelopment(const basis::byte_array &key, int key_size, const EVP_CIPHER *cipher_type);
+ //!< uses a pre-existing "key" for encryption.
+
+ cryptical_envelopment(const cryptical_envelopment &to_copy); //!< copy constructor.
+
+ virtual ~cryptical_envelopment();
+
+ cryptical_envelopment &operator = (const cryptical_envelopment &to_copy);
+
+ DEFINE_CLASS_NAME("cryptical_envelopment");
+
+ 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" with a "key_size" in bits.
+
+ 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 cryptical_envelopment.cpp). */
+
+private:
+ int _key_size; //!< number of bits in the key.
+ basis::byte_array *_key; //!< our secret key.
+ const EVP_CIPHER *_cipher_type; //!< what kind of encryption are we using?
+};
+
+} //namespace.
+
+#endif
+
TYPE = library
PROJECT = crypto
-SOURCE = blowfish_crypto.cpp rsa_crypto.cpp ssl_init.cpp
+SOURCE = blowfish_crypto.cpp cryptical_envelopment.cpp old_school_rsa_crypto.cpp ssl_init.cpp
USE_SSL = t
TARGETS = crypto.lib
--- /dev/null
+/*
+* Name : RSA public key encryption
+* Author : Chris Koeritz
+* Purpose:
+* Supports public (and private) key encryption and decryption using the
+* OpenSSL package's support for RSA encryption.
+****
+* 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: rsa crypto provides a nice printing method... RSA_print_fp(stdout, private_key, 0);
+
+// notes from openssl docs: length to be encrypted in a chunk must be less than
+// RSA_size(rsa) - 11 for the PKCS #1 v1.5 based padding modes, less than
+// RSA_size(rsa) - 41 for RSA_PKCS1_OAEP_PADDING and exactly RSA_size(rsa)
+// for RSA_NO_PADDING.
+
+#include "old_school_rsa_crypto.h"
+#include "ssl_init.h"
+
+#include <basis/functions.h>
+#include <loggers/critical_events.h>
+#include <loggers/program_wide_logger.h>
+#include <mathematics/chaos.h>
+#include <structures/object_packers.h>
+#include <structures/static_memory_gremlin.h>
+
+#include <openssl/bn.h>
+#include <openssl/err.h>
+#include <openssl/rsa.h>
+
+using namespace basis;
+using namespace loggers;
+using namespace mathematics;
+using namespace structures;
+
+namespace crypto {
+
+//#define DEBUG_RSA_CRYPTO
+ // uncomment for noisier version.
+
+#ifdef DEBUG_RSA_CRYPTO
+ #undef LOG
+ #define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger::get(), s)
+#else
+ #undef LOG
+ #define LOG(s)
+#endif
+
+SAFE_STATIC(mutex, __single_stepper, )
+ // protects unsafe areas of rsa crypto from access by multiple threads at once.
+
+old_school_rsa_crypto::old_school_rsa_crypto(int key_size)
+: _key(NULL_POINTER)
+{
+ FUNCDEF("ctor(int)");
+ LOG("prior to generating key");
+ _key = generate_key(key_size); // generate_key initializes ssl for us.
+ LOG("after generating key");
+}
+
+old_school_rsa_crypto::old_school_rsa_crypto(const byte_array &key)
+: _key(NULL_POINTER)
+{
+ FUNCDEF("ctor(byte_array)");
+ static_ssl_initializer();
+ byte_array key_copy = key;
+ LOG("prior to set key");
+ set_key(key_copy);
+ LOG("after set key");
+}
+
+old_school_rsa_crypto::old_school_rsa_crypto(RSA *key)
+: _key(NULL_POINTER)
+{
+ FUNCDEF("ctor(RSA)");
+ static_ssl_initializer();
+ LOG("prior to set key");
+ set_key(key);
+ LOG("after set key");
+}
+
+old_school_rsa_crypto::old_school_rsa_crypto(const old_school_rsa_crypto &to_copy)
+: root_object(),
+ _key(NULL_POINTER)
+{
+ FUNCDEF("copy ctor");
+ static_ssl_initializer();
+ LOG("prior to set key");
+ set_key(to_copy._key);
+ LOG("after set key");
+}
+
+old_school_rsa_crypto::~old_school_rsa_crypto()
+{
+ FUNCDEF("destructor");
+ LOG("prior to rsa free");
+ auto_synchronizer mutt(__single_stepper());
+ RSA_free(_key);
+ LOG("after rsa free");
+}
+
+const old_school_rsa_crypto &old_school_rsa_crypto::operator = (const old_school_rsa_crypto &to_copy)
+{
+ if (this == &to_copy) return *this;
+ set_key(to_copy._key);
+ return *this;
+}
+
+RSA *old_school_rsa_crypto::generate_key(int key_size)
+{
+ FUNCDEF("generate_key");
+ if (key_size < 4) key_size = 4; // laughable lower default.
+ static_ssl_initializer();
+ LOG("into generate key");
+ auto_synchronizer mutt(__single_stepper());
+ RSA *to_return = RSA_new();
+ BIGNUM *e = BN_new();
+ BN_set_word(e, 65537);
+//hmmm: only one value of e?
+ int ret = RSA_generate_key_ex(to_return, key_size, e, NULL_POINTER);
+ if (!ret) {
+ continuable_error(static_class_name(), func,
+ a_sprintf("failed to generate a key of %d bits: error is %ld.", key_size, ERR_get_error()));
+ BN_free(e);
+ RSA_free(to_return);
+ return NULL;
+ }
+ LOG("after key generated");
+ BN_free(e);
+ return to_return;
+}
+
+bool old_school_rsa_crypto::check_key(RSA *key)
+{
+ auto_synchronizer mutt(__single_stepper());
+ return RSA_check_key(key) == 1;
+}
+
+bool old_school_rsa_crypto::set_key(byte_array &key)
+{
+ FUNCDEF("set_key [byte_array]");
+ if (!key.length()) return false;
+ auto_synchronizer mutt(__single_stepper());
+ if (_key) RSA_free(_key);
+ _key = RSA_new();
+ abyte type;
+ if (!structures::detach(key, type)) return false;
+ if ( (type != 'r') && (type != 'u') ) return false;
+ // get the public key bits first.
+ byte_array n;
+ if (!structures::detach(key, n)) return false;
+ BIGNUM *the_n = BN_bin2bn(n.access(), n.length(), NULL_POINTER);
+ if (!the_n) return false;
+ byte_array e;
+ if (!structures::detach(key, e)) return false;
+ BIGNUM *the_e = BN_bin2bn(e.access(), e.length(), NULL_POINTER);
+ if (!the_e) return false;
+
+ if (type == 'u') {
+ // done with public key.
+#ifdef NEWER_OPENSSL
+ RSA_set0_key(_key, the_n, the_e, NULL_POINTER);
+#else
+ _key->n = the_n; _key->e = the_e;
+#endif
+ return true;
+ }
+
+ // the rest is for a private key.
+ byte_array d;
+ if (!structures::detach(key, d)) return false;
+ BIGNUM *the_d = BN_bin2bn(d.access(), d.length(), NULL_POINTER);
+ if (!the_d) return false;
+
+ byte_array p;
+ if (!structures::detach(key, p)) return false;
+ BIGNUM *the_p = BN_bin2bn(p.access(), p.length(), NULL_POINTER);
+ if (!the_p) return false;
+ byte_array q;
+ if (!structures::detach(key, q)) return false;
+ BIGNUM *the_q = BN_bin2bn(q.access(), q.length(), NULL_POINTER);
+ if (!the_q) return false;
+ byte_array dmp1;
+ if (!structures::detach(key, dmp1)) return false;
+ BIGNUM *the_dmp1 = BN_bin2bn(dmp1.access(), dmp1.length(), NULL_POINTER);
+ if (!the_dmp1) return false;
+ byte_array dmq1;
+ if (!structures::detach(key, dmq1)) return false;
+ BIGNUM *the_dmq1 = BN_bin2bn(dmq1.access(), dmq1.length(), NULL_POINTER);
+ if (!the_dmq1) return false;
+ byte_array iqmp;
+ if (!structures::detach(key, iqmp)) return false;
+ BIGNUM *the_iqmp = BN_bin2bn(iqmp.access(), iqmp.length(), NULL_POINTER);
+ if (!the_iqmp) return false;
+
+ // we can set the n, e and d now.
+#ifdef NEWER_OPENSSL
+ int ret = RSA_set0_key(_key, the_n, the_e, the_d);
+ if (ret != 1) return false;
+ ret = RSA_set0_factors(_key, the_p, the_q);
+ if (ret != 1) return false;
+ ret = RSA_set0_crt_params(_key, the_dmp1, the_dmq1, the_iqmp);
+ if (ret != 1) return false;
+#else
+ _key->n = the_n; _key->e = the_e; _key->d = the_d;
+ _key->p = the_p; _key->q = the_q;
+ _key->dmp1 = the_dmp1; _key->dmq1 = the_dmq1; _key->iqmp = the_iqmp;
+#endif
+
+ int check = RSA_check_key(_key);
+ if (check != 1) {
+ continuable_error(static_class_name(), func, "failed to check the private "
+ "portion of the key!");
+ return false;
+ }
+
+ return true;
+}
+
+bool old_school_rsa_crypto::set_key(RSA *key)
+{
+ FUNCDEF("set_key [RSA]");
+ if (!key) return NULL_POINTER;
+ // test the incoming key.
+ auto_synchronizer mutt(__single_stepper());
+ int check = RSA_check_key(key);
+ if (check != 1) return false;
+ // clean out the old key.
+ if (_key) RSA_free(_key);
+ _key = RSAPrivateKey_dup(key);
+ if (!_key) {
+ continuable_error(static_class_name(), func, "failed to create a "
+ "duplicate of the key!");
+ return false;
+ }
+ return true;
+}
+
+bool old_school_rsa_crypto::public_key(byte_array &pubkey) const
+{
+ FUNCDEF("public_key");
+ if (!_key) return false;
+ structures::attach(pubkey, abyte('u')); // signal a public key.
+ // convert the two public portions into binary.
+ BIGNUM **the_n = new BIGNUM *, **the_e = new BIGNUM *, **the_d = new BIGNUM *;
+#ifdef NEWER_OPENSSL
+ RSA_get0_key(_key, (const BIGNUM **)the_n, (const BIGNUM **)the_e, (const BIGNUM **)the_d);
+#else
+ *the_n = _key->n; *the_e = _key->e; *the_d = _key->d;
+#endif
+ byte_array n(BN_num_bytes(*the_n));
+ int ret = BN_bn2bin(*the_n, n.access());
+ byte_array e(BN_num_bytes(*the_e));
+ ret = BN_bn2bin(*the_e, e.access());
+ // pack those two chunks.
+ structures::attach(pubkey, n);
+ structures::attach(pubkey, e);
+ WHACK(the_n); WHACK(the_e); WHACK(the_d);
+
+ return true;
+}
+
+bool old_school_rsa_crypto::private_key(byte_array &privkey) const
+{
+ FUNCDEF("private_key");
+ if (!_key) return false;
+ int posn = privkey.length();
+ bool worked = public_key(privkey); // get the public pieces first.
+ if (!worked) return false;
+ privkey[posn] = abyte('r'); // switch public key flag to private.
+ // convert the multiple private portions into binary.
+ //const BIGNUM **the_n = NULL_POINTER, **the_e = NULL_POINTER, **the_d = NULL_POINTER;
+ BIGNUM **the_n = new BIGNUM *, **the_e = new BIGNUM *, **the_d = new BIGNUM *;
+ BIGNUM **the_p = new BIGNUM *, **the_q = new BIGNUM *;
+ BIGNUM **the_dmp1 = new BIGNUM *, **the_dmq1 = new BIGNUM *, **the_iqmp = new BIGNUM *;
+#ifdef NEWER_OPENSSL
+ RSA_get0_key(_key, (const BIGNUM **)the_n, (const BIGNUM **)the_e, (const BIGNUM **)the_d);
+ RSA_get0_factors(_key, (const BIGNUM **)the_p, (const BIGNUM **)the_q);
+ RSA_get0_crt_params(_key, (const BIGNUM **)the_dmp1, (const BIGNUM **)the_dmq1, (const BIGNUM **)the_iqmp);
+#else
+ *the_n = _key->n; *the_e = _key->e; *the_d = _key->d;
+ *the_p = _key->p; *the_q = _key->q;
+ *the_dmp1 = _key->dmp1; *the_dmq1 = _key->dmq1; *the_iqmp = _key->iqmp;
+#endif
+ byte_array d(BN_num_bytes(*the_d));
+ int ret = BN_bn2bin(*the_d, d.access());
+ byte_array p(BN_num_bytes(*the_p));
+ ret = BN_bn2bin(*the_p, p.access());
+ byte_array q(BN_num_bytes(*the_q));
+ ret = BN_bn2bin(*the_q, q.access());
+ byte_array dmp1(BN_num_bytes(*the_dmp1));
+ ret = BN_bn2bin(*the_dmp1, dmp1.access());
+ byte_array dmq1(BN_num_bytes(*the_dmq1));
+ ret = BN_bn2bin(*the_dmq1, dmq1.access());
+ byte_array iqmp(BN_num_bytes(*the_iqmp));
+ ret = BN_bn2bin(*the_iqmp, iqmp.access());
+ // pack all those in now.
+ structures::attach(privkey, d);
+ structures::attach(privkey, p);
+ structures::attach(privkey, q);
+ structures::attach(privkey, dmp1);
+ structures::attach(privkey, dmq1);
+ structures::attach(privkey, iqmp);
+ return true;
+}
+
+bool old_school_rsa_crypto::public_encrypt(const byte_array &source,
+ byte_array &target) const
+{
+ FUNCDEF("public_encrypt");
+ target.reset();
+ if (!source.length()) return false;
+
+ auto_synchronizer mutt(__single_stepper());
+ const int max_chunk = RSA_size(_key) - 12;
+
+ byte_array encoded(RSA_size(_key));
+ for (int i = 0; i < source.length(); i += max_chunk) {
+ int edge = i + max_chunk - 1;
+ if (edge > source.last())
+ edge = source.last();
+ int next_chunk = edge - i + 1;
+ RSA_public_encrypt(next_chunk, &source[i],
+ encoded.access(), _key, RSA_PKCS1_PADDING);
+ target += encoded;
+ }
+ return true;
+}
+
+bool old_school_rsa_crypto::private_decrypt(const byte_array &source,
+ byte_array &target) const
+{
+ FUNCDEF("private_decrypt");
+ target.reset();
+ if (!source.length()) return false;
+
+ auto_synchronizer mutt(__single_stepper());
+ const int max_chunk = RSA_size(_key);
+
+ byte_array decoded(max_chunk);
+ for (int i = 0; i < source.length(); i += max_chunk) {
+ int edge = i + max_chunk - 1;
+ if (edge > source.last())
+ edge = source.last();
+ int next_chunk = edge - i + 1;
+ int dec_size = RSA_private_decrypt(next_chunk, &source[i],
+ decoded.access(), _key, RSA_PKCS1_PADDING);
+ if (dec_size < 0) return false; // that didn't work.
+ decoded.zap(dec_size, decoded.last());
+ target += decoded;
+ decoded.reset(max_chunk);
+ }
+ return true;
+}
+
+bool old_school_rsa_crypto::private_encrypt(const byte_array &source,
+ byte_array &target) const
+{
+ FUNCDEF("private_encrypt");
+ target.reset();
+ if (!source.length()) return false;
+
+ auto_synchronizer mutt(__single_stepper());
+ const int max_chunk = RSA_size(_key) - 12;
+
+ byte_array encoded(RSA_size(_key));
+ for (int i = 0; i < source.length(); i += max_chunk) {
+ int edge = i + max_chunk - 1;
+ if (edge > source.last())
+ edge = source.last();
+ int next_chunk = edge - i + 1;
+ RSA_private_encrypt(next_chunk, &source[i],
+ encoded.access(), _key, RSA_PKCS1_PADDING);
+ target += encoded;
+ }
+ return true;
+}
+
+bool old_school_rsa_crypto::public_decrypt(const byte_array &source,
+ byte_array &target) const
+{
+ FUNCDEF("public_decrypt");
+ target.reset();
+ if (!source.length()) return false;
+
+ auto_synchronizer mutt(__single_stepper());
+ const int max_chunk = RSA_size(_key);
+
+ byte_array decoded(max_chunk);
+ for (int i = 0; i < source.length(); i += max_chunk) {
+ int edge = i + max_chunk - 1;
+ if (edge > source.last())
+ edge = source.last();
+ int next_chunk = edge - i + 1;
+ int dec_size = RSA_public_decrypt(next_chunk, &source[i],
+ decoded.access(), _key, RSA_PKCS1_PADDING);
+ if (dec_size < 0) return false; // that didn't work.
+ decoded.zap(dec_size, decoded.last());
+ target += decoded;
+ decoded.reset(max_chunk);
+ }
+ return true;
+}
+
+} //namespace.
+
--- /dev/null
+#ifndef OLD_SCHOOL_RSA_CRYPTO_CLASS
+#define OLD_SCHOOL_RSA_CRYPTO_CLASS
+
+/*****************************************************************************\
+* *
+* Name : RSA public key 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 <basis/byte_array.h>
+#include <basis/contracts.h>
+
+// forward.
+typedef struct rsa_st RSA;
+
+namespace crypto {
+
+//! Supports public key encryption and decryption.
+/*!
+ This class uses the OpenSSL package's support for RSA encryption.
+*/
+
+class old_school_rsa_crypto : public virtual basis::nameable
+{
+public:
+ old_school_rsa_crypto(int key_size);
+ //!< constructs using a randomized private key of the "key_size".
+ /*!< the "key_size" must be at least 1024 bits for acceptable security.
+ smaller keys are considered insecure. */
+
+ old_school_rsa_crypto(const basis::byte_array &key);
+ //!< constructs with the specified "key" as our private key.
+ /*!< the "key" is used for encryption rather than generating a random one.
+ the key is only valid if it was created with this class. also, if the key
+ is a public key, then only the public_encryption and public_decryption
+ methods will be available. */
+
+ old_school_rsa_crypto(RSA *key);
+ //!< starts with a pre-existing "key" in the low-level form.
+
+ old_school_rsa_crypto(const old_school_rsa_crypto &to_copy);
+
+ virtual ~old_school_rsa_crypto();
+
+ const old_school_rsa_crypto &operator = (const old_school_rsa_crypto &to_copy);
+
+ DEFINE_CLASS_NAME("old_school_rsa_crypto");
+
+ bool set_key(basis::byte_array &key);
+ //!< resets this object's key to "key".
+ /*!< the key is only valid if this class created it. note: the "key"
+ is destructively consumed during the set method; do not pass in your
+ only copy. */
+
+ bool set_key(RSA *key);
+ //!< sets our new "key".
+ /*!< this must be a valid key created via the RSA algorithms. */
+
+ bool check_key(RSA *key);
+ //!< checks the RSA "key" provided for validity.
+
+ bool public_encrypt(const basis::byte_array &source, basis::byte_array &target) const;
+ //!< encrypts "source" using our public key and stores it in "target".
+ /*!< public_encrypt and private_decrypt are a pair. an untrusted user can
+ encrypt with the public key and only the possessor of the private key
+ should be able to decrypt it. */
+ bool private_decrypt(const basis::byte_array &source, basis::byte_array &target) const;
+ //!< decrypts "source" using our private key and stores it in "target".
+
+ bool private_encrypt(const basis::byte_array &source, basis::byte_array &target) const;
+ //!< encrypts "source" using our private key and stores it in "target".
+ /*!< private_encrypt and public_decrypt are also a pair. the trusted
+ user with the private key can create encrypted chunks that anyone with
+ the public key can decrypt. */
+ bool public_decrypt(const basis::byte_array &source, basis::byte_array &target) const;
+ //!< decrypts "source" using our public key and stores it in "target".
+
+ bool public_key(basis::byte_array &pubkey) const;
+ //!< makes a copy of the public key held here.
+ bool private_key(basis::byte_array &privkey) const;
+ //!< makes a copy of the private key held here.
+ /*!< the private key should never be exposed to anyone else. */
+
+ static RSA *generate_key(int key_size);
+ //!< creates a random RSA key using the lower-level openssl methods.
+
+private:
+ RSA *_key; //!< our internal key.
+};
+
+} //namespace.
+
+#endif
+
+++ /dev/null
-/*
-* Name : RSA public key encryption
-* Author : Chris Koeritz
-* Purpose:
-* Supports public (and private) key encryption and decryption using the
-* OpenSSL package's support for RSA encryption.
-****
-* 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: rsa crypto provides a nice printing method... RSA_print_fp(stdout, private_key, 0);
-
-// notes from openssl docs: length to be encrypted in a chunk must be less than
-// RSA_size(rsa) - 11 for the PKCS #1 v1.5 based padding modes, less than
-// RSA_size(rsa) - 41 for RSA_PKCS1_OAEP_PADDING and exactly RSA_size(rsa)
-// for RSA_NO_PADDING.
-
-#include "rsa_crypto.h"
-#include "ssl_init.h"
-
-#include <basis/functions.h>
-#include <loggers/critical_events.h>
-#include <loggers/program_wide_logger.h>
-#include <mathematics/chaos.h>
-#include <structures/object_packers.h>
-#include <structures/static_memory_gremlin.h>
-
-#include <openssl/bn.h>
-#include <openssl/err.h>
-#include <openssl/rsa.h>
-
-using namespace basis;
-using namespace loggers;
-using namespace mathematics;
-using namespace structures;
-
-namespace crypto {
-
-//#define DEBUG_RSA_CRYPTO
- // uncomment for noisier version.
-
-#ifdef DEBUG_RSA_CRYPTO
- #undef LOG
- #define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger::get(), s)
-#else
- #undef LOG
- #define LOG(s)
-#endif
-
-SAFE_STATIC(mutex, __single_stepper, )
- // protects unsafe areas of rsa crypto from access by multiple threads at once.
-
-rsa_crypto::rsa_crypto(int key_size)
-: _key(NULL_POINTER)
-{
- FUNCDEF("ctor(int)");
- LOG("prior to generating key");
- _key = generate_key(key_size); // generate_key initializes ssl for us.
- LOG("after generating key");
-}
-
-rsa_crypto::rsa_crypto(const byte_array &key)
-: _key(NULL_POINTER)
-{
- FUNCDEF("ctor(byte_array)");
- static_ssl_initializer();
- byte_array key_copy = key;
- LOG("prior to set key");
- set_key(key_copy);
- LOG("after set key");
-}
-
-rsa_crypto::rsa_crypto(RSA *key)
-: _key(NULL_POINTER)
-{
- FUNCDEF("ctor(RSA)");
- static_ssl_initializer();
- LOG("prior to set key");
- set_key(key);
- LOG("after set key");
-}
-
-rsa_crypto::rsa_crypto(const rsa_crypto &to_copy)
-: root_object(),
- _key(NULL_POINTER)
-{
- FUNCDEF("copy ctor");
- static_ssl_initializer();
- LOG("prior to set key");
- set_key(to_copy._key);
- LOG("after set key");
-}
-
-rsa_crypto::~rsa_crypto()
-{
- FUNCDEF("destructor");
- LOG("prior to rsa free");
- auto_synchronizer mutt(__single_stepper());
- RSA_free(_key);
- LOG("after rsa free");
-}
-
-const rsa_crypto &rsa_crypto::operator = (const rsa_crypto &to_copy)
-{
- if (this == &to_copy) return *this;
- set_key(to_copy._key);
- return *this;
-}
-
-RSA *rsa_crypto::generate_key(int key_size)
-{
- FUNCDEF("generate_key");
- if (key_size < 4) key_size = 4; // laughable lower default.
- static_ssl_initializer();
- LOG("into generate key");
- auto_synchronizer mutt(__single_stepper());
- RSA *to_return = RSA_new();
- BIGNUM *e = BN_new();
- BN_set_word(e, 65537);
-//hmmm: only one value of e?
- int ret = RSA_generate_key_ex(to_return, key_size, e, NULL_POINTER);
- if (!ret) {
- continuable_error(static_class_name(), func,
- a_sprintf("failed to generate a key of %d bits: error is %ld.", key_size, ERR_get_error()));
- BN_free(e);
- RSA_free(to_return);
- return NULL;
- }
- LOG("after key generated");
- BN_free(e);
- return to_return;
-}
-
-bool rsa_crypto::check_key(RSA *key)
-{
- auto_synchronizer mutt(__single_stepper());
- return RSA_check_key(key) == 1;
-}
-
-bool rsa_crypto::set_key(byte_array &key)
-{
- FUNCDEF("set_key [byte_array]");
- if (!key.length()) return false;
- auto_synchronizer mutt(__single_stepper());
- if (_key) RSA_free(_key);
- _key = RSA_new();
- abyte type;
- if (!structures::detach(key, type)) return false;
- if ( (type != 'r') && (type != 'u') ) return false;
- // get the public key bits first.
- byte_array n;
- if (!structures::detach(key, n)) return false;
- BIGNUM *the_n = BN_bin2bn(n.access(), n.length(), NULL_POINTER);
- if (!the_n) return false;
- byte_array e;
- if (!structures::detach(key, e)) return false;
- BIGNUM *the_e = BN_bin2bn(e.access(), e.length(), NULL_POINTER);
- if (!the_e) return false;
-
- if (type == 'u') {
- // done with public key.
-#ifdef NEWER_OPENSSL
- RSA_set0_key(_key, the_n, the_e, NULL_POINTER);
-#else
- _key->n = the_n; _key->e = the_e;
-#endif
- return true;
- }
-
- // the rest is for a private key.
- byte_array d;
- if (!structures::detach(key, d)) return false;
- BIGNUM *the_d = BN_bin2bn(d.access(), d.length(), NULL_POINTER);
- if (!the_d) return false;
-
- byte_array p;
- if (!structures::detach(key, p)) return false;
- BIGNUM *the_p = BN_bin2bn(p.access(), p.length(), NULL_POINTER);
- if (!the_p) return false;
- byte_array q;
- if (!structures::detach(key, q)) return false;
- BIGNUM *the_q = BN_bin2bn(q.access(), q.length(), NULL_POINTER);
- if (!the_q) return false;
- byte_array dmp1;
- if (!structures::detach(key, dmp1)) return false;
- BIGNUM *the_dmp1 = BN_bin2bn(dmp1.access(), dmp1.length(), NULL_POINTER);
- if (!the_dmp1) return false;
- byte_array dmq1;
- if (!structures::detach(key, dmq1)) return false;
- BIGNUM *the_dmq1 = BN_bin2bn(dmq1.access(), dmq1.length(), NULL_POINTER);
- if (!the_dmq1) return false;
- byte_array iqmp;
- if (!structures::detach(key, iqmp)) return false;
- BIGNUM *the_iqmp = BN_bin2bn(iqmp.access(), iqmp.length(), NULL_POINTER);
- if (!the_iqmp) return false;
-
- // we can set the n, e and d now.
-#ifdef NEWER_OPENSSL
- int ret = RSA_set0_key(_key, the_n, the_e, the_d);
- if (ret != 1) return false;
- ret = RSA_set0_factors(_key, the_p, the_q);
- if (ret != 1) return false;
- ret = RSA_set0_crt_params(_key, the_dmp1, the_dmq1, the_iqmp);
- if (ret != 1) return false;
-#else
- _key->n = the_n; _key->e = the_e; _key->d = the_d;
- _key->p = the_p; _key->q = the_q;
- _key->dmp1 = the_dmp1; _key->dmq1 = the_dmq1; _key->iqmp = the_iqmp;
-#endif
-
- int check = RSA_check_key(_key);
- if (check != 1) {
- continuable_error(static_class_name(), func, "failed to check the private "
- "portion of the key!");
- return false;
- }
-
- return true;
-}
-
-bool rsa_crypto::set_key(RSA *key)
-{
- FUNCDEF("set_key [RSA]");
- if (!key) return NULL_POINTER;
- // test the incoming key.
- auto_synchronizer mutt(__single_stepper());
- int check = RSA_check_key(key);
- if (check != 1) return false;
- // clean out the old key.
- if (_key) RSA_free(_key);
- _key = RSAPrivateKey_dup(key);
- if (!_key) {
- continuable_error(static_class_name(), func, "failed to create a "
- "duplicate of the key!");
- return false;
- }
- return true;
-}
-
-bool rsa_crypto::public_key(byte_array &pubkey) const
-{
- FUNCDEF("public_key");
- if (!_key) return false;
- structures::attach(pubkey, abyte('u')); // signal a public key.
- // convert the two public portions into binary.
- BIGNUM **the_n = new BIGNUM *, **the_e = new BIGNUM *, **the_d = new BIGNUM *;
-#ifdef NEWER_OPENSSL
- RSA_get0_key(_key, (const BIGNUM **)the_n, (const BIGNUM **)the_e, (const BIGNUM **)the_d);
-#else
- *the_n = _key->n; *the_e = _key->e; *the_d = _key->d;
-#endif
- byte_array n(BN_num_bytes(*the_n));
- int ret = BN_bn2bin(*the_n, n.access());
- byte_array e(BN_num_bytes(*the_e));
- ret = BN_bn2bin(*the_e, e.access());
- // pack those two chunks.
- structures::attach(pubkey, n);
- structures::attach(pubkey, e);
- WHACK(the_n); WHACK(the_e); WHACK(the_d);
-
- return true;
-}
-
-bool rsa_crypto::private_key(byte_array &privkey) const
-{
- FUNCDEF("private_key");
- if (!_key) return false;
- int posn = privkey.length();
- bool worked = public_key(privkey); // get the public pieces first.
- if (!worked) return false;
- privkey[posn] = abyte('r'); // switch public key flag to private.
- // convert the multiple private portions into binary.
- //const BIGNUM **the_n = NULL_POINTER, **the_e = NULL_POINTER, **the_d = NULL_POINTER;
- BIGNUM **the_n = new BIGNUM *, **the_e = new BIGNUM *, **the_d = new BIGNUM *;
- BIGNUM **the_p = new BIGNUM *, **the_q = new BIGNUM *;
- BIGNUM **the_dmp1 = new BIGNUM *, **the_dmq1 = new BIGNUM *, **the_iqmp = new BIGNUM *;
-#ifdef NEWER_OPENSSL
- RSA_get0_key(_key, (const BIGNUM **)the_n, (const BIGNUM **)the_e, (const BIGNUM **)the_d);
- RSA_get0_factors(_key, (const BIGNUM **)the_p, (const BIGNUM **)the_q);
- RSA_get0_crt_params(_key, (const BIGNUM **)the_dmp1, (const BIGNUM **)the_dmq1, (const BIGNUM **)the_iqmp);
-#else
- *the_n = _key->n; *the_e = _key->e; *the_d = _key->d;
- *the_p = _key->p; *the_q = _key->q;
- *the_dmp1 = _key->dmp1; *the_dmq1 = _key->dmq1; *the_iqmp = _key->iqmp;
-#endif
- byte_array d(BN_num_bytes(*the_d));
- int ret = BN_bn2bin(*the_d, d.access());
- byte_array p(BN_num_bytes(*the_p));
- ret = BN_bn2bin(*the_p, p.access());
- byte_array q(BN_num_bytes(*the_q));
- ret = BN_bn2bin(*the_q, q.access());
- byte_array dmp1(BN_num_bytes(*the_dmp1));
- ret = BN_bn2bin(*the_dmp1, dmp1.access());
- byte_array dmq1(BN_num_bytes(*the_dmq1));
- ret = BN_bn2bin(*the_dmq1, dmq1.access());
- byte_array iqmp(BN_num_bytes(*the_iqmp));
- ret = BN_bn2bin(*the_iqmp, iqmp.access());
- // pack all those in now.
- structures::attach(privkey, d);
- structures::attach(privkey, p);
- structures::attach(privkey, q);
- structures::attach(privkey, dmp1);
- structures::attach(privkey, dmq1);
- structures::attach(privkey, iqmp);
- return true;
-}
-
-bool rsa_crypto::public_encrypt(const byte_array &source,
- byte_array &target) const
-{
- FUNCDEF("public_encrypt");
- target.reset();
- if (!source.length()) return false;
-
- auto_synchronizer mutt(__single_stepper());
- const int max_chunk = RSA_size(_key) - 12;
-
- byte_array encoded(RSA_size(_key));
- for (int i = 0; i < source.length(); i += max_chunk) {
- int edge = i + max_chunk - 1;
- if (edge > source.last())
- edge = source.last();
- int next_chunk = edge - i + 1;
- RSA_public_encrypt(next_chunk, &source[i],
- encoded.access(), _key, RSA_PKCS1_PADDING);
- target += encoded;
- }
- return true;
-}
-
-bool rsa_crypto::private_decrypt(const byte_array &source,
- byte_array &target) const
-{
- FUNCDEF("private_decrypt");
- target.reset();
- if (!source.length()) return false;
-
- auto_synchronizer mutt(__single_stepper());
- const int max_chunk = RSA_size(_key);
-
- byte_array decoded(max_chunk);
- for (int i = 0; i < source.length(); i += max_chunk) {
- int edge = i + max_chunk - 1;
- if (edge > source.last())
- edge = source.last();
- int next_chunk = edge - i + 1;
- int dec_size = RSA_private_decrypt(next_chunk, &source[i],
- decoded.access(), _key, RSA_PKCS1_PADDING);
- if (dec_size < 0) return false; // that didn't work.
- decoded.zap(dec_size, decoded.last());
- target += decoded;
- decoded.reset(max_chunk);
- }
- return true;
-}
-
-bool rsa_crypto::private_encrypt(const byte_array &source,
- byte_array &target) const
-{
- FUNCDEF("private_encrypt");
- target.reset();
- if (!source.length()) return false;
-
- auto_synchronizer mutt(__single_stepper());
- const int max_chunk = RSA_size(_key) - 12;
-
- byte_array encoded(RSA_size(_key));
- for (int i = 0; i < source.length(); i += max_chunk) {
- int edge = i + max_chunk - 1;
- if (edge > source.last())
- edge = source.last();
- int next_chunk = edge - i + 1;
- RSA_private_encrypt(next_chunk, &source[i],
- encoded.access(), _key, RSA_PKCS1_PADDING);
- target += encoded;
- }
- return true;
-}
-
-bool rsa_crypto::public_decrypt(const byte_array &source,
- byte_array &target) const
-{
- FUNCDEF("public_decrypt");
- target.reset();
- if (!source.length()) return false;
-
- auto_synchronizer mutt(__single_stepper());
- const int max_chunk = RSA_size(_key);
-
- byte_array decoded(max_chunk);
- for (int i = 0; i < source.length(); i += max_chunk) {
- int edge = i + max_chunk - 1;
- if (edge > source.last())
- edge = source.last();
- int next_chunk = edge - i + 1;
- int dec_size = RSA_public_decrypt(next_chunk, &source[i],
- decoded.access(), _key, RSA_PKCS1_PADDING);
- if (dec_size < 0) return false; // that didn't work.
- decoded.zap(dec_size, decoded.last());
- target += decoded;
- decoded.reset(max_chunk);
- }
- return true;
-}
-
-} //namespace.
-
+++ /dev/null
-#ifndef RSA_CRYPTO_CLASS
-#define RSA_CRYPTO_CLASS
-
-/*****************************************************************************\
-* *
-* Name : RSA public key 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 <basis/byte_array.h>
-#include <basis/contracts.h>
-
-// forward.
-//struct RSA;
-typedef struct rsa_st RSA;
-
-namespace crypto {
-
-//! Supports public key encryption and decryption.
-/*!
- This class uses the OpenSSL package's support for RSA encryption.
-*/
-
-class rsa_crypto : public virtual basis::nameable
-{
-public:
- rsa_crypto(int key_size);
- //!< constructs using a randomized private key of the "key_size".
- /*!< the "key_size" must be at least 1024 bits for acceptable security.
- smaller keys are considered insecure. */
-
- rsa_crypto(const basis::byte_array &key);
- //!< constructs with the specified "key" as our private key.
- /*!< the "key" is used for encryption rather than generating a random one.
- the key is only valid if it was created with this class. also, if the key
- is a public key, then only the public_encryption and public_decryption
- methods will be available. */
-
- rsa_crypto(RSA *key);
- //!< starts with a pre-existing "key" in the low-level form.
-
- rsa_crypto(const rsa_crypto &to_copy);
-
- virtual ~rsa_crypto();
-
- const rsa_crypto &operator = (const rsa_crypto &to_copy);
-
- DEFINE_CLASS_NAME("rsa_crypto");
-
- bool set_key(basis::byte_array &key);
- //!< resets this object's key to "key".
- /*!< the key is only valid if this class created it. note: the "key"
- is destructively consumed during the set method; do not pass in your
- only copy. */
-
- bool set_key(RSA *key);
- //!< sets our new "key".
- /*!< this must be a valid key created via the RSA algorithms. */
-
- bool check_key(RSA *key);
- //!< checks the RSA "key" provided for validity.
-
- bool public_encrypt(const basis::byte_array &source, basis::byte_array &target) const;
- //!< encrypts "source" using our public key and stores it in "target".
- /*!< public_encrypt and private_decrypt are a pair. an untrusted user can
- encrypt with the public key and only the possessor of the private key
- should be able to decrypt it. */
- bool private_decrypt(const basis::byte_array &source, basis::byte_array &target) const;
- //!< decrypts "source" using our private key and stores it in "target".
-
- bool private_encrypt(const basis::byte_array &source, basis::byte_array &target) const;
- //!< encrypts "source" using our private key and stores it in "target".
- /*!< private_encrypt and public_decrypt are also a pair. the trusted
- user with the private key can create encrypted chunks that anyone with
- the public key can decrypt. */
- bool public_decrypt(const basis::byte_array &source, basis::byte_array &target) const;
- //!< decrypts "source" using our public key and stores it in "target".
-
- bool public_key(basis::byte_array &pubkey) const;
- //!< makes a copy of the public key held here.
- bool private_key(basis::byte_array &privkey) const;
- //!< makes a copy of the private key held here.
- /*!< the private key should never be exposed to anyone else. */
-
- static RSA *generate_key(int key_size);
- //!< creates a random RSA key using the lower-level openssl methods.
-
-private:
- RSA *_key; //!< our internal key.
-};
-
-} //namespace.
-
-#endif
-
PROJECT = tests_crypto
TYPE = test
-TARGETS = test_blowfish_crypto.exe test_rsa_crypto.exe
+TARGETS = test_blowfish_crypto.exe test_old_school_rsa_crypto.exe
LOCAL_LIBS_USED = unit_test crypto application processes loggers configuration textual timely \
filesystem structures basis
USE_SSL = t
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 = 64;
+const int blowfish_crypto_maximum_key_size_in_bits = 448;
+
//////////////
class test_blowfish; // forward.
int left = ITERATIONS;
while (left--) {
time_stamp key_start;
- blowfish_crypto bc(_parent.randomizer().inclusive
- (blowfish_crypto::minimum_key_size(),
- blowfish_crypto::maximum_key_size()));
+ blowfish_crypto bc(_parent.randomizer().inclusive(blowfish_crypto_minimum_key_size_in_bits,
+ 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());
--- /dev/null
+/*
+* Name : test RSA public key encryption
+* Author : Chris Koeritz
+* Purpose:
+* Exercises the RSA encryption functions from the crypto library.
+**
+* 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 <application/hoople_main.h>
+#include <basis/byte_array.h>
+#include <basis/astring.h>
+#include <crypto/old_school_rsa_crypto.h>
+#include <mathematics/chaos.h>
+#include <processes/ethread.h>
+#include <processes/thread_cabinet.h>
+#include <structures/static_memory_gremlin.h>
+#include <structures/unique_id.h>
+#include <textual/byte_formatter.h>
+#include <textual/string_manipulation.h>
+#include <timely/time_control.h>
+#include <timely/time_stamp.h>
+#include <unit_test/unit_base.h>
+
+#include <stdio.h>
+#include <string.h>
+
+using namespace application;
+using namespace basis;
+using namespace crypto;
+using namespace filesystem;
+using namespace loggers;
+using namespace mathematics;
+using namespace processes;
+using namespace structures;
+using namespace textual;
+using namespace timely;
+using namespace unit_test;
+
+//#define DEBUG_RSA_CRYPTO
+ // uncomment for noisy run.
+
+#define LOG(to_print) EMERGENCY_LOG(program_wide_logger::get(), to_print)
+
+const int KEY_SIZE = 1024;
+ // the size of the RSA key that we'll create.
+
+const int MAX_STRING = 4000;
+ // the largest chunk that we'll try to encrypt.
+
+const int THREAD_COUNT = 5; // number of threads testing rsa at once.
+
+const int ITERATIONS = 6; // number of test runs in our testing threads.
+
+//////////////
+
+class test_rsa; // forward.
+
+class rsa_thread : public ethread
+{
+public:
+ rsa_thread(test_rsa &parent) : ethread(), _parent(parent) {}
+
+ void perform_activity(void *ptr);
+ // try out random rsa keys on randomly chosen chunks of the fodder.
+
+private:
+ test_rsa &_parent;
+};
+
+//////////////
+
+class test_rsa : public virtual unit_base, virtual public application_shell
+{
+public:
+ test_rsa()
+ : _fodder(string_manipulation::make_random_name(MAX_STRING + 1, MAX_STRING + 1)) {}
+ virtual ~test_rsa() {}
+ DEFINE_CLASS_NAME("test_rsa");
+
+ const astring &fodder() const { return _fodder; }
+
+ int execute();
+
+private:
+ astring _fodder; // chunks taken from this are encrypted and decrypted.
+ time_stamp _program_start; // the time at which we started executing.
+ thread_cabinet _threads; // manages our testing threads.
+ friend class rsa_thread; // bad practice, but saves time in test app.
+};
+
+int test_rsa::execute()
+{
+ FUNCDEF("execute");
+ int left = THREAD_COUNT;
+ while (left--) {
+ _threads.add_thread(new rsa_thread(*this), true, NULL_POINTER);
+ }
+
+ while (_threads.threads()) {
+#ifdef DEBUG_RSA_CRYPTO
+ LOG(astring("cleaning debris."));
+#endif
+ _threads.clean_debris();
+#ifdef DEBUG_RSA_CRYPTO
+ LOG(astring("after cleaning debris."));
+#endif
+ time_control::sleep_ms(1000);
+ }
+
+#ifdef DEBUG_RSA_CRYPTO
+ int duration = int(time_stamp().value() - _program_start.value());
+ LOG(a_sprintf("duration for %d keys and encrypt/decrypt=%d ms,",
+ ITERATIONS * THREAD_COUNT, duration));
+ LOG(a_sprintf("that comes to %d ms per cycle.", int(double(duration
+ / ITERATIONS / THREAD_COUNT))));
+#endif
+
+ return final_report();
+}
+
+//////////////
+
+#undef UNIT_BASE_THIS_OBJECT
+#define UNIT_BASE_THIS_OBJECT (*dynamic_cast<unit_base *>(application_shell::single_instance()))
+
+void rsa_thread::perform_activity(void *)
+{
+ FUNCDEF("perform_activity");
+ int left = ITERATIONS;
+ while (left--) {
+ time_stamp start;
+
+ old_school_rsa_crypto rc_private_here(KEY_SIZE);
+ int key_durat = int(time_stamp().value() - start.value());
+
+ byte_array public_key;
+ rc_private_here.public_key(public_key); // get our public portion.
+ byte_array private_key;
+ rc_private_here.private_key(private_key); // get our private portion.
+
+//RSA_print_fp(stdout, private_key, 0);
+//RSA_print_fp(stdout, public_key, 0);
+
+ int string_start = _parent.randomizer().inclusive(0, MAX_STRING);
+ int string_end = _parent.randomizer().inclusive(0, MAX_STRING);
+ flip_increasing(string_start, string_end);
+ astring ranstring = _parent.fodder().substring(string_start, string_end);
+ byte_array target;
+
+ // the first phase tests the outsiders sending back data that only we,
+ // with our private key, can decrypt.
+
+ start.reset();
+ old_school_rsa_crypto rc_pub(public_key);
+ bool worked = rc_pub.public_encrypt(byte_array(ranstring.length() + 1,
+ (abyte*)ranstring.s()), target);
+ int pub_enc_durat = int(time_stamp().value() - start.value());
+ ASSERT_TRUE(worked, "phase 1 shouldn't fail to encrypt the string");
+
+ old_school_rsa_crypto rc_priv(private_key);
+ byte_array recovered;
+ start.reset();
+ worked = rc_priv.private_decrypt(target, recovered);
+ int priv_dec_durat = int(time_stamp().value() - start.value());
+ ASSERT_TRUE(worked, "phase 1 should not fail to decrypt the string");
+
+ astring teddro = (char *)recovered.observe();
+
+ ASSERT_EQUAL(teddro, ranstring, "should not fail to get back the data");
+
+ // the second phase tests us using our private key to encrypt data which
+ // anyone with the public key can decode.
+
+ start.reset();
+ worked = rc_priv.private_encrypt(byte_array(ranstring.length() + 1,
+ (abyte*)ranstring.s()), target);
+ int priv_enc_durat = int(time_stamp().value() - start.value());
+ ASSERT_TRUE(worked, "phase 2 should not fail to encrypt the string");
+
+ start.reset();
+ worked = rc_pub.public_decrypt(target, recovered);
+ int pub_dec_durat = int(time_stamp().value() - start.value());
+ ASSERT_TRUE(worked, "phase 2 should not fail to decrypt the string");
+
+ teddro = (char *)recovered.observe();
+
+ ASSERT_EQUAL(teddro, ranstring, "should not fail to get back the data here either");
+
+#ifdef DEBUG_RSA_CRYPTO
+ LOG(a_sprintf("key generation: %d ms, public encrypt: %d ms, private "
+ "decrypt: %d ms", key_durat, pub_enc_durat, priv_dec_durat));
+ LOG(a_sprintf("data size: %d bytes, private encrypt: %d ms, public "
+ "decrypt: %d ms",
+ string_end - string_start + 1, priv_enc_durat, pub_dec_durat));
+#endif
+
+ time_control::sleep_ms(0); // take a rest.
+ }
+}
+
+HOOPLE_MAIN(test_rsa, )
+
+++ /dev/null
-/*
-* Name : test RSA public key encryption
-* Author : Chris Koeritz
-* Purpose:
-* Exercises the RSA encryption functions from the crypto library.
-**
-* 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 <application/hoople_main.h>
-#include <basis/byte_array.h>
-#include <basis/astring.h>
-#include <crypto/rsa_crypto.h>
-#include <mathematics/chaos.h>
-#include <processes/ethread.h>
-#include <processes/thread_cabinet.h>
-#include <structures/static_memory_gremlin.h>
-#include <structures/unique_id.h>
-#include <textual/byte_formatter.h>
-#include <textual/string_manipulation.h>
-#include <timely/time_control.h>
-#include <timely/time_stamp.h>
-#include <unit_test/unit_base.h>
-
-#include <stdio.h>
-#include <string.h>
-
-using namespace application;
-using namespace basis;
-using namespace crypto;
-using namespace filesystem;
-using namespace loggers;
-using namespace mathematics;
-using namespace processes;
-using namespace structures;
-using namespace textual;
-using namespace timely;
-using namespace unit_test;
-
-//#define DEBUG_RSA_CRYPTO
- // uncomment for noisy run.
-
-#define LOG(to_print) EMERGENCY_LOG(program_wide_logger::get(), to_print)
-
-const int KEY_SIZE = 1024;
- // the size of the RSA key that we'll create.
-
-const int MAX_STRING = 4000;
- // the largest chunk that we'll try to encrypt.
-
-const int THREAD_COUNT = 5; // number of threads testing rsa at once.
-
-const int ITERATIONS = 6; // number of test runs in our testing threads.
-
-//////////////
-
-class test_rsa; // forward.
-
-class rsa_thread : public ethread
-{
-public:
- rsa_thread(test_rsa &parent) : ethread(), _parent(parent) {}
-
- void perform_activity(void *ptr);
- // try out random rsa keys on randomly chosen chunks of the fodder.
-
-private:
- test_rsa &_parent;
-};
-
-//////////////
-
-class test_rsa : public virtual unit_base, virtual public application_shell
-{
-public:
- test_rsa()
- : _fodder(string_manipulation::make_random_name(MAX_STRING + 1, MAX_STRING + 1)) {}
- virtual ~test_rsa() {}
- DEFINE_CLASS_NAME("test_rsa");
-
- const astring &fodder() const { return _fodder; }
-
- int execute();
-
-private:
- astring _fodder; // chunks taken from this are encrypted and decrypted.
- time_stamp _program_start; // the time at which we started executing.
- thread_cabinet _threads; // manages our testing threads.
- friend class rsa_thread; // bad practice, but saves time in test app.
-};
-
-int test_rsa::execute()
-{
- FUNCDEF("execute");
- int left = THREAD_COUNT;
- while (left--) {
- _threads.add_thread(new rsa_thread(*this), true, NULL_POINTER);
- }
-
- while (_threads.threads()) {
-#ifdef DEBUG_RSA_CRYPTO
- LOG(astring("cleaning debris."));
-#endif
- _threads.clean_debris();
-#ifdef DEBUG_RSA_CRYPTO
- LOG(astring("after cleaning debris."));
-#endif
- time_control::sleep_ms(1000);
- }
-
-#ifdef DEBUG_RSA_CRYPTO
- int duration = int(time_stamp().value() - _program_start.value());
- LOG(a_sprintf("duration for %d keys and encrypt/decrypt=%d ms,",
- ITERATIONS * THREAD_COUNT, duration));
- LOG(a_sprintf("that comes to %d ms per cycle.", int(double(duration
- / ITERATIONS / THREAD_COUNT))));
-#endif
-
- return final_report();
-}
-
-//////////////
-
-#undef UNIT_BASE_THIS_OBJECT
-#define UNIT_BASE_THIS_OBJECT (*dynamic_cast<unit_base *>(application_shell::single_instance()))
-
-void rsa_thread::perform_activity(void *)
-{
- FUNCDEF("perform_activity");
- int left = ITERATIONS;
- while (left--) {
- time_stamp start;
-
- rsa_crypto rc_private_here(KEY_SIZE);
- int key_durat = int(time_stamp().value() - start.value());
-
- byte_array public_key;
- rc_private_here.public_key(public_key); // get our public portion.
- byte_array private_key;
- rc_private_here.private_key(private_key); // get our private portion.
-
-//RSA_print_fp(stdout, private_key, 0);
-//RSA_print_fp(stdout, public_key, 0);
-
- int string_start = _parent.randomizer().inclusive(0, MAX_STRING);
- int string_end = _parent.randomizer().inclusive(0, MAX_STRING);
- flip_increasing(string_start, string_end);
- astring ranstring = _parent.fodder().substring(string_start, string_end);
- byte_array target;
-
- // the first phase tests the outsiders sending back data that only we,
- // with our private key, can decrypt.
-
- start.reset();
- rsa_crypto rc_pub(public_key);
- bool worked = rc_pub.public_encrypt(byte_array(ranstring.length() + 1,
- (abyte*)ranstring.s()), target);
- int pub_enc_durat = int(time_stamp().value() - start.value());
- ASSERT_TRUE(worked, "phase 1 shouldn't fail to encrypt the string");
-
- rsa_crypto rc_priv(private_key);
- byte_array recovered;
- start.reset();
- worked = rc_priv.private_decrypt(target, recovered);
- int priv_dec_durat = int(time_stamp().value() - start.value());
- ASSERT_TRUE(worked, "phase 1 should not fail to decrypt the string");
-
- astring teddro = (char *)recovered.observe();
-
- ASSERT_EQUAL(teddro, ranstring, "should not fail to get back the data");
-
- // the second phase tests us using our private key to encrypt data which
- // anyone with the public key can decode.
-
- start.reset();
- worked = rc_priv.private_encrypt(byte_array(ranstring.length() + 1,
- (abyte*)ranstring.s()), target);
- int priv_enc_durat = int(time_stamp().value() - start.value());
- ASSERT_TRUE(worked, "phase 2 should not fail to encrypt the string");
-
- start.reset();
- worked = rc_pub.public_decrypt(target, recovered);
- int pub_dec_durat = int(time_stamp().value() - start.value());
- ASSERT_TRUE(worked, "phase 2 should not fail to decrypt the string");
-
- teddro = (char *)recovered.observe();
-
- ASSERT_EQUAL(teddro, ranstring, "should not fail to get back the data here either");
-
-#ifdef DEBUG_RSA_CRYPTO
- LOG(a_sprintf("key generation: %d ms, public encrypt: %d ms, private "
- "decrypt: %d ms", key_durat, pub_enc_durat, priv_dec_durat));
- LOG(a_sprintf("data size: %d bytes, private encrypt: %d ms, public "
- "decrypt: %d ms",
- string_end - string_start + 1, priv_enc_durat, pub_dec_durat));
-#endif
-
- time_control::sleep_ms(0); // take a rest.
- }
-}
-
-HOOPLE_MAIN(test_rsa, )
-
#include <basis/functions.h>
#include <basis/mutex.h>
#include <configuration/application_configuration.h>
-#include <crypto/rsa_crypto.h>
+#include <crypto/old_school_rsa_crypto.h>
#include <loggers/program_wide_logger.h>
#include <mathematics/chaos.h>
#include <octopus/entity_defs.h>
#include <basis/functions.h>
#include <basis/astring.h>
#include <basis/mutex.h>
-#include <crypto/rsa_crypto.h>
+#include <crypto/old_school_rsa_crypto.h>
#include <loggers/program_wide_logger.h>
#include <octopus/entity_data_bin.h>
#include <octopus/entity_defs.h>
double cromp_common::_bytes_sent_total = 0.0;
double cromp_common::_bytes_received_total = 0.0;
- SAFE_STATIC_CONST(rsa_crypto, _hidden_localhost_only_key,
+ SAFE_STATIC_CONST(old_school_rsa_crypto, _hidden_localhost_only_key,
(encryption_infoton::RSA_KEY_SIZE))
- const rsa_crypto &cromp_common::localhost_only_key() {
+ const old_school_rsa_crypto &cromp_common::localhost_only_key() {
#ifdef DEBUG_CROMP_COMMON
FUNCDEF("localhost_only_key");
#endif
if (!was_initted)
LOG("started creating localhost RSA key.");
#endif
- const rsa_crypto &to_return = _hidden_localhost_only_key();
+ const old_school_rsa_crypto &to_return = _hidden_localhost_only_key();
#ifdef DEBUG_CROMP_COMMON
if (!was_initted)
LOG("done creating localhost RSA key.");
* Please send any updates to: fred@gruntose.com *
\*****************************************************************************/
-#include <crypto/rsa_crypto.h>
+#include <crypto/old_school_rsa_crypto.h>
#include <octopus/octopus.h>
#include <octopus/entity_defs.h>
#include <octopus/entity_data_bin.h>
// returns our octopus support object. this should always exist when this
// object is constructed properly.
- static const crypto::rsa_crypto &localhost_only_key();
+ static const crypto::old_school_rsa_crypto &localhost_only_key();
// this key should *only* be used for speeding up encryption on the local
// host. it is generated when the first caller needs it but then is
// a constant key during the program's runtime. this object can be used
#include <basis/mutex.h>
#include <basis/functions.h>
#include <crypto/blowfish_crypto.h>
-#include <crypto/rsa_crypto.h>
+#include <crypto/old_school_rsa_crypto.h>
#include <octopus/tentacle.h>
#include <structures/static_memory_gremlin.h>
#include <textual/byte_formatter.h>
return _success;
}
- rsa_crypto pub(_public_key); // suck in the provided key.
+ old_school_rsa_crypto pub(_public_key); // suck in the provided key.
blowfish_crypto agreed_key(BLOWFISH_KEY_SIZE); // random blowfish key.
new_key = agreed_key;
return _success;
}
-outcome encryption_infoton::prepare_both_keys(rsa_crypto &private_key)
+outcome encryption_infoton::prepare_both_keys(old_school_rsa_crypto &private_key)
{
- rsa_crypto priv(RSA_KEY_SIZE); // generate random key.
+ old_school_rsa_crypto priv(RSA_KEY_SIZE); // generate random key.
outcome to_return = prepare_public_key(priv);
if (to_return == tentacle::OKAY) private_key = priv;
return to_return;
}
-outcome encryption_infoton::prepare_public_key(const rsa_crypto &private_key)
+outcome encryption_infoton::prepare_public_key(const old_school_rsa_crypto &private_key)
{
bool worked = private_key.public_key(_public_key);
if (!worked) return tentacle::DISALLOWED; // why would that ever fail?
return tentacle::OKAY;
}
-outcome encryption_infoton::extract_response(const rsa_crypto &private_key,
+outcome encryption_infoton::extract_response(const old_school_rsa_crypto &private_key,
blowfish_crypto &new_key) const
{
FUNCDEF("extract_response");
\*****************************************************************************/
#include <crypto/blowfish_crypto.h>
-#include <crypto/rsa_crypto.h>
+#include <crypto/old_school_rsa_crypto.h>
#include <octopus/entity_defs.h>
#include <octopus/infoton.h>
"new_key" will always be used to communicate with the client after this.
*/
- basis::outcome prepare_public_key(const crypto::rsa_crypto &private_key);
+ basis::outcome prepare_public_key(const crypto::old_school_rsa_crypto &private_key);
//!< prepares the request side for a client.
/*!< the rsa public key will be generated from the "private_key". */
- basis::outcome prepare_both_keys(crypto::rsa_crypto &private_key);
+ basis::outcome prepare_both_keys(crypto::old_school_rsa_crypto &private_key);
//!< sets up both keys by randomly generating the "private_key".
- basis::outcome extract_response(const crypto::rsa_crypto &private_key,
+ basis::outcome extract_response(const crypto::old_school_rsa_crypto &private_key,
crypto::blowfish_crypto &new_key) const;
//!< used by the client to extract the shared blowfish key from the server.
/*!< using the private key, the server's response is decrypted and stored
#include "key_repository.h"
#include <crypto/blowfish_crypto.h>
-#include <crypto/rsa_crypto.h>
+#include <crypto/old_school_rsa_crypto.h>
#include <loggers/program_wide_logger.h>
#include <structures/symbol_table.h>
#include <textual/byte_formatter.h>
(encryption_infoton::encryption_classifier(), false),
_server_side(false),
_keys(new key_repository),
- _rsa_private(new rsa_crypto(private_key))
+ _rsa_private(new old_school_rsa_crypto(private_key))
{
}
(encryption_infoton::encryption_classifier(), false),
_server_side(false),
_keys(new key_repository),
- _rsa_private(new rsa_crypto(key_size))
+ _rsa_private(new old_school_rsa_crypto(key_size))
{
}
key_repository &encryption_tentacle::keys() const { return *_keys; }
-const rsa_crypto &encryption_tentacle::private_key() const
+const old_school_rsa_crypto &encryption_tentacle::private_key() const
{ return *_rsa_private; }
outcome encryption_tentacle::reconstitute(const string_array &classifier,
/*!< this is very private info, but it's needed for encrypting items
going back to the client. */
- const crypto::rsa_crypto &private_key() const;
+ const crypto::old_school_rsa_crypto &private_key() const;
//!< provides access to the key held here.
/*!< this is an important object; do not expose it externally. */
private:
bool _server_side; //!< true if we're acting as a server.
key_repository *_keys; //!< our table of keys that we've agreed on.
- crypto::rsa_crypto *_rsa_private; //!< the private key for a client side.
+ crypto::old_school_rsa_crypto *_rsa_private; //!< the private key for a client side.
};
} //namespace.
| sed -e 's/class encryption_tentacle;/#include <tentacles\/encryption_tentacle.h>/g' \
| sed -e 's/class login_tentacle;/#include <tentacles\/login_tentacle.h>/g' \
| sed -e 's/class thread_cabinet;/#include <processes\/thread_cabinet.h>/g' \
- | sed -e 's/RSA_crypto/rsa_crypto/g' \
+ | sed -e 's/RSA_crypto/old_school_rsa_crypto/g' \
| sed -e 's/float_plus<double>/double_plus/g' \
| sed -e 's/basis::obscure_/structures::obscure_/g' \
| sed -e 's/program_wide_logger()/program_wide_logger::get()/g' \