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