Coverage Report

Created: 2024-11-29 06:10

/src/botan/src/lib/pubkey/curve448/x448/x448.cpp
Line
Count
Source (jump to first uncovered line)
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/rng.h>
14
#include <botan/internal/ct_utils.h>
15
#include <botan/internal/pk_ops_impl.h>
16
#include <botan/internal/x448_internal.h>
17
18
namespace Botan {
19
20
namespace {
21
1.87k
void x448_basepoint_from_data(std::span<uint8_t, X448_LEN> mypublic, std::span<const uint8_t, X448_LEN> secret) {
22
1.87k
   auto bp = x448_basepoint(decode_scalar(secret));
23
1.87k
   auto bp_bytes = encode_point(bp);
24
1.87k
   copy_mem(mypublic, bp_bytes);
25
1.87k
}
26
27
409
secure_vector<uint8_t> ber_decode_sk(std::span<const uint8_t> key_bits) {
28
409
   secure_vector<uint8_t> decoded_bits;
29
409
   BER_Decoder(key_bits).decode(decoded_bits, ASN1_Type::OctetString).verify_end();
30
409
   BOTAN_ASSERT_NOMSG(decoded_bits.size() == X448_LEN);
31
409
   return decoded_bits;
32
409
}
33
34
}  // namespace
35
36
0
AlgorithmIdentifier X448_PublicKey::algorithm_identifier() const {
37
0
   return AlgorithmIdentifier(object_identifier(), AlgorithmIdentifier::USE_EMPTY_PARAM);
38
0
}
39
40
0
bool X448_PublicKey::check_key(RandomNumberGenerator& /*rng*/, bool /*strong*/) const {
41
0
   return true;  // no tests possible?
42
0
}
43
44
462
std::vector<uint8_t> X448_PublicKey::raw_public_key_bits() const {
45
462
   return public_value();
46
462
}
47
48
1.47k
std::vector<uint8_t> X448_PublicKey::public_key_bits() const {
49
1.47k
   return public_value();
50
1.47k
}
51
52
0
std::unique_ptr<Private_Key> X448_PublicKey::generate_another(RandomNumberGenerator& rng) const {
53
0
   return std::make_unique<X448_PrivateKey>(rng);
54
0
}
55
56
X448_PublicKey::X448_PublicKey(const AlgorithmIdentifier& /*alg_id*/, std::span<const uint8_t> key_bits) :
57
0
      X448_PublicKey(key_bits) {}
Unexecuted instantiation: Botan::X448_PublicKey::X448_PublicKey(Botan::AlgorithmIdentifier const&, std::__1::span<unsigned char const, 18446744073709551615ul>)
Unexecuted instantiation: Botan::X448_PublicKey::X448_PublicKey(Botan::AlgorithmIdentifier const&, std::__1::span<unsigned char const, 18446744073709551615ul>)
58
59
468
X448_PublicKey::X448_PublicKey(std::span<const uint8_t> pub) {
60
468
   BOTAN_ARG_CHECK(pub.size() == X448_LEN, "Invalid size for X448 public key");
61
468
   copy_mem(m_public, pub);
62
468
}
Unexecuted instantiation: Botan::X448_PublicKey::X448_PublicKey(std::__1::span<unsigned char const, 18446744073709551615ul>)
Botan::X448_PublicKey::X448_PublicKey(std::__1::span<unsigned char const, 18446744073709551615ul>)
Line
Count
Source
59
468
X448_PublicKey::X448_PublicKey(std::span<const uint8_t> pub) {
60
468
   BOTAN_ARG_CHECK(pub.size() == X448_LEN, "Invalid size for X448 public key");
61
468
   copy_mem(m_public, pub);
62
468
}
63
64
X448_PrivateKey::X448_PrivateKey(const AlgorithmIdentifier& /*alg_id*/, std::span<const uint8_t> key_bits) :
65
409
      X448_PrivateKey(ber_decode_sk(key_bits)) {}
Unexecuted instantiation: Botan::X448_PrivateKey::X448_PrivateKey(Botan::AlgorithmIdentifier const&, std::__1::span<unsigned char const, 18446744073709551615ul>)
Botan::X448_PrivateKey::X448_PrivateKey(Botan::AlgorithmIdentifier const&, std::__1::span<unsigned char const, 18446744073709551615ul>)
Line
Count
Source
65
409
      X448_PrivateKey(ber_decode_sk(key_bits)) {}
66
67
1.87k
X448_PrivateKey::X448_PrivateKey(std::span<const uint8_t> secret_key) {
68
1.87k
   BOTAN_ARG_CHECK(secret_key.size() == X448_LEN, "Invalid size for X448 private key");
69
1.87k
   m_private.assign(secret_key.begin(), secret_key.end());
70
1.87k
   auto scope = CT::scoped_poison(m_private);
71
1.87k
   x448_basepoint_from_data(m_public, std::span(m_private).first<X448_LEN>());
72
1.87k
   CT::unpoison(m_public);
73
1.87k
}
Unexecuted instantiation: Botan::X448_PrivateKey::X448_PrivateKey(std::__1::span<unsigned char const, 18446744073709551615ul>)
Botan::X448_PrivateKey::X448_PrivateKey(std::__1::span<unsigned char const, 18446744073709551615ul>)
Line
Count
Source
67
1.87k
X448_PrivateKey::X448_PrivateKey(std::span<const uint8_t> secret_key) {
68
1.87k
   BOTAN_ARG_CHECK(secret_key.size() == X448_LEN, "Invalid size for X448 private key");
69
1.87k
   m_private.assign(secret_key.begin(), secret_key.end());
70
1.87k
   auto scope = CT::scoped_poison(m_private);
71
1.87k
   x448_basepoint_from_data(m_public, std::span(m_private).first<X448_LEN>());
72
1.87k
   CT::unpoison(m_public);
73
1.87k
}
74
75
1.47k
X448_PrivateKey::X448_PrivateKey(RandomNumberGenerator& rng) : X448_PrivateKey(rng.random_vec(X448_LEN)) {}
Unexecuted instantiation: Botan::X448_PrivateKey::X448_PrivateKey(Botan::RandomNumberGenerator&)
Botan::X448_PrivateKey::X448_PrivateKey(Botan::RandomNumberGenerator&)
Line
Count
Source
75
1.47k
X448_PrivateKey::X448_PrivateKey(RandomNumberGenerator& rng) : X448_PrivateKey(rng.random_vec(X448_LEN)) {}
76
77
0
std::unique_ptr<Public_Key> X448_PrivateKey::public_key() const {
78
0
   return std::make_unique<X448_PublicKey>(public_value());
79
0
}
80
81
0
secure_vector<uint8_t> X448_PrivateKey::private_key_bits() const {
82
0
   return DER_Encoder().encode(m_private, ASN1_Type::OctetString).get_contents();
83
0
}
84
85
0
bool X448_PrivateKey::check_key(RandomNumberGenerator& /*rng*/, bool /*strong*/) const {
86
0
   std::array<uint8_t, X448_LEN> public_point;
87
0
   BOTAN_ASSERT_NOMSG(m_private.size() == X448_LEN);
88
0
   auto scope = CT::scoped_poison(m_private);
89
0
   x448_basepoint_from_data(public_point, std::span(m_private).first<X448_LEN>());
90
0
   return CT::is_equal(public_point.data(), m_public.data(), m_public.size()).as_bool();
91
0
}
92
93
namespace {
94
95
/**
96
* X448 operation
97
*/
98
class X448_KA_Operation final : public PK_Ops::Key_Agreement_with_KDF {
99
   public:
100
      X448_KA_Operation(std::span<const uint8_t> sk, std::string_view kdf) :
101
462
            PK_Ops::Key_Agreement_with_KDF(kdf), m_sk(sk.begin(), sk.end()) {
102
462
         BOTAN_ARG_CHECK(sk.size() == X448_LEN, "Invalid size for X448 private key");
103
462
      }
104
105
0
      size_t agreed_value_size() const override { return X448_LEN; }
106
107
462
      secure_vector<uint8_t> raw_agree(const uint8_t w_data[], size_t w_len) override {
108
462
         auto scope = CT::scoped_poison(m_sk);
109
110
462
         std::span<const uint8_t> w(w_data, w_len);
111
462
         BOTAN_ARG_CHECK(w.size() == X448_LEN, "Invalid size for X448 private key");
112
462
         BOTAN_ASSERT_NOMSG(m_sk.size() == X448_LEN);
113
462
         const auto k = decode_scalar(m_sk);
114
462
         const auto u = decode_point(w);
115
116
462
         auto shared_secret = encode_point(x448(k, u));
117
462
         CT::unpoison(shared_secret);
118
119
         // RFC 7748 Section 6.2
120
         //    As with X25519, both sides MAY check, without leaking extra
121
         //    information about the value of K, whether the resulting shared K
122
         //    is the all-zero value and abort if so.
123
         //
124
         // TODO: once the generic Key Agreement operation creation is equipped
125
         //       with a more flexible parameterization, this check could be
126
         //       made optional.
127
         //       For instance: `sk->agree().with_optional_sanity_checks(true)`.
128
         //       See also:     https://github.com/randombit/botan/pull/4318
129
462
         if(CT::all_zeros(shared_secret.data(), shared_secret.size()).as_bool()) {
130
1
            throw Invalid_Argument("X448 public point appears to be of low order");
131
1
         }
132
133
461
         return shared_secret;
134
462
      }
135
136
   private:
137
      secure_vector<uint8_t> m_sk;
138
};
139
140
}  // namespace
141
142
std::unique_ptr<PK_Ops::Key_Agreement> X448_PrivateKey::create_key_agreement_op(RandomNumberGenerator& /*rng*/,
143
                                                                                std::string_view params,
144
462
                                                                                std::string_view provider) const {
145
462
   if(provider == "base" || provider.empty()) {
146
462
      return std::make_unique<X448_KA_Operation>(m_private, params);
147
462
   }
148
0
   throw Provider_Not_Found(algo_name(), provider);
149
462
}
150
151
}  // namespace Botan