Botan 3.13.0
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/exceptn.h>
10#include <botan/mem_ops.h>
11#include <botan/rng.h>
12
13namespace Botan {
14
15namespace {
16
17EC_AffinePoint decode_ec_public_key_point(const EC_Group& group, std::span<const uint8_t> bytes) {
18 /*
19 * RFC 5480 section 2.2:
20 * The first octet of the OCTET STRING indicates whether the key is
21 * compressed or uncompressed. The uncompressed form is indicated
22 * by 0x04 and the compressed form is indicated by either 0x02 or
23 * 0x03 (see 2.3.3 in [SEC1]). The public key MUST be rejected if
24 * any other value is included in the first octet.
25 */
26 if(auto pt_uncompressed = EC_AffinePoint::deserialize_uncompressed(group, bytes)) {
27 return std::move(pt_uncompressed).value();
28 } else if(auto pt_compressed = EC_AffinePoint::deserialize_compressed(group, bytes)) {
29 return std::move(pt_compressed).value();
30 } else {
31 throw Decoding_Error("Failed to deserialize elliptic curve point");
32 }
33}
34
35} // namespace
36
37EC_PublicKey_Data::EC_PublicKey_Data(const EC_Group& group, std::span<const uint8_t> bytes) :
38 EC_PublicKey_Data(group, decode_ec_public_key_point(group, bytes)) {}
39
41 m_group(std::move(group)), m_point(std::move(pt)) {
42#if defined(BOTAN_HAS_LEGACY_EC_POINT)
43 m_legacy_point = m_point.to_legacy_point();
44#endif
45
46 // Checking that the point lies on the curve is done in the deserialization
47 // of EC_AffinePoint.
48 BOTAN_ARG_CHECK(!m_point.is_identity(), "ECC public key cannot be point at infinity");
49}
50
52 m_group(std::move(group)), m_scalar(std::move(x)), m_legacy_x(m_scalar.to_bigint()) {
53 // Checking that the scalar is lower than the group order is ensured in the
54 // deserialization of the EC_Scalar or during the random generation respectively.
55 BOTAN_ARG_CHECK(m_scalar.is_nonzero(), "ECC private key cannot be zero");
56}
57
58namespace {
59
60EC_Scalar decode_ec_secret_key_scalar(const EC_Group& group, std::span<const uint8_t> bytes) {
61 const size_t order_bytes = group.get_order_bytes();
62
63 if(bytes.size() < order_bytes) {
64 /*
65 * Older versions had a bug which caused secret keys to not be encoded to
66 * the full byte length of the order if there were leading zero bytes. This
67 * was particularly a problem for P-521, where on average half of keys do
68 * not have their high bit set and so can be encoded in 65 bytes, vs 66
69 * bytes for the full order.
70 *
71 * To accommodate this, zero prefix the key if we see such a short input
72 */
73 secure_vector<uint8_t> padded_sk(order_bytes);
74 copy_mem(std::span{padded_sk}.last(bytes.size()), bytes);
75 return decode_ec_secret_key_scalar(group, padded_sk);
76 }
77
78 if(auto s = EC_Scalar::deserialize(group, bytes)) {
79 return s.value();
80 } else {
81 throw Decoding_Error("EC private key is invalid for this group");
82 }
83}
84
85} // namespace
86
87EC_PrivateKey_Data::EC_PrivateKey_Data(const EC_Group& group, std::span<const uint8_t> bytes) :
88 Botan::EC_PrivateKey_Data(group, decode_ec_secret_key_scalar(group, bytes)) {}
89
91 m_scalar.zeroize();
92}
93
94std::shared_ptr<EC_PublicKey_Data> EC_PrivateKey_Data::public_key(RandomNumberGenerator& rng,
95 bool with_modular_inverse) const {
96 auto public_point = [&] {
97 if(with_modular_inverse) {
98 return EC_AffinePoint::g_mul(m_scalar.invert(), rng);
99 } else {
100 return EC_AffinePoint::g_mul(m_scalar, rng);
101 }
102 };
103
104 return std::make_shared<EC_PublicKey_Data>(m_group, public_point());
105}
106
107std::shared_ptr<EC_PublicKey_Data> EC_PrivateKey_Data::public_key(bool with_modular_inverse) const {
108 Null_RNG null_rng;
109 return this->public_key(null_rng, with_modular_inverse);
110}
111
112void EC_PrivateKey_Data::serialize_to(std::span<uint8_t> output) const {
113 m_scalar.serialize_to(output);
114}
115
116} // namespace Botan
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:33
static std::optional< EC_AffinePoint > deserialize_uncompressed(const EC_Group &group, std::span< const uint8_t > bytes)
static EC_AffinePoint g_mul(const EC_Scalar &scalar, RandomNumberGenerator &rng)
Multiply by the group generator returning a complete point.
static std::optional< EC_AffinePoint > deserialize_compressed(const EC_Group &group, std::span< const uint8_t > bytes)
size_t get_order_bytes() const
Definition ec_group.cpp:666
const EC_Group & group() const
Definition ec_key_data.h:71
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:30
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)
constexpr void copy_mem(T *out, const T *in, size_t n)
Definition mem_ops.h:144
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:128