Botan 3.8.1
Crypto and TLS for C&
ec_key_data.cpp
Go to the documentation of this file.
1/*
2* (C) 2024 Jack Lloyd
3*
4* Botan is released under the Simplified BSD License (see license.txt)
5*/
6
7#include <botan/internal/ec_key_data.h>
8
9#include <botan/mem_ops.h>
10#include <botan/rng.h>
11
12namespace Botan {
13
15 m_group(std::move(group)), m_point(std::move(pt)) {
16#if defined(BOTAN_HAS_LEGACY_EC_POINT)
17 m_legacy_point = m_point.to_legacy_point();
18#endif
19
20 // Checking that the point lies on the curve is done in the deserialization
21 // of EC_AffinePoint.
22 BOTAN_ARG_CHECK(!m_point.is_identity(), "ECC public key cannot be point at infinity");
23}
24
26 m_group(std::move(group)), m_scalar(std::move(x)), m_legacy_x(m_scalar.to_bigint()) {
27 // Checking that the scalar is lower than the group order is ensured in the
28 // deserialization of the EC_Scalar or during the random generation respectively.
29 BOTAN_ARG_CHECK(m_scalar.is_nonzero(), "ECC private key cannot be zero");
30}
31
32namespace {
33
34EC_Scalar decode_ec_secret_key_scalar(const EC_Group& group, std::span<const uint8_t> bytes) {
35 const size_t order_bytes = group.get_order_bytes();
36
37 if(bytes.size() < order_bytes) {
38 /*
39 * Older versions had a bug which caused secret keys to not be encoded to
40 * the full byte length of the order if there were leading zero bytes. This
41 * was particularly a problem for P-521, where on average half of keys do
42 * not have their high bit set and so can be encoded in 65 bytes, vs 66
43 * bytes for the full order.
44 *
45 * To accomodate this, zero prefix the key if we see such a short input
46 */
47 secure_vector<uint8_t> padded_sk(order_bytes);
48 copy_mem(std::span{padded_sk}.last(bytes.size()), bytes);
49 return decode_ec_secret_key_scalar(group, padded_sk);
50 }
51
52 if(auto s = EC_Scalar::deserialize(group, bytes)) {
53 return s.value();
54 } else {
55 throw Decoding_Error("EC private key is invalid for this group");
56 }
57}
58
59} // namespace
60
61EC_PrivateKey_Data::EC_PrivateKey_Data(const EC_Group& group, std::span<const uint8_t> bytes) :
62 Botan::EC_PrivateKey_Data(group, decode_ec_secret_key_scalar(group, bytes)) {}
63
64std::shared_ptr<EC_PublicKey_Data> EC_PrivateKey_Data::public_key(RandomNumberGenerator& rng,
65 bool with_modular_inverse) const {
66 auto public_point = [&] {
67 if(with_modular_inverse) {
68 return EC_AffinePoint::g_mul(m_scalar.invert(), rng);
69 } else {
70 return EC_AffinePoint::g_mul(m_scalar, rng);
71 }
72 };
73
74 return std::make_shared<EC_PublicKey_Data>(m_group, public_point());
75}
76
77std::shared_ptr<EC_PublicKey_Data> EC_PrivateKey_Data::public_key(bool with_modular_inverse) const {
78 Null_RNG null_rng;
79 return this->public_key(null_rng, with_modular_inverse);
80}
81
82void EC_PrivateKey_Data::serialize_to(std::span<uint8_t> output) const {
83 m_scalar.serialize_to(output);
84}
85
86} // namespace Botan
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:31
static EC_AffinePoint g_mul(const EC_Scalar &scalar, RandomNumberGenerator &rng)
Multiply by the group generator returning a complete point.
size_t get_order_bytes() const
Definition ec_group.cpp:532
const EC_Group & group() const
Definition ec_key_data.h:66
void serialize_to(std::span< uint8_t > output) const
std::shared_ptr< EC_PublicKey_Data > public_key(RandomNumberGenerator &rng, bool with_modular_inverse) const
EC_PrivateKey_Data(EC_Group group, EC_Scalar x)
const EC_Group & group() const
Definition ec_key_data.h:31
EC_PublicKey_Data(EC_Group group, EC_AffinePoint pt)
static std::optional< EC_Scalar > deserialize(const EC_Group &group, std::span< const uint8_t > bytes)
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:65
constexpr void copy_mem(T *out, const T *in, size_t n)
Definition mem_ops.h:149