aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/pubkey/ec_group
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/pubkey/ec_group')
-rw-r--r--src/lib/pubkey/ec_group/ec_group.cpp249
-rw-r--r--src/lib/pubkey/ec_group/ec_group.h92
2 files changed, 262 insertions, 79 deletions
diff --git a/src/lib/pubkey/ec_group/ec_group.cpp b/src/lib/pubkey/ec_group/ec_group.cpp
index 6ae8c16d8..8a3ffa718 100644
--- a/src/lib/pubkey/ec_group/ec_group.cpp
+++ b/src/lib/pubkey/ec_group/ec_group.cpp
@@ -2,7 +2,7 @@
* ECC Domain Parameters
*
* (C) 2007 Falko Strenzke, FlexSecure GmbH
-* 2008 Jack Lloyd
+* 2008,2018 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -16,56 +16,42 @@
namespace Botan {
-EC_Group::EC_Group(const OID& domain_oid)
+struct EC_Group_Data
{
- const std::string pem = PEM_for_named_group(OIDS::lookup(domain_oid));
+ CurveGFp m_curve;
+ PointGFp m_base_point;
+ BigInt m_order;
+ BigInt m_cofactor;
+ OID m_oid;
+ size_t m_p_bits, m_p_bytes;
+ };
- if(pem == "")
- {
- throw Lookup_Error("No ECC domain data for '" + domain_oid.as_string() + "'");
- }
+namespace {
- *this = EC_Group(pem);
- m_oid = domain_oid.as_string();
- }
+std::shared_ptr<EC_Group_Data> lookup_EC_group_by_oid(const OID& oid);
-EC_Group::EC_Group(const std::string& str)
+std::shared_ptr<EC_Group_Data> BER_decode_EC_group(const uint8_t bits[], size_t len)
{
- if(str == "")
- return; // no initialization / uninitialized
-
- try
- {
- std::vector<uint8_t> ber =
- unlock(PEM_Code::decode_check_label(str, "EC PARAMETERS"));
-
- *this = EC_Group(ber);
- }
- catch(Decoding_Error) // hmm, not PEM?
- {
- *this = EC_Group(OIDS::lookup(str));
- }
- }
-
-EC_Group::EC_Group(const std::vector<uint8_t>& ber_data)
- {
- BER_Decoder ber(ber_data);
+ BER_Decoder ber(bits, len);
BER_Object obj = ber.get_next_object();
if(obj.type() == NULL_TAG)
- throw Decoding_Error("Cannot handle ImplicitCA ECDSA parameters");
+ {
+ throw Decoding_Error("Cannot handle ImplicitCA ECC parameters");
+ }
else if(obj.type() == OBJECT_ID)
{
OID dom_par_oid;
- BER_Decoder(ber_data).decode(dom_par_oid);
- *this = EC_Group(dom_par_oid);
+ BER_Decoder(bits, len).decode(dom_par_oid);
+ return lookup_EC_group_by_oid(dom_par_oid);
}
else if(obj.type() == SEQUENCE)
{
+ std::shared_ptr<EC_Group_Data> data = std::make_shared<EC_Group_Data>();
BigInt p, a, b;
std::vector<uint8_t> sv_base_point;
- BER_Decoder(ber_data)
+ BER_Decoder(bits, len)
.start_cons(SEQUENCE)
.decode_and_check<size_t>(1, "Unknown ECC param version code")
.start_cons(SEQUENCE)
@@ -78,16 +64,166 @@ EC_Group::EC_Group(const std::vector<uint8_t>& ber_data)
.decode_octet_string_bigint(b)
.end_cons()
.decode(sv_base_point, OCTET_STRING)
- .decode(m_order)
- .decode(m_cofactor)
+ .decode(data->m_order)
+ .decode(data->m_cofactor)
.end_cons()
.verify_end();
- m_curve = CurveGFp(p, a, b);
- m_base_point = OS2ECP(sv_base_point, m_curve);
+ data->m_curve = CurveGFp(p, a, b);
+ data->m_base_point = Botan::OS2ECP(sv_base_point, data->m_curve);
+
+ data->m_p_bits = p.bits();
+ data->m_p_bytes = p.bytes();
+ return data;
}
else
+ {
throw Decoding_Error("Unexpected tag while decoding ECC domain params");
+ }
+ }
+
+std::shared_ptr<EC_Group_Data> BER_decode_EC_group(const std::string& pem)
+ {
+ secure_vector<uint8_t> ber = PEM_Code::decode_check_label(pem, "EC PARAMETERS");
+ return BER_decode_EC_group(ber.data(), ber.size());
+ }
+
+std::shared_ptr<EC_Group_Data> lookup_EC_group_by_oid(const OID& oid)
+ {
+ if(oid.empty())
+ throw Invalid_Argument("lookup_EC_group_by_oid with empty oid");
+
+ const std::string oid_name = OIDS::oid2str(oid);
+ if(oid_name.empty())
+ throw Invalid_Argument("Unknown EC group OID " + oid.as_string());
+
+ const std::string pem = EC_Group::PEM_for_named_group(oid_name);
+ if(pem.empty())
+ throw Invalid_Argument("EC group OID (" + oid_name + ") is not known");
+ std::shared_ptr<EC_Group_Data> data = BER_decode_EC_group(pem);
+ data->m_oid = oid;
+ return data;
+ }
+
+}
+
+EC_Group::EC_Group(const OID& domain_oid)
+ {
+ this->m_data = lookup_EC_group_by_oid(domain_oid);
+ }
+
+EC_Group::EC_Group(const std::string& str)
+ {
+ if(str == "")
+ return; // no initialization / uninitialized
+
+ try
+ {
+ OID oid = OIDS::lookup(str);
+ if(oid.empty() == false)
+ m_data = lookup_EC_group_by_oid(oid);
+ }
+ catch(Invalid_OID)
+ {
+ }
+
+ if(m_data == nullptr)
+ {
+ // OK try it as PEM ...
+ this->m_data = BER_decode_EC_group(str);
+ }
+ }
+
+EC_Group::EC_Group(const CurveGFp& curve,
+ const PointGFp& base_point,
+ const BigInt& order,
+ const BigInt& cofactor)
+ {
+ m_data.reset(new EC_Group_Data);
+
+ m_data->m_curve = curve;
+ m_data->m_base_point = base_point;
+ m_data->m_order = order;
+ m_data->m_cofactor = cofactor;
+ m_data->m_p_bits = curve.get_p().bits();
+ m_data->m_p_bytes = curve.get_p().bytes();
+ }
+
+EC_Group::EC_Group(const std::vector<uint8_t>& ber)
+ {
+ m_data = BER_decode_EC_group(ber.data(), ber.size());
+ }
+
+const EC_Group_Data& EC_Group::data() const
+ {
+ if(m_data == nullptr)
+ throw Invalid_State("EC_Group uninitialized");
+ return *m_data;
+ }
+
+const CurveGFp& EC_Group::get_curve() const
+ {
+ return data().m_curve;
+ }
+
+size_t EC_Group::get_p_bits() const
+ {
+ return data().m_p_bits;
+ }
+
+size_t EC_Group::get_p_bytes() const
+ {
+ return data().m_p_bytes;
+ }
+
+const BigInt& EC_Group::get_p() const
+ {
+ return data().m_curve.get_p();
+ }
+
+const BigInt& EC_Group::get_a() const
+ {
+ return data().m_curve.get_a();
+ }
+
+const BigInt& EC_Group::get_b() const
+ {
+ return data().m_curve.get_b();
+ }
+
+const PointGFp& EC_Group::get_base_point() const
+ {
+ return data().m_base_point;
+ }
+
+const BigInt& EC_Group::get_order() const
+ {
+ return data().m_order;
+ }
+
+const BigInt& EC_Group::get_cofactor() const
+ {
+ return data().m_cofactor;
+ }
+
+const OID& EC_Group::get_curve_oid() const
+ {
+ return data().m_oid;
+ }
+
+PointGFp EC_Group::OS2ECP(const uint8_t bits[], size_t len) const
+ {
+ return Botan::OS2ECP(bits, len, get_curve());
+ }
+
+PointGFp EC_Group::point(const BigInt& x, const BigInt& y) const
+ {
+ return PointGFp(get_curve(), x, y);
+ }
+
+PointGFp EC_Group::zero_point() const
+ {
+ return PointGFp(get_curve());
}
std::vector<uint8_t>
@@ -96,36 +232,37 @@ EC_Group::DER_encode(EC_Group_Encoding form) const
if(form == EC_DOMPAR_ENC_EXPLICIT)
{
const size_t ecpVers1 = 1;
- OID curve_type("1.2.840.10045.1.1");
+ OID curve_type("1.2.840.10045.1.1"); // prime field
- const size_t p_bytes = m_curve.get_p().bytes();
+ const size_t p_bytes = get_p_bytes();
return DER_Encoder()
.start_cons(SEQUENCE)
.encode(ecpVers1)
.start_cons(SEQUENCE)
.encode(curve_type)
- .encode(m_curve.get_p())
+ .encode(get_p())
.end_cons()
.start_cons(SEQUENCE)
- .encode(BigInt::encode_1363(m_curve.get_a(), p_bytes),
+ .encode(BigInt::encode_1363(get_a(), p_bytes),
OCTET_STRING)
- .encode(BigInt::encode_1363(m_curve.get_b(), p_bytes),
+ .encode(BigInt::encode_1363(get_b(), p_bytes),
OCTET_STRING)
.end_cons()
- .encode(EC2OSP(m_base_point, PointGFp::UNCOMPRESSED), OCTET_STRING)
- .encode(m_order)
- .encode(m_cofactor)
+ .encode(EC2OSP(get_base_point(), PointGFp::UNCOMPRESSED), OCTET_STRING)
+ .encode(get_order())
+ .encode(get_cofactor())
.end_cons()
.get_contents_unlocked();
}
else if(form == EC_DOMPAR_ENC_OID)
{
- if(get_oid().empty())
+ const OID oid = get_curve_oid();
+ if(oid.empty())
{
throw Encoding_Error("Cannot encode EC_Group as OID because OID not set");
}
- return DER_Encoder().encode(OID(get_oid())).get_contents_unlocked();
+ return DER_Encoder().encode(oid).get_contents_unlocked();
}
else if(form == EC_DOMPAR_ENC_IMPLICITCA)
return DER_Encoder().encode_null().get_contents_unlocked();
@@ -143,9 +280,9 @@ bool EC_Group::verify_group(RandomNumberGenerator& rng,
bool) const
{
//compute the discriminant
- Modular_Reducer p(m_curve.get_p());
- BigInt discriminant = p.multiply(4, m_curve.get_a());
- discriminant += p.multiply(27, m_curve.get_b());
+ Modular_Reducer p(get_p());
+ BigInt discriminant = p.multiply(4, get_a());
+ discriminant += p.multiply(27, get_b());
discriminant = p.reduce(discriminant);
//check the discriminant
if(discriminant == 0)
@@ -153,26 +290,26 @@ bool EC_Group::verify_group(RandomNumberGenerator& rng,
return false;
}
//check for valid cofactor
- if(m_cofactor < 1)
+ if(get_cofactor() < 1)
{
return false;
}
//check if the base point is on the curve
- if(!m_base_point.on_the_curve())
+ if(!get_base_point().on_the_curve())
{
return false;
}
- if((m_base_point * m_cofactor).is_zero())
+ if((get_base_point() * get_cofactor()).is_zero())
{
return false;
}
//check if order is prime
- if(!is_prime(m_order, rng, 128))
+ if(!is_prime(get_order(), rng, 128))
{
return false;
}
//check if order of the base point is correct
- if(!(m_base_point * m_order).is_zero())
+ if(!(get_base_point() * get_order()).is_zero())
{
return false;
}
diff --git a/src/lib/pubkey/ec_group/ec_group.h b/src/lib/pubkey/ec_group/ec_group.h
index 18ffed12c..3da38a7da 100644
--- a/src/lib/pubkey/ec_group/ec_group.h
+++ b/src/lib/pubkey/ec_group/ec_group.h
@@ -13,6 +13,7 @@
#include <botan/point_gfp.h>
#include <botan/curve_gfp.h>
#include <botan/asn1_oid.h>
+#include <memory>
#include <set>
namespace Botan {
@@ -26,6 +27,8 @@ enum EC_Group_Encoding {
EC_DOMPAR_ENC_OID = 2
};
+struct EC_Group_Data;
+
/**
* Class representing an elliptic curve
*/
@@ -43,13 +46,7 @@ class BOTAN_PUBLIC_API(2,0) EC_Group final
EC_Group(const CurveGFp& curve,
const PointGFp& base_point,
const BigInt& order,
- const BigInt& cofactor) :
- m_curve(curve),
- m_base_point(base_point),
- m_order(order),
- m_cofactor(cofactor),
- m_oid("")
- {}
+ const BigInt& cofactor);
/**
* Decode a BER encoded ECC domain parameter set
@@ -68,7 +65,7 @@ class BOTAN_PUBLIC_API(2,0) EC_Group final
* from an OID name (eg "secp256r1", or "1.2.840.10045.3.1.7")
* @param pem_or_oid PEM-encoded data, or an OID
*/
- EC_Group(const std::string& pem_or_oid = "");
+ explicit EC_Group(const std::string& pem_or_oid = "");
/**
* Create the DER encoding of this domain
@@ -87,41 +84,90 @@ class BOTAN_PUBLIC_API(2,0) EC_Group final
* Return domain parameter curve
* @result domain parameter curve
*/
- const CurveGFp& get_curve() const { return m_curve; }
+ const CurveGFp& BOTAN_DEPRECATED("Avoid CurveGFp") get_curve() const;
+
+ /**
+ * Return the size of p in bits (same as get_p().bits())
+ */
+ size_t get_p_bits() const;
+
+ /**
+ * Return the size of p in bits (same as get_p().bytes())
+ */
+ size_t get_p_bytes() const;
+
+ /**
+ * Return the prime modulus of the field
+ */
+ const BigInt& get_p() const;
+
+ /**
+ * Return the a parameter of the elliptic curve equation
+ */
+ const BigInt& get_a() const;
+
+ /**
+ * Return the b parameter of the elliptic curve equation
+ */
+ const BigInt& get_b() const;
/**
* Return group base point
* @result base point
*/
- const PointGFp& get_base_point() const { return m_base_point; }
+ const PointGFp& get_base_point() const;
/**
* Return the order of the base point
* @result order of the base point
*/
- const BigInt& get_order() const { return m_order; }
+ const BigInt& get_order() const;
+
+ /**
+ * Return the OID of these domain parameters
+ * @result the OID as a string
+ */
+ std::string BOTAN_DEPRECATED("Use get_curve_oid") get_oid() const { return get_curve_oid().as_string(); }
+
+ /**
+ * Return the OID of these domain parameters
+ * @result the OID
+ */
+ const OID& get_curve_oid() const;
/**
* Return the cofactor
* @result the cofactor
*/
- const BigInt& get_cofactor() const { return m_cofactor; }
+ const BigInt& get_cofactor() const;
- bool initialized() const { return !m_base_point.is_zero(); }
+ /**
+ * Return a point on this curve with the affine values x, y
+ */
+ PointGFp point(const BigInt& x, const BigInt& y) const;
/**
- * Return the OID of these domain parameters
- * @result the OID
+ * Return the zero (or infinite) point on this curve
*/
- std::string get_oid() const { return m_oid; }
-
+ PointGFp zero_point() const;
+
+ PointGFp OS2ECP(const uint8_t bits[], size_t len) const;
+
+ template<typename Alloc>
+ PointGFp OS2ECP(const std::vector<uint8_t, Alloc>& vec) const
+ {
+ return this->OS2ECP(vec.data(), vec.size());
+ }
+
+ bool initialized() const { return (m_data != nullptr); }
+
/**
* Verify EC_Group domain
* @returns true if group is valid. false otherwise
*/
bool verify_group(RandomNumberGenerator& rng,
- bool strong = false) const;
-
+ bool strong = false) const;
+
bool operator==(const EC_Group& other) const
{
return ((get_curve() == other.get_curve()) &&
@@ -140,11 +186,11 @@ class BOTAN_PUBLIC_API(2,0) EC_Group final
*/
static const std::set<std::string>& known_named_groups();
+ static void add_named_group(const std::string& name, const OID& oid, const EC_Group& group);
+
private:
- CurveGFp m_curve;
- PointGFp m_base_point;
- BigInt m_order, m_cofactor;
- std::string m_oid;
+ const EC_Group_Data& data() const;
+ std::shared_ptr<EC_Group_Data> m_data;
};
inline bool operator!=(const EC_Group& lhs,