aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/engine/openssl
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/engine/openssl')
-rw-r--r--src/lib/engine/openssl/bn_powm.cpp54
-rw-r--r--src/lib/engine/openssl/bn_wrap.cpp116
-rw-r--r--src/lib/engine/openssl/bn_wrap.h60
-rw-r--r--src/lib/engine/openssl/info.txt25
-rw-r--r--src/lib/engine/openssl/openssl_engine.h49
-rw-r--r--src/lib/engine/openssl/ossl_arc4.cpp89
-rw-r--r--src/lib/engine/openssl/ossl_bc.cpp248
-rw-r--r--src/lib/engine/openssl/ossl_md.cpp150
-rw-r--r--src/lib/engine/openssl/ossl_pk.cpp338
9 files changed, 1129 insertions, 0 deletions
diff --git a/src/lib/engine/openssl/bn_powm.cpp b/src/lib/engine/openssl/bn_powm.cpp
new file mode 100644
index 000000000..ac06fbe77
--- /dev/null
+++ b/src/lib/engine/openssl/bn_powm.cpp
@@ -0,0 +1,54 @@
+/*
+* OpenSSL Modular Exponentiation
+* (C) 1999-2007 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/internal/openssl_engine.h>
+#include <botan/internal/bn_wrap.h>
+
+namespace Botan {
+
+namespace {
+
+/*
+* OpenSSL Modular Exponentiator
+*/
+class OpenSSL_Modular_Exponentiator : public Modular_Exponentiator
+ {
+ public:
+ void set_base(const BigInt& b) { base = b; }
+ void set_exponent(const BigInt& e) { exp = e; }
+ BigInt execute() const;
+ Modular_Exponentiator* copy() const
+ { return new OpenSSL_Modular_Exponentiator(*this); }
+
+ OpenSSL_Modular_Exponentiator(const BigInt& n) : mod(n) {}
+ private:
+ OSSL_BN base, exp, mod;
+ OSSL_BN_CTX ctx;
+ };
+
+/*
+* Compute the result
+*/
+BigInt OpenSSL_Modular_Exponentiator::execute() const
+ {
+ OSSL_BN r;
+ BN_mod_exp(r.ptr(), base.ptr(), exp.ptr(), mod.ptr(), ctx.ptr());
+ return r.to_bigint();
+ }
+
+}
+
+/*
+* Return the OpenSSL-based modular exponentiator
+*/
+Modular_Exponentiator* OpenSSL_Engine::mod_exp(const BigInt& n,
+ Power_Mod::Usage_Hints) const
+ {
+ return new OpenSSL_Modular_Exponentiator(n);
+ }
+
+}
diff --git a/src/lib/engine/openssl/bn_wrap.cpp b/src/lib/engine/openssl/bn_wrap.cpp
new file mode 100644
index 000000000..0a7e42368
--- /dev/null
+++ b/src/lib/engine/openssl/bn_wrap.cpp
@@ -0,0 +1,116 @@
+/*
+* OpenSSL BN Wrapper
+* (C) 1999-2007 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/internal/bn_wrap.h>
+
+namespace Botan {
+
+/*
+* OSSL_BN Constructor
+*/
+OSSL_BN::OSSL_BN(const BigInt& in)
+ {
+ m_bn = BN_new();
+ secure_vector<byte> encoding = BigInt::encode_locked(in);
+ if(in != 0)
+ BN_bin2bn(&encoding[0], encoding.size(), m_bn);
+ }
+
+/*
+* OSSL_BN Constructor
+*/
+OSSL_BN::OSSL_BN(const byte in[], size_t length)
+ {
+ m_bn = BN_new();
+ BN_bin2bn(in, length, m_bn);
+ }
+
+/*
+* OSSL_BN Copy Constructor
+*/
+OSSL_BN::OSSL_BN(const OSSL_BN& other)
+ {
+ m_bn = BN_dup(other.m_bn);
+ }
+
+/*
+* OSSL_BN Destructor
+*/
+OSSL_BN::~OSSL_BN()
+ {
+ BN_clear_free(m_bn);
+ }
+
+/*
+* OSSL_BN Assignment Operator
+*/
+OSSL_BN& OSSL_BN::operator=(const OSSL_BN& other)
+ {
+ BN_copy(m_bn, other.m_bn);
+ return (*this);
+ }
+
+/*
+* Export the BIGNUM as a bytestring
+*/
+void OSSL_BN::encode(byte out[], size_t length) const
+ {
+ BN_bn2bin(m_bn, out + (length - bytes()));
+ }
+
+/*
+* Return the number of significant bytes
+*/
+size_t OSSL_BN::bytes() const
+ {
+ return BN_num_bytes(m_bn);
+ }
+
+/*
+* OpenSSL to BigInt Conversions
+*/
+BigInt OSSL_BN::to_bigint() const
+ {
+ secure_vector<byte> out(bytes());
+ BN_bn2bin(m_bn, &out[0]);
+ return BigInt::decode(out);
+ }
+
+/*
+* OSSL_BN_CTX Constructor
+*/
+OSSL_BN_CTX::OSSL_BN_CTX()
+ {
+ m_ctx = BN_CTX_new();
+ }
+
+/*
+* OSSL_BN_CTX Copy Constructor
+*/
+OSSL_BN_CTX::OSSL_BN_CTX(const OSSL_BN_CTX&)
+ {
+ m_ctx = BN_CTX_new();
+ }
+
+/*
+* OSSL_BN_CTX Destructor
+*/
+OSSL_BN_CTX::~OSSL_BN_CTX()
+ {
+ BN_CTX_free(m_ctx);
+ }
+
+/*
+* OSSL_BN_CTX Assignment Operator
+*/
+OSSL_BN_CTX& OSSL_BN_CTX::operator=(const OSSL_BN_CTX&)
+ {
+ m_ctx = BN_CTX_new();
+ return (*this);
+ }
+
+}
diff --git a/src/lib/engine/openssl/bn_wrap.h b/src/lib/engine/openssl/bn_wrap.h
new file mode 100644
index 000000000..12bcec152
--- /dev/null
+++ b/src/lib/engine/openssl/bn_wrap.h
@@ -0,0 +1,60 @@
+/*
+* OpenSSL BN Wrapper
+* (C) 1999-2007 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_OPENSSL_BN_WRAP_H__
+#define BOTAN_OPENSSL_BN_WRAP_H__
+
+#include <botan/bigint.h>
+#include <openssl/bn.h>
+
+namespace Botan {
+
+/**
+* Lightweight OpenSSL BN wrapper. For internal use only.
+*/
+class OSSL_BN
+ {
+ public:
+ BigInt to_bigint() const;
+ void encode(byte[], size_t) const;
+ size_t bytes() const;
+
+ secure_vector<byte> to_bytes() const
+ { return BigInt::encode_locked(to_bigint()); }
+
+ OSSL_BN& operator=(const OSSL_BN&);
+
+ OSSL_BN(const OSSL_BN&);
+ OSSL_BN(const BigInt& = 0);
+ OSSL_BN(const byte[], size_t);
+ ~OSSL_BN();
+
+ BIGNUM* ptr() const { return m_bn; }
+ private:
+ BIGNUM* m_bn;
+ };
+
+/**
+* Lightweight OpenSSL BN_CTX wrapper. For internal use only.
+*/
+class OSSL_BN_CTX
+ {
+ public:
+ OSSL_BN_CTX& operator=(const OSSL_BN_CTX&);
+
+ OSSL_BN_CTX();
+ OSSL_BN_CTX(const OSSL_BN_CTX&);
+ ~OSSL_BN_CTX();
+
+ BN_CTX* ptr() const { return m_ctx; }
+ private:
+ BN_CTX* m_ctx;
+ };
+
+}
+
+#endif
diff --git a/src/lib/engine/openssl/info.txt b/src/lib/engine/openssl/info.txt
new file mode 100644
index 000000000..d500816d5
--- /dev/null
+++ b/src/lib/engine/openssl/info.txt
@@ -0,0 +1,25 @@
+define ENGINE_OPENSSL 20131128
+
+load_on request
+
+<libs>
+all -> crypto
+</libs>
+
+<header:internal>
+openssl_engine.h
+bn_wrap.h
+</header:internal>
+
+<source>
+bn_powm.cpp
+bn_wrap.cpp
+ossl_arc4.cpp
+ossl_bc.cpp
+ossl_md.cpp
+ossl_pk.cpp
+</source>
+
+<requires>
+bigint
+</requires>
diff --git a/src/lib/engine/openssl/openssl_engine.h b/src/lib/engine/openssl/openssl_engine.h
new file mode 100644
index 000000000..90f315c00
--- /dev/null
+++ b/src/lib/engine/openssl/openssl_engine.h
@@ -0,0 +1,49 @@
+/*
+* OpenSSL Engine
+* (C) 1999-2007 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_ENGINE_OPENSSL_H__
+#define BOTAN_ENGINE_OPENSSL_H__
+
+#include <botan/engine.h>
+
+namespace Botan {
+
+/**
+* OpenSSL Engine
+*/
+class OpenSSL_Engine : public Engine
+ {
+ public:
+ std::string provider_name() const override { return "openssl"; }
+
+ PK_Ops::Key_Agreement*
+ get_key_agreement_op(const Private_Key& key, RandomNumberGenerator& rng) const override;
+
+ PK_Ops::Signature*
+ get_signature_op(const Private_Key& key, RandomNumberGenerator& rng) const override;
+
+ PK_Ops::Verification* get_verify_op(const Public_Key& key, RandomNumberGenerator& rng) const override;
+
+ PK_Ops::Encryption* get_encryption_op(const Public_Key& key, RandomNumberGenerator& rng) const override;
+
+ PK_Ops::Decryption* get_decryption_op(const Private_Key& key, RandomNumberGenerator& rng) const override;
+
+ Modular_Exponentiator* mod_exp(const BigInt&,
+ Power_Mod::Usage_Hints) const override;
+
+ BlockCipher* find_block_cipher(const SCAN_Name&,
+ Algorithm_Factory&) const override;
+
+ StreamCipher* find_stream_cipher(const SCAN_Name&,
+ Algorithm_Factory&) const override;
+
+ HashFunction* find_hash(const SCAN_Name&, Algorithm_Factory&) const override;
+ };
+
+}
+
+#endif
diff --git a/src/lib/engine/openssl/ossl_arc4.cpp b/src/lib/engine/openssl/ossl_arc4.cpp
new file mode 100644
index 000000000..0eb404af1
--- /dev/null
+++ b/src/lib/engine/openssl/ossl_arc4.cpp
@@ -0,0 +1,89 @@
+/*
+* OpenSSL RC4
+* (C) 1999-2007 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#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/engine/openssl/ossl_bc.cpp b/src/lib/engine/openssl/ossl_bc.cpp
new file mode 100644
index 000000000..b3b509c36
--- /dev/null
+++ b/src/lib/engine/openssl/ossl_bc.cpp
@@ -0,0 +1,248 @@
+/*
+* OpenSSL Block Cipher
+* (C) 1999-2010 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#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/engine/openssl/ossl_md.cpp b/src/lib/engine/openssl/ossl_md.cpp
new file mode 100644
index 000000000..e09a68a8e
--- /dev/null
+++ b/src/lib/engine/openssl/ossl_md.cpp
@@ -0,0 +1,150 @@
+/*
+* OpenSSL Hash Functions
+* (C) 1999-2007 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#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;
+ }
+
+}
diff --git a/src/lib/engine/openssl/ossl_pk.cpp b/src/lib/engine/openssl/ossl_pk.cpp
new file mode 100644
index 000000000..cbe03d7b3
--- /dev/null
+++ b/src/lib/engine/openssl/ossl_pk.cpp
@@ -0,0 +1,338 @@
+/*
+* OpenSSL PK operations
+* (C) 1999-2010 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/internal/openssl_engine.h>
+#include <botan/internal/bn_wrap.h>
+
+#if defined(BOTAN_HAS_RSA)
+ #include <botan/rsa.h>
+#endif
+
+#if defined(BOTAN_HAS_DSA)
+ #include <botan/dsa.h>
+#endif
+
+#if defined(BOTAN_HAS_ECDSA)
+ #include <botan/ecdsa.h>
+ #include <openssl/ecdsa.h>
+#endif
+
+#if defined(BOTAN_HAS_DIFFIE_HELLMAN)
+ #include <botan/dh.h>
+#endif
+
+namespace Botan {
+
+namespace {
+
+#if defined(BOTAN_HAS_DIFFIE_HELLMAN)
+class OSSL_DH_KA_Operation : public PK_Ops::Key_Agreement
+ {
+ public:
+ OSSL_DH_KA_Operation(const DH_PrivateKey& dh) :
+ x(dh.get_x()), p(dh.group_p()) {}
+
+ secure_vector<byte> agree(const byte w[], size_t w_len)
+ {
+ OSSL_BN i(w, w_len), r;
+ BN_mod_exp(r.ptr(), i.ptr(), x.ptr(), p.ptr(), ctx.ptr());
+ return r.to_bytes();
+ }
+
+ private:
+ const OSSL_BN x, p;
+ OSSL_BN_CTX ctx;
+ };
+#endif
+
+#if defined(BOTAN_HAS_DSA)
+
+class OSSL_DSA_Signature_Operation : public PK_Ops::Signature
+ {
+ public:
+ OSSL_DSA_Signature_Operation(const DSA_PrivateKey& dsa) :
+ x(dsa.get_x()),
+ p(dsa.group_p()),
+ q(dsa.group_q()),
+ g(dsa.group_g()),
+ q_bits(dsa.group_q().bits()) {}
+
+ size_t message_parts() const { return 2; }
+ size_t message_part_size() const { return (q_bits + 7) / 8; }
+ size_t max_input_bits() const { return q_bits; }
+
+ secure_vector<byte> sign(const byte msg[], size_t msg_len,
+ RandomNumberGenerator& rng);
+ private:
+ const OSSL_BN x, p, q, g;
+ const OSSL_BN_CTX ctx;
+ size_t q_bits;
+ };
+
+secure_vector<byte>
+OSSL_DSA_Signature_Operation::sign(const byte msg[], size_t msg_len,
+ RandomNumberGenerator& rng)
+ {
+ const size_t q_bytes = (q_bits + 7) / 8;
+
+ rng.add_entropy(msg, msg_len);
+
+ BigInt k_bn;
+ do
+ k_bn.randomize(rng, q_bits);
+ while(k_bn >= q.to_bigint());
+
+ OSSL_BN i(msg, msg_len);
+ OSSL_BN k(k_bn);
+
+ OSSL_BN r;
+ BN_mod_exp(r.ptr(), g.ptr(), k.ptr(), p.ptr(), ctx.ptr());
+ BN_nnmod(r.ptr(), r.ptr(), q.ptr(), ctx.ptr());
+
+ BN_mod_inverse(k.ptr(), k.ptr(), q.ptr(), ctx.ptr());
+
+ OSSL_BN s;
+ BN_mul(s.ptr(), x.ptr(), r.ptr(), ctx.ptr());
+ BN_add(s.ptr(), s.ptr(), i.ptr());
+ BN_mod_mul(s.ptr(), s.ptr(), k.ptr(), q.ptr(), ctx.ptr());
+
+ if(BN_is_zero(r.ptr()) || BN_is_zero(s.ptr()))
+ throw Internal_Error("OpenSSL_DSA_Op::sign: r or s was zero");
+
+ secure_vector<byte> output(2*q_bytes);
+ r.encode(&output[0], q_bytes);
+ s.encode(&output[q_bytes], q_bytes);
+ return output;
+ }
+
+class OSSL_DSA_Verification_Operation : public PK_Ops::Verification
+ {
+ public:
+ OSSL_DSA_Verification_Operation(const DSA_PublicKey& dsa) :
+ y(dsa.get_y()),
+ p(dsa.group_p()),
+ q(dsa.group_q()),
+ g(dsa.group_g()),
+ q_bits(dsa.group_q().bits()) {}
+
+ size_t message_parts() const { return 2; }
+ size_t message_part_size() const { return (q_bits + 7) / 8; }
+ size_t max_input_bits() const { return q_bits; }
+
+ bool with_recovery() const { return false; }
+
+ bool verify(const byte msg[], size_t msg_len,
+ const byte sig[], size_t sig_len);
+ private:
+ const OSSL_BN y, p, q, g;
+ const OSSL_BN_CTX ctx;
+ size_t q_bits;
+ };
+
+bool OSSL_DSA_Verification_Operation::verify(const byte msg[], size_t msg_len,
+ const byte sig[], size_t sig_len)
+ {
+ const size_t q_bytes = q.bytes();
+
+ if(sig_len != 2*q_bytes || msg_len > q_bytes)
+ return false;
+
+ OSSL_BN r(sig, q_bytes);
+ OSSL_BN s(sig + q_bytes, q_bytes);
+ OSSL_BN i(msg, msg_len);
+
+ if(BN_is_zero(r.ptr()) || BN_cmp(r.ptr(), q.ptr()) >= 0)
+ return false;
+ if(BN_is_zero(s.ptr()) || BN_cmp(s.ptr(), q.ptr()) >= 0)
+ return false;
+
+ if(BN_mod_inverse(s.ptr(), s.ptr(), q.ptr(), ctx.ptr()) == 0)
+ return false;
+
+ OSSL_BN si;
+ BN_mod_mul(si.ptr(), s.ptr(), i.ptr(), q.ptr(), ctx.ptr());
+ BN_mod_exp(si.ptr(), g.ptr(), si.ptr(), p.ptr(), ctx.ptr());
+
+ OSSL_BN sr;
+ BN_mod_mul(sr.ptr(), s.ptr(), r.ptr(), q.ptr(), ctx.ptr());
+ BN_mod_exp(sr.ptr(), y.ptr(), sr.ptr(), p.ptr(), ctx.ptr());
+
+ BN_mod_mul(si.ptr(), si.ptr(), sr.ptr(), p.ptr(), ctx.ptr());
+ BN_nnmod(si.ptr(), si.ptr(), q.ptr(), ctx.ptr());
+
+ if(BN_cmp(si.ptr(), r.ptr()) == 0)
+ return true;
+ return false;
+
+ return false;
+ }
+
+#endif
+
+#if defined(BOTAN_HAS_RSA)
+
+class OSSL_RSA_Private_Operation : public PK_Ops::Signature,
+ public PK_Ops::Decryption
+ {
+ public:
+ OSSL_RSA_Private_Operation(const RSA_PrivateKey& rsa) :
+ mod(rsa.get_n()),
+ p(rsa.get_p()),
+ q(rsa.get_q()),
+ d1(rsa.get_d1()),
+ d2(rsa.get_d2()),
+ c(rsa.get_c()),
+ n_bits(rsa.get_n().bits())
+ {}
+
+ size_t max_input_bits() const { return (n_bits - 1); }
+
+ secure_vector<byte> sign(const byte msg[], size_t msg_len,
+ RandomNumberGenerator&)
+ {
+ BigInt m(msg, msg_len);
+ BigInt x = private_op(m);
+ return BigInt::encode_1363(x, (n_bits + 7) / 8);
+ }
+
+ secure_vector<byte> decrypt(const byte msg[], size_t msg_len)
+ {
+ BigInt m(msg, msg_len);
+ return BigInt::encode_locked(private_op(m));
+ }
+
+ private:
+ BigInt private_op(const BigInt& m) const;
+
+ const OSSL_BN mod, p, q, d1, d2, c;
+ const OSSL_BN_CTX ctx;
+ size_t n_bits;
+ };
+
+BigInt OSSL_RSA_Private_Operation::private_op(const BigInt& m) const
+ {
+ OSSL_BN j1, j2, h(m);
+
+ BN_mod_exp(j1.ptr(), h.ptr(), d1.ptr(), p.ptr(), ctx.ptr());
+ BN_mod_exp(j2.ptr(), h.ptr(), d2.ptr(), q.ptr(), ctx.ptr());
+ BN_sub(h.ptr(), j1.ptr(), j2.ptr());
+ BN_mod_mul(h.ptr(), h.ptr(), c.ptr(), p.ptr(), ctx.ptr());
+ BN_mul(h.ptr(), h.ptr(), q.ptr(), ctx.ptr());
+ BN_add(h.ptr(), h.ptr(), j2.ptr());
+ return h.to_bigint();
+ }
+
+class OSSL_RSA_Public_Operation : public PK_Ops::Verification,
+ public PK_Ops::Encryption
+ {
+ public:
+ OSSL_RSA_Public_Operation(const RSA_PublicKey& rsa) :
+ n(rsa.get_n()), e(rsa.get_e()), mod(rsa.get_n())
+ {}
+
+ size_t max_input_bits() const { return (n.bits() - 1); }
+ bool with_recovery() const { return true; }
+
+ secure_vector<byte> encrypt(const byte msg[], size_t msg_len,
+ RandomNumberGenerator&)
+ {
+ BigInt m(msg, msg_len);
+ return BigInt::encode_1363(public_op(m), n.bytes());
+ }
+
+ secure_vector<byte> verify_mr(const byte msg[], size_t msg_len)
+ {
+ BigInt m(msg, msg_len);
+ return BigInt::encode_locked(public_op(m));
+ }
+
+ private:
+ BigInt public_op(const BigInt& m) const
+ {
+ if(m >= n)
+ throw Invalid_Argument("RSA public op - input is too large");
+
+ OSSL_BN m_bn(m), r;
+ BN_mod_exp(r.ptr(), m_bn.ptr(), e.ptr(), mod.ptr(), ctx.ptr());
+ return r.to_bigint();
+ }
+
+ const BigInt& n;
+ const OSSL_BN e, mod;
+ const OSSL_BN_CTX ctx;
+ };
+
+#endif
+
+}
+
+PK_Ops::Key_Agreement*
+OpenSSL_Engine::get_key_agreement_op(const Private_Key& key, RandomNumberGenerator&) const
+ {
+#if defined(BOTAN_HAS_DIFFIE_HELLMAN)
+ if(const DH_PrivateKey* dh = dynamic_cast<const DH_PrivateKey*>(&key))
+ return new OSSL_DH_KA_Operation(*dh);
+#endif
+
+ return 0;
+ }
+
+PK_Ops::Signature*
+OpenSSL_Engine::get_signature_op(const Private_Key& key, RandomNumberGenerator&) const
+ {
+#if defined(BOTAN_HAS_RSA)
+ if(const RSA_PrivateKey* s = dynamic_cast<const RSA_PrivateKey*>(&key))
+ return new OSSL_RSA_Private_Operation(*s);
+#endif
+
+#if defined(BOTAN_HAS_DSA)
+ if(const DSA_PrivateKey* s = dynamic_cast<const DSA_PrivateKey*>(&key))
+ return new OSSL_DSA_Signature_Operation(*s);
+#endif
+
+ return 0;
+ }
+
+PK_Ops::Verification*
+OpenSSL_Engine::get_verify_op(const Public_Key& key, RandomNumberGenerator&) const
+ {
+#if defined(BOTAN_HAS_RSA)
+ if(const RSA_PublicKey* s = dynamic_cast<const RSA_PublicKey*>(&key))
+ return new OSSL_RSA_Public_Operation(*s);
+#endif
+
+#if defined(BOTAN_HAS_DSA)
+ if(const DSA_PublicKey* s = dynamic_cast<const DSA_PublicKey*>(&key))
+ return new OSSL_DSA_Verification_Operation(*s);
+#endif
+
+ return 0;
+ }
+
+PK_Ops::Encryption*
+OpenSSL_Engine::get_encryption_op(const Public_Key& key, RandomNumberGenerator&) const
+ {
+#if defined(BOTAN_HAS_RSA)
+ if(const RSA_PublicKey* s = dynamic_cast<const RSA_PublicKey*>(&key))
+ return new OSSL_RSA_Public_Operation(*s);
+#endif
+
+ return 0;
+ }
+
+PK_Ops::Decryption*
+OpenSSL_Engine::get_decryption_op(const Private_Key& key, RandomNumberGenerator&) const
+ {
+#if defined(BOTAN_HAS_RSA)
+ if(const RSA_PrivateKey* s = dynamic_cast<const RSA_PrivateKey*>(&key))
+ return new OSSL_RSA_Private_Operation(*s);
+#endif
+
+ return 0;
+ }
+
+}