/* * ECC Key implemenation * (C) 2007 Manuel Hartl, FlexSecure GmbH * Falko Strenzke, FlexSecure GmbH * 2008-2010 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #include #include #include #include #include #include #include #include namespace Botan { size_t EC_PublicKey::key_length() const { return domain().get_curve().get_p().bits(); } size_t EC_PublicKey::estimated_strength() const { return ecp_work_factor(key_length()); } EC_PublicKey::EC_PublicKey(const EC_Group& dom_par, const PointGFp& pub_point) : m_domain_params(dom_par), m_public_key(pub_point) { if (!dom_par.get_oid().empty()) m_domain_encoding = EC_DOMPAR_ENC_OID; else m_domain_encoding = EC_DOMPAR_ENC_EXPLICIT; if(domain().get_curve() != public_point().get_curve()) throw Invalid_Argument("EC_PublicKey: curve mismatch in constructor"); } EC_PublicKey::EC_PublicKey(const AlgorithmIdentifier& alg_id, const std::vector& key_bits) : m_domain_params{EC_Group(alg_id.parameters)}, m_public_key{OS2ECP(key_bits, domain().get_curve())} { if (!domain().get_oid().empty()) m_domain_encoding = EC_DOMPAR_ENC_OID; else m_domain_encoding = EC_DOMPAR_ENC_EXPLICIT; } bool EC_PublicKey::check_key(RandomNumberGenerator& rng, bool) const { //verify domain parameters if(!m_domain_params.verify_group(rng)) { return false; } //check that public point is not at infinity if(public_point().is_zero()) { return false; } //check that public point is on the curve if(!public_point().on_the_curve()) { return false; } if(m_domain_params.get_cofactor() > 1) { if((public_point() * m_domain_params.get_cofactor()).is_zero()) { return false; } //check that public point has order q if(!(public_point() * m_domain_params.get_order()).is_zero()) { return false; } } return true; } AlgorithmIdentifier EC_PublicKey::algorithm_identifier() const { return AlgorithmIdentifier(get_oid(), DER_domain()); } std::vector EC_PublicKey::public_key_bits() const { return unlock(EC2OSP(public_point(), PointGFp::COMPRESSED)); } void EC_PublicKey::set_parameter_encoding(EC_Group_Encoding form) { if(form != EC_DOMPAR_ENC_EXPLICIT && form != EC_DOMPAR_ENC_IMPLICITCA && form != EC_DOMPAR_ENC_OID) throw Invalid_Argument("Invalid encoding form for EC-key object specified"); if((form == EC_DOMPAR_ENC_OID) && (m_domain_params.get_oid() == "")) throw Invalid_Argument("Invalid encoding form OID specified for " "EC-key object whose corresponding domain " "parameters are without oid"); m_domain_encoding = form; } const BigInt& EC_PrivateKey::private_value() const { if(m_private_key == 0) throw Invalid_State("EC_PrivateKey::private_value - uninitialized"); return m_private_key; } /** * EC_PrivateKey constructor */ EC_PrivateKey::EC_PrivateKey(RandomNumberGenerator& rng, const EC_Group& ec_group, const BigInt& x, bool with_modular_inverse) { m_domain_params = ec_group; if (!ec_group.get_oid().empty()) m_domain_encoding = EC_DOMPAR_ENC_OID; else m_domain_encoding = EC_DOMPAR_ENC_EXPLICIT; if(x == 0) { m_private_key = BigInt::random_integer(rng, 1, domain().get_order()); } else { m_private_key = x; } m_public_key = domain().get_base_point() * ((with_modular_inverse) ? inverse_mod(m_private_key, m_domain_params.get_order()) : m_private_key); BOTAN_ASSERT(m_public_key.on_the_curve(), "Generated public key point was on the curve"); } secure_vector EC_PrivateKey::private_key_bits() const { return DER_Encoder() .start_cons(SEQUENCE) .encode(static_cast(1)) .encode(BigInt::encode_1363(m_private_key, m_private_key.bytes()), OCTET_STRING) .end_cons() .get_contents(); } EC_PrivateKey::EC_PrivateKey(const AlgorithmIdentifier& alg_id, const secure_vector& key_bits, bool with_modular_inverse) { m_domain_params = EC_Group(alg_id.parameters); m_domain_encoding = EC_DOMPAR_ENC_EXPLICIT; OID key_parameters; secure_vector public_key_bits; BER_Decoder(key_bits) .start_cons(SEQUENCE) .decode_and_check(1, "Unknown version code for ECC key") .decode_octet_string_bigint(m_private_key) .decode_optional(key_parameters, ASN1_Tag(0), PRIVATE) .decode_optional_string(public_key_bits, BIT_STRING, 1, PRIVATE) .end_cons(); if(public_key_bits.empty()) { m_public_key = domain().get_base_point() * ((with_modular_inverse) ? inverse_mod(m_private_key, m_domain_params.get_order()) : m_private_key); BOTAN_ASSERT(m_public_key.on_the_curve(), "Public point derived from loaded key was on the curve"); } else { m_public_key = OS2ECP(public_key_bits, domain().get_curve()); // OS2ECP verifies that the point is on the curve } } }