aboutsummaryrefslogtreecommitdiffstats
path: root/src/engine/openssl
diff options
context:
space:
mode:
Diffstat (limited to 'src/engine/openssl')
-rw-r--r--src/engine/openssl/arc4_openssl.cpp80
-rw-r--r--src/engine/openssl/bn_powm.cpp52
-rw-r--r--src/engine/openssl/bn_wrap.cpp114
-rw-r--r--src/engine/openssl/bn_wrap.h51
-rw-r--r--src/engine/openssl/eng_ossl.h62
-rw-r--r--src/engine/openssl/info.txt28
-rw-r--r--src/engine/openssl/ossl_bc.cpp192
-rw-r--r--src/engine/openssl/ossl_dh.cpp58
-rw-r--r--src/engine/openssl/ossl_dsa.cpp124
-rw-r--r--src/engine/openssl/ossl_elg.cpp93
-rw-r--r--src/engine/openssl/ossl_if.cpp83
-rw-r--r--src/engine/openssl/ossl_md.cpp114
-rw-r--r--src/engine/openssl/ossl_nr.cpp111
13 files changed, 1162 insertions, 0 deletions
diff --git a/src/engine/openssl/arc4_openssl.cpp b/src/engine/openssl/arc4_openssl.cpp
new file mode 100644
index 000000000..09fb52919
--- /dev/null
+++ b/src/engine/openssl/arc4_openssl.cpp
@@ -0,0 +1,80 @@
+/*************************************************
+* OpenSSL ARC4 Source File *
+* (C) 1999-2007 Jack Lloyd *
+*************************************************/
+
+#include <botan/eng_ossl.h>
+#include <botan/parsing.h>
+#include <openssl/rc4.h>
+
+namespace Botan {
+
+namespace {
+
+/**
+* ARC4 as implemented by OpenSSL
+*/
+class ARC4_OpenSSL : public StreamCipher
+ {
+ public:
+ void clear() throw() { std::memset(&state, 0, sizeof(state)); }
+ std::string name() const;
+ StreamCipher* clone() const { return new ARC4_OpenSSL(SKIP); }
+
+ ARC4_OpenSSL(u32bit s = 0) : StreamCipher(1, 32), SKIP(s) { clear(); }
+ ~ARC4_OpenSSL() { clear(); }
+ private:
+ void cipher(const byte[], byte[], u32bit);
+ void key_schedule(const byte[], u32bit);
+
+ const u32bit SKIP;
+ RC4_KEY state;
+ };
+
+/*************************************************
+* Return the name of this type *
+*************************************************/
+std::string ARC4_OpenSSL::name() const
+ {
+ if(SKIP == 0) return "ARC4";
+ if(SKIP == 256) return "MARK-4";
+ else return "RC4_skip(" + to_string(SKIP) + ")";
+ }
+
+/*************************************************
+* ARC4 Key Schedule *
+*************************************************/
+void ARC4_OpenSSL::key_schedule(const byte key[], u32bit length)
+ {
+ RC4_set_key(&state, length, key);
+ byte dummy = 0;
+ for(u32bit j = 0; j != SKIP; j++)
+ RC4(&state, 1, &dummy, &dummy);
+ }
+
+/*************************************************
+* ARC4 Encryption *
+*************************************************/
+void ARC4_OpenSSL::cipher(const byte in[], byte out[], u32bit length)
+ {
+ RC4(&state, length, in, out);
+ }
+
+}
+
+/**
+* Look for an OpenSSL-suported stream cipher (ARC4)
+*/
+StreamCipher*
+OpenSSL_Engine::find_stream_cipher(const SCAN_Name& request,
+ Algorithm_Factory&) const
+ {
+ if(request.algo_name() == "ARC4")
+ return new ARC4_OpenSSL(request.arg_as_u32bit(0, 0));
+ if(request.algo_name() == "RC4_drop")
+ return new ARC4_OpenSSL(768);
+
+ return 0;
+ }
+
+}
diff --git a/src/engine/openssl/bn_powm.cpp b/src/engine/openssl/bn_powm.cpp
new file mode 100644
index 000000000..f54411240
--- /dev/null
+++ b/src/engine/openssl/bn_powm.cpp
@@ -0,0 +1,52 @@
+/*************************************************
+* OpenSSL Modular Exponentiation Source File *
+* (C) 1999-2007 Jack Lloyd *
+*************************************************/
+
+#include <botan/eng_ossl.h>
+#include <botan/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.value, base.value, exp.value, mod.value, ctx.value);
+ 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/engine/openssl/bn_wrap.cpp b/src/engine/openssl/bn_wrap.cpp
new file mode 100644
index 000000000..4f7ea0078
--- /dev/null
+++ b/src/engine/openssl/bn_wrap.cpp
@@ -0,0 +1,114 @@
+/*************************************************
+* OpenSSL BN Wrapper Source File *
+* (C) 1999-2007 Jack Lloyd *
+*************************************************/
+
+#include <botan/bn_wrap.h>
+
+namespace Botan {
+
+/*************************************************
+* OSSL_BN Constructor *
+*************************************************/
+OSSL_BN::OSSL_BN(const BigInt& in)
+ {
+ value = BN_new();
+ SecureVector<byte> encoding = BigInt::encode(in);
+ if(in != 0)
+ BN_bin2bn(encoding, encoding.size(), value);
+ }
+
+/*************************************************
+* OSSL_BN Constructor *
+*************************************************/
+OSSL_BN::OSSL_BN(const byte in[], u32bit length)
+ {
+ value = BN_new();
+ BN_bin2bn(in, length, value);
+ }
+
+/*************************************************
+* OSSL_BN Copy Constructor *
+*************************************************/
+OSSL_BN::OSSL_BN(const OSSL_BN& other)
+ {
+ value = BN_dup(other.value);
+ }
+
+/*************************************************
+* OSSL_BN Destructor *
+*************************************************/
+OSSL_BN::~OSSL_BN()
+ {
+ BN_clear_free(value);
+ }
+
+/*************************************************
+* OSSL_BN Assignment Operator *
+*************************************************/
+OSSL_BN& OSSL_BN::operator=(const OSSL_BN& other)
+ {
+ BN_copy(value, other.value);
+ return (*this);
+ }
+
+/*************************************************
+* Export the BIGNUM as a bytestring *
+*************************************************/
+void OSSL_BN::encode(byte out[], u32bit length) const
+ {
+ BN_bn2bin(value, out + (length - bytes()));
+ }
+
+/*************************************************
+* Return the number of significant bytes *
+*************************************************/
+u32bit OSSL_BN::bytes() const
+ {
+ return BN_num_bytes(value);
+ }
+
+/*************************************************
+* OpenSSL to BigInt Conversions *
+*************************************************/
+BigInt OSSL_BN::to_bigint() const
+ {
+ SecureVector<byte> out(bytes());
+ BN_bn2bin(value, out);
+ return BigInt::decode(out);
+ }
+
+/*************************************************
+* OSSL_BN_CTX Constructor *
+*************************************************/
+OSSL_BN_CTX::OSSL_BN_CTX()
+ {
+ value = BN_CTX_new();
+ }
+
+/*************************************************
+* OSSL_BN_CTX Copy Constructor *
+*************************************************/
+OSSL_BN_CTX::OSSL_BN_CTX(const OSSL_BN_CTX&)
+ {
+ value = BN_CTX_new();
+ }
+
+/*************************************************
+* OSSL_BN_CTX Destructor *
+*************************************************/
+OSSL_BN_CTX::~OSSL_BN_CTX()
+ {
+ BN_CTX_free(value);
+ }
+
+/*************************************************
+* OSSL_BN_CTX Assignment Operator *
+*************************************************/
+OSSL_BN_CTX& OSSL_BN_CTX::operator=(const OSSL_BN_CTX&)
+ {
+ value = BN_CTX_new();
+ return (*this);
+ }
+
+}
diff --git a/src/engine/openssl/bn_wrap.h b/src/engine/openssl/bn_wrap.h
new file mode 100644
index 000000000..e8464e74e
--- /dev/null
+++ b/src/engine/openssl/bn_wrap.h
@@ -0,0 +1,51 @@
+/*************************************************
+* OpenSSL BN Wrapper Header File *
+* (C) 1999-2007 Jack Lloyd *
+*************************************************/
+
+#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 *
+*************************************************/
+class BOTAN_DLL OSSL_BN
+ {
+ public:
+ BIGNUM* value;
+
+ BigInt to_bigint() const;
+ void encode(byte[], u32bit) const;
+ u32bit bytes() const;
+
+ OSSL_BN& operator=(const OSSL_BN&);
+
+ OSSL_BN(const OSSL_BN&);
+ OSSL_BN(const BigInt& = 0);
+ OSSL_BN(const byte[], u32bit);
+ ~OSSL_BN();
+ };
+
+/*************************************************
+* Lightweight OpenSSL BN_CTX Wrapper *
+*************************************************/
+class BOTAN_DLL OSSL_BN_CTX
+ {
+ public:
+ BN_CTX* value;
+
+ OSSL_BN_CTX& operator=(const OSSL_BN_CTX&);
+
+ OSSL_BN_CTX();
+ OSSL_BN_CTX(const OSSL_BN_CTX&);
+ ~OSSL_BN_CTX();
+ };
+
+}
+
+#endif
diff --git a/src/engine/openssl/eng_ossl.h b/src/engine/openssl/eng_ossl.h
new file mode 100644
index 000000000..7f345f0ff
--- /dev/null
+++ b/src/engine/openssl/eng_ossl.h
@@ -0,0 +1,62 @@
+/*************************************************
+* OpenSSL Engine Header File *
+* (C) 1999-2007 Jack Lloyd *
+*************************************************/
+
+#ifndef BOTAN_ENGINE_OPENSSL_H__
+#define BOTAN_ENGINE_OPENSSL_H__
+
+#include <botan/engine.h>
+
+namespace Botan {
+
+/*************************************************
+* OpenSSL Engine *
+*************************************************/
+class BOTAN_DLL OpenSSL_Engine : public Engine
+ {
+ public:
+ /**
+ * Return the provider name ("openssl")
+ */
+ std::string provider_name() const { return "openssl"; }
+
+#if defined(BOTAN_HAS_IF_PUBLIC_KEY_FAMILY)
+ IF_Operation* if_op(const BigInt&, const BigInt&, const BigInt&,
+ const BigInt&, const BigInt&, const BigInt&,
+ const BigInt&, const BigInt&) const;
+#endif
+
+#if defined(BOTAN_HAS_DSA)
+ DSA_Operation* dsa_op(const DL_Group&, const BigInt&,
+ const BigInt&) const;
+#endif
+
+#if defined(BOTAN_HAS_NYBERG_RUEPPEL)
+ NR_Operation* nr_op(const DL_Group&, const BigInt&, const BigInt&) const;
+#endif
+
+#if defined(BOTAN_HAS_ELGAMAL)
+ ELG_Operation* elg_op(const DL_Group&, const BigInt&,
+ const BigInt&) const;
+#endif
+
+#if defined(BOTAN_HAS_DIFFIE_HELLMAN)
+ DH_Operation* dh_op(const DL_Group&, const BigInt&) const;
+#endif
+
+ Modular_Exponentiator* mod_exp(const BigInt&,
+ Power_Mod::Usage_Hints) const;
+ private:
+ BlockCipher* find_block_cipher(const SCAN_Name&,
+ Algorithm_Factory&) const;
+
+ StreamCipher* find_stream_cipher(const SCAN_Name&,
+ Algorithm_Factory&) const;
+
+ HashFunction* find_hash(const SCAN_Name&, Algorithm_Factory&) const;
+ };
+
+}
+
+#endif
diff --git a/src/engine/openssl/info.txt b/src/engine/openssl/info.txt
new file mode 100644
index 000000000..1d8ff7fce
--- /dev/null
+++ b/src/engine/openssl/info.txt
@@ -0,0 +1,28 @@
+realname "OpenSSL Engine"
+
+define ENGINE_OPENSSL
+
+load_on request
+
+<libs>
+all -> crypto
+</libs>
+
+<requires>
+libstate
+</requires>
+
+<add>
+arc4_openssl.cpp
+bn_powm.cpp
+bn_wrap.cpp
+bn_wrap.h
+eng_ossl.h
+ossl_bc.cpp
+ossl_dh.cpp
+ossl_dsa.cpp
+ossl_elg.cpp
+ossl_if.cpp
+ossl_md.cpp
+ossl_nr.cpp
+</add>
diff --git a/src/engine/openssl/ossl_bc.cpp b/src/engine/openssl/ossl_bc.cpp
new file mode 100644
index 000000000..a9110f008
--- /dev/null
+++ b/src/engine/openssl/ossl_bc.cpp
@@ -0,0 +1,192 @@
+/*************************************************
+* OpenSSL Block Cipher Source File *
+* (C) 1999-2007 Jack Lloyd *
+*************************************************/
+
+#include <botan/eng_ossl.h>
+#include <openssl/evp.h>
+
+namespace Botan {
+
+namespace {
+
+/*************************************************
+* EVP Block Cipher *
+*************************************************/
+class EVP_BlockCipher : public BlockCipher
+ {
+ public:
+ void clear() throw();
+ std::string name() const { return cipher_name; }
+ BlockCipher* clone() const;
+ EVP_BlockCipher(const EVP_CIPHER*, const std::string&);
+ EVP_BlockCipher(const EVP_CIPHER*, const std::string&,
+ u32bit, u32bit, u32bit);
+
+ ~EVP_BlockCipher();
+ private:
+ void enc(const byte[], byte[]) const;
+ void dec(const byte[], byte[]) const;
+ void key_schedule(const byte[], u32bit);
+ 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) :
+ BlockCipher(EVP_CIPHER_block_size(algo), 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,
+ u32bit key_min, u32bit key_max,
+ u32bit key_mod) :
+ BlockCipher(EVP_CIPHER_block_size(algo), 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::enc(const byte in[], byte out[]) const
+ {
+ int out_len = 0;
+ EVP_EncryptUpdate(&encrypt, out, &out_len, in, BLOCK_SIZE);
+ }
+
+/*************************************************
+* Decrypt a block *
+*************************************************/
+void EVP_BlockCipher::dec(const byte in[], byte out[]) const
+ {
+ int out_len = 0;
+ EVP_DecryptUpdate(&decrypt, out, &out_len, in, BLOCK_SIZE);
+ }
+
+/*************************************************
+* Set the key *
+*************************************************/
+void EVP_BlockCipher::key_schedule(const byte key[], u32bit length)
+ {
+ SecureVector<byte> full_key(key, length);
+
+ if(cipher_name == "TripleDES" && length == 16)
+ full_key.append(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.begin(), 0);
+ EVP_DecryptInit_ex(&decrypt, 0, 0, full_key.begin(), 0);
+ }
+
+/*************************************************
+* Return a clone of this object *
+*************************************************/
+BlockCipher* EVP_BlockCipher::clone() const
+ {
+ return new EVP_BlockCipher(EVP_CIPHER_CTX_cipher(&encrypt),
+ cipher_name, MINIMUM_KEYLENGTH,
+ MAXIMUM_KEYLENGTH, KEYLENGTH_MULTIPLE);
+ }
+
+/*************************************************
+* Clear memory of sensitive data *
+*************************************************/
+void EVP_BlockCipher::clear() throw()
+ {
+ 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);
+
+ 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());
+
+ HANDLE_EVP_CIPHER("DES", EVP_des_ecb());
+ HANDLE_EVP_CIPHER_KEYLEN("TripleDES", EVP_des_ede3_ecb(), 16, 24, 8);
+
+ HANDLE_EVP_CIPHER_KEYLEN("Blowfish", EVP_bf_ecb(), 1, 56, 1);
+ HANDLE_EVP_CIPHER_KEYLEN("CAST-128", EVP_cast5_ecb(), 1, 16, 1);
+ HANDLE_EVP_CIPHER_KEYLEN("RC2", EVP_rc2_ecb(), 1, 32, 1);
+
+#undef HANDLE_EVP_CIPHER
+#undef HANDLE_EVP_CIPHER_KEYLEN
+
+ return 0;
+ }
+
+}
diff --git a/src/engine/openssl/ossl_dh.cpp b/src/engine/openssl/ossl_dh.cpp
new file mode 100644
index 000000000..290b95622
--- /dev/null
+++ b/src/engine/openssl/ossl_dh.cpp
@@ -0,0 +1,58 @@
+/*************************************************
+* OpenSSL Engine Source File *
+* (C) 1999-2007 Jack Lloyd *
+*************************************************/
+
+#include <botan/eng_ossl.h>
+#include <botan/bn_wrap.h>
+#include <openssl/opensslv.h>
+
+#if OPENSSL_VERSION_NUMBER < 0x0090700F
+ #error Your OpenSSL install is too old, upgrade to 0.9.7 or later
+#endif
+
+namespace Botan {
+
+#if defined(BOTAN_HAS_DIFFIE_HELLMAN)
+
+namespace {
+
+/*************************************************
+* OpenSSL DH Operation *
+*************************************************/
+class OpenSSL_DH_Op : public DH_Operation
+ {
+ public:
+ BigInt agree(const BigInt& i) const;
+ DH_Operation* clone() const { return new OpenSSL_DH_Op(*this); }
+
+ OpenSSL_DH_Op(const DL_Group& group, const BigInt& x_bn) :
+ x(x_bn), p(group.get_p()) {}
+ private:
+ OSSL_BN x, p;
+ OSSL_BN_CTX ctx;
+ };
+
+/*************************************************
+* OpenSSL DH Key Agreement Operation *
+*************************************************/
+BigInt OpenSSL_DH_Op::agree(const BigInt& i_bn) const
+ {
+ OSSL_BN i(i_bn), r;
+ BN_mod_exp(r.value, i.value, x.value, p.value, ctx.value);
+ return r.to_bigint();
+ }
+
+}
+
+/*************************************************
+* Acquire a DH op *
+*************************************************/
+DH_Operation* OpenSSL_Engine::dh_op(const DL_Group& group,
+ const BigInt& x) const
+ {
+ return new OpenSSL_DH_Op(group, x);
+ }
+#endif
+
+}
diff --git a/src/engine/openssl/ossl_dsa.cpp b/src/engine/openssl/ossl_dsa.cpp
new file mode 100644
index 000000000..2757234e2
--- /dev/null
+++ b/src/engine/openssl/ossl_dsa.cpp
@@ -0,0 +1,124 @@
+/*************************************************
+* OpenSSL DSA Engine Source File *
+* (C) 1999-2007 Jack Lloyd *
+*************************************************/
+
+#include <botan/eng_ossl.h>
+#include <botan/bn_wrap.h>
+#include <openssl/opensslv.h>
+
+#if OPENSSL_VERSION_NUMBER < 0x0090700F
+ #error Your OpenSSL install is too old, upgrade to 0.9.7 or later
+#endif
+
+namespace Botan {
+
+#if defined(BOTAN_HAS_DSA)
+
+namespace {
+
+/*************************************************
+* OpenSSL DSA Operation *
+*************************************************/
+class OpenSSL_DSA_Op : public DSA_Operation
+ {
+ public:
+ bool verify(const byte[], u32bit, const byte[], u32bit) const;
+ SecureVector<byte> sign(const byte[], u32bit, const BigInt&) const;
+
+ DSA_Operation* clone() const { return new OpenSSL_DSA_Op(*this); }
+
+ OpenSSL_DSA_Op(const DL_Group& group, const BigInt& y1,
+ const BigInt& x1) :
+ x(x1), y(y1), p(group.get_p()), q(group.get_q()), g(group.get_g()) {}
+ private:
+ const OSSL_BN x, y, p, q, g;
+ OSSL_BN_CTX ctx;
+ };
+
+/*************************************************
+* OpenSSL DSA Verify Operation *
+*************************************************/
+bool OpenSSL_DSA_Op::verify(const byte msg[], u32bit msg_len,
+ const byte sig[], u32bit sig_len) const
+ {
+ const u32bit 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.value) || BN_cmp(r.value, q.value) >= 0)
+ return false;
+ if(BN_is_zero(s.value) || BN_cmp(s.value, q.value) >= 0)
+ return false;
+
+ if(BN_mod_inverse(s.value, s.value, q.value, ctx.value) == 0)
+ return false;
+
+ OSSL_BN si;
+ BN_mod_mul(si.value, s.value, i.value, q.value, ctx.value);
+ BN_mod_exp(si.value, g.value, si.value, p.value, ctx.value);
+
+ OSSL_BN sr;
+ BN_mod_mul(sr.value, s.value, r.value, q.value, ctx.value);
+ BN_mod_exp(sr.value, y.value, sr.value, p.value, ctx.value);
+
+ BN_mod_mul(si.value, si.value, sr.value, p.value, ctx.value);
+ BN_nnmod(si.value, si.value, q.value, ctx.value);
+
+ if(BN_cmp(si.value, r.value) == 0)
+ return true;
+ return false;
+ }
+
+/*************************************************
+* OpenSSL DSA Sign Operation *
+*************************************************/
+SecureVector<byte> OpenSSL_DSA_Op::sign(const byte in[], u32bit length,
+ const BigInt& k_bn) const
+ {
+ if(BN_is_zero(x.value))
+ throw Internal_Error("OpenSSL_DSA_Op::sign: No private key");
+
+ OSSL_BN i(in, length);
+ OSSL_BN k(k_bn);
+
+ OSSL_BN r;
+ BN_mod_exp(r.value, g.value, k.value, p.value, ctx.value);
+ BN_nnmod(r.value, r.value, q.value, ctx.value);
+
+ BN_mod_inverse(k.value, k.value, q.value, ctx.value);
+
+ OSSL_BN s;
+ BN_mul(s.value, x.value, r.value, ctx.value);
+ BN_add(s.value, s.value, i.value);
+ BN_mod_mul(s.value, s.value, k.value, q.value, ctx.value);
+
+ if(BN_is_zero(r.value) || BN_is_zero(s.value))
+ throw Internal_Error("OpenSSL_DSA_Op::sign: r or s was zero");
+
+ const u32bit q_bytes = q.bytes();
+
+ SecureVector<byte> output(2*q_bytes);
+ r.encode(output, q_bytes);
+ s.encode(output + q_bytes, q_bytes);
+ return output;
+ }
+
+}
+
+/*************************************************
+* Acquire a DSA op *
+*************************************************/
+DSA_Operation* OpenSSL_Engine::dsa_op(const DL_Group& group, const BigInt& y,
+ const BigInt& x) const
+ {
+ return new OpenSSL_DSA_Op(group, y, x);
+ }
+#endif
+
+}
diff --git a/src/engine/openssl/ossl_elg.cpp b/src/engine/openssl/ossl_elg.cpp
new file mode 100644
index 000000000..25d628ba8
--- /dev/null
+++ b/src/engine/openssl/ossl_elg.cpp
@@ -0,0 +1,93 @@
+/*************************************************
+* OpenSSL Engine Source File *
+* (C) 1999-2007 Jack Lloyd *
+*************************************************/
+
+#include <botan/eng_ossl.h>
+#include <botan/bn_wrap.h>
+#include <openssl/opensslv.h>
+
+#if OPENSSL_VERSION_NUMBER < 0x0090700F
+ #error Your OpenSSL install is too old, upgrade to 0.9.7 or later
+#endif
+
+namespace Botan {
+
+#if defined(BOTAN_HAS_ELGAMAL)
+
+namespace {
+
+/*************************************************
+* OpenSSL ElGamal Operation *
+*************************************************/
+class OpenSSL_ELG_Op : public ELG_Operation
+ {
+ public:
+ SecureVector<byte> encrypt(const byte[], u32bit, const BigInt&) const;
+ BigInt decrypt(const BigInt&, const BigInt&) const;
+
+ ELG_Operation* clone() const { return new OpenSSL_ELG_Op(*this); }
+ OpenSSL_ELG_Op(const DL_Group& group, const BigInt& y1,
+ const BigInt& x1) :
+ x(x1), y(y1), g(group.get_g()), p(group.get_p()) {}
+ private:
+ OSSL_BN x, y, g, p;
+ OSSL_BN_CTX ctx;
+ };
+
+/*************************************************
+* OpenSSL ElGamal Encrypt Operation *
+*************************************************/
+SecureVector<byte> OpenSSL_ELG_Op::encrypt(const byte in[], u32bit length,
+ const BigInt& k_bn) const
+ {
+ OSSL_BN i(in, length);
+
+ if(BN_cmp(i.value, p.value) >= 0)
+ throw Invalid_Argument("OpenSSL_ELG_Op: Input is too large");
+
+ OSSL_BN a, b, k(k_bn);
+
+ BN_mod_exp(a.value, g.value, k.value, p.value, ctx.value);
+ BN_mod_exp(b.value, y.value, k.value, p.value, ctx.value);
+ BN_mod_mul(b.value, b.value, i.value, p.value, ctx.value);
+
+ const u32bit p_bytes = p.bytes();
+ SecureVector<byte> output(2*p_bytes);
+ a.encode(output, p_bytes);
+ b.encode(output + p_bytes, p_bytes);
+ return output;
+ }
+
+/*************************************************
+* OpenSSL ElGamal Decrypt Operation *
+*************************************************/
+BigInt OpenSSL_ELG_Op::decrypt(const BigInt& a_bn, const BigInt& b_bn) const
+ {
+ if(BN_is_zero(x.value))
+ throw Internal_Error("OpenSSL_ELG_Op::decrypt: No private key");
+
+ OSSL_BN a(a_bn), b(b_bn), t;
+
+ if(BN_cmp(a.value, p.value) >= 0 || BN_cmp(b.value, p.value) >= 0)
+ throw Invalid_Argument("OpenSSL_ELG_Op: Invalid message");
+
+ BN_mod_exp(t.value, a.value, x.value, p.value, ctx.value);
+ BN_mod_inverse(a.value, t.value, p.value, ctx.value);
+ BN_mod_mul(a.value, a.value, b.value, p.value, ctx.value);
+ return a.to_bigint();
+ }
+
+}
+
+/*************************************************
+* Acquire an ElGamal op *
+*************************************************/
+ELG_Operation* OpenSSL_Engine::elg_op(const DL_Group& group, const BigInt& y,
+ const BigInt& x) const
+ {
+ return new OpenSSL_ELG_Op(group, y, x);
+ }
+#endif
+
+}
diff --git a/src/engine/openssl/ossl_if.cpp b/src/engine/openssl/ossl_if.cpp
new file mode 100644
index 000000000..08a43e63e
--- /dev/null
+++ b/src/engine/openssl/ossl_if.cpp
@@ -0,0 +1,83 @@
+/*************************************************
+* OpenSSL IF Engine Source File *
+* (C) 1999-2007 Jack Lloyd *
+*************************************************/
+
+#include <botan/eng_ossl.h>
+#include <botan/bn_wrap.h>
+#include <openssl/opensslv.h>
+
+#if OPENSSL_VERSION_NUMBER < 0x0090700F
+ #error Your OpenSSL install is too old, upgrade to 0.9.7 or later
+#endif
+
+namespace Botan {
+
+#if defined(BOTAN_HAS_IF_PUBLIC_KEY_FAMILY)
+
+namespace {
+
+/*************************************************
+* OpenSSL IF Operation *
+*************************************************/
+class OpenSSL_IF_Op : public IF_Operation
+ {
+ public:
+ BigInt public_op(const BigInt&) const;
+ BigInt private_op(const BigInt&) const;
+
+ IF_Operation* clone() const { return new OpenSSL_IF_Op(*this); }
+
+ OpenSSL_IF_Op(const BigInt& e_bn, const BigInt& n_bn, const BigInt&,
+ const BigInt& p_bn, const BigInt& q_bn, const BigInt& d1_bn,
+ const BigInt& d2_bn, const BigInt& c_bn) :
+ e(e_bn), n(n_bn), p(p_bn), q(q_bn), d1(d1_bn), d2(d2_bn), c(c_bn) {}
+ private:
+ const OSSL_BN e, n, p, q, d1, d2, c;
+ OSSL_BN_CTX ctx;
+ };
+
+/*************************************************
+* OpenSSL IF Public Operation *
+*************************************************/
+BigInt OpenSSL_IF_Op::public_op(const BigInt& i_bn) const
+ {
+ OSSL_BN i(i_bn), r;
+ BN_mod_exp(r.value, i.value, e.value, n.value, ctx.value);
+ return r.to_bigint();
+ }
+
+/*************************************************
+* OpenSSL IF Private Operation *
+*************************************************/
+BigInt OpenSSL_IF_Op::private_op(const BigInt& i_bn) const
+ {
+ if(BN_is_zero(p.value))
+ throw Internal_Error("OpenSSL_IF_Op::private_op: No private key");
+
+ OSSL_BN j1, j2, h(i_bn);
+
+ BN_mod_exp(j1.value, h.value, d1.value, p.value, ctx.value);
+ BN_mod_exp(j2.value, h.value, d2.value, q.value, ctx.value);
+ BN_sub(h.value, j1.value, j2.value);
+ BN_mod_mul(h.value, h.value, c.value, p.value, ctx.value);
+ BN_mul(h.value, h.value, q.value, ctx.value);
+ BN_add(h.value, h.value, j2.value);
+ return h.to_bigint();
+ }
+
+}
+
+/*************************************************
+* Acquire an IF op *
+*************************************************/
+IF_Operation* OpenSSL_Engine::if_op(const BigInt& e, const BigInt& n,
+ const BigInt& d, const BigInt& p,
+ const BigInt& q, const BigInt& d1,
+ const BigInt& d2, const BigInt& c) const
+ {
+ return new OpenSSL_IF_Op(e, n, d, p, q, d1, d2, c);
+ }
+#endif
+
+}
diff --git a/src/engine/openssl/ossl_md.cpp b/src/engine/openssl/ossl_md.cpp
new file mode 100644
index 000000000..4e28c515e
--- /dev/null
+++ b/src/engine/openssl/ossl_md.cpp
@@ -0,0 +1,114 @@
+/*************************************************
+* OpenSSL Hash Functions Source File *
+* (C) 1999-2007 Jack Lloyd *
+*************************************************/
+
+#include <botan/eng_ossl.h>
+#include <openssl/evp.h>
+
+namespace Botan {
+
+namespace {
+
+/*************************************************
+* EVP Hash Function *
+*************************************************/
+class EVP_HashFunction : public HashFunction
+ {
+ public:
+ void clear() throw();
+ std::string name() const { return algo_name; }
+ HashFunction* clone() const;
+ EVP_HashFunction(const EVP_MD*, const std::string&);
+ ~EVP_HashFunction();
+ private:
+ void add_data(const byte[], u32bit);
+ 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[], u32bit 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() throw()
+ {
+ 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) :
+ HashFunction(EVP_MD_size(algo), EVP_MD_block_size(algo)),
+ 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(request.algo_name() == "SHA-160")
+ return new EVP_HashFunction(EVP_sha1(), "SHA-160");
+
+ if(request.algo_name() == "MD2")
+ return new EVP_HashFunction(EVP_md2(), "MD2");
+
+ if(request.algo_name() == "MD4")
+ return new EVP_HashFunction(EVP_md4(), "MD4");
+
+ if(request.algo_name() == "MD5")
+ return new EVP_HashFunction(EVP_md5(), "MD5");
+
+ if(request.algo_name() == "RIPEMD-160")
+ return new EVP_HashFunction(EVP_ripemd160(), "RIPEMD-160");
+
+ return 0;
+ }
+
+}
diff --git a/src/engine/openssl/ossl_nr.cpp b/src/engine/openssl/ossl_nr.cpp
new file mode 100644
index 000000000..210e2fec2
--- /dev/null
+++ b/src/engine/openssl/ossl_nr.cpp
@@ -0,0 +1,111 @@
+/*************************************************
+* OpenSSL NR Engine Source File *
+* (C) 1999-2007 Jack Lloyd *
+*************************************************/
+
+#include <botan/eng_ossl.h>
+#include <botan/bn_wrap.h>
+#include <openssl/opensslv.h>
+
+#if OPENSSL_VERSION_NUMBER < 0x0090700F
+ #error Your OpenSSL install is too old, upgrade to 0.9.7 or later
+#endif
+
+namespace Botan {
+
+#if defined(BOTAN_HAS_NYBERG_RUEPPEL)
+
+namespace {
+
+/*************************************************
+* OpenSSL NR Operation *
+*************************************************/
+class OpenSSL_NR_Op : public NR_Operation
+ {
+ public:
+ SecureVector<byte> verify(const byte[], u32bit) const;
+ SecureVector<byte> sign(const byte[], u32bit, const BigInt&) const;
+
+ NR_Operation* clone() const { return new OpenSSL_NR_Op(*this); }
+
+ OpenSSL_NR_Op(const DL_Group& group, const BigInt& y1,
+ const BigInt& x1) :
+ x(x1), y(y1), p(group.get_p()), q(group.get_q()), g(group.get_g()) {}
+ private:
+ const OSSL_BN x, y, p, q, g;
+ OSSL_BN_CTX ctx;
+ };
+
+/*************************************************
+* OpenSSL NR Verify Operation *
+*************************************************/
+SecureVector<byte> OpenSSL_NR_Op::verify(const byte sig[],
+ u32bit sig_len) const
+ {
+ const u32bit q_bytes = q.bytes();
+
+ if(sig_len != 2*q_bytes)
+ return false;
+
+ OSSL_BN c(sig, q_bytes);
+ OSSL_BN d(sig + q_bytes, q_bytes);
+
+ if(BN_is_zero(c.value) || BN_cmp(c.value, q.value) >= 0 ||
+ BN_cmp(d.value, q.value) >= 0)
+ throw Invalid_Argument("OpenSSL_NR_Op::verify: Invalid signature");
+
+ OSSL_BN i1, i2;
+ BN_mod_exp(i1.value, g.value, d.value, p.value, ctx.value);
+ BN_mod_exp(i2.value, y.value, c.value, p.value, ctx.value);
+ BN_mod_mul(i1.value, i1.value, i2.value, p.value, ctx.value);
+ BN_sub(i1.value, c.value, i1.value);
+ BN_nnmod(i1.value, i1.value, q.value, ctx.value);
+ return BigInt::encode(i1.to_bigint());
+ }
+
+/*************************************************
+* OpenSSL NR Sign Operation *
+*************************************************/
+SecureVector<byte> OpenSSL_NR_Op::sign(const byte in[], u32bit length,
+ const BigInt& k_bn) const
+ {
+ if(BN_is_zero(x.value))
+ throw Internal_Error("OpenSSL_NR_Op::sign: No private key");
+
+ OSSL_BN f(in, length);
+ OSSL_BN k(k_bn);
+
+ if(BN_cmp(f.value, q.value) >= 0)
+ throw Invalid_Argument("OpenSSL_NR_Op::sign: Input is out of range");
+
+ OSSL_BN c, d;
+ BN_mod_exp(c.value, g.value, k.value, p.value, ctx.value);
+ BN_add(c.value, c.value, f.value);
+ BN_nnmod(c.value, c.value, q.value, ctx.value);
+ BN_mul(d.value, x.value, c.value, ctx.value);
+ BN_sub(d.value, k.value, d.value);
+ BN_nnmod(d.value, d.value, q.value, ctx.value);
+
+ if(BN_is_zero(c.value))
+ throw Internal_Error("Default_NR_Op::sign: c was zero");
+
+ const u32bit q_bytes = q.bytes();
+ SecureVector<byte> output(2*q_bytes);
+ c.encode(output, q_bytes);
+ d.encode(output + q_bytes, q_bytes);
+ return output;
+ }
+
+}
+
+/*************************************************
+* Acquire a NR op *
+*************************************************/
+NR_Operation* OpenSSL_Engine::nr_op(const DL_Group& group, const BigInt& y,
+ const BigInt& x) const
+ {
+ return new OpenSSL_NR_Op(group, y, x);
+ }
+#endif
+
+}