aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/libstate/policy.cpp3
-rw-r--r--src/math/gfpmath/curve_gfp.cpp2
-rw-r--r--src/pubkey/ec_dompar/ec_dompar.cpp12
-rw-r--r--src/pubkey/gost_3410/gost_3410.cpp356
-rw-r--r--src/pubkey/gost_3410/gost_3410.h164
-rw-r--r--src/pubkey/gost_3410/info.txt14
-rw-r--r--src/pubkey/pk_algs.cpp12
7 files changed, 562 insertions, 1 deletions
diff --git a/src/libstate/policy.cpp b/src/libstate/policy.cpp
index dfc1dfc7a..45c99e674 100644
--- a/src/libstate/policy.cpp
+++ b/src/libstate/policy.cpp
@@ -38,6 +38,7 @@ void set_default_oids(Library_State& config)
add_oid(config, "1.3.6.1.4.1.25258.1.1", "RW");
add_oid(config, "1.3.6.1.4.1.25258.1.2", "NR");
add_oid(config, "1.2.840.10045.2.1", "ECDSA"); // X9.62
+ add_oid(config, "1.2.643.2.2.19", "GOST-34.10"); // RFC 4491
/* Ciphers */
add_oid(config, "1.3.14.3.2.7", "DES/CBC");
@@ -94,6 +95,8 @@ void set_default_oids(Library_State& config)
add_oid(config, "1.2.840.10045.4.3.3", "ECDSA/EMSA1(SHA-384)");
add_oid(config, "1.2.840.10045.4.3.4", "ECDSA/EMSA1(SHA-512)");
+ add_oid(config, "1.2.643.2.2.3", "GOST-34.10/EMSA1(GOST-R-34.11-94)");
+
add_oid(config, "1.3.6.1.4.1.25258.2.1.1.1", "RW/EMSA2(RIPEMD-160)");
add_oid(config, "1.3.6.1.4.1.25258.2.1.1.2", "RW/EMSA2(SHA-160)");
add_oid(config, "1.3.6.1.4.1.25258.2.1.1.3", "RW/EMSA2(SHA-224)");
diff --git a/src/math/gfpmath/curve_gfp.cpp b/src/math/gfpmath/curve_gfp.cpp
index 9a3ffd482..3cdb08a65 100644
--- a/src/math/gfpmath/curve_gfp.cpp
+++ b/src/math/gfpmath/curve_gfp.cpp
@@ -159,7 +159,7 @@ bool operator==(const CurveGFp& lhs, const CurveGFp& rhs)
std::ostream& operator<<(std::ostream& output, const CurveGFp& elem)
{
- return output << "y^2f = x^3 + (" << elem.get_a() << ")x + (" << elem.get_b() << ")";
+ return output << "y^2 = x^3 + (" << elem.get_a() << ")x + (" << elem.get_b() << ")";
}
}
diff --git a/src/pubkey/ec_dompar/ec_dompar.cpp b/src/pubkey/ec_dompar/ec_dompar.cpp
index 0b5a6e681..6c688f34e 100644
--- a/src/pubkey/ec_dompar/ec_dompar.cpp
+++ b/src/pubkey/ec_dompar/ec_dompar.cpp
@@ -409,6 +409,18 @@ std::vector<std::string> get_standard_domain_parameter(const std::string& oid)
return dom_par;
}
+ if(oid == "1.2.643.2.2.35.1" || oid == "1.2.643.2.2.36.0") // GostR3410-2001-CryptoPro-A-ParamSet
+ {
+ std::vector<std::string> dom_par;
+ dom_par.push_back("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD97");
+ dom_par.push_back("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD94");
+ dom_par.push_back("166");
+ dom_par.push_back("0400000000000000000000000000000000000000000000000000000000000000018D91E471E0989CDA27DF505A453F2B7635294F2DDF23E3B122ACC99C9E9F1E14");
+ dom_par.push_back("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C611070995AD10045841B09B761B893");
+ dom_par.push_back("1");
+ return dom_par;
+ }
+
throw Invalid_Argument("No such ECC curve " + oid);
}
diff --git a/src/pubkey/gost_3410/gost_3410.cpp b/src/pubkey/gost_3410/gost_3410.cpp
new file mode 100644
index 000000000..0569dc8f0
--- /dev/null
+++ b/src/pubkey/gost_3410/gost_3410.cpp
@@ -0,0 +1,356 @@
+/*
+* GOST 34.10-2001 implemenation
+* (C) 2007 Falko Strenzke, FlexSecure GmbH
+* Manuel Hartl, FlexSecure GmbH
+* (C) 2008-2009 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/gost_3410.h>
+#include <botan/numthry.h>
+#include <botan/der_enc.h>
+#include <botan/ber_dec.h>
+#include <botan/secmem.h>
+#include <botan/point_gfp.h>
+
+#include <iostream>
+
+namespace Botan {
+
+GOST_3410_PrivateKey::GOST_3410_PrivateKey(RandomNumberGenerator& rng,
+ const EC_Domain_Params& dom_pars)
+ {
+ mp_dom_pars = std::auto_ptr<EC_Domain_Params>(new EC_Domain_Params(dom_pars));
+ generate_private_key(rng);
+
+ try
+ {
+ mp_public_point->check_invariants();
+ }
+ catch(Illegal_Point& e)
+ {
+ throw Invalid_State("GOST_3410 key generation failed");
+ }
+ }
+
+GOST_3410_PrivateKey::GOST_3410_PrivateKey(const EC_Domain_Params& domain,
+ const BigInt& x)
+ {
+ mp_dom_pars = std::auto_ptr<EC_Domain_Params>(new EC_Domain_Params(domain));
+
+ m_private_value = x;
+ mp_public_point = std::auto_ptr<PointGFp>(new PointGFp (mp_dom_pars->get_base_point()));
+ mp_public_point->mult_this_secure(m_private_value,
+ mp_dom_pars->get_order(),
+ mp_dom_pars->get_order()-1);
+
+ try
+ {
+ mp_public_point->check_invariants();
+ }
+ catch(Illegal_Point)
+ {
+ throw Invalid_State("GOST_3410 key generation failed");
+ }
+ }
+
+X509_Encoder* GOST_3410_PublicKey::x509_encoder() const
+ {
+ class GOST_3410_Key_Encoder : public X509_Encoder
+ {
+ public:
+ AlgorithmIdentifier alg_id() const
+ {
+ key->affirm_init();
+
+ SecureVector<byte> params =
+ encode_der_ec_dompar(key->domain_parameters(), key->m_param_enc);
+
+ return AlgorithmIdentifier(key->get_oid(), params);
+ }
+
+ MemoryVector<byte> key_bits() const
+ {
+ key->affirm_init();
+
+ // Trust CryptoPro to come up with something obnoxious
+ const BigInt x = key->mp_public_point->get_affine_x().get_value();
+ const BigInt y = key->mp_public_point->get_affine_y().get_value();
+
+ SecureVector<byte> bits(2*std::max(x.bytes(), y.bytes()));
+
+ y.binary_encode(bits + (bits.size() / 2 - y.bytes()));
+ x.binary_encode(bits + (bits.size() - y.bytes()));
+
+ return DER_Encoder().encode(bits, OCTET_STRING).get_contents();
+ }
+
+ GOST_3410_Key_Encoder(const GOST_3410_PublicKey* k): key(k) {}
+ private:
+ const GOST_3410_PublicKey* key;
+ };
+
+ return new GOST_3410_Key_Encoder(this);
+ }
+
+X509_Decoder* GOST_3410_PublicKey::x509_decoder()
+ {
+ class GOST_3410_Key_Decoder : public X509_Decoder
+ {
+ public:
+ void alg_id(const AlgorithmIdentifier& alg_id)
+ {
+ // Also includes hash and cipher OIDs... brilliant design guys
+ OID ecc_param_id;
+
+ BER_Decoder ber(alg_id.parameters);
+ ber.start_cons(SEQUENCE).decode(ecc_param_id);
+
+ EC_Domain_Params ecc_params = get_EC_Dom_Pars_by_oid(ecc_param_id.as_string());
+
+ key->mp_dom_pars.reset(new EC_Domain_Params(ecc_params));
+ }
+
+ void key_bits(const MemoryRegion<byte>& bits)
+ {
+
+ SecureVector<byte> key_bits;
+ BER_Decoder ber(bits);
+ ber.decode(key_bits, OCTET_STRING);
+
+ const u32bit part_size = key_bits.size() / 2;
+
+ BigInt y(key_bits, part_size);
+ BigInt x(key_bits + part_size, part_size);
+
+ const BigInt p = key->domain_parameters().get_curve().get_p();
+
+ key->mp_public_point.reset(
+ new PointGFp(key->domain_parameters().get_curve(),
+ GFpElement(x, p),
+ GFpElement(y, p)));
+
+ key->X509_load_hook();
+ }
+
+ GOST_3410_Key_Decoder(GOST_3410_PublicKey* k): key(k) {}
+ private:
+ GOST_3410_PublicKey* key;
+ };
+
+ return new GOST_3410_Key_Decoder(this);
+ }
+
+/*
+* GOST_3410_PublicKey
+*/
+void GOST_3410_PublicKey::affirm_init() const // virtual
+ {
+ EC_PublicKey::affirm_init();
+ }
+
+void GOST_3410_PublicKey::set_domain_parameters(const EC_Domain_Params& dom_pars)
+ {
+ if(mp_dom_pars.get())
+ {
+ // they are already set, we must ensure that they are equal to the arg
+ if(dom_pars != *mp_dom_pars.get())
+ throw Invalid_Argument("EC_PublicKey::set_domain_parameters - cannot reset to a new value");
+
+ return;
+ }
+
+ if(m_enc_public_point.size() == 0)
+ throw Invalid_State("EC_PublicKey::set_domain_parameters(): encoded public point isn't set");
+
+ // now try to decode the public key ...
+ PointGFp tmp_pp(OS2ECP(m_enc_public_point, dom_pars.get_curve()));
+ try
+ {
+ tmp_pp.check_invariants();
+ }
+ catch(Illegal_Point e)
+ {
+ throw Invalid_State("EC_PublicKey::set_domain_parameters(): point does not lie on provided curve");
+ }
+
+ std::auto_ptr<EC_Domain_Params> p_tmp_pars(new EC_Domain_Params(dom_pars));
+ mp_public_point.reset(new PointGFp(tmp_pp));
+ mp_dom_pars = p_tmp_pars;
+ }
+
+void GOST_3410_PublicKey::set_all_values(const GOST_3410_PublicKey& other)
+ {
+ m_param_enc = other.m_param_enc;
+ m_enc_public_point = other.m_enc_public_point;
+ if(other.mp_dom_pars.get())
+ mp_dom_pars.reset(new EC_Domain_Params(other.domain_parameters()));
+
+ if(other.mp_public_point.get())
+ mp_public_point.reset(new PointGFp(other.public_point()));
+ }
+
+GOST_3410_PublicKey::GOST_3410_PublicKey(const GOST_3410_PublicKey& other)
+ : Public_Key(),
+ EC_PublicKey(),
+ PK_Verifying_wo_MR_Key()
+ {
+ set_all_values(other);
+ }
+
+const GOST_3410_PublicKey& GOST_3410_PublicKey::operator=(const GOST_3410_PublicKey& rhs)
+ {
+ set_all_values(rhs);
+ return *this;
+ }
+
+bool GOST_3410_PublicKey::verify(const byte msg[], u32bit msg_len,
+ const byte sig[], u32bit sig_len) const
+ {
+ affirm_init();
+
+ const BigInt& n = mp_dom_pars->get_order();
+
+ if(sig_len != n.bytes()*2)
+ return false;
+
+ // NOTE: it is not checked whether the public point is set
+ if(mp_dom_pars->get_curve().get_p() == 0)
+ throw Internal_Error("domain parameters not set");
+
+ BigInt e(msg, msg_len);
+
+ BigInt r(sig, sig_len / 2);
+ BigInt s(sig + sig_len / 2, sig_len / 2);
+
+ if(r < 0 || r >= n || s < 0 || s >= n)
+ return false;
+
+ e %= n;
+ if(e == 0)
+ e = 1;
+
+ BigInt v = inverse_mod(e, n);
+
+ BigInt z1 = (s*v) % n;
+ BigInt z2 = (-r*v) % n;
+
+ PointGFp R = (z1 * mp_dom_pars->get_base_point() + z2 * *mp_public_point);
+
+ return (R.get_affine_x().get_value() == r);
+ }
+
+GOST_3410_PublicKey::GOST_3410_PublicKey(const EC_Domain_Params& dom_par,
+ const PointGFp& public_point)
+ {
+ mp_dom_pars = std::auto_ptr<EC_Domain_Params>(new EC_Domain_Params(dom_par));
+ mp_public_point = std::auto_ptr<PointGFp>(new PointGFp(public_point));
+ m_param_enc = ENC_EXPLICIT;
+ }
+
+void GOST_3410_PublicKey::X509_load_hook()
+ {
+ EC_PublicKey::X509_load_hook();
+ EC_PublicKey::affirm_init();
+ }
+
+u32bit GOST_3410_PublicKey::max_input_bits() const
+ {
+ if(!mp_dom_pars.get())
+ {
+ throw Invalid_State("GOST_3410_PublicKey::max_input_bits(): domain parameters not set");
+ }
+ return mp_dom_pars->get_order().bits();
+ }
+
+/*************************
+* GOST_3410_PrivateKey
+*************************/
+void GOST_3410_PrivateKey::affirm_init() const // virtual
+ {
+ EC_PrivateKey::affirm_init();
+ }
+
+void GOST_3410_PrivateKey::PKCS8_load_hook(bool generated)
+ {
+ EC_PrivateKey::PKCS8_load_hook(generated);
+ EC_PrivateKey::affirm_init();
+ }
+
+void GOST_3410_PrivateKey::set_all_values(const GOST_3410_PrivateKey& other)
+ {
+ m_private_value = other.m_private_value;
+ m_param_enc = other.m_param_enc;
+ m_enc_public_point = other.m_enc_public_point;
+
+ if(other.mp_dom_pars.get())
+ mp_dom_pars.reset(new EC_Domain_Params(other.domain_parameters()));
+
+ if(other.mp_public_point.get())
+ mp_public_point.reset(new PointGFp(other.public_point()));
+ }
+
+GOST_3410_PrivateKey::GOST_3410_PrivateKey(GOST_3410_PrivateKey const& other)
+ : Public_Key(),
+ EC_PublicKey(),
+ Private_Key(),
+ GOST_3410_PublicKey(),
+ EC_PrivateKey(),
+ PK_Signing_Key()
+ {
+ set_all_values(other);
+ }
+
+const GOST_3410_PrivateKey& GOST_3410_PrivateKey::operator=(const GOST_3410_PrivateKey& rhs)
+ {
+ set_all_values(rhs);
+ return *this;
+ }
+
+SecureVector<byte>
+GOST_3410_PrivateKey::sign(const byte msg[],
+ u32bit msg_len,
+ RandomNumberGenerator& rng) const
+ {
+ affirm_init();
+
+ const BigInt& n = mp_dom_pars->get_order();
+
+ BigInt k;
+ do
+ k.randomize(rng, n.bits()-1);
+ while(k >= n);
+
+ if(m_private_value == 0)
+ throw Internal_Error("GOST_3410::sign(): no private key");
+
+ if(n == 0)
+ throw Internal_Error("GOST_3410::sign(): domain parameters not set");
+
+ BigInt e(msg, msg_len);
+
+ e %= n;
+ if(e == 0)
+ e = 1;
+
+ PointGFp k_times_P(mp_dom_pars->get_base_point());
+ k_times_P.mult_this_secure(k, n, n-1);
+ k_times_P.check_invariants();
+ BigInt r = k_times_P.get_affine_x().get_value() % n;
+
+ if(r == 0)
+ throw Internal_Error("GOST_3410::sign: r was zero");
+
+ BigInt s = (r*m_private_value + k*e) % n;
+
+ std::cout << "r = " << r << '\n';
+ std::cout << "s = " << s << '\n';
+
+ SecureVector<byte> output(2*n.bytes());
+ r.binary_encode(output + (output.size() / 2 - r.bytes()));
+ s.binary_encode(output + (output.size() - s.bytes()));
+ return output;
+ }
+
+}
diff --git a/src/pubkey/gost_3410/gost_3410.h b/src/pubkey/gost_3410/gost_3410.h
new file mode 100644
index 000000000..460aca9bf
--- /dev/null
+++ b/src/pubkey/gost_3410/gost_3410.h
@@ -0,0 +1,164 @@
+/*
+* GOST 34.10-2001
+* (C) 2007 Falko Strenzke, FlexSecure GmbH
+* Manuel Hartl, FlexSecure GmbH
+* (C) 2008-2009 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_GOST_3410_KEY_H__
+#define BOTAN_GOST_3410_KEY_H__
+
+#include <botan/ecc_key.h>
+
+namespace Botan {
+
+/**
+* This class represents GOST_3410 Public Keys.
+*/
+class BOTAN_DLL GOST_3410_PublicKey : public virtual EC_PublicKey,
+ public PK_Verifying_wo_MR_Key
+ {
+ public:
+
+ /**
+ * Get this keys algorithm name.
+ * @result this keys algorithm name
+ */
+ std::string algo_name() const { return "GOST-34.10"; }
+
+ /**
+ * Get the maximum number of bits allowed to be fed to this key.
+ * This is the bitlength of the order of the base point.
+
+ * @result the maximum number of input bits
+ */
+ u32bit max_input_bits() const;
+
+ u32bit message_parts() const { return 2; }
+
+ u32bit message_part_size() const
+ { return mp_dom_pars->get_order().bytes(); }
+
+ /**
+ * Verify a message with this key.
+ * @param message the byte array containing the message
+ * @param mess_len the number of bytes in the message byte array
+ * @param signature the byte array containing the signature
+ * @param sig_len the number of bytes in the signature byte array
+ */
+ bool verify(const byte message[], u32bit mess_len,
+ const byte signature[], u32bit sig_len) const;
+
+ /**
+ * Default constructor. Use this one if you want to later fill
+ * this object with data from an encoded key.
+ */
+ GOST_3410_PublicKey() {}
+
+ /**
+ * Construct a public key from a given public point.
+ * @param dom_par the domain parameters associated with this key
+ * @param public_point the public point defining this key
+ */
+ GOST_3410_PublicKey(const EC_Domain_Params& dom_par,
+ const PointGFp& public_point); // sets core
+
+ GOST_3410_PublicKey const& operator=(const GOST_3410_PublicKey& rhs);
+
+ GOST_3410_PublicKey(const GOST_3410_PublicKey& other);
+
+ /**
+ * Set the domain parameters of this key. This function has to be
+ * used when a key encoded without domain parameters was decoded into
+ * this key. Otherwise it will not be able to verify a signature.
+ * @param dom_pars the domain_parameters associated with this key
+ * @throw Invalid_Argument if the point was found not to be satisfying the
+ * curve equation of the provided domain parameters
+ * or if this key already has domain parameters set
+ * and these are differing from those given as the parameter
+ */
+ void set_domain_parameters(const EC_Domain_Params& dom_pars);
+
+ /**
+ * Ensure that the public point and domain parameters of this key are set.
+ * @throw Invalid_State if either of the two data members is not set
+ */
+ virtual void affirm_init() const;
+
+ /**
+ * Get an x509_encoder that can be used to encode this key.
+ * @result an x509_encoder for this key
+ */
+ X509_Encoder* x509_encoder() const;
+
+ /**
+ * Get an x509_decoder that can be used to decode a stored key into
+ * this key.
+ * @result an x509_decoder for this key
+ */
+ X509_Decoder* x509_decoder();
+
+ protected:
+ void X509_load_hook();
+ void set_all_values(const GOST_3410_PublicKey& other);
+ };
+
+/**
+* This class represents GOST_3410 Private Keys
+*/
+class BOTAN_DLL GOST_3410_PrivateKey : public GOST_3410_PublicKey,
+ public EC_PrivateKey,
+ public PK_Signing_Key
+ {
+ public:
+ /**
+ * Default constructor. Use this one if you want to later fill
+ * this object with data from an encoded key.
+ */
+ GOST_3410_PrivateKey() {}
+
+ /**
+ * Generate a new private key
+ * @param the domain parameters to used for this key
+ */
+ GOST_3410_PrivateKey(RandomNumberGenerator& rng,
+ const EC_Domain_Params& domain);
+
+ /**
+ * Load a private key
+ * @param domain parameters
+ * @param x the private key
+ */
+ GOST_3410_PrivateKey(const EC_Domain_Params& domain, const BigInt& x);
+
+ GOST_3410_PrivateKey(const GOST_3410_PrivateKey& other);
+ GOST_3410_PrivateKey const& operator=(const GOST_3410_PrivateKey& rhs);
+
+ /**
+ * Sign a message with this key.
+ * @param message the byte array representing the message to be signed
+ * @param mess_len the length of the message byte array
+ * @result the signature
+ */
+
+ SecureVector<byte> sign(const byte message[], u32bit mess_len,
+ RandomNumberGenerator& rng) const;
+
+ /**
+ * Make sure that the public key parts of this object are set
+ * (calls EC_PublicKey::affirm_init()) as well as the private key
+ * value.
+ * @throw Invalid_State if the above conditions are not satisfied
+ */
+ virtual void affirm_init() const;
+
+ private:
+ void set_all_values(const GOST_3410_PrivateKey& other);
+ void PKCS8_load_hook(bool = false);
+ };
+
+}
+
+#endif
diff --git a/src/pubkey/gost_3410/info.txt b/src/pubkey/gost_3410/info.txt
new file mode 100644
index 000000000..1d6c1ed17
--- /dev/null
+++ b/src/pubkey/gost_3410/info.txt
@@ -0,0 +1,14 @@
+define GOST_34_10_2001
+
+load_on auto
+
+<requires>
+alloc
+asn1
+ec_dompar
+ecc_key
+gfpmath
+libstate
+numbertheory
+rng
+</requires>
diff --git a/src/pubkey/pk_algs.cpp b/src/pubkey/pk_algs.cpp
index 99d7294f0..ab922217a 100644
--- a/src/pubkey/pk_algs.cpp
+++ b/src/pubkey/pk_algs.cpp
@@ -23,6 +23,10 @@
#include <botan/ecdsa.h>
#endif
+#if defined(BOTAN_HAS_GOST_34_10_2001)
+ #include <botan/gost_3410.h>
+#endif
+
#if defined(BOTAN_HAS_NYBERG_RUEPPEL)
#include <botan/nr.h>
#endif
@@ -70,6 +74,10 @@ Public_Key* get_public_key(const std::string& alg_name)
if(alg_name == "ECDSA") return new ECDSA_PublicKey;
#endif
+#if defined(BOTAN_HAS_GOST_34_10_2001)
+ if(alg_name == "GOST-34.10") return new GOST_3410_PublicKey;
+#endif
+
return 0;
}
@@ -106,6 +114,10 @@ Private_Key* get_private_key(const std::string& alg_name)
if(alg_name == "ECDSA") return new ECDSA_PrivateKey;
#endif
+#if defined(BOTAN_HAS_GOST_34_10_2001)
+ if(alg_name == "GOST-34.10") return new GOST_3410_PrivateKey;
+#endif
+
return 0;
}