11#include <botan/ec_group.h>
13#include <botan/ber_dec.h>
14#include <botan/der_enc.h>
15#include <botan/mutex.h>
17#include <botan/reducer.h>
19#include <botan/internal/ec_inner_data.h>
20#include <botan/internal/fmt.h>
21#include <botan/internal/primality.h>
26class EC_Group_Data_Map
final {
28 EC_Group_Data_Map() =
default;
32 size_t count = m_registered_curves.size();
33 m_registered_curves.clear();
37 std::shared_ptr<EC_Group_Data> lookup(
const OID& oid) {
40 for(
auto i : m_registered_curves) {
50 for(
auto curve : m_registered_curves) {
51 if(curve->oid().empty() ==
true && curve->params_match(*data)) {
57 m_registered_curves.push_back(data);
62 return std::shared_ptr<EC_Group_Data>();
65 std::shared_ptr<EC_Group_Data> lookup_or_create(
const BigInt& p,
71 const BigInt& cofactor,
76 for(
auto i : m_registered_curves) {
82 if(!oid.empty() && !i->oid().empty() && i->oid() != oid) {
86 const bool same_oid = !oid.empty() && i->oid() == oid;
87 const bool same_params = i->params_match(p, a,
b, g_x, g_y, order, cofactor);
93 if(same_params && same_oid) {
100 if(same_params && oid.empty()) {
107 if(same_oid && !same_params) {
108 throw Invalid_Argument(
"Attempting to register a curve using OID " + oid.to_string() +
109 " but a distinct curve is already registered using that OID");
116 if(same_params && i->oid().empty() && !oid.empty()) {
129 std::shared_ptr<EC_Group_Data> new_group =
130 std::make_shared<EC_Group_Data>(p, a,
b, g_x, g_y, order, cofactor, oid, source);
132 if(oid.has_value()) {
134 if(data !=
nullptr && !new_group->params_match(*data)) {
135 throw Invalid_Argument(
"Attempting to register an EC group under OID of hardcoded group");
140 if(oid_from_store.has_value()) {
154 if(new_group->params_match(*data)) {
155 new_group->set_oid(oid_from_store);
160 m_registered_curves.push_back(new_group);
166 std::vector<std::shared_ptr<EC_Group_Data>> m_registered_curves;
170EC_Group_Data_Map& EC_Group::ec_group_data() {
176 static Allocator_Initializer g_init_allocator;
177 static EC_Group_Data_Map g_ec_data;
183 return ec_group_data().clear();
187std::shared_ptr<EC_Group_Data> EC_Group::load_EC_group_info(
const char* p_str,
192 const char* order_str,
197 const BigInt g_x(g_x_str);
198 const BigInt g_y(g_y_str);
199 const BigInt order(order_str);
206std::pair<std::shared_ptr<EC_Group_Data>,
bool> EC_Group::BER_decode_EC_group(std::span<const uint8_t> bits,
208 BER_Decoder ber(bits);
209 BER_Object obj = ber.get_next_object();
213 BER_Decoder(bits).decode(oid);
215 auto data = ec_group_data().lookup(oid);
217 throw Decoding_Error(
fmt(
"Unknown namedCurve OID '{}'", oid.to_string()));
220 return std::make_pair(data,
false);
224 BigInt p, a,
b, order, cofactor;
225 std::vector<uint8_t> base_pt;
226 std::vector<uint8_t> seed;
230 .decode_and_check<
size_t>(1,
"Unknown ECC param version code")
232 .decode_and_check(OID(
"1.2.840.10045.1.1"),
"Only prime ECC fields supported")
236 .decode_octet_string_bigint(a)
237 .decode_octet_string_bigint(
b)
246 if(p.bits() < 112 || p.bits() > 521) {
247 throw Decoding_Error(
"ECC p parameter is invalid size");
251 throw Decoding_Error(
"ECC p parameter is not a prime");
254 if(a.is_negative() || a >= p) {
255 throw Decoding_Error(
"Invalid ECC a parameter");
259 throw Decoding_Error(
"Invalid ECC b parameter");
263 throw Decoding_Error(
"Invalid ECC order parameter");
266 if(cofactor <= 0 || cofactor >= 16) {
267 throw Decoding_Error(
"Invalid ECC cofactor parameter");
270 std::pair<BigInt, BigInt> base_xy =
Botan::OS2ECP(base_pt.data(), base_pt.size(), p, a,
b);
273 ec_group_data().lookup_or_create(p, a,
b, base_xy.first, base_xy.second, order, cofactor, OID(),
source);
274 return std::make_pair(data,
true);
278 throw Decoding_Error(
"Cannot handle ImplicitCA ECC parameters");
280 throw Decoding_Error(
fmt(
"Unexpected tag {} while decoding ECC domain params",
asn1_tag_to_string(obj.type())));
297 auto data = ec_group_data().lookup(oid);
308 std::shared_ptr<EC_Group_Data> data;
311 data = ec_group_data().lookup(oid.value());
329 m_data = ec_group_data().lookup(oid);
333 if(m_data ==
nullptr) {
334 if(str.size() > 30 && str.substr(0, 29) ==
"-----BEGIN EC PARAMETERS-----") {
339 this->m_data = data.first;
340 this->m_explicit_encoding = data.second;
344 if(m_data ==
nullptr) {
378 if(p.
bits() == 521) {
384 BOTAN_ARG_CHECK(p % 4 == 3,
"EC_Group p must be congruent to 3 modulo 4");
388 BOTAN_ARG_CHECK(base_x >= 0 && base_x < p,
"EC_Group base_x is invalid");
389 BOTAN_ARG_CHECK(base_y >= 0 && base_y < p,
"EC_Group base_y is invalid");
408 m_explicit_encoding = data.second;
412 if(m_data ==
nullptr) {
419 return data().p_bits();
423 return data().p_bytes();
427 return data().order_bits();
431 return data().order_bytes();
447 return data().base_point();
451 return data().base_point();
455 return data().order();
467 return data().cofactor();
471 return data().has_cofactor();
475 return data().mod_order(k);
483 return data().source();
487 const auto& der_named_curve = data().der_named_curve();
489 if(der_named_curve.empty()) {
490 throw Encoding_Error(
"Cannot encode EC_Group as OID because OID not set");
493 return der_named_curve;
498 std::vector<uint8_t> output;
500 const size_t ecpVers1 = 1;
501 const OID curve_type(
"1.2.840.10045.1.1");
535 if(m_data == other.m_data) {
572 if(is_builtin && !strong) {
582 if(p <= 3 || order <= 0) {
585 if(a < 0 || a >= p) {
592 const size_t test_prob = 128;
593 const bool is_randomly_generated = is_builtin;
596 if(!
is_prime(p, rng, test_prob, is_randomly_generated)) {
601 if(!
is_prime(order, rng, test_prob, is_randomly_generated)) {
610 if(discriminant == 0) {
627 if(!(base_point * order).is_zero()) {
662 return this->mul2_vartime_x_mod_order_eq(v, c * x, c * y);
#define BOTAN_ASSERT_NOMSG(expr)
#define BOTAN_ARG_CHECK(expr, msg)
static BigInt power_of_2(size_t n)
DER_Encoder & start_sequence()
DER_Encoder & encode(bool b)
static EC_AffinePoint _from_inner(std::unique_ptr< EC_AffinePoint_Data > inner)
std::optional< EC_AffinePoint > mul2_vartime(const EC_Scalar &x, const EC_Scalar &y) const
Mul2Table(const EC_AffinePoint &h)
bool mul2_vartime_x_mod_order_eq(const EC_Scalar &v, const EC_Scalar &x, const EC_Scalar &y) const
static EC_Group from_name(std::string_view name)
static EC_Group from_PEM(std::string_view pem)
const BigInt & get_b() const
const BigInt & get_a() const
const BigInt & get_g_y() const
const BigInt & get_cofactor() const
BigInt mod_order(const BigInt &x) const
bool operator==(const EC_Group &other) const
EC_Group_Source source() const
const EC_Point & generator() const
bool verify_public_element(const EC_Point &y) const
const BigInt & get_p() const
bool verify_group(RandomNumberGenerator &rng, bool strong=false) const
const BigInt & get_order() const
size_t get_p_bits() const
const EC_Point & get_base_point() const
EC_Point point(const BigInt &x, const BigInt &y) const
static EC_Group from_OID(const OID &oid)
static std::shared_ptr< EC_Group_Data > EC_group_info(const OID &oid)
std::vector< uint8_t > DER_encode() const
std::string PEM_encode() const
const BigInt & get_g_x() const
const OID & get_curve_oid() const
bool has_cofactor() const
static size_t clear_registered_curve_data()
EC_Group & operator=(const EC_Group &)
size_t get_p_bytes() const
static OID EC_group_identity_from_order(const BigInt &order)
size_t get_order_bits() const
size_t get_order_bytes() const
bool on_the_curve() const
const EC_Scalar_Data & _inner() const
BigInt cube(const BigInt &x) const
BigInt square(const BigInt &x) const
BigInt multiply(const BigInt &x, const BigInt &y) const
BigInt reduce(const BigInt &x) const
static std::optional< OID > from_name(std::string_view name)
std::string to_string() const
static OID from_string(std::string_view str)
int(* final)(unsigned char *, CTX *)
std::string encode(const uint8_t der[], size_t length, std::string_view label, size_t width)
secure_vector< uint8_t > decode_check_label(DataSource &source, std::string_view label_want)
std::string asn1_tag_to_string(ASN1_Type type)
std::string fmt(std::string_view format, const T &... args)
BigInt abs(const BigInt &n)
secure_vector< T > lock(const std::vector< T > &in)
bool is_prime(const BigInt &n, RandomNumberGenerator &rng, size_t prob, bool is_random)
bool is_bailie_psw_probable_prime(const BigInt &n, const Modular_Reducer &mod_n)
EC_Point OS2ECP(const uint8_t data[], size_t data_len, const CurveGFp &curve)
lock_guard< T > lock_guard_type