Skip to content

Commit

Permalink
Add a new EC_Group constructor for explicit parameters
Browse files Browse the repository at this point in the history
Unlike the existing (deprecated) constructor, this constructor
requires an OID, does not accept a cofactor, limits the field to at
most 521 bits, and performs basic validation of the arguments.
  • Loading branch information
randombit committed May 19, 2024
1 parent bb6c6c1 commit c4f51d4
Show file tree
Hide file tree
Showing 14 changed files with 123 additions and 108 deletions.
11 changes: 11 additions & 0 deletions doc/dev_ref/oids.rst
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,14 @@ Values currently assigned are::
camellia-192-siv OBJECT IDENTIFIER ::= { sivModes 7 }
camellia-256-siv OBJECT IDENTIFIER ::= { sivModes 8 }
sm4-128-siv OBJECT IDENTIFIER ::= { sivModes 9 }

ellipticCurve OBJECT IDENTIFIER ::= { randombit 4 }

numsp256d1 OBJECT IDENTIFIER ::= { ellipticCurve 1 }
numsp384d1 OBJECT IDENTIFIER ::= { ellipticCurve 2 }
numsp512d1 OBJECT IDENTIFIER ::= { ellipticCurve 3 }

-- These are just for testing purposes internally in the library
-- and are not included in oids.txt
sm2test OBJECT IDENTIFIER ::= { ellipticCurve 5459250 }
iso18003 OBJECT IDENTIFIER ::= { ellipticCurve 18003 }
28 changes: 27 additions & 1 deletion src/lib/pubkey/ec_group/ec_group.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ std::pair<std::shared_ptr<EC_Group_Data>, bool> EC_Group::BER_decode_EC_group(co
.end_cons()
.verify_end();

if(p.bits() < 112 || p.bits() > 1024) {
if(p.bits() < 112 || p.bits() > 521) {
throw Decoding_Error("ECC p parameter is invalid size");
}

Expand Down Expand Up @@ -478,6 +478,32 @@ EC_Group::EC_Group(const BigInt& p,
ec_group_data().lookup_or_create(p, a, b, base_x, base_y, order, cofactor, oid, EC_Group_Source::ExternalSource);
}

EC_Group::EC_Group(const OID& oid,
const BigInt& p,
const BigInt& a,
const BigInt& b,
const BigInt& base_x,
const BigInt& base_y,
const BigInt& order) {
BOTAN_ARG_CHECK(oid.has_value(), "An OID is required for creating an EC_Group");
BOTAN_ARG_CHECK(p.bits() <= 521, "EC_Group p too large");
BOTAN_ARG_CHECK(is_bailie_psw_probable_prime(p), "EC_Group p is not prime");
BOTAN_ARG_CHECK(is_bailie_psw_probable_prime(order), "EC_Group order is not prime");
BOTAN_ARG_CHECK(a >= 0 && a < p, "EC_Group a is invalid");
BOTAN_ARG_CHECK(b > 0 && b < p, "EC_Group b is invalid");
BOTAN_ARG_CHECK(base_x >= 0 && base_x < p, "EC_Group base_x is invalid");
BOTAN_ARG_CHECK(base_y >= 0 && base_y < p, "EC_Group base_y is invalid");

// This catches someone "ignoring" a cofactor and just trying to
// provide the subgroup order
BOTAN_ARG_CHECK((p - order).abs().bits() <= (p.bits() / 2) + 1, "Hasse bound invalid");

BigInt cofactor(1);

m_data =
ec_group_data().lookup_or_create(p, a, b, base_x, base_y, order, cofactor, oid, EC_Group_Source::ExternalSource);
}

EC_Group::EC_Group(const uint8_t ber[], size_t ber_len) {
auto data = BER_decode_EC_group(ber, ber_len, EC_Group_Source::ExternalSource);
m_data = data.first;
Expand Down
36 changes: 34 additions & 2 deletions src/lib/pubkey/ec_group/ec_group.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ class EC_Group_Data_Map;
class BOTAN_PUBLIC_API(2, 0) EC_Group final {
public:
/**
* Construct Domain paramers from specified parameters
* Construct elliptic curve from the specified parameters
*
* @param p the elliptic curve p
* @param a the elliptic curve a param
* @param b the elliptic curve b param
Expand All @@ -66,7 +67,7 @@ class BOTAN_PUBLIC_API(2, 0) EC_Group final {
* Warning: Support for explicitly encoded curve parameters is deprecated.
* An OID must be assigned.
*/
BOTAN_DEPRECATED("Explicit curves are deprecated. See Doxygen comment for related info")
BOTAN_DEPRECATED("Use alternate constructor")
EC_Group(const BigInt& p,
const BigInt& a,
const BigInt& b,
Expand All @@ -76,6 +77,37 @@ class BOTAN_PUBLIC_API(2, 0) EC_Group final {
const BigInt& cofactor,
const OID& oid = OID());

/**
* Construct elliptic curve from the specified parameters
*
* Unlike the deprecated constructor, this constructor requires:
* - That p is at most 521 bits
* - That an object identifier is provided
* - That the cofactor is 1 (this is implicit due to not having
* cofactor argument)
* - That the curve is at least plausibly valid (for example
* it checks that p is prime). It does not fully verify
* the group since certain things cannot be checked until
* the EC_Group object is constructed.
*
* WARNING use only elliptic curve parameters that you trust
*
* @param oid an object identifier used to identify this curve
* @param p the elliptic curve prime (at most 521 bits)
* @param a the elliptic curve a param
* @param b the elliptic curve b param
* @param base_x the x coordinate of the group generator
* @param base_y the y coordinate of the group generator
* @param order the order of the group
*/
EC_Group(const OID& oid,
const BigInt& p,
const BigInt& a,
const BigInt& b,
const BigInt& base_x,
const BigInt& base_y,
const BigInt& order);

/**
* Decode a BER encoded ECC domain parameter set
* @param ber the bytes of the BER encoding
Expand Down
45 changes: 15 additions & 30 deletions src/tests/data/pubkey/ecies-18033.vec
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
# ISO/IEC 18033-2 2006
# ECIES-KEM test vectors for ECModp-Group

p = 0xfffffffffffffffffffffffffffffffeffffffffffffffff
a = 0xfffffffffffffffffffffffffffffffefffffffffffffffc
b = 0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1
Order = 0xffffffffffffffffffffffff99def836146bc9b1b4d22831
Gx = 0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012
Gy = 0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811
Oid = 1.3.6.1.4.1.25258.4.18033

# Public Key
hx = 0x1cbc74a41b4e84a1509f935e2328a0bb06104d8dbb8d2130
hy = 0x7b2ab1f10d76fde1ea046a4ad5fb903734190151bb30cec2

# Private Key
x = 0xb67048c28d2d26a73f713d5ebb994ac92588464e7fe7d3f3

# ----------------------------------------------------------------------------------------------------

# C.2.2
Expand All @@ -13,21 +28,6 @@

format = uncompressed

p = 0xfffffffffffffffffffffffffffffffeffffffffffffffff
a = 0xfffffffffffffffffffffffffffffffefffffffffffffffc
b = 0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1
mu = 0xffffffffffffffffffffffff99def836146bc9b1b4d22831
nu = 0x01
gx = 0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012
gy = 0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811

# Public Key
hx = 0x1cbc74a41b4e84a1509f935e2328a0bb06104d8dbb8d2130
hy = 0x7b2ab1f10d76fde1ea046a4ad5fb903734190151bb30cec2

# Private Key
x = 0xb67048c28d2d26a73f713d5ebb994ac92588464e7fe7d3f3

# Encoding format = uncompressed_fmt
r = 0x083d4ac64f1960a9836a84f91ca211a185814fa43a2c8f21
C0 = 04ccc9ea07b8b71d25646b22b0e251362a3fa9e993042315df047b2e07dd2ffb89359945f3d22ca8757874be2536e0f924
Expand All @@ -45,21 +45,6 @@ K = 9a709adeb6c7590ccfc7d594670dd2d74fcdda3f8622f2dbcf0f0c02966d5d9002db578c989

format = compressed

p = 0xfffffffffffffffffffffffffffffffeffffffffffffffff
a = 0xfffffffffffffffffffffffffffffffefffffffffffffffc
b = 0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1
mu = 0xffffffffffffffffffffffff99def836146bc9b1b4d22831
nu = 0x01
gx = 0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012
gy = 0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811

# Public Key
hx = 0x1cbc74a41b4e84a1509f935e2328a0bb06104d8dbb8d2130
hy = 0x7b2ab1f10d76fde1ea046a4ad5fb903734190151bb30cec2

# Private Key
x = 0xb67048c28d2d26a73f713d5ebb994ac92588464e7fe7d3f3

# Encoding format = compressed_fmt
r = 0x083d4ac64f1960a9836a84f91ca211a185814fa43a2c8f21
C0 = 02ccc9ea07b8b71d25646b22b0e251362a3fa9e993042315df
Expand Down
1 change: 0 additions & 1 deletion src/tests/data/pubkey/gost_3410_sign.vec
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ P = 0x8000000000000000000000000000000000000000000000000000000000000431
A = 0x7
B = 0x5FBFF498AA938CE739B8E022FBAFEF40563F6E6A3472FC2A514C0CE9DAE23B7E
Order = 0x8000000000000000000000000000000150FE8A1892976154C59CFC193ACCF5B3
Cofactor = 1
Gx = 2
Gy = 0x8E2A8A0E65147D4BD6316030E16D19C85C97F0A9CA267122B96ABBCEA7E8FC8
Oid = 1.3.6.1.4.1.25258.2
Expand Down
1 change: 0 additions & 1 deletion src/tests/data/pubkey/gost_3410_verify.vec
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ P = 0x8000000000000000000000000000000000000000000000000000000000000431
A = 0x7
B = 0x5FBFF498AA938CE739B8E022FBAFEF40563F6E6A3472FC2A514C0CE9DAE23B7E
Order = 0x8000000000000000000000000000000150FE8A1892976154C59CFC193ACCF5B3
Cofactor = 1
Gx = 2
Gy = 0x8E2A8A0E65147D4BD6316030E16D19C85C97F0A9CA267122B96ABBCEA7E8FC8
Oid = 1.3.6.1.4.1.25258.2
Expand Down
2 changes: 1 addition & 1 deletion src/tests/data/pubkey/sm2_enc.vec
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ B = 0x63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A
xG = 0x421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D
yG = 0x0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2
Order = 0x8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7
Cofactor = 1
Oid = 1.3.6.1.4.1.25258.4.5459250

x = 0x1649AB77A00637BD5E2EFE283FBF353534AA7F7CB89463F208DDBC2920BB0DA0

Expand Down
6 changes: 3 additions & 3 deletions src/tests/data/pubkey/sm2_sig.vec
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ B = 0x63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A
xG = 0x421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D
yG = 0x0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2
Order = 0x8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7
Cofactor = 1
Oid = 1.3.6.1.4.1.25258.4.5459250

Hash = SM3
Ident = [email protected]
Expand Down Expand Up @@ -39,7 +39,7 @@ B = 0x28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93
xG = 0x32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7
yG = 0xBC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0
Order = 0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123
Cofactor = 1
Oid = 1.2.156.10197.1.301

Hash = SM3
Ident = [email protected]
Expand All @@ -63,7 +63,7 @@ B = 0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B
xG = 0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296
yG = 0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5
Order = 0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551
Cofactor = 1
Oid = 1.2.840.10045.3.1.7

Hash = SM3
Ident = [email protected]
Expand Down
19 changes: 12 additions & 7 deletions src/tests/test_ec_group.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -243,27 +243,29 @@ class EC_Group_Tests : public Test {

const auto group = Botan::EC_Group::from_name(group_name);

result.confirm("EC_Group is known", !group.get_curve_oid().empty());
result.confirm("EC_Group is known", group.get_curve_oid().has_value());
result.confirm("EC_Group is considered valid", group.verify_group(this->rng(), true));
result.confirm("EC_Group is not considered explict encoding", !group.used_explicit_encoding());

result.test_eq("EC_Group has correct bit size", group.get_p().bits(), group.get_p_bits());
result.test_eq("EC_Group has byte size", group.get_p().bytes(), group.get_p_bytes());

result.test_eq("EC_Group has cofactor == 1", group.get_cofactor(), 1);

const Botan::OID from_order = Botan::EC_Group::EC_group_identity_from_order(group.get_order());

result.test_eq(
"EC_group_identity_from_order works", from_order.to_string(), group.get_curve_oid().to_string());

result.confirm("Same group is same", group == Botan::EC_Group::from_name(group_name));

const Botan::EC_Group copy(group.get_p(),
const Botan::EC_Group copy(group.get_curve_oid(),
group.get_p(),
group.get_a(),
group.get_b(),
group.get_g_x(),
group.get_g_y(),
group.get_order(),
group.get_cofactor());
group.get_order());

result.confirm("Same group is same even with copy", group == copy);

Expand Down Expand Up @@ -595,6 +597,7 @@ Test::Result test_enc_dec_uncompressed_112() {
const Botan::BigInt order("0x36DF0AAFD8B8D7597CA10520D04B");
const Botan::BigInt cofactor("4"); // !

// This uses the deprecated constructor due to making use of cofactor > 1
const Botan::EC_Group group(p, a, b, g_x, g_y, order, cofactor);

const std::string G_secp_uncomp = "044BA30AB5E892B4E1649DD0928643ADCD46F5882E3747DEF36E956E97";
Expand Down Expand Up @@ -642,7 +645,7 @@ Test::Result test_ecc_registration() {
const Botan::OID oid("1.3.132.0.6");

// Creating this object implicitly registers the curve for future use ...
Botan::EC_Group reg_group(p, a, b, g_x, g_y, order, 1, oid);
Botan::EC_Group reg_group(oid, p, a, b, g_x, g_y, order);

auto group = Botan::EC_Group::from_OID(oid);

Expand All @@ -667,6 +670,8 @@ Test::Result test_ec_group_from_params() {

const Botan::OID oid("1.3.132.0.8");

// This uses the deprecated constructor to verify we dedup even without an OID
// This whole test can be removed once explicit curve support is removed
Botan::EC_Group reg_group(p, a, b, g_x, g_y, order, 1);
result.confirm("Group has correct OID", reg_group.get_curve_oid() == oid);

Expand All @@ -690,7 +695,7 @@ Test::Result test_ec_group_bad_registration() {
const Botan::OID oid("1.3.132.0.8");

try {
Botan::EC_Group reg_group(p, a, b, g_x, g_y, order, 1, oid);
Botan::EC_Group reg_group(oid, p, a, b, g_x, g_y, order);
result.test_failure("Should have failed");
} catch(Botan::Invalid_Argument&) {
result.test_success("Got expected exception");
Expand All @@ -715,7 +720,7 @@ Test::Result test_ec_group_duplicate_orders() {

const Botan::OID oid("1.3.6.1.4.1.25258.100.0"); // some other random OID

Botan::EC_Group reg_group(p, a, b, g_x, g_y, order, 1, oid);
Botan::EC_Group reg_group(oid, p, a, b, g_x, g_y, order);
result.test_success("Registration success");
result.confirm("Group has correct OID", reg_group.get_curve_oid() == oid);

Expand Down
14 changes: 8 additions & 6 deletions src/tests/test_ecies.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,9 @@ void check_encrypt_decrypt(Test::Result& result,

class ECIES_ISO_Tests final : public Text_Based_Test {
public:
ECIES_ISO_Tests() : Text_Based_Test("pubkey/ecies-18033.vec", "format,p,a,b,mu,nu,gx,gy,hx,hy,x,r,C0,K") {}
ECIES_ISO_Tests() : Text_Based_Test("pubkey/ecies-18033.vec", "format,p,a,b,Order,Gx,Gy,Oid,hx,hy,x,r,C0,K") {}

bool clear_between_callbacks() const override { return false; }

Test::Result run_one_test(const std::string& /*header*/, const VarMap& vars) override {
Test::Result result("ECIES-ISO");
Expand All @@ -108,18 +110,18 @@ class ECIES_ISO_Tests final : public Text_Based_Test {
const Botan::BigInt p = vars.get_req_bn("p");
const Botan::BigInt a = vars.get_req_bn("a");
const Botan::BigInt b = vars.get_req_bn("b");
const Botan::BigInt mu = vars.get_req_bn("mu"); // order
const Botan::BigInt nu = vars.get_req_bn("nu"); // cofactor
const Botan::BigInt gx = vars.get_req_bn("gx"); // base point x
const Botan::BigInt gy = vars.get_req_bn("gy"); // base point y
const Botan::BigInt order = vars.get_req_bn("Order"); // order
const Botan::BigInt gx = vars.get_req_bn("Gx"); // base point x
const Botan::BigInt gy = vars.get_req_bn("Gy"); // base point y
const Botan::OID oid(vars.get_req_str("Oid"));
const Botan::BigInt hx = vars.get_req_bn("hx"); // x of public point of bob
const Botan::BigInt hy = vars.get_req_bn("hy"); // y of public point of bob
const Botan::BigInt x = vars.get_req_bn("x"); // private key of bob
const Botan::BigInt r = vars.get_req_bn("r"); // (ephemeral) private key of alice
const std::vector<uint8_t> c0 = vars.get_req_bin("C0"); // expected encoded (ephemeral) public key
const std::vector<uint8_t> k = vars.get_req_bin("K"); // expected derived secret

const Botan::EC_Group domain(p, a, b, gx, gy, mu, nu);
const Botan::EC_Group domain(oid, p, a, b, gx, gy, order);

// keys of bob
const Botan::ECDH_PrivateKey other_private_key(this->rng(), domain, x);
Expand Down
16 changes: 6 additions & 10 deletions src/tests/test_gost_3410.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,8 @@ namespace {
class GOST_3410_2001_Verification_Tests final : public PK_Signature_Verification_Test {
public:
GOST_3410_2001_Verification_Tests() :
PK_Signature_Verification_Test("GOST 34.10-2001",
"pubkey/gost_3410_verify.vec",
"P,A,B,Gx,Gy,Oid,Order,Cofactor,Px,Py,Hash,Msg,Signature") {}
PK_Signature_Verification_Test(
"GOST 34.10-2001", "pubkey/gost_3410_verify.vec", "P,A,B,Gx,Gy,Oid,Order,Px,Py,Hash,Msg,Signature") {}

std::unique_ptr<Botan::Public_Key> load_public_key(const VarMap& vars) override {
const BigInt p = vars.get_req_bn("P");
Expand All @@ -31,10 +30,9 @@ class GOST_3410_2001_Verification_Tests final : public PK_Signature_Verification
const BigInt Gx = vars.get_req_bn("Gx");
const BigInt Gy = vars.get_req_bn("Gy");
const BigInt order = vars.get_req_bn("Order");
const BigInt cofactor = vars.get_req_bn("Cofactor");
const Botan::OID oid(vars.get_req_str("Oid"));

Botan::EC_Group group(p, a, b, Gx, Gy, order, cofactor, oid);
Botan::EC_Group group(oid, p, a, b, Gx, Gy, order);

const BigInt Px = vars.get_req_bn("Px");
const BigInt Py = vars.get_req_bn("Py");
Expand All @@ -50,9 +48,8 @@ class GOST_3410_2001_Verification_Tests final : public PK_Signature_Verification
class GOST_3410_2001_Signature_Tests final : public PK_Signature_Generation_Test {
public:
GOST_3410_2001_Signature_Tests() :
PK_Signature_Generation_Test("GOST 34.10-2001",
"pubkey/gost_3410_sign.vec",
"P,A,B,Gx,Gy,Oid,Order,X,Cofactor,Hash,Nonce,Msg,Signature") {}
PK_Signature_Generation_Test(
"GOST 34.10-2001", "pubkey/gost_3410_sign.vec", "P,A,B,Gx,Gy,Oid,Order,X,Hash,Nonce,Msg,Signature") {}

std::unique_ptr<Botan::Private_Key> load_private_key(const VarMap& vars) override {
const BigInt p = vars.get_req_bn("P");
Expand All @@ -61,10 +58,9 @@ class GOST_3410_2001_Signature_Tests final : public PK_Signature_Generation_Test
const BigInt Gx = vars.get_req_bn("Gx");
const BigInt Gy = vars.get_req_bn("Gy");
const BigInt order = vars.get_req_bn("Order");
const BigInt cofactor = vars.get_req_bn("Cofactor");
const Botan::OID oid(vars.get_req_str("Oid"));

Botan::EC_Group group(p, a, b, Gx, Gy, order, cofactor, oid);
Botan::EC_Group group(oid, p, a, b, Gx, Gy, order);

const BigInt x = vars.get_req_bn("X");

Expand Down
Loading

0 comments on commit c4f51d4

Please sign in to comment.