/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 | m_prefix.resize(public_point_x.bytes() + public_point_y.bytes()); |
61 | 0 | public_point_x.binary_encode(m_prefix.data()); |
62 | 0 | public_point_y.binary_encode(&m_prefix[public_point_x.bytes()]); |
63 | 0 | m_prefix.resize(HashFunction::create(hash_for_signature())->hash_block_size()); // use only the "hash input block size" leftmost bits |
64 | 0 | } |
65 | | |
66 | | secure_vector<uint8_t> raw_sign(const uint8_t msg[], size_t msg_len, |
67 | | RandomNumberGenerator& rng) override; |
68 | | |
69 | 0 | size_t signature_length() const override { return 2*m_group.get_order_bytes(); } |
70 | 0 | size_t max_input_bits() const override { return m_group.get_order_bits(); } |
71 | | |
72 | 0 | bool has_prefix() override { return true; } |
73 | 0 | secure_vector<uint8_t> message_prefix() const override { return m_prefix; } |
74 | | |
75 | | private: |
76 | | const EC_Group m_group; |
77 | | const BigInt& m_x; |
78 | | secure_vector<uint8_t> m_prefix; |
79 | | std::vector<BigInt> m_ws; |
80 | | }; |
81 | | |
82 | | secure_vector<uint8_t> |
83 | | ECKCDSA_Signature_Operation::raw_sign(const uint8_t msg[], size_t, |
84 | | RandomNumberGenerator& rng) |
85 | 0 | { |
86 | 0 | const BigInt k = m_group.random_scalar(rng); |
87 | 0 | const BigInt k_times_P_x = m_group.blinded_base_point_multiply_x(k, rng, m_ws); |
88 | |
|
89 | 0 | secure_vector<uint8_t> to_be_hashed(k_times_P_x.bytes()); |
90 | 0 | k_times_P_x.binary_encode(to_be_hashed.data()); |
91 | |
|
92 | 0 | std::unique_ptr<EMSA> emsa = this->clone_emsa(); |
93 | 0 | emsa->update(to_be_hashed.data(), to_be_hashed.size()); |
94 | 0 | secure_vector<uint8_t> c = emsa->raw_data(); |
95 | 0 | c = emsa->encoding_of(c, max_input_bits(), rng); |
96 | |
|
97 | 0 | const BigInt r(c.data(), c.size()); |
98 | |
|
99 | 0 | xor_buf(c, msg, c.size()); |
100 | 0 | BigInt w(c.data(), c.size()); |
101 | 0 | w = m_group.mod_order(w); |
102 | |
|
103 | 0 | const BigInt s = m_group.multiply_mod_order(m_x, k - w); |
104 | 0 | if(s.is_zero()) |
105 | 0 | throw Internal_Error("During ECKCDSA signature generation created zero s"); |
106 | | |
107 | 0 | secure_vector<uint8_t> output = BigInt::encode_1363(r, c.size()); |
108 | 0 | output += BigInt::encode_1363(s, m_group.get_order_bytes()); |
109 | 0 | return output; |
110 | 0 | } |
111 | | |
112 | | /** |
113 | | * ECKCDSA verification operation |
114 | | */ |
115 | | class ECKCDSA_Verification_Operation final : public PK_Ops::Verification_with_EMSA |
116 | | { |
117 | | public: |
118 | | |
119 | | ECKCDSA_Verification_Operation(const ECKCDSA_PublicKey& eckcdsa, |
120 | | const std::string& emsa) : |
121 | | PK_Ops::Verification_with_EMSA(emsa), |
122 | | m_group(eckcdsa.domain()), |
123 | | m_gy_mul(m_group.get_base_point(), eckcdsa.public_point()), |
124 | | m_prefix() |
125 | 0 | { |
126 | 0 | const BigInt public_point_x = eckcdsa.public_point().get_affine_x(); |
127 | 0 | const BigInt public_point_y = eckcdsa.public_point().get_affine_y(); |
128 | |
|
129 | 0 | m_prefix.resize(public_point_x.bytes() + public_point_y.bytes()); |
130 | 0 | public_point_x.binary_encode(&m_prefix[0]); |
131 | 0 | public_point_y.binary_encode(&m_prefix[public_point_x.bytes()]); |
132 | 0 | m_prefix.resize(HashFunction::create(hash_for_signature())->hash_block_size()); // use only the "hash input block size" leftmost bits |
133 | 0 | } |
134 | | |
135 | 0 | bool has_prefix() override { return true; } |
136 | 0 | secure_vector<uint8_t> message_prefix() const override { return m_prefix; } |
137 | | |
138 | 0 | size_t max_input_bits() const override { return m_group.get_order_bits(); } |
139 | | |
140 | 0 | bool with_recovery() const override { return false; } |
141 | | |
142 | | bool verify(const uint8_t msg[], size_t msg_len, |
143 | | const uint8_t sig[], size_t sig_len) override; |
144 | | private: |
145 | | const EC_Group m_group; |
146 | | const PointGFp_Multi_Point_Precompute m_gy_mul; |
147 | | secure_vector<uint8_t> m_prefix; |
148 | | }; |
149 | | |
150 | | bool ECKCDSA_Verification_Operation::verify(const uint8_t msg[], size_t, |
151 | | const uint8_t sig[], size_t sig_len) |
152 | 0 | { |
153 | 0 | const std::unique_ptr<HashFunction> hash = HashFunction::create(hash_for_signature()); |
154 | | //calculate size of r |
155 | |
|
156 | 0 | const size_t order_bytes = m_group.get_order_bytes(); |
157 | |
|
158 | 0 | const size_t size_r = std::min(hash -> output_length(), order_bytes); |
159 | 0 | if(sig_len != size_r + order_bytes) |
160 | 0 | { |
161 | 0 | return false; |
162 | 0 | } |
163 | | |
164 | 0 | secure_vector<uint8_t> r(sig, sig + size_r); |
165 | | |
166 | | // check that 0 < s < q |
167 | 0 | const BigInt s(sig + size_r, order_bytes); |
168 | |
|
169 | 0 | if(s <= 0 || s >= m_group.get_order()) |
170 | 0 | { |
171 | 0 | return false; |
172 | 0 | } |
173 | | |
174 | 0 | secure_vector<uint8_t> r_xor_e(r); |
175 | 0 | xor_buf(r_xor_e, msg, r.size()); |
176 | 0 | BigInt w(r_xor_e.data(), r_xor_e.size()); |
177 | 0 | w = m_group.mod_order(w); |
178 | |
|
179 | 0 | const PointGFp q = m_gy_mul.multi_exp(w, s); |
180 | 0 | if(q.is_zero()) |
181 | 0 | return false; |
182 | 0 | const BigInt q_x = q.get_affine_x(); |
183 | 0 | secure_vector<uint8_t> c(q_x.bytes()); |
184 | 0 | q_x.binary_encode(c.data()); |
185 | 0 | std::unique_ptr<EMSA> emsa = this->clone_emsa(); |
186 | 0 | emsa->update(c.data(), c.size()); |
187 | 0 | secure_vector<uint8_t> v = emsa->raw_data(); |
188 | 0 | Null_RNG rng; |
189 | 0 | v = emsa->encoding_of(v, max_input_bits(), rng); |
190 | |
|
191 | 0 | return (v == r); |
192 | 0 | } |
193 | | |
194 | | } |
195 | | |
196 | | std::unique_ptr<PK_Ops::Verification> |
197 | | ECKCDSA_PublicKey::create_verification_op(const std::string& params, |
198 | | const std::string& provider) const |
199 | 0 | { |
200 | 0 | if(provider == "base" || provider.empty()) |
201 | 0 | return std::make_unique<ECKCDSA_Verification_Operation>(*this, params); |
202 | 0 | throw Provider_Not_Found(algo_name(), provider); |
203 | 0 | } |
204 | | |
205 | | std::unique_ptr<PK_Ops::Signature> |
206 | | ECKCDSA_PrivateKey::create_signature_op(RandomNumberGenerator& /*rng*/, |
207 | | const std::string& params, |
208 | | const std::string& provider) const |
209 | 0 | { |
210 | 0 | if(provider == "base" || provider.empty()) |
211 | 0 | return std::make_unique<ECKCDSA_Signature_Operation>(*this, params); |
212 | 0 | throw Provider_Not_Found(algo_name(), provider); |
213 | 0 | } |
214 | | |
215 | | } |