aboutsummaryrefslogtreecommitdiffstats
path: root/src/pubkey/gost_3410/gost_3410.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/pubkey/gost_3410/gost_3410.cpp')
-rw-r--r--src/pubkey/gost_3410/gost_3410.cpp356
1 files changed, 356 insertions, 0 deletions
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;
+ }
+
+}