Coverage Report

Created: 2025-07-31 06:10

/src/botan/src/lib/pubkey/x25519/x25519.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
* X25519
3
* (C) 2014,2024 Jack Lloyd
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7
8
#include <botan/x25519.h>
9
10
#include <botan/ber_dec.h>
11
#include <botan/der_enc.h>
12
#include <botan/rng.h>
13
#include <botan/internal/ct_utils.h>
14
#include <botan/internal/fmt.h>
15
#include <botan/internal/pk_ops_impl.h>
16
17
namespace Botan {
18
19
555
void curve25519_basepoint(uint8_t mypublic[32], const uint8_t secret[32]) {
20
555
   const uint8_t basepoint[32] = {9};
21
555
   curve25519_donna(mypublic, secret, basepoint);
22
555
}
23
24
namespace {
25
26
28
void size_check(size_t size, const char* thing) {
27
28
   if(size != 32) {
28
22
      throw Decoding_Error(fmt("Invalid size {} for X25519 {}", size, thing));
29
22
   }
30
28
}
31
32
2
secure_vector<uint8_t> curve25519(const secure_vector<uint8_t>& secret, const uint8_t pubval[32]) {
33
2
   secure_vector<uint8_t> out(32);
34
2
   curve25519_donna(out.data(), secret.data(), pubval);
35
2
   return out;
36
2
}
37
38
}  // namespace
39
40
0
AlgorithmIdentifier X25519_PublicKey::algorithm_identifier() const {
41
0
   return AlgorithmIdentifier(object_identifier(), AlgorithmIdentifier::USE_EMPTY_PARAM);
42
0
}
43
44
0
bool X25519_PublicKey::check_key(RandomNumberGenerator& /*rng*/, bool /*strong*/) const {
45
0
   return true;  // no tests possible?
46
0
}
47
48
X25519_PublicKey::X25519_PublicKey(const AlgorithmIdentifier& /*unused*/, std::span<const uint8_t> key_bits) :
49
0
      X25519_PublicKey(key_bits) {}
Unexecuted instantiation: Botan::X25519_PublicKey::X25519_PublicKey(Botan::AlgorithmIdentifier const&, std::__1::span<unsigned char const, 18446744073709551615ul>)
Unexecuted instantiation: Botan::X25519_PublicKey::X25519_PublicKey(Botan::AlgorithmIdentifier const&, std::__1::span<unsigned char const, 18446744073709551615ul>)
50
51
10
X25519_PublicKey::X25519_PublicKey(std::span<const uint8_t> pub) {
52
10
   m_public.assign(pub.begin(), pub.end());
53
54
10
   size_check(m_public.size(), "public key");
55
10
}
Unexecuted instantiation: Botan::X25519_PublicKey::X25519_PublicKey(std::__1::span<unsigned char const, 18446744073709551615ul>)
Botan::X25519_PublicKey::X25519_PublicKey(std::__1::span<unsigned char const, 18446744073709551615ul>)
Line
Count
Source
51
10
X25519_PublicKey::X25519_PublicKey(std::span<const uint8_t> pub) {
52
10
   m_public.assign(pub.begin(), pub.end());
53
54
10
   size_check(m_public.size(), "public key");
55
10
}
56
57
552
std::vector<uint8_t> X25519_PublicKey::raw_public_key_bits() const {
58
552
   return m_public;
59
552
}
60
61
0
std::vector<uint8_t> X25519_PublicKey::public_key_bits() const {
62
0
   return raw_public_key_bits();
63
0
}
64
65
0
std::unique_ptr<Private_Key> X25519_PublicKey::generate_another(RandomNumberGenerator& rng) const {
66
0
   return std::make_unique<X25519_PrivateKey>(rng);
67
0
}
68
69
0
X25519_PrivateKey::X25519_PrivateKey(std::span<const uint8_t> secret_key) {
70
0
   if(secret_key.size() != 32) {
71
0
      throw Decoding_Error("Invalid size for X25519 private key");
72
0
   }
73
74
0
   m_public.resize(32);
75
0
   m_private.assign(secret_key.begin(), secret_key.end());
76
0
   curve25519_basepoint(m_public.data(), m_private.data());
77
0
}
Unexecuted instantiation: Botan::X25519_PrivateKey::X25519_PrivateKey(std::__1::span<unsigned char const, 18446744073709551615ul>)
Unexecuted instantiation: Botan::X25519_PrivateKey::X25519_PrivateKey(std::__1::span<unsigned char const, 18446744073709551615ul>)
78
79
553
X25519_PrivateKey::X25519_PrivateKey(RandomNumberGenerator& rng) {
80
553
   m_private = rng.random_vec(32);
81
553
   m_public.resize(32);
82
553
   curve25519_basepoint(m_public.data(), m_private.data());
83
553
}
Unexecuted instantiation: Botan::X25519_PrivateKey::X25519_PrivateKey(Botan::RandomNumberGenerator&)
Botan::X25519_PrivateKey::X25519_PrivateKey(Botan::RandomNumberGenerator&)
Line
Count
Source
79
553
X25519_PrivateKey::X25519_PrivateKey(RandomNumberGenerator& rng) {
80
553
   m_private = rng.random_vec(32);
81
553
   m_public.resize(32);
82
553
   curve25519_basepoint(m_public.data(), m_private.data());
83
553
}
84
85
20
X25519_PrivateKey::X25519_PrivateKey(const AlgorithmIdentifier& /*unused*/, std::span<const uint8_t> key_bits) {
86
20
   BER_Decoder(key_bits).decode(m_private, ASN1_Type::OctetString).discard_remaining();
87
88
20
   size_check(m_private.size(), "private key");
89
20
   m_public.resize(32);
90
20
   curve25519_basepoint(m_public.data(), m_private.data());
91
20
}
Unexecuted instantiation: Botan::X25519_PrivateKey::X25519_PrivateKey(Botan::AlgorithmIdentifier const&, std::__1::span<unsigned char const, 18446744073709551615ul>)
Botan::X25519_PrivateKey::X25519_PrivateKey(Botan::AlgorithmIdentifier const&, std::__1::span<unsigned char const, 18446744073709551615ul>)
Line
Count
Source
85
20
X25519_PrivateKey::X25519_PrivateKey(const AlgorithmIdentifier& /*unused*/, std::span<const uint8_t> key_bits) {
86
20
   BER_Decoder(key_bits).decode(m_private, ASN1_Type::OctetString).discard_remaining();
87
88
20
   size_check(m_private.size(), "private key");
89
20
   m_public.resize(32);
90
20
   curve25519_basepoint(m_public.data(), m_private.data());
91
20
}
92
93
0
std::unique_ptr<Public_Key> X25519_PrivateKey::public_key() const {
94
0
   return std::make_unique<X25519_PublicKey>(public_value());
95
0
}
96
97
0
secure_vector<uint8_t> X25519_PrivateKey::private_key_bits() const {
98
0
   return DER_Encoder().encode(m_private, ASN1_Type::OctetString).get_contents();
99
0
}
100
101
0
bool X25519_PrivateKey::check_key(RandomNumberGenerator& /*rng*/, bool /*strong*/) const {
102
0
   std::vector<uint8_t> public_point(32);
103
0
   curve25519_basepoint(public_point.data(), m_private.data());
104
0
   return public_point == m_public;
105
0
}
106
107
2
secure_vector<uint8_t> X25519_PrivateKey::agree(const uint8_t w[], size_t w_len) const {
108
2
   size_check(w_len, "public value");
109
2
   return curve25519(m_private, w);
110
2
}
111
112
namespace {
113
114
/**
115
* X25519 operation
116
*/
117
class X25519_KA_Operation final : public PK_Ops::Key_Agreement_with_KDF {
118
   public:
119
      X25519_KA_Operation(const X25519_PrivateKey& key, std::string_view kdf) :
120
2
            PK_Ops::Key_Agreement_with_KDF(kdf), m_key(key) {}
121
122
0
      size_t agreed_value_size() const override { return 32; }
123
124
2
      secure_vector<uint8_t> raw_agree(const uint8_t w[], size_t w_len) override {
125
2
         auto shared_key = m_key.agree(w, w_len);
126
127
         // RFC 7748 Section 6.1
128
         //    Both [parties] MAY check, without leaking extra information about
129
         //    the value of K, whether K is the all-zero value and abort if so.
130
         //
131
         // TODO: once the generic Key Agreement operation creation is equipped
132
         //       with a more flexible parameterization, this check could be
133
         //       made optional.
134
         //       For instance: `sk->agree().with_optional_sanity_checks(true)`.
135
         //       See also:     https://github.com/randombit/botan/pull/4318
136
2
         if(CT::all_zeros(shared_key.data(), shared_key.size()).as_bool()) {
137
1
            throw Invalid_Argument("X25519 public point appears to be of low order");
138
1
         }
139
140
1
         return shared_key;
141
2
      }
142
143
   private:
144
      const X25519_PrivateKey& m_key;
145
};
146
147
}  // namespace
148
149
std::unique_ptr<PK_Ops::Key_Agreement> X25519_PrivateKey::create_key_agreement_op(RandomNumberGenerator& /*rng*/,
150
                                                                                  std::string_view params,
151
2
                                                                                  std::string_view provider) const {
152
2
   if(provider == "base" || provider.empty()) {
153
2
      return std::make_unique<X25519_KA_Operation>(*this, params);
154
2
   }
155
0
   throw Provider_Not_Found(algo_name(), provider);
156
2
}
157
158
}  // namespace Botan