Botan 3.13.0
Crypto and TLS for C&
x448.cpp
Go to the documentation of this file.
1/*
2* X448
3* (C) 2024 Jack Lloyd
4* 2024 Fabian Albert - Rohde & Schwarz Cybersecurity
5*
6* Botan is released under the Simplified BSD License (see license.txt)
7*/
8
9#include <botan/x448.h>
10
11#include <botan/ber_dec.h>
12#include <botan/der_enc.h>
13#include <botan/mem_ops.h>
14#include <botan/rng.h>
15#include <botan/internal/ct_utils.h>
16#include <botan/internal/pk_ops_impl.h>
17#include <botan/internal/x448_internal.h>
18
19namespace Botan {
20
21class X448_PublicKey_Data final {
22 public:
23 explicit X448_PublicKey_Data(std::array<uint8_t, X448_LEN> key) : m_key(key) {}
24
25 const std::array<uint8_t, X448_LEN>& key() const { return m_key; }
26
27 private:
28 std::array<uint8_t, X448_LEN> m_key;
29};
30
31class X448_PrivateKey_Data final {
32 public:
33 explicit X448_PrivateKey_Data(secure_vector<uint8_t> key) : m_key(std::move(key)) {}
34
35 const secure_vector<uint8_t>& key() const { return m_key; }
36
37 private:
39};
40
42 const auto& sk = m_private->key();
43 return {sk.begin(), sk.end()};
44}
45
46namespace {
47void x448_basepoint_from_data(std::span<uint8_t, X448_LEN> mypublic, std::span<const uint8_t, X448_LEN> secret) {
48 auto bp = x448_basepoint(decode_scalar(secret));
49 auto bp_bytes = encode_point(bp);
50 copy_mem(mypublic, bp_bytes);
51}
52
53secure_vector<uint8_t> ber_decode_sk(std::span<const uint8_t> key_bits) {
54 secure_vector<uint8_t> decoded_bits;
55 BER_Decoder(key_bits, BER_Decoder::Limits::DER()).decode(decoded_bits, ASN1_Type::OctetString).verify_end();
56 if(decoded_bits.size() != X448_LEN) {
57 throw Decoding_Error("Invalid size for X448 private key");
58 }
59 return decoded_bits;
60}
61
62// Given a secret key compute the public value and build the immutable public
63// and private key data objects.
64void load_x448_keypair(secure_vector<uint8_t> secret,
65 std::shared_ptr<const X448_PublicKey_Data>& pk_out,
66 std::shared_ptr<const X448_PrivateKey_Data>& sk_out) {
67 BOTAN_ASSERT_NOMSG(secret.size() == X448_LEN);
68 std::array<uint8_t, X448_LEN> pub{};
69 {
70 auto scope = CT::scoped_poison(secret);
71 x448_basepoint_from_data(pub, std::span(secret).first<X448_LEN>());
72 CT::unpoison(pub);
73 }
74 pk_out = std::make_shared<const X448_PublicKey_Data>(pub);
75 sk_out = std::make_shared<const X448_PrivateKey_Data>(std::move(secret));
76}
77
78} // namespace
79
83
84bool X448_PublicKey::check_key(RandomNumberGenerator& /*rng*/, bool /*strong*/) const {
85 return true; // no tests possible?
86}
87
88std::vector<uint8_t> X448_PublicKey::raw_public_key_bits() const {
89 const auto& pub = m_public->key();
90 return {pub.begin(), pub.end()};
91}
92
93std::vector<uint8_t> X448_PublicKey::public_key_bits() const {
94 return raw_public_key_bits();
95}
96
97std::unique_ptr<Private_Key> X448_PublicKey::generate_another(RandomNumberGenerator& rng) const {
98 return std::make_unique<X448_PrivateKey>(rng);
99}
100
101X448_PublicKey::X448_PublicKey(const AlgorithmIdentifier& alg_id, std::span<const uint8_t> key_bits) :
102 X448_PublicKey(key_bits) {
103 // RFC 8410 Section 3: "the parameters MUST be absent".
104 if(!alg_id.parameters_are_empty()) {
105 throw Decoding_Error("Unexpected parameters for X448 public key");
106 }
107}
108
109X448_PublicKey::X448_PublicKey(std::span<const uint8_t> pub) {
110 BOTAN_ARG_CHECK(pub.size() == X448_LEN, "Invalid size for X448 public key");
111 std::array<uint8_t, X448_LEN> pub_arr{};
112 copy_mem(pub_arr, pub);
113 m_public = std::make_shared<const X448_PublicKey_Data>(pub_arr);
114}
115
116X448_PrivateKey::X448_PrivateKey(const AlgorithmIdentifier& alg_id, std::span<const uint8_t> key_bits) :
117 X448_PrivateKey(ber_decode_sk(key_bits)) {
118 // RFC 8410 Section 3: "the parameters MUST be absent".
119 if(!alg_id.parameters_are_empty()) {
120 throw Decoding_Error("Unexpected parameters for X448 private key");
121 }
122}
123
124X448_PrivateKey::X448_PrivateKey(std::span<const uint8_t> secret_key) {
125 BOTAN_ARG_CHECK(secret_key.size() == X448_LEN, "Invalid size for X448 private key");
126 load_x448_keypair(secure_vector<uint8_t>(secret_key.begin(), secret_key.end()), m_public, m_private);
127}
128
130
131std::unique_ptr<Public_Key> X448_PrivateKey::public_key() const {
132 return std::make_unique<X448_PublicKey>(public_value());
133}
134
138
139bool X448_PrivateKey::check_key(RandomNumberGenerator& /*rng*/, bool /*strong*/) const {
140 const auto& sk = m_private->key();
141 const auto& pub = m_public->key();
142 std::array<uint8_t, X448_LEN> public_point{};
143 BOTAN_ASSERT_NOMSG(sk.size() == X448_LEN);
144 auto scope = CT::scoped_poison(sk);
145 x448_basepoint_from_data(public_point, std::span(sk).first<X448_LEN>());
146 return CT::is_equal(public_point.data(), pub.data(), pub.size()).as_bool();
147}
148
149namespace {
150
151/**
152* X448 operation
153*/
154class X448_KA_Operation final : public PK_Ops::Key_Agreement_with_KDF {
155 public:
156 X448_KA_Operation(std::shared_ptr<const X448_PrivateKey_Data> key, std::string_view kdf) :
157 PK_Ops::Key_Agreement_with_KDF(kdf), m_key(std::move(key)) {}
158
159 size_t agreed_value_size() const override { return X448_LEN; }
160
161 secure_vector<uint8_t> raw_agree(const uint8_t w_data[], size_t w_len) override {
162 const auto& sk = m_key->key();
163 BOTAN_ASSERT_NOMSG(sk.size() == X448_LEN);
164 auto scope = CT::scoped_poison(sk);
165
166 const std::span<const uint8_t> w(w_data, w_len);
167 if(w.size() != X448_LEN) {
168 throw Decoding_Error("Invalid size for X448 public key");
169 }
170 const auto k = decode_scalar(sk);
171 const auto u = decode_point(w);
172
173 auto shared_secret = encode_point(x448(k, u));
174 CT::unpoison(shared_secret);
175
176 // RFC 7748 Section 6.2
177 // As with X25519, both sides MAY check, without leaking extra
178 // information about the value of K, whether the resulting shared K
179 // is the all-zero value and abort if so.
180 //
181 // TODO: once the generic Key Agreement operation creation is equipped
182 // with a more flexible parameterization, this check could be
183 // made optional.
184 // For instance: `sk->agree().with_optional_sanity_checks(true)`.
185 // See also: https://github.com/randombit/botan/pull/4318
186 if(CT::all_zeros(shared_secret.data(), shared_secret.size()).as_bool()) {
187 throw Invalid_Argument("X448 public point appears to be of low order");
188 }
189
190 return shared_secret;
191 }
192
193 private:
194 std::shared_ptr<const X448_PrivateKey_Data> m_key;
195};
196
197} // namespace
198
199std::unique_ptr<PK_Ops::Key_Agreement> X448_PrivateKey::create_key_agreement_op(RandomNumberGenerator& /*rng*/,
200 std::string_view params,
201 std::string_view provider) const {
202 if(provider == "base" || provider.empty()) {
203 return std::make_unique<X448_KA_Operation>(m_private, params);
204 }
205 throw Provider_Not_Found(algo_name(), provider);
206}
207
208} // namespace Botan
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:75
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:33
bool parameters_are_empty() const
Definition asn1_obj.h:715
virtual OID object_identifier() const
Definition pk_keys.cpp:22
static Limits DER()
Definition ber_dec.h:42
secure_vector< uint8_t > get_contents()
Definition der_enc.cpp:161
DER_Encoder & encode(bool b)
Definition der_enc.cpp:313
std::unique_ptr< Public_Key > public_key() const override
Definition x448.cpp:131
secure_vector< uint8_t > private_key_bits() const override
Definition x448.cpp:135
secure_vector< uint8_t > raw_private_key_bits() const override
Definition x448.cpp:41
X448_PrivateKey(const AlgorithmIdentifier &alg_id, std::span< const uint8_t > key_bits)
Definition x448.cpp:116
std::vector< uint8_t > public_value() const override
Definition x448.h:95
std::unique_ptr< PK_Ops::Key_Agreement > create_key_agreement_op(RandomNumberGenerator &rng, std::string_view params, std::string_view provider) const override
Definition x448.cpp:199
bool check_key(RandomNumberGenerator &rng, bool strong) const override
Definition x448.cpp:139
AlgorithmIdentifier algorithm_identifier() const override
Definition x448.cpp:80
std::unique_ptr< Private_Key > generate_another(RandomNumberGenerator &rng) const final
Definition x448.cpp:97
std::vector< uint8_t > raw_public_key_bits() const override
Definition x448.cpp:88
std::shared_ptr< const X448_PublicKey_Data > m_public
Definition x448.h:63
bool check_key(RandomNumberGenerator &rng, bool strong) const override
Definition x448.cpp:84
X448_PublicKey(const AlgorithmIdentifier &alg_id, std::span< const uint8_t > key_bits)
Definition x448.cpp:101
std::vector< uint8_t > public_key_bits() const override
Definition x448.cpp:93
std::string algo_name() const override
Definition x448.h:39
constexpr auto scoped_poison(const Ts &... xs)
Definition ct_utils.h:222
constexpr CT::Mask< T > is_equal(const T x[], const T y[], size_t len)
Definition ct_utils.h:798
constexpr void unpoison(const T *p, size_t n)
Definition ct_utils.h:67
constexpr CT::Mask< T > all_zeros(const T elem[], size_t len)
Definition ct_utils.h:785
Point448 x448_basepoint(const ScalarX448 &k)
Multiply a scalar with the base group element (5).
constexpr void copy_mem(T *out, const T *in, size_t n)
Definition mem_ops.h:144
Point448 decode_point(std::span< const uint8_t > p_bytes)
Decode a point from a byte array. RFC 7748 Section 5 (decodeUCoordinate).
constexpr size_t X448_LEN
secure_vector< uint8_t > encode_point(const Point448 &p)
Encode a point to a 56 byte vector. RFC 7748 Section 5 (encodeUCoordinate).
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:128
ScalarX448 decode_scalar(std::span< const uint8_t > scalar_bytes)
Decode a scalar from a byte array. RFC 7748 Section 5 (decodeScalar448).
Point448 x448(const ScalarX448 &k, const Point448 &u)
Multiply a scalar k with a point u.