Botan 3.6.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_Point 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();
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->to_legacy_point();
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 for(uint8_t v = 0; v != 4; ++v) {
85 try {
86 EC_Point R = recover_ecdsa_public_key(this->domain(), msg, r, s, v);
87
88 if(R == this->public_point()) {
89 return v;
90 }
91 } catch(Decoding_Error&) {
92 // try the next v
93 }
94 }
95
96 throw Internal_Error("Could not determine ECDSA recovery parameter");
97}
98
99std::unique_ptr<Public_Key> ECDSA_PrivateKey::public_key() const {
100 return std::make_unique<ECDSA_PublicKey>(domain(), public_point());
101}
102
104 if(!EC_PrivateKey::check_key(rng, strong)) {
105 return false;
106 }
107
108 if(!strong) {
109 return true;
110 }
111
112 return KeyPair::signature_consistency_check(rng, *this, "SHA-256");
113}
114
115namespace {
116
117/**
118* ECDSA signature operation
119*/
120class ECDSA_Signature_Operation final : public PK_Ops::Signature_with_Hash {
121 public:
122 ECDSA_Signature_Operation(const ECDSA_PrivateKey& ecdsa, std::string_view padding, RandomNumberGenerator& rng) :
123 PK_Ops::Signature_with_Hash(padding),
124 m_group(ecdsa.domain()),
125 m_x(ecdsa._private_key()),
126 m_b(EC_Scalar::random(m_group, rng)),
127 m_b_inv(m_b.invert()) {
128#if defined(BOTAN_HAS_RFC6979_GENERATOR)
129 m_rfc6979 = std::make_unique<RFC6979_Nonce_Generator>(
130 this->rfc6979_hash_function(), m_group.get_order_bits(), ecdsa._private_key());
131#endif
132 }
133
134 size_t signature_length() const override { return 2 * m_group.get_order_bytes(); }
135
136 std::vector<uint8_t> raw_sign(std::span<const uint8_t> msg, RandomNumberGenerator& rng) override;
137
138 AlgorithmIdentifier algorithm_identifier() const override;
139
140 private:
141 const EC_Group m_group;
142 const EC_Scalar m_x;
143
144#if defined(BOTAN_HAS_RFC6979_GENERATOR)
145 std::unique_ptr<RFC6979_Nonce_Generator> m_rfc6979;
146#endif
147
148 std::vector<BigInt> m_ws;
149
150 EC_Scalar m_b;
151 EC_Scalar m_b_inv;
152};
153
154AlgorithmIdentifier ECDSA_Signature_Operation::algorithm_identifier() const {
155 const std::string full_name = "ECDSA/" + hash_function();
156 const OID oid = OID::from_string(full_name);
157 return AlgorithmIdentifier(oid, AlgorithmIdentifier::USE_EMPTY_PARAM);
158}
159
160std::vector<uint8_t> ECDSA_Signature_Operation::raw_sign(std::span<const uint8_t> msg, RandomNumberGenerator& rng) {
161 const auto m = EC_Scalar::from_bytes_with_trunc(m_group, msg);
162
163#if defined(BOTAN_HAS_RFC6979_GENERATOR)
164 const auto k = m_rfc6979->nonce_for(m_group, m);
165#else
166 const auto k = EC_Scalar::random(m_group, rng);
167#endif
168
169 const auto r = EC_Scalar::gk_x_mod_order(k, rng, m_ws);
170
171 // Blind the inversion of k
172 const auto k_inv = (m_b * k).invert() * m_b;
173
174 /*
175 * Blind the input message and compute x*r+m as (x*r*b + m*b)/b
176 */
177 m_b.square_self();
178 m_b_inv.square_self();
179
180 const auto xr_m = ((m_x * m_b) * r) + (m * m_b);
181
182 const auto s = (k_inv * xr_m) * m_b_inv;
183
184 // With overwhelming probability, a bug rather than actual zero r/s
185 if(r.is_zero() || s.is_zero()) {
186 throw Internal_Error("During ECDSA signature generated zero r/s");
187 }
188
189 return EC_Scalar::serialize_pair(r, s);
190}
191
192/**
193* ECDSA verification operation
194*/
195class ECDSA_Verification_Operation final : public PK_Ops::Verification_with_Hash {
196 public:
197 ECDSA_Verification_Operation(const ECDSA_PublicKey& ecdsa, std::string_view padding) :
198 PK_Ops::Verification_with_Hash(padding), m_group(ecdsa.domain()), m_gy_mul(ecdsa._public_key()) {}
199
200 ECDSA_Verification_Operation(const ECDSA_PublicKey& ecdsa, const AlgorithmIdentifier& alg_id) :
201 PK_Ops::Verification_with_Hash(alg_id, "ECDSA", true),
202 m_group(ecdsa.domain()),
203 m_gy_mul(ecdsa._public_key()) {}
204
205 bool verify(std::span<const uint8_t> msg, std::span<const uint8_t> sig) override;
206
207 private:
208 const EC_Group m_group;
209 const EC_Group::Mul2Table m_gy_mul;
210};
211
212bool ECDSA_Verification_Operation::verify(std::span<const uint8_t> msg, std::span<const uint8_t> sig) {
213 if(auto rs = EC_Scalar::deserialize_pair(m_group, sig)) {
214 const auto& [r, s] = rs.value();
215
216 if(r.is_nonzero() && s.is_nonzero()) {
217 const auto m = EC_Scalar::from_bytes_with_trunc(m_group, msg);
218
219 const auto w = s.invert();
220
221 // Check if r == x_coord(g*w*m + y*w*r) % n
222 return m_gy_mul.mul2_vartime_x_mod_order_eq(r, w, m, r);
223 }
224 }
225
226 return false;
227}
228
229} // namespace
230
231std::unique_ptr<PK_Ops::Verification> ECDSA_PublicKey::create_verification_op(std::string_view params,
232 std::string_view provider) const {
233 if(provider == "base" || provider.empty()) {
234 return std::make_unique<ECDSA_Verification_Operation>(*this, params);
235 }
236
237 throw Provider_Not_Found(algo_name(), provider);
238}
239
240std::unique_ptr<PK_Ops::Verification> ECDSA_PublicKey::create_x509_verification_op(
241 const AlgorithmIdentifier& signature_algorithm, std::string_view provider) const {
242 if(provider == "base" || provider.empty()) {
243 return std::make_unique<ECDSA_Verification_Operation>(*this, signature_algorithm);
244 }
245
246 throw Provider_Not_Found(algo_name(), provider);
247}
248
249std::unique_ptr<PK_Ops::Signature> ECDSA_PrivateKey::create_signature_op(RandomNumberGenerator& rng,
250 std::string_view params,
251 std::string_view provider) const {
252 if(provider == "base" || provider.empty()) {
253 return std::make_unique<ECDSA_Signature_Operation>(*this, params, rng);
254 }
255
256 throw Provider_Not_Found(algo_name(), provider);
257}
258
259} // namespace Botan
std::unique_ptr< Public_Key > public_key() const override
Definition ecdsa.cpp:99
std::unique_ptr< PK_Ops::Signature > create_signature_op(RandomNumberGenerator &rng, std::string_view params, std::string_view provider) const override
Definition ecdsa.cpp:249
bool check_key(RandomNumberGenerator &rng, bool) const override
Definition ecdsa.cpp:103
std::unique_ptr< PK_Ops::Verification > create_x509_verification_op(const AlgorithmIdentifier &signature_algorithm, std::string_view provider) const override
Definition ecdsa.cpp:240
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:231
static std::optional< EC_AffinePoint > deserialize(const EC_Group &group, std::span< const uint8_t > bytes)
Definition ec_apoint.cpp:97
bool mul2_vartime_x_mod_order_eq(const EC_Scalar &v, const EC_Scalar &x, const EC_Scalar &y) const
Definition ec_group.cpp:652
const EC_Scalar & _private_key() const
Definition ecc_key.cpp:115
bool check_key(RandomNumberGenerator &rng, bool strong) const override
Definition ecc_key.cpp:196
const EC_Group & domain() const
Definition ecc_key.cpp:59
const EC_Point & public_point() const
Definition ecc_key.cpp:64
static EC_Scalar from_bigint(const EC_Group &group, const BigInt &bn)
Definition ec_scalar.cpp:65
EC_Scalar invert() 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