/src/botan/src/lib/pubkey/eckcdsa/eckcdsa.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * ECKCDSA (ISO/IEC 14888-3:2006/Cor.2:2009) |
3 | | * (C) 2016 René Korthaus, Sirrix AG |
4 | | * (C) 2018 Jack Lloyd |
5 | | * |
6 | | * Botan is released under the Simplified BSD License (see license.txt) |
7 | | */ |
8 | | |
9 | | #include <botan/eckcdsa.h> |
10 | | #include <botan/internal/pk_ops_impl.h> |
11 | | #include <botan/internal/point_mul.h> |
12 | | #include <botan/internal/keypair.h> |
13 | | #include <botan/reducer.h> |
14 | | #include <botan/internal/emsa.h> |
15 | | #include <botan/hash.h> |
16 | | #include <botan/rng.h> |
17 | | |
18 | | namespace Botan { |
19 | | |
20 | | std::unique_ptr<Public_Key> ECKCDSA_PrivateKey::public_key() const |
21 | 0 | { |
22 | 0 | return std::make_unique<ECKCDSA_PublicKey>(domain(), public_point()); |
23 | 0 | } |
24 | | |
25 | | bool ECKCDSA_PrivateKey::check_key(RandomNumberGenerator& rng, |
26 | | bool strong) const |
27 | 0 | { |
28 | 0 | if(!public_point().on_the_curve()) |
29 | 0 | { |
30 | 0 | return false; |
31 | 0 | } |
32 | | |
33 | 0 | if(!strong) |
34 | 0 | { |
35 | 0 | return true; |
36 | 0 | } |
37 | | |
38 | 0 | return KeyPair::signature_consistency_check(rng, *this, "EMSA1(SHA-256)"); |
39 | 0 | } |
40 | | |
41 | | namespace { |
42 | | |
43 | | /** |
44 | | * ECKCDSA signature operation |
45 | | */ |
46 | | class ECKCDSA_Signature_Operation final : public PK_Ops::Signature_with_EMSA |
47 | | { |
48 | | public: |
49 | | |
50 | | ECKCDSA_Signature_Operation(const ECKCDSA_PrivateKey& eckcdsa, |
51 | | const std::string& emsa) : |
52 | | PK_Ops::Signature_with_EMSA(emsa), |
53 | | m_group(eckcdsa.domain()), |
54 | | m_x(eckcdsa.private_value()), |
55 | | m_prefix() |
56 | 0 | { |
57 | 0 | const BigInt public_point_x = eckcdsa.public_point().get_affine_x(); |
58 | 0 | const BigInt public_point_y = eckcdsa.public_point().get_affine_y(); |
59 | |
|
60 | 0 | const size_t order_bytes = m_group.get_order_bytes(); |
61 | |
|
62 | 0 | m_prefix.resize(2*order_bytes); |
63 | 0 | BigInt::encode_1363(&m_prefix[0], order_bytes, public_point_x); |
64 | 0 | BigInt::encode_1363(&m_prefix[order_bytes], order_bytes, public_point_y); |
65 | |
|
66 | 0 | const size_t block_size = HashFunction::create(hash_for_signature())->hash_block_size(); |
67 | | // Either truncate or zero-extend to match the hash block size |
68 | 0 | m_prefix.resize(block_size); |
69 | 0 | } |
70 | | |
71 | | secure_vector<uint8_t> raw_sign(const uint8_t msg[], size_t msg_len, |
72 | | RandomNumberGenerator& rng) override; |
73 | | |
74 | 0 | size_t signature_length() const override { return 2*m_group.get_order_bytes(); } |
75 | 0 | size_t max_input_bits() const override { return m_group.get_order_bits(); } |
76 | | |
77 | 0 | bool has_prefix() override { return true; } |
78 | 0 | secure_vector<uint8_t> message_prefix() const override { return m_prefix; } |
79 | | |
80 | | private: |
81 | | const EC_Group m_group; |
82 | | const BigInt& m_x; |
83 | | secure_vector<uint8_t> m_prefix; |
84 | | std::vector<BigInt> m_ws; |
85 | | }; |
86 | | |
87 | | secure_vector<uint8_t> |
88 | | ECKCDSA_Signature_Operation::raw_sign(const uint8_t msg[], size_t /*msg_len*/, |
89 | | RandomNumberGenerator& rng) |
90 | 0 | { |
91 | 0 | const BigInt k = m_group.random_scalar(rng); |
92 | 0 | const BigInt k_times_P_x = m_group.blinded_base_point_multiply_x(k, rng, m_ws); |
93 | |
|
94 | 0 | secure_vector<uint8_t> to_be_hashed(k_times_P_x.bytes()); |
95 | 0 | k_times_P_x.binary_encode(to_be_hashed.data()); |
96 | |
|
97 | 0 | std::unique_ptr<EMSA> emsa = this->clone_emsa(); |
98 | 0 | emsa->update(to_be_hashed.data(), to_be_hashed.size()); |
99 | 0 | secure_vector<uint8_t> c = emsa->raw_data(); |
100 | 0 | c = emsa->encoding_of(c, max_input_bits(), rng); |
101 | |
|
102 | 0 | const BigInt r(c.data(), c.size()); |
103 | |
|
104 | 0 | xor_buf(c, msg, c.size()); |
105 | 0 | BigInt w(c.data(), c.size()); |
106 | 0 | w = m_group.mod_order(w); |
107 | |
|
108 | 0 | const BigInt s = m_group.multiply_mod_order(m_x, k - w); |
109 | 0 | if(s.is_zero()) |
110 | 0 | throw Internal_Error("During ECKCDSA signature generation created zero s"); |
111 | | |
112 | 0 | secure_vector<uint8_t> output = BigInt::encode_1363(r, c.size()); |
113 | 0 | output += BigInt::encode_1363(s, m_group.get_order_bytes()); |
114 | 0 | return output; |
115 | 0 | } |
116 | | |
117 | | /** |
118 | | * ECKCDSA verification operation |
119 | | */ |
120 | | class ECKCDSA_Verification_Operation final : public PK_Ops::Verification_with_EMSA |
121 | | { |
122 | | public: |
123 | | |
124 | | ECKCDSA_Verification_Operation(const ECKCDSA_PublicKey& eckcdsa, |
125 | | const std::string& emsa) : |
126 | | PK_Ops::Verification_with_EMSA(emsa), |
127 | | m_group(eckcdsa.domain()), |
128 | | m_gy_mul(m_group.get_base_point(), eckcdsa.public_point()), |
129 | | m_prefix() |
130 | 0 | { |
131 | 0 | const BigInt public_point_x = eckcdsa.public_point().get_affine_x(); |
132 | 0 | const BigInt public_point_y = eckcdsa.public_point().get_affine_y(); |
133 | |
|
134 | 0 | const size_t order_bytes = m_group.get_order_bytes(); |
135 | |
|
136 | 0 | m_prefix.resize(2*order_bytes); |
137 | 0 | BigInt::encode_1363(&m_prefix[0], order_bytes, public_point_x); |
138 | 0 | BigInt::encode_1363(&m_prefix[order_bytes], order_bytes, public_point_y); |
139 | |
|
140 | 0 | const size_t block_size = HashFunction::create(hash_for_signature())->hash_block_size(); |
141 | | // Either truncate or zero-extend to match the hash block size |
142 | 0 | m_prefix.resize(block_size); |
143 | 0 | } |
144 | | |
145 | 0 | bool has_prefix() override { return true; } |
146 | 0 | secure_vector<uint8_t> message_prefix() const override { return m_prefix; } |
147 | | |
148 | 0 | size_t max_input_bits() const override { return m_group.get_order_bits(); } |
149 | | |
150 | 0 | bool with_recovery() const override { return false; } |
151 | | |
152 | | bool verify(const uint8_t msg[], size_t msg_len, |
153 | | const uint8_t sig[], size_t sig_len) override; |
154 | | private: |
155 | | const EC_Group m_group; |
156 | | const PointGFp_Multi_Point_Precompute m_gy_mul; |
157 | | secure_vector<uint8_t> m_prefix; |
158 | | }; |
159 | | |
160 | | bool ECKCDSA_Verification_Operation::verify(const uint8_t msg[], size_t /*msg_len*/, |
161 | | const uint8_t sig[], size_t sig_len) |
162 | 0 | { |
163 | 0 | const std::unique_ptr<HashFunction> hash = HashFunction::create(hash_for_signature()); |
164 | | //calculate size of r |
165 | |
|
166 | 0 | const size_t order_bytes = m_group.get_order_bytes(); |
167 | |
|
168 | 0 | const size_t size_r = std::min(hash -> output_length(), order_bytes); |
169 | 0 | if(sig_len != size_r + order_bytes) |
170 | 0 | { |
171 | 0 | return false; |
172 | 0 | } |
173 | | |
174 | 0 | secure_vector<uint8_t> r(sig, sig + size_r); |
175 | | |
176 | | // check that 0 < s < q |
177 | 0 | const BigInt s(sig + size_r, order_bytes); |
178 | |
|
179 | 0 | if(s <= 0 || s >= m_group.get_order()) |
180 | 0 | { |
181 | 0 | return false; |
182 | 0 | } |
183 | | |
184 | 0 | secure_vector<uint8_t> r_xor_e(r); |
185 | 0 | xor_buf(r_xor_e, msg, r.size()); |
186 | 0 | BigInt w(r_xor_e.data(), r_xor_e.size()); |
187 | 0 | w = m_group.mod_order(w); |
188 | |
|
189 | 0 | const PointGFp q = m_gy_mul.multi_exp(w, s); |
190 | 0 | if(q.is_zero()) |
191 | 0 | { |
192 | 0 | return false; |
193 | 0 | } |
194 | | |
195 | 0 | const BigInt q_x = q.get_affine_x(); |
196 | 0 | secure_vector<uint8_t> c(q_x.bytes()); |
197 | 0 | q_x.binary_encode(c.data()); |
198 | 0 | std::unique_ptr<EMSA> emsa = this->clone_emsa(); |
199 | 0 | emsa->update(c.data(), c.size()); |
200 | 0 | secure_vector<uint8_t> v = emsa->raw_data(); |
201 | 0 | Null_RNG rng; |
202 | 0 | v = emsa->encoding_of(v, max_input_bits(), rng); |
203 | |
|
204 | 0 | return (v == r); |
205 | 0 | } |
206 | | |
207 | | } |
208 | | |
209 | | std::unique_ptr<PK_Ops::Verification> |
210 | | ECKCDSA_PublicKey::create_verification_op(const std::string& params, |
211 | | const std::string& provider) const |
212 | 0 | { |
213 | 0 | if(provider == "base" || provider.empty()) |
214 | 0 | return std::make_unique<ECKCDSA_Verification_Operation>(*this, params); |
215 | 0 | throw Provider_Not_Found(algo_name(), provider); |
216 | 0 | } |
217 | | |
218 | | std::unique_ptr<PK_Ops::Signature> |
219 | | ECKCDSA_PrivateKey::create_signature_op(RandomNumberGenerator& /*rng*/, |
220 | | const std::string& params, |
221 | | const std::string& provider) const |
222 | 0 | { |
223 | 0 | if(provider == "base" || provider.empty()) |
224 | 0 | return std::make_unique<ECKCDSA_Signature_Operation>(*this, params); |
225 | 0 | throw Provider_Not_Found(algo_name(), provider); |
226 | 0 | } |
227 | | |
228 | | } |