Coverage Report

Created: 2024-02-25 06:16

/src/botan/src/lib/pubkey/ecgdsa/ecgdsa.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
* ECGDSA (BSI-TR-03111, version 2.0)
3
* (C) 2016 René Korthaus
4
* (C) 2018 Jack Lloyd
5
*
6
* Botan is released under the Simplified BSD License (see license.txt)
7
*/
8
9
#include <botan/ecgdsa.h>
10
11
#include <botan/reducer.h>
12
#include <botan/internal/keypair.h>
13
#include <botan/internal/pk_ops_impl.h>
14
#include <botan/internal/point_mul.h>
15
16
namespace Botan {
17
18
0
std::unique_ptr<Public_Key> ECGDSA_PrivateKey::public_key() const {
19
0
   return std::make_unique<ECGDSA_PublicKey>(domain(), public_point());
20
0
}
21
22
0
bool ECGDSA_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const {
23
0
   if(!EC_PrivateKey::check_key(rng, strong)) {
24
0
      return false;
25
0
   }
26
27
0
   if(!strong) {
28
0
      return true;
29
0
   }
30
31
0
   return KeyPair::signature_consistency_check(rng, *this, "SHA-256");
32
0
}
33
34
namespace {
35
36
/**
37
* ECGDSA signature operation
38
*/
39
class ECGDSA_Signature_Operation final : public PK_Ops::Signature_with_Hash {
40
   public:
41
      ECGDSA_Signature_Operation(const ECGDSA_PrivateKey& ecgdsa, std::string_view emsa) :
42
168
            PK_Ops::Signature_with_Hash(emsa), m_group(ecgdsa.domain()), m_x(ecgdsa.private_value()) {}
43
44
      secure_vector<uint8_t> raw_sign(const uint8_t msg[], size_t msg_len, RandomNumberGenerator& rng) override;
45
46
0
      size_t signature_length() const override { return 2 * m_group.get_order_bytes(); }
47
48
      AlgorithmIdentifier algorithm_identifier() const override;
49
50
   private:
51
      const EC_Group m_group;
52
      const BigInt m_x;
53
      std::vector<BigInt> m_ws;
54
};
55
56
0
AlgorithmIdentifier ECGDSA_Signature_Operation::algorithm_identifier() const {
57
0
   const std::string full_name = "ECGDSA/" + hash_function();
58
0
   const OID oid = OID::from_string(full_name);
59
0
   return AlgorithmIdentifier(oid, AlgorithmIdentifier::USE_EMPTY_PARAM);
60
0
}
61
62
secure_vector<uint8_t> ECGDSA_Signature_Operation::raw_sign(const uint8_t msg[],
63
                                                            size_t msg_len,
64
168
                                                            RandomNumberGenerator& rng) {
65
168
   const BigInt m = BigInt::from_bytes_with_max_bits(msg, msg_len, m_group.get_order_bits());
66
67
168
   const BigInt k = m_group.random_scalar(rng);
68
69
168
   const BigInt r = m_group.mod_order(m_group.blinded_base_point_multiply_x(k, rng, m_ws));
70
71
168
   const BigInt kr = m_group.multiply_mod_order(k, r);
72
73
168
   const BigInt s = m_group.multiply_mod_order(m_x, kr - m);
74
75
   // With overwhelming probability, a bug rather than actual zero r/s
76
168
   if(r.is_zero() || s.is_zero()) {
77
2
      throw Internal_Error("During ECGDSA signature generated zero r/s");
78
2
   }
79
80
166
   return BigInt::encode_fixed_length_int_pair(r, s, m_group.get_order_bytes());
81
168
}
82
83
/**
84
* ECGDSA verification operation
85
*/
86
class ECGDSA_Verification_Operation final : public PK_Ops::Verification_with_Hash {
87
   public:
88
      ECGDSA_Verification_Operation(const ECGDSA_PublicKey& ecgdsa, std::string_view padding) :
89
            PK_Ops::Verification_with_Hash(padding),
90
            m_group(ecgdsa.domain()),
91
221
            m_gy_mul(m_group.get_base_point(), ecgdsa.public_point()) {}
92
93
      ECGDSA_Verification_Operation(const ECGDSA_PublicKey& ecgdsa, const AlgorithmIdentifier& alg_id) :
94
            PK_Ops::Verification_with_Hash(alg_id, "ECGDSA"),
95
            m_group(ecgdsa.domain()),
96
0
            m_gy_mul(m_group.get_base_point(), ecgdsa.public_point()) {}
97
98
      bool verify(const uint8_t msg[], size_t msg_len, const uint8_t sig[], size_t sig_len) override;
99
100
   private:
101
      const EC_Group m_group;
102
      const EC_Point_Multi_Point_Precompute m_gy_mul;
103
};
104
105
221
bool ECGDSA_Verification_Operation::verify(const uint8_t msg[], size_t msg_len, const uint8_t sig[], size_t sig_len) {
106
221
   if(sig_len != m_group.get_order_bytes() * 2) {
107
0
      return false;
108
0
   }
109
110
221
   const BigInt e = BigInt::from_bytes_with_max_bits(msg, msg_len, m_group.get_order_bits());
111
112
221
   const BigInt r(sig, sig_len / 2);
113
221
   const BigInt s(sig + sig_len / 2, sig_len / 2);
114
115
221
   if(r <= 0 || r >= m_group.get_order() || s <= 0 || s >= m_group.get_order()) {
116
78
      return false;
117
78
   }
118
119
143
   const BigInt w = m_group.inverse_mod_order(r);
120
121
143
   const BigInt u1 = m_group.multiply_mod_order(e, w);
122
143
   const BigInt u2 = m_group.multiply_mod_order(s, w);
123
143
   const EC_Point R = m_gy_mul.multi_exp(u1, u2);
124
125
143
   if(R.is_zero()) {
126
75
      return false;
127
75
   }
128
129
68
   const BigInt v = m_group.mod_order(R.get_affine_x());
130
68
   return (v == r);
131
143
}
132
133
}  // namespace
134
135
0
std::unique_ptr<Private_Key> ECGDSA_PublicKey::generate_another(RandomNumberGenerator& rng) const {
136
0
   return std::make_unique<ECGDSA_PrivateKey>(rng, domain());
137
0
}
138
139
std::unique_ptr<PK_Ops::Verification> ECGDSA_PublicKey::create_verification_op(std::string_view params,
140
221
                                                                               std::string_view provider) const {
141
221
   if(provider == "base" || provider.empty()) {
142
221
      return std::make_unique<ECGDSA_Verification_Operation>(*this, params);
143
221
   }
144
0
   throw Provider_Not_Found(algo_name(), provider);
145
221
}
146
147
std::unique_ptr<PK_Ops::Verification> ECGDSA_PublicKey::create_x509_verification_op(
148
0
   const AlgorithmIdentifier& signature_algorithm, std::string_view provider) const {
149
0
   if(provider == "base" || provider.empty()) {
150
0
      return std::make_unique<ECGDSA_Verification_Operation>(*this, signature_algorithm);
151
0
   }
152
153
0
   throw Provider_Not_Found(algo_name(), provider);
154
0
}
155
156
std::unique_ptr<PK_Ops::Signature> ECGDSA_PrivateKey::create_signature_op(RandomNumberGenerator& /*rng*/,
157
                                                                          std::string_view params,
158
168
                                                                          std::string_view provider) const {
159
168
   if(provider == "base" || provider.empty()) {
160
168
      return std::make_unique<ECGDSA_Signature_Operation>(*this, params);
161
168
   }
162
0
   throw Provider_Not_Found(algo_name(), provider);
163
168
}
164
165
}  // namespace Botan