aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/engine/gnump
diff options
context:
space:
mode:
authorlloyd <[email protected]>2014-01-10 03:41:59 +0000
committerlloyd <[email protected]>2014-01-10 03:41:59 +0000
commit6894dca64c04936d07048c0e8cbf7e25858548c3 (patch)
tree5d572bfde9fe667dab14e3f04b5285a85d8acd95 /src/lib/engine/gnump
parent9efa3be92442afb3d0b69890a36c7f122df18eda (diff)
Move lib into src
Diffstat (limited to 'src/lib/engine/gnump')
-rw-r--r--src/lib/engine/gnump/gmp_mem.cpp83
-rw-r--r--src/lib/engine/gnump/gmp_powm.cpp53
-rw-r--r--src/lib/engine/gnump/gmp_wrap.cpp101
-rw-r--r--src/lib/engine/gnump/gmp_wrap.h41
-rw-r--r--src/lib/engine/gnump/gnump_engine.h44
-rw-r--r--src/lib/engine/gnump/gnump_pk.cpp338
-rw-r--r--src/lib/engine/gnump/info.txt23
7 files changed, 683 insertions, 0 deletions
diff --git a/src/lib/engine/gnump/gmp_mem.cpp b/src/lib/engine/gnump/gmp_mem.cpp
new file mode 100644
index 000000000..b5a5a303e
--- /dev/null
+++ b/src/lib/engine/gnump/gmp_mem.cpp
@@ -0,0 +1,83 @@
+/*
+* GNU MP Memory Handlers
+* (C) 1999-2010 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/internal/gnump_engine.h>
+#include <cstring>
+#include <atomic>
+#include <gmp.h>
+
+namespace Botan {
+
+namespace {
+
+/*
+* For keeping track of existing GMP_Engines and only
+* resetting the memory when none are in use.
+*/
+std::atomic<size_t> gmp_alloc_refcnt(0);
+
+/*
+* Allocation Function for GNU MP
+*/
+void* gmp_malloc(size_t n)
+ {
+ // Maintain alignment, mlock goes for sizeof(T) alignment
+ if(n % 8 == 0)
+ return secure_allocator<u64bit>().allocate(n / 8);
+ else if(n % 4 == 0)
+ return secure_allocator<u32bit>().allocate(n / 4);
+ else if(n % 2 == 0)
+ return secure_allocator<u16bit>().allocate(n / 2);
+
+ return secure_allocator<byte>().allocate(n);
+ }
+
+/*
+* Deallocation Function for GNU MP
+*/
+void gmp_free(void* ptr, size_t n)
+ {
+ secure_allocator<byte>().deallocate(static_cast<byte*>(ptr), n);
+ }
+
+/*
+* Reallocation Function for GNU MP
+*/
+void* gmp_realloc(void* ptr, size_t old_n, size_t new_n)
+ {
+ void* new_buf = gmp_malloc(new_n);
+ std::memcpy(new_buf, ptr, std::min(old_n, new_n));
+ gmp_free(ptr, old_n);
+ return new_buf;
+ }
+
+}
+
+/*
+* GMP_Engine Constructor
+*/
+GMP_Engine::GMP_Engine()
+ {
+ /*
+ if(gmp_alloc_refcnt == 0)
+ mp_set_memory_functions(gmp_malloc, gmp_realloc, gmp_free);
+
+ gmp_alloc_refcnt++;
+ */
+ }
+
+GMP_Engine::~GMP_Engine()
+ {
+ /*
+ --gmp_alloc_refcnt;
+
+ if(gmp_alloc_refcnt == 0)
+ mp_set_memory_functions(NULL, NULL, NULL);
+ */
+ }
+
+}
diff --git a/src/lib/engine/gnump/gmp_powm.cpp b/src/lib/engine/gnump/gmp_powm.cpp
new file mode 100644
index 000000000..70c2b2f5e
--- /dev/null
+++ b/src/lib/engine/gnump/gmp_powm.cpp
@@ -0,0 +1,53 @@
+/*
+* GMP Modular Exponentiation
+* (C) 1999-2007 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/internal/gnump_engine.h>
+#include <botan/internal/gmp_wrap.h>
+
+namespace Botan {
+
+namespace {
+
+/*
+* GMP Modular Exponentiator
+*/
+class GMP_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 GMP_Modular_Exponentiator(*this); }
+
+ GMP_Modular_Exponentiator(const BigInt& n) : mod(n) {}
+ private:
+ GMP_MPZ base, exp, mod;
+ };
+
+/*
+* Compute the result
+*/
+BigInt GMP_Modular_Exponentiator::execute() const
+ {
+ GMP_MPZ r;
+ mpz_powm(r.value, base.value, exp.value, mod.value);
+ return r.to_bigint();
+ }
+
+}
+
+/*
+* Return the GMP-based modular exponentiator
+*/
+Modular_Exponentiator* GMP_Engine::mod_exp(const BigInt& n,
+ Power_Mod::Usage_Hints) const
+ {
+ return new GMP_Modular_Exponentiator(n);
+ }
+
+}
diff --git a/src/lib/engine/gnump/gmp_wrap.cpp b/src/lib/engine/gnump/gmp_wrap.cpp
new file mode 100644
index 000000000..974593d02
--- /dev/null
+++ b/src/lib/engine/gnump/gmp_wrap.cpp
@@ -0,0 +1,101 @@
+/*
+* GMP Wrapper
+* (C) 1999-2007 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/internal/gmp_wrap.h>
+
+#define GNU_MP_VERSION_CODE_FOR(a,b,c) ((a << 16) | (b << 8) | (c))
+
+#define GNU_MP_VERSION_CODE \
+ GNU_MP_VERSION_CODE_FOR(__GNU_MP_VERSION, __GNU_MP_VERSION_MINOR, \
+ __GNU_MP_VERSION_PATCHLEVEL)
+
+#if GNU_MP_VERSION_CODE < GNU_MP_VERSION_CODE_FOR(4,1,0)
+ #error Your GNU MP install is too old, upgrade to 4.1 or later
+#endif
+
+namespace Botan {
+
+/*
+* GMP_MPZ Constructor
+*/
+GMP_MPZ::GMP_MPZ(const BigInt& in)
+ {
+ mpz_init(value);
+ if(in != 0)
+ mpz_import(value, in.sig_words(), -1, sizeof(word), 0, 0, in.data());
+ }
+
+/*
+* GMP_MPZ Constructor
+*/
+GMP_MPZ::GMP_MPZ(const byte in[], size_t length)
+ {
+ mpz_init(value);
+ mpz_import(value, length, 1, 1, 0, 0, in);
+ }
+
+/*
+* GMP_MPZ Copy Constructor
+*/
+GMP_MPZ::GMP_MPZ(const GMP_MPZ& other)
+ {
+ mpz_init_set(value, other.value);
+ }
+
+/*
+* GMP_MPZ Destructor
+*/
+GMP_MPZ::~GMP_MPZ()
+ {
+ mpz_clear(value);
+ }
+
+/*
+* GMP_MPZ Assignment Operator
+*/
+GMP_MPZ& GMP_MPZ::operator=(const GMP_MPZ& other)
+ {
+ mpz_set(value, other.value);
+ return (*this);
+ }
+
+/*
+* Export the mpz_t as a bytestring
+*/
+void GMP_MPZ::encode(byte out[], size_t length) const
+ {
+ size_t dummy = 0;
+ mpz_export(out + (length - bytes()), &dummy, 1, 1, 0, 0, value);
+ }
+
+/*
+* Return the number of significant bytes
+*/
+size_t GMP_MPZ::bytes() const
+ {
+ return ((mpz_sizeinbase(value, 2) + 7) / 8);
+ }
+
+/*
+* GMP to BigInt Conversions
+*/
+BigInt GMP_MPZ::to_bigint() const
+ {
+ BigInt out(BigInt::Positive, (bytes() + sizeof(word) - 1) / sizeof(word));
+ size_t dummy = 0;
+
+ word* reg = out.mutable_data();
+
+ mpz_export(reg, &dummy, -1, sizeof(word), 0, 0, value);
+
+ if(mpz_sgn(value) < 0)
+ out.flip_sign();
+
+ return out;
+ }
+
+}
diff --git a/src/lib/engine/gnump/gmp_wrap.h b/src/lib/engine/gnump/gmp_wrap.h
new file mode 100644
index 000000000..291d65a01
--- /dev/null
+++ b/src/lib/engine/gnump/gmp_wrap.h
@@ -0,0 +1,41 @@
+/*
+* GMP MPZ Wrapper
+* (C) 1999-2007 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_GMP_MPZ_WRAP_H__
+#define BOTAN_GMP_MPZ_WRAP_H__
+
+#include <botan/bigint.h>
+#include <gmp.h>
+
+namespace Botan {
+
+/**
+* Lightweight GMP mpz_t wrapper. For internal use only.
+*/
+class GMP_MPZ
+ {
+ public:
+ mpz_t value;
+
+ 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()); }
+
+ GMP_MPZ& operator=(const GMP_MPZ&);
+
+ GMP_MPZ(const GMP_MPZ&);
+ GMP_MPZ(const BigInt& = 0);
+ GMP_MPZ(const byte[], size_t);
+ ~GMP_MPZ();
+ };
+
+}
+
+#endif
diff --git a/src/lib/engine/gnump/gnump_engine.h b/src/lib/engine/gnump/gnump_engine.h
new file mode 100644
index 000000000..ccc723514
--- /dev/null
+++ b/src/lib/engine/gnump/gnump_engine.h
@@ -0,0 +1,44 @@
+/*
+* GMP Engine
+* (C) 1999-2007 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_ENGINE_GMP_H__
+#define BOTAN_ENGINE_GMP_H__
+
+#include <botan/engine.h>
+
+namespace Botan {
+
+/**
+* Engine using GNU MP
+*/
+class GMP_Engine : public Engine
+ {
+ public:
+ GMP_Engine();
+ ~GMP_Engine();
+
+ std::string provider_name() const override { return "gmp"; }
+
+ PK_Ops::Key_Agreement*
+ get_key_agreement_op(const Private_Key& key, RandomNumberGenerator&) const override;
+
+ PK_Ops::Signature*
+ get_signature_op(const Private_Key& key, RandomNumberGenerator&) const override;
+
+ PK_Ops::Verification* get_verify_op(const Public_Key& key, RandomNumberGenerator&) const override;
+
+ PK_Ops::Encryption* get_encryption_op(const Public_Key& key, RandomNumberGenerator&) const override;
+
+ PK_Ops::Decryption* get_decryption_op(const Private_Key& key, RandomNumberGenerator&) const override;
+
+ Modular_Exponentiator* mod_exp(const BigInt&,
+ Power_Mod::Usage_Hints) const override;
+ };
+
+}
+
+#endif
diff --git a/src/lib/engine/gnump/gnump_pk.cpp b/src/lib/engine/gnump/gnump_pk.cpp
new file mode 100644
index 000000000..29e172d47
--- /dev/null
+++ b/src/lib/engine/gnump/gnump_pk.cpp
@@ -0,0 +1,338 @@
+/*
+* GnuMP PK operations
+* (C) 1999-2010 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/internal/gnump_engine.h>
+#include <botan/internal/gmp_wrap.h>
+#include <gmp.h>
+
+/* GnuMP 5.0 and later have a side-channel resistent powm */
+#if defined(HAVE_MPZ_POWM_SEC)
+ #undef mpz_powm
+ #define mpz_powm mpz_powm_sec
+#endif
+
+#if defined(BOTAN_HAS_RSA)
+ #include <botan/rsa.h>
+#endif
+
+#if defined(BOTAN_HAS_DSA)
+ #include <botan/dsa.h>
+#endif
+
+#if defined(BOTAN_HAS_DIFFIE_HELLMAN)
+ #include <botan/dh.h>
+#endif
+
+namespace Botan {
+
+namespace {
+
+#if defined(BOTAN_HAS_DIFFIE_HELLMAN)
+class GMP_DH_KA_Operation : public PK_Ops::Key_Agreement
+ {
+ public:
+ GMP_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)
+ {
+ GMP_MPZ z(w, w_len);
+ mpz_powm(z.value, z.value, x.value, p.value);
+ return z.to_bytes();
+ }
+
+ private:
+ GMP_MPZ x, p;
+ };
+#endif
+
+#if defined(BOTAN_HAS_DSA)
+
+class GMP_DSA_Signature_Operation : public PK_Ops::Signature
+ {
+ public:
+ GMP_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 GMP_MPZ x, p, q, g;
+ size_t q_bits;
+ };
+
+secure_vector<byte>
+GMP_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());
+
+ GMP_MPZ i(msg, msg_len);
+ GMP_MPZ k(k_bn);
+
+ GMP_MPZ r;
+ mpz_powm(r.value, g.value, k.value, p.value);
+ mpz_mod(r.value, r.value, q.value);
+
+ mpz_invert(k.value, k.value, q.value);
+
+ GMP_MPZ s;
+ mpz_mul(s.value, x.value, r.value);
+ mpz_add(s.value, s.value, i.value);
+ mpz_mul(s.value, s.value, k.value);
+ mpz_mod(s.value, s.value, q.value);
+
+ if(mpz_cmp_ui(r.value, 0) == 0 || mpz_cmp_ui(s.value, 0) == 0)
+ throw Internal_Error("GMP_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 GMP_DSA_Verification_Operation : public PK_Ops::Verification
+ {
+ public:
+ GMP_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 GMP_MPZ y, p, q, g;
+ size_t q_bits;
+ };
+
+bool GMP_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;
+
+ GMP_MPZ r(sig, q_bytes);
+ GMP_MPZ s(sig + q_bytes, q_bytes);
+ GMP_MPZ i(msg, msg_len);
+
+ if(mpz_cmp_ui(r.value, 0) <= 0 || mpz_cmp(r.value, q.value) >= 0)
+ return false;
+ if(mpz_cmp_ui(s.value, 0) <= 0 || mpz_cmp(s.value, q.value) >= 0)
+ return false;
+
+ if(mpz_invert(s.value, s.value, q.value) == 0)
+ return false;
+
+ GMP_MPZ si;
+ mpz_mul(si.value, s.value, i.value);
+ mpz_mod(si.value, si.value, q.value);
+ mpz_powm(si.value, g.value, si.value, p.value);
+
+ GMP_MPZ sr;
+ mpz_mul(sr.value, s.value, r.value);
+ mpz_mod(sr.value, sr.value, q.value);
+ mpz_powm(sr.value, y.value, sr.value, p.value);
+
+ mpz_mul(si.value, si.value, sr.value);
+ mpz_mod(si.value, si.value, p.value);
+ mpz_mod(si.value, si.value, q.value);
+
+ if(mpz_cmp(si.value, r.value) == 0)
+ return true;
+ return false;
+ }
+
+#endif
+
+#if defined(BOTAN_HAS_RSA)
+
+class GMP_RSA_Private_Operation : public PK_Ops::Signature,
+ public PK_Ops::Decryption
+ {
+ public:
+ GMP_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;
+
+ GMP_MPZ mod, p, q, d1, d2, c;
+ size_t n_bits;
+ };
+
+BigInt GMP_RSA_Private_Operation::private_op(const BigInt& m) const
+ {
+ GMP_MPZ j1, j2, h(m);
+
+ mpz_powm(j1.value, h.value, d1.value, p.value);
+ mpz_powm(j2.value, h.value, d2.value, q.value);
+ mpz_sub(h.value, j1.value, j2.value);
+ mpz_mul(h.value, h.value, c.value);
+ mpz_mod(h.value, h.value, p.value);
+ mpz_mul(h.value, h.value, q.value);
+ mpz_add(h.value, h.value, j2.value);
+ return h.to_bigint();
+ }
+
+class GMP_RSA_Public_Operation : public PK_Ops::Verification,
+ public PK_Ops::Encryption
+ {
+ public:
+ GMP_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");
+
+ GMP_MPZ m_gmp(m);
+ mpz_powm(m_gmp.value, m_gmp.value, e.value, mod.value);
+ return m_gmp.to_bigint();
+ }
+
+ const BigInt& n;
+ const GMP_MPZ e, mod;
+ };
+
+#endif
+
+}
+
+PK_Ops::Key_Agreement*
+GMP_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 GMP_DH_KA_Operation(*dh);
+#endif
+
+ return nullptr;
+ }
+
+PK_Ops::Signature*
+GMP_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 GMP_RSA_Private_Operation(*s);
+#endif
+
+#if defined(BOTAN_HAS_DSA)
+ if(const DSA_PrivateKey* s = dynamic_cast<const DSA_PrivateKey*>(&key))
+ return new GMP_DSA_Signature_Operation(*s);
+#endif
+
+ return nullptr;
+ }
+
+PK_Ops::Verification*
+GMP_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 GMP_RSA_Public_Operation(*s);
+#endif
+
+#if defined(BOTAN_HAS_DSA)
+ if(const DSA_PublicKey* s = dynamic_cast<const DSA_PublicKey*>(&key))
+ return new GMP_DSA_Verification_Operation(*s);
+#endif
+
+ return nullptr;
+ }
+
+PK_Ops::Encryption*
+GMP_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 GMP_RSA_Public_Operation(*s);
+#endif
+
+ return nullptr;
+ }
+
+PK_Ops::Decryption*
+GMP_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 GMP_RSA_Private_Operation(*s);
+#endif
+
+ return nullptr;
+ }
+
+}
diff --git a/src/lib/engine/gnump/info.txt b/src/lib/engine/gnump/info.txt
new file mode 100644
index 000000000..ad03339e4
--- /dev/null
+++ b/src/lib/engine/gnump/info.txt
@@ -0,0 +1,23 @@
+define ENGINE_GNU_MP 20131128
+
+load_on request
+
+<libs>
+all -> gmp
+</libs>
+
+<header:internal>
+gnump_engine.h
+gmp_wrap.h
+</header:internal>
+
+<source>
+gmp_mem.cpp
+gmp_powm.cpp
+gmp_wrap.cpp
+gnump_pk.cpp
+</source>
+
+<requires>
+bigint
+</requires>