diff options
author | lloyd <[email protected]> | 2009-12-24 22:22:41 +0000 |
---|---|---|
committer | lloyd <[email protected]> | 2009-12-24 22:22:41 +0000 |
commit | 888fc3d0f2f6f1dc5e9764e83e9b7fd64da916d8 (patch) | |
tree | 1d296ec03fc39ebbdfde4d4c49d9257b4935a21c /src/pubkey | |
parent | 90394a98550551d882fb4d9610b9b8bfa7271c76 (diff) | |
parent | d76d52bc7417bd703a868338cfe751b79dbb009a (diff) |
propagate from branch 'net.randombit.botan' (head a338abd543caa402c32acd952e865c8ec8e85a69)
to branch 'net.randombit.botan.gost_3410' (head d09208e0a933da2df52494876849c542e5a556ca)
Diffstat (limited to 'src/pubkey')
-rw-r--r-- | src/pubkey/ec_dompar/ec_dompar.cpp | 12 | ||||
-rw-r--r-- | src/pubkey/gost_3410/gost_3410.cpp | 356 | ||||
-rw-r--r-- | src/pubkey/gost_3410/gost_3410.h | 164 | ||||
-rw-r--r-- | src/pubkey/gost_3410/info.txt | 14 | ||||
-rw-r--r-- | src/pubkey/pk_algs.cpp | 12 |
5 files changed, 558 insertions, 0 deletions
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 c040e006b..dd62eb5ac 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; } |