Botan 3.11.0
Crypto and TLS for C&
ecdsa.cpp
Go to the documentation of this file.
1/*
2* ECDSA implementation
3* (C) 2007 Manuel Hartl, FlexSecure GmbH
4* 2007 Falko Strenzke, FlexSecure GmbH
5* 2008-2010,2015,2016,2018,2024 Jack Lloyd
6* 2016 René Korthaus
7*
8* Botan is released under the Simplified BSD License (see license.txt)
9*/
10
11#include <botan/ecdsa.h>
12
13#include <botan/ec_group.h>
14#include <botan/internal/keypair.h>
15#include <botan/internal/pk_ops_impl.h>
16
17#if defined(BOTAN_HAS_RFC6979_GENERATOR)
18 #include <botan/internal/rfc6979.h>
19#endif
20
21namespace Botan {
22
23namespace {
24
25EC_AffinePoint recover_ecdsa_public_key(
26 const EC_Group& group, const std::vector<uint8_t>& msg, const BigInt& r, const BigInt& s, uint8_t v) {
27 if(group.has_cofactor()) {
28 throw Invalid_Argument("ECDSA public key recovery only supported for prime order groups");
29 }
30
31 if(v >= 4) {
32 throw Invalid_Argument("Unexpected v param for ECDSA public key recovery");
33 }
34
35 const BigInt& group_order = group.get_order();
36
37 if(r <= 0 || r >= group_order || s <= 0 || s >= group_order) {
38 throw Invalid_Argument("Out of range r/s cannot recover ECDSA public key");
39 }
40
41 const uint8_t y_odd = v % 2;
42 const bool add_order = (v >> 1) == 0x01;
43 const size_t p_bytes = group.get_p_bytes();
44
45 BigInt x = r;
46
47 if(add_order) {
48 x += group_order;
49 }
50
51 if(x.bytes() <= p_bytes) {
52 std::vector<uint8_t> X(p_bytes + 1);
53
54 X[0] = 0x02 | y_odd;
55 x.serialize_to(std::span{X}.subspan(1));
56
57 if(auto R = EC_AffinePoint::deserialize(group, X)) {
58 // Compute r_inv * (-eG + s*R)
59 const auto ne = EC_Scalar::from_bytes_with_trunc(group, msg).negate();
60 const auto ss = EC_Scalar::from_bigint(group, s);
61
62 const auto r_inv = EC_Scalar::from_bigint(group, r).invert_vartime();
63
64 const EC_Group::Mul2Table GR_mul(R.value());
65 if(auto egsr = GR_mul.mul2_vartime(ne * r_inv, ss * r_inv)) {
66 return egsr.value();
67 }
68 }
69 }
70
71 throw Decoding_Error("Failed to recover ECDSA public key from signature/msg pair");
72}
73
74} // namespace
75
77 const EC_Group& group, const std::vector<uint8_t>& msg, const BigInt& r, const BigInt& s, uint8_t v) :
78 EC_PublicKey(group, recover_ecdsa_public_key(group, msg, r, s, v)) {}
79
81 return domain().get_order_bytes();
82}
83
84std::unique_ptr<Private_Key> ECDSA_PublicKey::generate_another(RandomNumberGenerator& rng) const {
85 return std::make_unique<ECDSA_PrivateKey>(rng, domain());
86}
87
88uint8_t ECDSA_PublicKey::recovery_param(const std::vector<uint8_t>& msg, const BigInt& r, const BigInt& s) const {
89 const auto this_key = this->_public_ec_point().serialize_compressed();
90
91 for(uint8_t v = 0; v != 4; ++v) {
92 try {
93 const auto R = recover_ecdsa_public_key(this->domain(), msg, r, s, v);
94
95 if(R.serialize_compressed() == this_key) {
96 return v;
97 }
98 } catch(Decoding_Error&) {
99 // try the next v
100 }
101 }
102
103 throw Internal_Error("Could not determine ECDSA recovery parameter");
104}
105
106std::unique_ptr<Public_Key> ECDSA_PrivateKey::public_key() const {
107 return std::make_unique<ECDSA_PublicKey>(domain(), _public_ec_point());
108}
109
111 if(!EC_PrivateKey::check_key(rng, strong)) {
112 return false;
113 }
114
115 if(!strong) {
116 return true;
117 }
118
119 return KeyPair::signature_consistency_check(rng, *this, "SHA-256");
120}
121
122namespace {
123
124/**
125* ECDSA signature operation
126*/
127class ECDSA_Signature_Operation final : public PK_Ops::Signature_with_Hash {
128 public:
129 ECDSA_Signature_Operation(const ECDSA_PrivateKey& ecdsa, std::string_view padding, RandomNumberGenerator& rng) :
130 PK_Ops::Signature_with_Hash(padding),
131 m_group(ecdsa.domain()),
132 m_x(ecdsa._private_key()),
133 m_b(EC_Scalar::random(m_group, rng)) {
134#if defined(BOTAN_HAS_RFC6979_GENERATOR)
135 m_rfc6979 = std::make_unique<RFC6979_Nonce_Generator>(
136 this->rfc6979_hash_function(), m_group.get_order_bits(), ecdsa._private_key());
137#endif
138 }
139
140 size_t signature_length() const override { return 2 * m_group.get_order_bytes(); }
141
142 std::vector<uint8_t> raw_sign(std::span<const uint8_t> msg, RandomNumberGenerator& rng) override;
143
144 AlgorithmIdentifier algorithm_identifier() const override;
145
146 private:
147 const EC_Group m_group;
148 const EC_Scalar m_x;
149
150#if defined(BOTAN_HAS_RFC6979_GENERATOR)
151 std::unique_ptr<RFC6979_Nonce_Generator> m_rfc6979;
152#endif
153
154 EC_Scalar m_b;
155};
156
157AlgorithmIdentifier ECDSA_Signature_Operation::algorithm_identifier() const {
158 const std::string full_name = "ECDSA/" + hash_function();
159 const OID oid = OID::from_string(full_name);
160 return AlgorithmIdentifier(oid, AlgorithmIdentifier::USE_EMPTY_PARAM);
161}
162
163std::vector<uint8_t> ECDSA_Signature_Operation::raw_sign(std::span<const uint8_t> msg, RandomNumberGenerator& rng) {
164 const auto m = EC_Scalar::from_bytes_with_trunc(m_group, msg);
165
166#if defined(BOTAN_HAS_RFC6979_GENERATOR)
167 const auto k = m_rfc6979->nonce_for(m_group, m);
168#else
169 const auto k = EC_Scalar::random(m_group, rng);
170#endif
171
172 const auto r = EC_Scalar::gk_x_mod_order(k, rng);
173
174 /*
175 * Blind the inputs
176 *
177 * Here we are computing (x*r+m)/k
178 *
179 * Instead have a random b and compute (k*b)^-1
180 *
181 * Then compute (x*r+m) as (x*r*b + m*b)
182 *
183 * Finally (x*r*b + m*b)/(k*b) = (x*r+m)/k
184 *
185 * This effectively blinds both the inversion as well as the various scalar
186 * multiplications. All of these operations should be constant-time anyway but
187 * blinding is very cheap and may help if either the compiler introduces
188 * variable-time behavior, or for the case of EM/power side channel attacks [1].
189 *
190 * [1] But note that such attacks are currently outside of Botan's threat model.
191 *
192 */
193 const auto k_inv = (m_b * k).invert();
194
195 const auto xr_m = ((m_x * m_b) * r) + (m * m_b);
196
197 const auto s = (k_inv * xr_m);
198
199 // Generate the next blinding value via modular squaring
200 m_b.square_self();
201
202 // With overwhelming probability, a bug rather than actual zero r/s
203 if(r.is_zero() || s.is_zero()) {
204 throw Internal_Error("During ECDSA signature generated zero r/s");
205 }
206
207 return EC_Scalar::serialize_pair(r, s);
208}
209
210/**
211* ECDSA verification operation
212*/
213class ECDSA_Verification_Operation final : public PK_Ops::Verification_with_Hash {
214 public:
215 ECDSA_Verification_Operation(const ECDSA_PublicKey& ecdsa, std::string_view padding) :
216 PK_Ops::Verification_with_Hash(padding), m_group(ecdsa.domain()), m_gy_mul(ecdsa._public_ec_point()) {}
217
218 ECDSA_Verification_Operation(const ECDSA_PublicKey& ecdsa, const AlgorithmIdentifier& alg_id) :
219 PK_Ops::Verification_with_Hash(alg_id, "ECDSA", true),
220 m_group(ecdsa.domain()),
221 m_gy_mul(ecdsa._public_ec_point()) {}
222
223 bool verify(std::span<const uint8_t> msg, std::span<const uint8_t> sig) override;
224
225 private:
226 const EC_Group m_group;
227 const EC_Group::Mul2Table m_gy_mul;
228};
229
230bool ECDSA_Verification_Operation::verify(std::span<const uint8_t> msg, std::span<const uint8_t> sig) {
231 if(auto rs = EC_Scalar::deserialize_pair(m_group, sig)) {
232 const auto& [r, s] = rs.value();
233
234 if(r.is_nonzero() && s.is_nonzero()) {
235 const auto m = EC_Scalar::from_bytes_with_trunc(m_group, msg);
236
237 const auto w = s.invert_vartime();
238
239 // Check if r == x_coord(g*w*m + y*w*r) % n
240 return m_gy_mul.mul2_vartime_x_mod_order_eq(r, w, m, r);
241 }
242 }
243
244 return false;
245}
246
247} // namespace
248
249std::unique_ptr<PK_Ops::Verification> ECDSA_PublicKey::create_verification_op(std::string_view params,
250 std::string_view provider) const {
251 if(provider == "base" || provider.empty()) {
252 return std::make_unique<ECDSA_Verification_Operation>(*this, params);
253 }
254
255 throw Provider_Not_Found(algo_name(), provider);
256}
257
258std::unique_ptr<PK_Ops::Verification> ECDSA_PublicKey::create_x509_verification_op(
259 const AlgorithmIdentifier& signature_algorithm, std::string_view provider) const {
260 if(provider == "base" || provider.empty()) {
261 return std::make_unique<ECDSA_Verification_Operation>(*this, signature_algorithm);
262 }
263
264 throw Provider_Not_Found(algo_name(), provider);
265}
266
267std::unique_ptr<PK_Ops::Signature> ECDSA_PrivateKey::create_signature_op(RandomNumberGenerator& rng,
268 std::string_view params,
269 std::string_view provider) const {
270 if(provider == "base" || provider.empty()) {
271 return std::make_unique<ECDSA_Signature_Operation>(*this, params, rng);
272 }
273
274 throw Provider_Not_Found(algo_name(), provider);
275}
276
277} // namespace Botan
std::unique_ptr< Public_Key > public_key() const override
Definition ecdsa.cpp:106
std::unique_ptr< PK_Ops::Signature > create_signature_op(RandomNumberGenerator &rng, std::string_view params, std::string_view provider) const override
Definition ecdsa.cpp:267
bool check_key(RandomNumberGenerator &rng, bool strong) const override
Definition ecdsa.cpp:110
std::string algo_name() const override
Definition ecdsa.h:62
std::unique_ptr< PK_Ops::Verification > create_x509_verification_op(const AlgorithmIdentifier &signature_algorithm, std::string_view provider) const override
Definition ecdsa.cpp:258
std::unique_ptr< Private_Key > generate_another(RandomNumberGenerator &rng) const override
Definition ecdsa.cpp:84
uint8_t recovery_param(const std::vector< uint8_t > &msg, const BigInt &r, const BigInt &s) const
Definition ecdsa.cpp:88
std::unique_ptr< PK_Ops::Verification > create_verification_op(std::string_view params, std::string_view provider) const override
Definition ecdsa.cpp:249
std::optional< size_t > _signature_element_size_for_DER_encoding() const override
Definition ecdsa.cpp:80
static std::optional< EC_AffinePoint > deserialize(const EC_Group &group, std::span< const uint8_t > bytes)
T serialize_compressed() const
Definition ec_apoint.h:213
Table for computing g*x + h*y.
Definition ec_group.h:326
bool mul2_vartime_x_mod_order_eq(const EC_Scalar &v, const EC_Scalar &x, const EC_Scalar &y) const
Definition ec_group.cpp:843
size_t get_order_bytes() const
Definition ec_group.cpp:605
const EC_Scalar & _private_key() const
Definition ecc_key.cpp:123
bool check_key(RandomNumberGenerator &rng, bool strong) const override
Definition ecc_key.cpp:201
const EC_Group & domain() const
Definition ecc_key.cpp:64
EC_PublicKey(const EC_PublicKey &other)=default
const EC_AffinePoint & _public_ec_point() const
Definition ecc_key.cpp:76
static EC_Scalar from_bigint(const EC_Group &group, const BigInt &bn)
Definition ec_scalar.cpp:69
EC_Scalar invert_vartime() const
EC_Scalar negate() const
static EC_Scalar from_bytes_with_trunc(const EC_Group &group, std::span< const uint8_t > bytes)
Definition ec_scalar.cpp:49
bool signature_consistency_check(RandomNumberGenerator &rng, const Private_Key &private_key, const Public_Key &public_key, std::string_view padding)
Definition keypair.cpp:49