aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/openssl
diff options
context:
space:
mode:
authorlloyd <[email protected]>2015-02-04 04:03:38 +0000
committerlloyd <[email protected]>2015-02-04 04:03:38 +0000
commit0dd060fed07b0060f94e3bae62e125a85c1bb877 (patch)
treeed4bc7a961e2b30f17ed5e80769c84b0c313c8b7 /src/lib/openssl
parentf9a7c85b74be0f4a7273e8e0591703af83036e81 (diff)
Remove algo factory, engines, global RNG, global state, etc.
Convert all uses of Algorithm_Factory and the engines to using Algo_Registry The shared pool of entropy sources remains but is moved to EntropySource. With that and few remaining initializations (default OIDs and aliases) moved elsewhere, the global state is empty and init and shutdown are no-ops. Remove almost all of the headers and code for handling the global state, except LibraryInitializer which remains as a compatability stub. Update seeding for blinding so only one hacky almost-global RNG instance needs to be setup instead of across all pubkey uses (it uses either the system RNG or an AutoSeeded_RNG if the system RNG is not available).
Diffstat (limited to 'src/lib/openssl')
-rw-r--r--src/lib/openssl/ossl_arc4.cpp89
-rw-r--r--src/lib/openssl/ossl_bc.cpp248
-rw-r--r--src/lib/openssl/ossl_md.cpp150
3 files changed, 487 insertions, 0 deletions
diff --git a/src/lib/openssl/ossl_arc4.cpp b/src/lib/openssl/ossl_arc4.cpp
new file mode 100644
index 000000000..4533c2688
--- /dev/null
+++ b/src/lib/openssl/ossl_arc4.cpp
@@ -0,0 +1,89 @@
+/*
+* OpenSSL RC4
+* (C) 1999-2007 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/internal/openssl_engine.h>
+#include <botan/parsing.h>
+#include <openssl/rc4.h>
+
+namespace Botan {
+
+namespace {
+
+/**
+* RC4 as implemented by OpenSSL
+*/
+class RC4_OpenSSL : public StreamCipher
+ {
+ public:
+ void clear() { clear_mem(&state, 1); }
+
+ std::string name() const;
+ StreamCipher* clone() const { return new RC4_OpenSSL(SKIP); }
+
+ Key_Length_Specification key_spec() const
+ {
+ return Key_Length_Specification(1, 32);
+ }
+
+
+ RC4_OpenSSL(size_t s = 0) : SKIP(s) { clear(); }
+ ~RC4_OpenSSL() { clear(); }
+ private:
+ void cipher(const byte[], byte[], size_t);
+ void key_schedule(const byte[], size_t);
+
+ const size_t SKIP;
+ RC4_KEY state;
+ };
+
+/*
+* Return the name of this type
+*/
+std::string RC4_OpenSSL::name() const
+ {
+ if(SKIP == 0) return "RC4";
+ if(SKIP == 256) return "MARK-4";
+ else return "RC4_skip(" + std::to_string(SKIP) + ")";
+ }
+
+/*
+* RC4 Key Schedule
+*/
+void RC4_OpenSSL::key_schedule(const byte key[], size_t length)
+ {
+ RC4_set_key(&state, length, key);
+ byte dummy = 0;
+ for(size_t i = 0; i != SKIP; ++i)
+ RC4(&state, 1, &dummy, &dummy);
+ }
+
+/*
+* RC4 Encryption
+*/
+void RC4_OpenSSL::cipher(const byte in[], byte out[], size_t length)
+ {
+ RC4(&state, length, in, out);
+ }
+
+}
+
+/**
+* Look for an OpenSSL-supported stream cipher (RC4)
+*/
+StreamCipher*
+OpenSSL_Engine::find_stream_cipher(const SCAN_Name& request,
+ Algorithm_Factory&) const
+ {
+ if(request.algo_name() == "RC4")
+ return new RC4_OpenSSL(request.arg_as_integer(0, 0));
+ if(request.algo_name() == "RC4_drop")
+ return new RC4_OpenSSL(768);
+
+ return 0;
+ }
+
+}
diff --git a/src/lib/openssl/ossl_bc.cpp b/src/lib/openssl/ossl_bc.cpp
new file mode 100644
index 000000000..8e8c6e5a8
--- /dev/null
+++ b/src/lib/openssl/ossl_bc.cpp
@@ -0,0 +1,248 @@
+/*
+* OpenSSL Block Cipher
+* (C) 1999-2010 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/internal/openssl_engine.h>
+#include <openssl/evp.h>
+
+namespace Botan {
+
+namespace {
+
+/*
+* EVP Block Cipher
+*/
+class EVP_BlockCipher : public BlockCipher
+ {
+ public:
+ void clear();
+ std::string name() const { return cipher_name; }
+ BlockCipher* clone() const;
+
+ size_t block_size() const { return block_sz; }
+
+ EVP_BlockCipher(const EVP_CIPHER*, const std::string&);
+
+ EVP_BlockCipher(const EVP_CIPHER*, const std::string&,
+ size_t, size_t, size_t);
+
+ Key_Length_Specification key_spec() const { return cipher_key_spec; }
+
+ ~EVP_BlockCipher();
+ private:
+ void encrypt_n(const byte in[], byte out[], size_t blocks) const;
+ void decrypt_n(const byte in[], byte out[], size_t blocks) const;
+ void key_schedule(const byte[], size_t);
+
+ size_t block_sz;
+ Key_Length_Specification cipher_key_spec;
+ std::string cipher_name;
+ mutable EVP_CIPHER_CTX encrypt, decrypt;
+ };
+
+/*
+* EVP Block Cipher Constructor
+*/
+EVP_BlockCipher::EVP_BlockCipher(const EVP_CIPHER* algo,
+ const std::string& algo_name) :
+ block_sz(EVP_CIPHER_block_size(algo)),
+ cipher_key_spec(EVP_CIPHER_key_length(algo)),
+ cipher_name(algo_name)
+ {
+ if(EVP_CIPHER_mode(algo) != EVP_CIPH_ECB_MODE)
+ throw Invalid_Argument("EVP_BlockCipher: Non-ECB EVP was passed in");
+
+ EVP_CIPHER_CTX_init(&encrypt);
+ EVP_CIPHER_CTX_init(&decrypt);
+
+ EVP_EncryptInit_ex(&encrypt, algo, 0, 0, 0);
+ EVP_DecryptInit_ex(&decrypt, algo, 0, 0, 0);
+
+ EVP_CIPHER_CTX_set_padding(&encrypt, 0);
+ EVP_CIPHER_CTX_set_padding(&decrypt, 0);
+ }
+
+/*
+* EVP Block Cipher Constructor
+*/
+EVP_BlockCipher::EVP_BlockCipher(const EVP_CIPHER* algo,
+ const std::string& algo_name,
+ size_t key_min, size_t key_max,
+ size_t key_mod) :
+ block_sz(EVP_CIPHER_block_size(algo)),
+ cipher_key_spec(key_min, key_max, key_mod),
+ cipher_name(algo_name)
+ {
+ if(EVP_CIPHER_mode(algo) != EVP_CIPH_ECB_MODE)
+ throw Invalid_Argument("EVP_BlockCipher: Non-ECB EVP was passed in");
+
+ EVP_CIPHER_CTX_init(&encrypt);
+ EVP_CIPHER_CTX_init(&decrypt);
+
+ EVP_EncryptInit_ex(&encrypt, algo, 0, 0, 0);
+ EVP_DecryptInit_ex(&decrypt, algo, 0, 0, 0);
+
+ EVP_CIPHER_CTX_set_padding(&encrypt, 0);
+ EVP_CIPHER_CTX_set_padding(&decrypt, 0);
+ }
+
+/*
+* EVP Block Cipher Destructor
+*/
+EVP_BlockCipher::~EVP_BlockCipher()
+ {
+ EVP_CIPHER_CTX_cleanup(&encrypt);
+ EVP_CIPHER_CTX_cleanup(&decrypt);
+ }
+
+/*
+* Encrypt a block
+*/
+void EVP_BlockCipher::encrypt_n(const byte in[], byte out[],
+ size_t blocks) const
+ {
+ int out_len = 0;
+ EVP_EncryptUpdate(&encrypt, out, &out_len, in, blocks * block_sz);
+ }
+
+/*
+* Decrypt a block
+*/
+void EVP_BlockCipher::decrypt_n(const byte in[], byte out[],
+ size_t blocks) const
+ {
+ int out_len = 0;
+ EVP_DecryptUpdate(&decrypt, out, &out_len, in, blocks * block_sz);
+ }
+
+/*
+* Set the key
+*/
+void EVP_BlockCipher::key_schedule(const byte key[], size_t length)
+ {
+ secure_vector<byte> full_key(key, key + length);
+
+ if(cipher_name == "TripleDES" && length == 16)
+ {
+ full_key += std::make_pair(key, 8);
+ }
+ else
+ if(EVP_CIPHER_CTX_set_key_length(&encrypt, length) == 0 ||
+ EVP_CIPHER_CTX_set_key_length(&decrypt, length) == 0)
+ throw Invalid_Argument("EVP_BlockCipher: Bad key length for " +
+ cipher_name);
+
+ if(cipher_name == "RC2")
+ {
+ EVP_CIPHER_CTX_ctrl(&encrypt, EVP_CTRL_SET_RC2_KEY_BITS, length*8, 0);
+ EVP_CIPHER_CTX_ctrl(&decrypt, EVP_CTRL_SET_RC2_KEY_BITS, length*8, 0);
+ }
+
+ EVP_EncryptInit_ex(&encrypt, 0, 0, &full_key[0], 0);
+ EVP_DecryptInit_ex(&decrypt, 0, 0, &full_key[0], 0);
+ }
+
+/*
+* Return a clone of this object
+*/
+BlockCipher* EVP_BlockCipher::clone() const
+ {
+ return new EVP_BlockCipher(EVP_CIPHER_CTX_cipher(&encrypt),
+ cipher_name,
+ cipher_key_spec.minimum_keylength(),
+ cipher_key_spec.maximum_keylength(),
+ cipher_key_spec.keylength_multiple());
+ }
+
+/*
+* Clear memory of sensitive data
+*/
+void EVP_BlockCipher::clear()
+ {
+ const EVP_CIPHER* algo = EVP_CIPHER_CTX_cipher(&encrypt);
+
+ EVP_CIPHER_CTX_cleanup(&encrypt);
+ EVP_CIPHER_CTX_cleanup(&decrypt);
+ EVP_CIPHER_CTX_init(&encrypt);
+ EVP_CIPHER_CTX_init(&decrypt);
+ EVP_EncryptInit_ex(&encrypt, algo, 0, 0, 0);
+ EVP_DecryptInit_ex(&decrypt, algo, 0, 0, 0);
+ EVP_CIPHER_CTX_set_padding(&encrypt, 0);
+ EVP_CIPHER_CTX_set_padding(&decrypt, 0);
+ }
+
+}
+
+/*
+* Look for an algorithm with this name
+*/
+BlockCipher*
+OpenSSL_Engine::find_block_cipher(const SCAN_Name& request,
+ Algorithm_Factory&) const
+ {
+#define HANDLE_EVP_CIPHER(NAME, EVP) \
+ if(request.algo_name() == NAME && request.arg_count() == 0) \
+ return new EVP_BlockCipher(EVP, NAME);
+
+#define HANDLE_EVP_CIPHER_KEYLEN(NAME, EVP, MIN, MAX, MOD) \
+ if(request.algo_name() == NAME && request.arg_count() == 0) \
+ return new EVP_BlockCipher(EVP, NAME, MIN, MAX, MOD);
+
+#if !defined(OPENSSL_NO_AES)
+ /*
+ Using OpenSSL's AES causes crashes inside EVP on x86-64 with OpenSSL 0.9.8g
+ cause is unknown
+ */
+ HANDLE_EVP_CIPHER("AES-128", EVP_aes_128_ecb());
+ HANDLE_EVP_CIPHER("AES-192", EVP_aes_192_ecb());
+ HANDLE_EVP_CIPHER("AES-256", EVP_aes_256_ecb());
+#endif
+
+#if !defined(OPENSSL_NO_DES)
+ HANDLE_EVP_CIPHER("DES", EVP_des_ecb());
+ HANDLE_EVP_CIPHER_KEYLEN("TripleDES", EVP_des_ede3_ecb(), 16, 24, 8);
+#endif
+
+#if !defined(OPENSSL_NO_BF)
+ HANDLE_EVP_CIPHER_KEYLEN("Blowfish", EVP_bf_ecb(), 1, 56, 1);
+#endif
+
+#if !defined(OPENSSL_NO_CAST)
+ HANDLE_EVP_CIPHER_KEYLEN("CAST-128", EVP_cast5_ecb(), 1, 16, 1);
+#endif
+
+#if !defined(OPENSSL_NO_CAMELLIA)
+ HANDLE_EVP_CIPHER("Camellia-128", EVP_camellia_128_ecb());
+ HANDLE_EVP_CIPHER("Camellia-192", EVP_camellia_192_ecb());
+ HANDLE_EVP_CIPHER("Camellia-256", EVP_camellia_256_ecb());
+#endif
+
+#if !defined(OPENSSL_NO_RC2)
+ HANDLE_EVP_CIPHER_KEYLEN("RC2", EVP_rc2_ecb(), 1, 32, 1);
+#endif
+
+#if !defined(OPENSSL_NO_RC5) && 0
+ if(request.algo_name() == "RC5")
+ if(request.arg_as_integer(0, 12) == 12)
+ return new EVP_BlockCipher(EVP_rc5_32_12_16_ecb(),
+ "RC5(12)", 1, 32, 1);
+#endif
+
+#if !defined(OPENSSL_NO_IDEA) && 0
+ HANDLE_EVP_CIPHER("IDEA", EVP_idea_ecb());
+#endif
+
+#if !defined(OPENSSL_NO_SEED)
+ HANDLE_EVP_CIPHER("SEED", EVP_seed_ecb());
+#endif
+
+#undef HANDLE_EVP_CIPHER
+#undef HANDLE_EVP_CIPHER_KEYLEN
+
+ return 0;
+ }
+
+}
diff --git a/src/lib/openssl/ossl_md.cpp b/src/lib/openssl/ossl_md.cpp
new file mode 100644
index 000000000..063271151
--- /dev/null
+++ b/src/lib/openssl/ossl_md.cpp
@@ -0,0 +1,150 @@
+/*
+* OpenSSL Hash Functions
+* (C) 1999-2007 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/internal/openssl_engine.h>
+#include <openssl/evp.h>
+
+namespace Botan {
+
+namespace {
+
+/*
+* EVP Hash Function
+*/
+class EVP_HashFunction : public HashFunction
+ {
+ public:
+ void clear();
+ std::string name() const { return algo_name; }
+ HashFunction* clone() const;
+
+ size_t output_length() const
+ {
+ return EVP_MD_size(EVP_MD_CTX_md(&md));
+ }
+
+ size_t hash_block_size() const
+ {
+ return EVP_MD_block_size(EVP_MD_CTX_md(&md));
+ }
+
+ EVP_HashFunction(const EVP_MD*, const std::string&);
+ ~EVP_HashFunction();
+ private:
+ void add_data(const byte[], size_t);
+ void final_result(byte[]);
+
+ std::string algo_name;
+ EVP_MD_CTX md;
+ };
+
+/*
+* Update an EVP Hash Calculation
+*/
+void EVP_HashFunction::add_data(const byte input[], size_t length)
+ {
+ EVP_DigestUpdate(&md, input, length);
+ }
+
+/*
+* Finalize an EVP Hash Calculation
+*/
+void EVP_HashFunction::final_result(byte output[])
+ {
+ EVP_DigestFinal_ex(&md, output, 0);
+ const EVP_MD* algo = EVP_MD_CTX_md(&md);
+ EVP_DigestInit_ex(&md, algo, 0);
+ }
+
+/*
+* Clear memory of sensitive data
+*/
+void EVP_HashFunction::clear()
+ {
+ const EVP_MD* algo = EVP_MD_CTX_md(&md);
+ EVP_DigestInit_ex(&md, algo, 0);
+ }
+
+/*
+* Return a clone of this object
+*/
+HashFunction* EVP_HashFunction::clone() const
+ {
+ const EVP_MD* algo = EVP_MD_CTX_md(&md);
+ return new EVP_HashFunction(algo, name());
+ }
+
+/*
+* Create an EVP hash function
+*/
+EVP_HashFunction::EVP_HashFunction(const EVP_MD* algo,
+ const std::string& name) :
+ algo_name(name)
+ {
+ EVP_MD_CTX_init(&md);
+ EVP_DigestInit_ex(&md, algo, 0);
+ }
+
+/*
+* Destroy an EVP hash function
+*/
+EVP_HashFunction::~EVP_HashFunction()
+ {
+ EVP_MD_CTX_cleanup(&md);
+ }
+
+}
+
+/*
+* Look for an algorithm with this name
+*/
+HashFunction* OpenSSL_Engine::find_hash(const SCAN_Name& request,
+ Algorithm_Factory&) const
+ {
+#if !defined(OPENSSL_NO_SHA)
+ if(request.algo_name() == "SHA-160")
+ return new EVP_HashFunction(EVP_sha1(), "SHA-160");
+#endif
+
+#if !defined(OPENSSL_NO_SHA256)
+ if(request.algo_name() == "SHA-224")
+ return new EVP_HashFunction(EVP_sha224(), "SHA-224");
+ if(request.algo_name() == "SHA-256")
+ return new EVP_HashFunction(EVP_sha256(), "SHA-256");
+#endif
+
+#if !defined(OPENSSL_NO_SHA512)
+ if(request.algo_name() == "SHA-384")
+ return new EVP_HashFunction(EVP_sha384(), "SHA-384");
+ if(request.algo_name() == "SHA-512")
+ return new EVP_HashFunction(EVP_sha512(), "SHA-512");
+#endif
+
+#if !defined(OPENSSL_NO_MD2)
+ if(request.algo_name() == "MD2")
+ return new EVP_HashFunction(EVP_md2(), "MD2");
+#endif
+
+#if !defined(OPENSSL_NO_MD4)
+ if(request.algo_name() == "MD4")
+ return new EVP_HashFunction(EVP_md4(), "MD4");
+#endif
+
+#if !defined(OPENSSL_NO_MD5)
+ if(request.algo_name() == "MD5")
+ return new EVP_HashFunction(EVP_md5(), "MD5");
+#endif
+
+#if !defined(OPENSSL_NO_RIPEMD)
+ if(request.algo_name() == "RIPEMD-160")
+ return new EVP_HashFunction(EVP_ripemd160(), "RIPEMD-160");
+#endif
+
+ return 0;
+ }
+
+}