summaryrefslogtreecommitdiffstats
path: root/botan/src/pubkey/ecc_key/ecc_key.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'botan/src/pubkey/ecc_key/ecc_key.cpp')
-rw-r--r--botan/src/pubkey/ecc_key/ecc_key.cpp269
1 files changed, 269 insertions, 0 deletions
diff --git a/botan/src/pubkey/ecc_key/ecc_key.cpp b/botan/src/pubkey/ecc_key/ecc_key.cpp
new file mode 100644
index 0000000..615efec
--- /dev/null
+++ b/botan/src/pubkey/ecc_key/ecc_key.cpp
@@ -0,0 +1,269 @@
+/*
+* ECC Key implemenation
+* (C) 2007 Manuel Hartl, FlexSecure GmbH
+* Falko Strenzke, FlexSecure GmbH
+* 2008 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/ecc_key.h>
+#include <botan/x509_key.h>
+#include <botan/numthry.h>
+#include <botan/util.h>
+#include <botan/der_enc.h>
+#include <botan/ber_dec.h>
+#include <botan/secmem.h>
+#include <botan/point_gfp.h>
+
+namespace Botan {
+
+/*
+* EC_PublicKey
+*/
+void EC_PublicKey::affirm_init() const // virtual
+ {
+ if((mp_dom_pars.get() == 0) || (mp_public_point.get() == 0))
+ throw Invalid_State("cannot use uninitialized EC_Key");
+ }
+
+const EC_Domain_Params& EC_PublicKey::domain_parameters() const
+ {
+ if(!mp_dom_pars.get())
+ throw Invalid_State("EC_PublicKey::domain_parameters(): "
+ "ec domain parameters are not yet set");
+
+ return *mp_dom_pars;
+ }
+
+const PointGFp& EC_PublicKey::public_point() const
+ {
+ if(!mp_public_point.get())
+ throw Invalid_State("EC_PublicKey::public_point(): public point not set");
+
+ return *mp_public_point;
+ }
+
+bool EC_PublicKey::domain_parameters_set()
+ {
+ return mp_dom_pars.get();
+ }
+
+void EC_PublicKey::X509_load_hook()
+ {
+ try
+ {
+ // the base point is checked to be on curve already when decoding it
+ affirm_init();
+ mp_public_point->check_invariants();
+ }
+ catch(Illegal_Point)
+ {
+ throw Decoding_Error("decoded public point was found not to lie on curve");
+ }
+ }
+
+X509_Encoder* EC_PublicKey::x509_encoder() const
+ {
+ class EC_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();
+ return EC2OSP(*(key->mp_public_point), PointGFp::COMPRESSED);
+ }
+
+ EC_Key_Encoder(const EC_PublicKey* k): key(k) {}
+ private:
+ const EC_PublicKey* key;
+ };
+
+ return new EC_Key_Encoder(this);
+ }
+
+X509_Decoder* EC_PublicKey::x509_decoder()
+ {
+ class EC_Key_Decoder : public X509_Decoder
+ {
+ public:
+ void alg_id(const AlgorithmIdentifier& alg_id)
+ {
+ key->mp_dom_pars.reset(new EC_Domain_Params(decode_ber_ec_dompar(alg_id.parameters)));
+ }
+
+ void key_bits(const MemoryRegion<byte>& bits)
+ {
+ key->mp_public_point.reset(
+ new PointGFp(
+ OS2ECP(bits, key->domain_parameters().get_curve())
+ ));
+
+ key->X509_load_hook();
+ }
+
+ EC_Key_Decoder(EC_PublicKey* k): key(k) {}
+ private:
+ EC_PublicKey* key;
+ };
+
+ return new EC_Key_Decoder(this);
+ }
+
+void EC_PublicKey::set_parameter_encoding(EC_dompar_enc type)
+ {
+ if((type != ENC_EXPLICIT) && (type != ENC_IMPLICITCA) && (type != ENC_OID))
+ throw Invalid_Argument("Invalid encoding type for EC-key object specified");
+
+ affirm_init();
+
+ if((type == ENC_OID) && (mp_dom_pars->get_oid() == ""))
+ throw Invalid_Argument("Invalid encoding type ENC_OID specified for "
+ "EC-key object whose corresponding domain "
+ "parameters are without oid");
+
+ m_param_enc = type;
+ }
+
+/********************************
+* EC_PrivateKey
+********************************/
+void EC_PrivateKey::affirm_init() const // virtual
+ {
+ if(m_private_value == 0)
+ throw Invalid_State("cannot use EC_PrivateKey when private key is uninitialized");
+
+ EC_PublicKey::affirm_init();
+ }
+
+const BigInt& EC_PrivateKey::private_value() const
+ {
+ if(m_private_value == 0)
+ throw Invalid_State("cannot use EC_PrivateKey when private key is uninitialized");
+
+ return m_private_value;
+ }
+
+/**
+* EC_PrivateKey generator
+**/
+void EC_PrivateKey::generate_private_key(RandomNumberGenerator& rng)
+ {
+ if(mp_dom_pars.get() == 0)
+ {
+ throw Invalid_State("cannot generate private key when domain parameters are not set");
+ }
+
+ BigInt tmp_private_value(0);
+ tmp_private_value = BigInt::random_integer(rng, 1, mp_dom_pars->get_order());
+ mp_public_point = std::auto_ptr<PointGFp>( new PointGFp (mp_dom_pars->get_base_point()));
+ mp_public_point->mult_this_secure(tmp_private_value,
+ mp_dom_pars->get_order(),
+ mp_dom_pars->get_order()-1);
+
+ //assert(mp_public_point.get() != 0);
+ tmp_private_value.swap(m_private_value);
+ }
+
+/**
+* Return the PKCS #8 public key encoder
+**/
+PKCS8_Encoder* EC_PrivateKey::pkcs8_encoder() const
+ {
+ class EC_Key_Encoder : public PKCS8_Encoder
+ {
+ public:
+ AlgorithmIdentifier alg_id() const
+ {
+ key->affirm_init();
+
+ SecureVector<byte> params =
+ encode_der_ec_dompar(key->domain_parameters(), ENC_EXPLICIT);
+
+ return AlgorithmIdentifier(key->get_oid(), params);
+ }
+
+ MemoryVector<byte> key_bits() const
+ {
+ key->affirm_init();
+ SecureVector<byte> octstr_secret =
+ BigInt::encode_1363(key->m_private_value, key->m_private_value.bytes());
+
+ return DER_Encoder()
+ .start_cons(SEQUENCE)
+ .encode(BigInt(1))
+ .encode(octstr_secret, OCTET_STRING)
+ .end_cons()
+ .get_contents();
+ }
+
+ EC_Key_Encoder(const EC_PrivateKey* k): key(k) {}
+ private:
+ const EC_PrivateKey* key;
+ };
+
+ return new EC_Key_Encoder(this);
+ }
+
+/**
+* Return the PKCS #8 public key decoder
+*/
+PKCS8_Decoder* EC_PrivateKey::pkcs8_decoder(RandomNumberGenerator&)
+ {
+ class EC_Key_Decoder : public PKCS8_Decoder
+ {
+ public:
+ void alg_id(const AlgorithmIdentifier& alg_id)
+ {
+ key->mp_dom_pars.reset(new EC_Domain_Params(decode_ber_ec_dompar(alg_id.parameters)));
+ }
+
+ void key_bits(const MemoryRegion<byte>& bits)
+ {
+ u32bit version;
+ SecureVector<byte> octstr_secret;
+
+ BER_Decoder(bits)
+ .start_cons(SEQUENCE)
+ .decode(version)
+ .decode(octstr_secret, OCTET_STRING)
+ .verify_end()
+ .end_cons();
+
+ key->m_private_value = BigInt::decode(octstr_secret, octstr_secret.size());
+
+ if(version != 1)
+ throw Decoding_Error("Wrong PKCS #1 key format version for EC key");
+
+ key->PKCS8_load_hook();
+ }
+
+ EC_Key_Decoder(EC_PrivateKey* k): key(k) {}
+ private:
+ EC_PrivateKey* key;
+ };
+
+ return new EC_Key_Decoder(this);
+ }
+
+void EC_PrivateKey::PKCS8_load_hook(bool)
+ {
+ // we cannot use affirm_init() here because mp_public_point might still be null
+ if(mp_dom_pars.get() == 0)
+ throw Invalid_State("attempt to set public point for an uninitialized key");
+
+ mp_public_point.reset(new PointGFp(m_private_value * mp_dom_pars->get_base_point()));
+ mp_public_point->check_invariants();
+ }
+
+}