Botan 3.7.1
Crypto and TLS for C&
ecdsa.cpp
Go to the documentation of this file.
1/*
2* ECDSA implemenation
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/internal/keypair.h>
14#include <botan/internal/pk_ops_impl.h>
15
16#if defined(BOTAN_HAS_RFC6979_GENERATOR)
17 #include <botan/internal/rfc6979.h>
18#endif
19
20namespace Botan {
21
22namespace {
23
24EC_AffinePoint recover_ecdsa_public_key(
25 const EC_Group& group, const std::vector<uint8_t>& msg, const BigInt& r, const BigInt& s, uint8_t v) {
26 if(group.has_cofactor()) {
27 throw Invalid_Argument("ECDSA public key recovery only supported for prime order groups");
28 }
29
30 if(v >= 4) {
31 throw Invalid_Argument("Unexpected v param for ECDSA public key recovery");
32 }
33
34 const BigInt& group_order = group.get_order();
35
36 if(r <= 0 || r >= group_order || s <= 0 || s >= group_order) {
37 throw Invalid_Argument("Out of range r/s cannot recover ECDSA public key");
38 }
39
40 const uint8_t y_odd = v % 2;
41 const uint8_t add_order = v >> 1;
42 const size_t p_bytes = group.get_p_bytes();
43
44 BigInt x = r;
45
46 if(add_order) {
47 x += group_order;
48 }
49
50 if(x.bytes() <= p_bytes) {
51 std::vector<uint8_t> X(p_bytes + 1);
52
53 X[0] = 0x02 | y_odd;
54 x.serialize_to(std::span{X}.subspan(1));
55
56 if(auto R = EC_AffinePoint::deserialize(group, X)) {
57 // Compute r_inv * (-eG + s*R)
58 const auto ne = EC_Scalar::from_bytes_with_trunc(group, msg).negate();
59 const auto ss = EC_Scalar::from_bigint(group, s);
60
61 const auto r_inv = EC_Scalar::from_bigint(group, r).invert_vartime();
62
63 EC_Group::Mul2Table GR_mul(R.value());
64 if(auto egsr = GR_mul.mul2_vartime(ne * r_inv, ss * r_inv)) {
65 return egsr.value();
66 }
67 }
68 }
69
70 throw Decoding_Error("Failed to recover ECDSA public key from signature/msg pair");
71}
72
73} // namespace
74
76 const EC_Group& group, const std::vector<uint8_t>& msg, const BigInt& r, const BigInt& s, uint8_t v) :
77 EC_PublicKey(group, recover_ecdsa_public_key(group, msg, r, s, v)) {}
78
79std::unique_ptr<Private_Key> ECDSA_PublicKey::generate_another(RandomNumberGenerator& rng) const {
80 return std::make_unique<ECDSA_PrivateKey>(rng, domain());
81}
82
83uint8_t ECDSA_PublicKey::recovery_param(const std::vector<uint8_t>& msg, const BigInt& r, const BigInt& s) const {
84 const auto this_key = this->_public_ec_point().serialize_compressed();
85
86 for(uint8_t v = 0; v != 4; ++v) {
87 try {
88 const auto R = recover_ecdsa_public_key(this->domain(), msg, r, s, v);
89
90 if(R.serialize_compressed() == this_key) {
91 return v;
92 }
93 } catch(Decoding_Error&) {
94 // try the next v
95 }
96 }
97
98 throw Internal_Error("Could not determine ECDSA recovery parameter");
99}
100
101std::unique_ptr<Public_Key> ECDSA_PrivateKey::public_key() const {
102 return std::make_unique<ECDSA_PublicKey>(domain(), _public_ec_point());
103}
104
106 if(!EC_PrivateKey::check_key(rng, strong)) {
107 return false;
108 }
109
110 if(!strong) {
111 return true;
112 }
113
114 return KeyPair::signature_consistency_check(rng, *this, "SHA-256");
115}
116
117namespace {
118
119/**
120* ECDSA signature operation
121*/
122class ECDSA_Signature_Operation final : public PK_Ops::Signature_with_Hash {
123 public:
124 ECDSA_Signature_Operation(const ECDSA_PrivateKey& ecdsa, std::string_view padding, RandomNumberGenerator& rng) :
125 PK_Ops::Signature_with_Hash(padding),
126 m_group(ecdsa.domain()),
127 m_x(ecdsa._private_key()),
128 m_b(EC_Scalar::random(m_group, rng)),
129 m_b_inv(m_b.invert()) {
130#if defined(BOTAN_HAS_RFC6979_GENERATOR)
131 m_rfc6979 = std::make_unique<RFC6979_Nonce_Generator>(
132 this->rfc6979_hash_function(), m_group.get_order_bits(), ecdsa._private_key());
133#endif
134 }
135
136 size_t signature_length() const override { return 2 * m_group.get_order_bytes(); }
137
138 std::vector<uint8_t> raw_sign(std::span<const uint8_t> msg, RandomNumberGenerator& rng) override;
139
140 AlgorithmIdentifier algorithm_identifier() const override;
141
142 private:
143 const EC_Group m_group;
144 const EC_Scalar m_x;
145
146#if defined(BOTAN_HAS_RFC6979_GENERATOR)
147 std::unique_ptr<RFC6979_Nonce_Generator> m_rfc6979;
148#endif
149
150 std::vector<BigInt> m_ws;
151
152 EC_Scalar m_b;
153 EC_Scalar m_b_inv;
154};
155
156AlgorithmIdentifier ECDSA_Signature_Operation::algorithm_identifier() const {
157 const std::string full_name = "ECDSA/" + hash_function();
158 const OID oid = OID::from_string(full_name);
159 return AlgorithmIdentifier(oid, AlgorithmIdentifier::USE_EMPTY_PARAM);
160}
161
162std::vector<uint8_t> ECDSA_Signature_Operation::raw_sign(std::span<const uint8_t> msg, RandomNumberGenerator& rng) {
163 const auto m = EC_Scalar::from_bytes_with_trunc(m_group, msg);
164
165#if defined(BOTAN_HAS_RFC6979_GENERATOR)
166 const auto k = m_rfc6979->nonce_for(m_group, m);
167#else
168 const auto k = EC_Scalar::random(m_group, rng);
169#endif
170
171 const auto r = EC_Scalar::gk_x_mod_order(k, rng, m_ws);
172
173 // Blind the inversion of k
174 const auto k_inv = (m_b * k).invert() * m_b;
175
176 /*
177 * Blind the input message and compute x*r+m as (x*r*b + m*b)/b
178 */
179 m_b.square_self();
180 m_b_inv.square_self();
181
182 const auto xr_m = ((m_x * m_b) * r) + (m * m_b);
183
184 const auto s = (k_inv * xr_m) * m_b_inv;
185
186 // With overwhelming probability, a bug rather than actual zero r/s
187 if(r.is_zero() || s.is_zero()) {
188 throw Internal_Error("During ECDSA signature generated zero r/s");
189 }
190
191 return EC_Scalar::serialize_pair(r, s);
192}
193
194/**
195* ECDSA verification operation
196*/
197class ECDSA_Verification_Operation final : public PK_Ops::Verification_with_Hash {
198 public:
199 ECDSA_Verification_Operation(const ECDSA_PublicKey& ecdsa, std::string_view padding) :
200 PK_Ops::Verification_with_Hash(padding), m_group(ecdsa.domain()), m_gy_mul(ecdsa._public_ec_point()) {}
201
202 ECDSA_Verification_Operation(const ECDSA_PublicKey& ecdsa, const AlgorithmIdentifier& alg_id) :
203 PK_Ops::Verification_with_Hash(alg_id, "ECDSA", true),
204 m_group(ecdsa.domain()),
205 m_gy_mul(ecdsa._public_ec_point()) {}
206
207 bool verify(std::span<const uint8_t> msg, std::span<const uint8_t> sig) override;
208
209 private:
210 const EC_Group m_group;
211 const EC_Group::Mul2Table m_gy_mul;
212};
213
214bool ECDSA_Verification_Operation::verify(std::span<const uint8_t> msg, std::span<const uint8_t> sig) {
215 if(auto rs = EC_Scalar::deserialize_pair(m_group, sig)) {
216 const auto& [r, s] = rs.value();
217
218 if(r.is_nonzero() && s.is_nonzero()) {
219 const auto m = EC_Scalar::from_bytes_with_trunc(m_group, msg);
220
221 const auto w = s.invert_vartime();
222
223 // Check if r == x_coord(g*w*m + y*w*r) % n
224 return m_gy_mul.mul2_vartime_x_mod_order_eq(r, w, m, r);
225 }
226 }
227
228 return false;
229}
230
231} // namespace
232
233std::unique_ptr<PK_Ops::Verification> ECDSA_PublicKey::create_verification_op(std::string_view params,
234 std::string_view provider) const {
235 if(provider == "base" || provider.empty()) {
236 return std::make_unique<ECDSA_Verification_Operation>(*this, params);
237 }
238
239 throw Provider_Not_Found(algo_name(), provider);
240}
241
242std::unique_ptr<PK_Ops::Verification> ECDSA_PublicKey::create_x509_verification_op(
243 const AlgorithmIdentifier& signature_algorithm, std::string_view provider) const {
244 if(provider == "base" || provider.empty()) {
245 return std::make_unique<ECDSA_Verification_Operation>(*this, signature_algorithm);
246 }
247
248 throw Provider_Not_Found(algo_name(), provider);
249}
250
251std::unique_ptr<PK_Ops::Signature> ECDSA_PrivateKey::create_signature_op(RandomNumberGenerator& rng,
252 std::string_view params,
253 std::string_view provider) const {
254 if(provider == "base" || provider.empty()) {
255 return std::make_unique<ECDSA_Signature_Operation>(*this, params, rng);
256 }
257
258 throw Provider_Not_Found(algo_name(), provider);
259}
260
261} // namespace Botan
std::unique_ptr< Public_Key > public_key() const override
Definition ecdsa.cpp:101
std::unique_ptr< PK_Ops::Signature > create_signature_op(RandomNumberGenerator &rng, std::string_view params, std::string_view provider) const override
Definition ecdsa.cpp:251
bool check_key(RandomNumberGenerator &rng, bool) const override
Definition ecdsa.cpp:105
std::unique_ptr< PK_Ops::Verification > create_x509_verification_op(const AlgorithmIdentifier &signature_algorithm, std::string_view provider) const override
Definition ecdsa.cpp:242
std::unique_ptr< Private_Key > generate_another(RandomNumberGenerator &rng) const override
Definition ecdsa.cpp:79
uint8_t recovery_param(const std::vector< uint8_t > &msg, const BigInt &r, const BigInt &s) const
Definition ecdsa.cpp:83
std::unique_ptr< PK_Ops::Verification > create_verification_op(std::string_view params, std::string_view provider) const override
Definition ecdsa.cpp:233
static std::optional< EC_AffinePoint > deserialize(const EC_Group &group, std::span< const uint8_t > bytes)
T serialize_compressed() const
Definition ec_apoint.h:204
bool mul2_vartime_x_mod_order_eq(const EC_Scalar &v, const EC_Scalar &x, const EC_Scalar &y) const
Definition ec_group.cpp:743
const EC_Scalar & _private_key() const
Definition ecc_key.cpp:122
bool check_key(RandomNumberGenerator &rng, bool strong) const override
Definition ecc_key.cpp:200
const EC_Group & domain() const
Definition ecc_key.cpp:63
const EC_AffinePoint & _public_ec_point() const
Definition ecc_key.cpp:75
static EC_Scalar from_bigint(const EC_Group &group, const BigInt &bn)
Definition ec_scalar.cpp:65
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:45
int(* final)(unsigned char *, CTX *)
FE_25519 X
Definition ge.cpp:25
bool signature_consistency_check(RandomNumberGenerator &rng, const Private_Key &private_key, const Public_Key &public_key, std::string_view padding)
Definition keypair.cpp:49