/src/botan/src/lib/pubkey/gost_3410/gost_3410.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * GOST 34.10-2012 |
3 | | * (C) 2007 Falko Strenzke, FlexSecure GmbH |
4 | | * Manuel Hartl, FlexSecure GmbH |
5 | | * (C) 2008-2010,2015,2018 Jack Lloyd |
6 | | * |
7 | | * Botan is released under the Simplified BSD License (see license.txt) |
8 | | */ |
9 | | |
10 | | #include <botan/gost_3410.h> |
11 | | #include <botan/internal/pk_ops_impl.h> |
12 | | #include <botan/internal/point_mul.h> |
13 | | #include <botan/reducer.h> |
14 | | #include <botan/der_enc.h> |
15 | | #include <botan/ber_dec.h> |
16 | | |
17 | | namespace Botan { |
18 | | |
19 | | std::vector<uint8_t> GOST_3410_PublicKey::public_key_bits() const |
20 | 0 | { |
21 | 0 | const BigInt x = public_point().get_affine_x(); |
22 | 0 | const BigInt y = public_point().get_affine_y(); |
23 | |
|
24 | 0 | size_t part_size = std::max(x.bytes(), y.bytes()); |
25 | |
|
26 | 0 | std::vector<uint8_t> bits(2*part_size); |
27 | |
|
28 | 0 | x.binary_encode(&bits[part_size - x.bytes()]); |
29 | 0 | y.binary_encode(&bits[2*part_size - y.bytes()]); |
30 | | |
31 | | // Keys are stored in little endian format (WTF) |
32 | 0 | for(size_t i = 0; i != part_size / 2; ++i) |
33 | 0 | { |
34 | 0 | std::swap(bits[i], bits[part_size-1-i]); |
35 | 0 | std::swap(bits[part_size+i], bits[2*part_size-1-i]); |
36 | 0 | } |
37 | |
|
38 | 0 | std::vector<uint8_t> output; |
39 | 0 | DER_Encoder(output).encode(bits, ASN1_Type::OctetString); |
40 | 0 | return output; |
41 | 0 | } |
42 | | |
43 | | std::string GOST_3410_PublicKey::algo_name() const |
44 | 76 | { |
45 | 76 | const size_t p_bits = domain().get_p_bits(); |
46 | | |
47 | 76 | if(p_bits == 256 || p_bits == 512) |
48 | 76 | return "GOST-34.10-2012-" + std::to_string(p_bits); |
49 | 0 | else |
50 | 0 | throw Encoding_Error("GOST-34.10-2012 is not defined for parameters of this size"); |
51 | 76 | } |
52 | | |
53 | | AlgorithmIdentifier GOST_3410_PublicKey::algorithm_identifier() const |
54 | 0 | { |
55 | 0 | std::vector<uint8_t> params; |
56 | |
|
57 | 0 | const OID gost_oid = get_oid(); |
58 | 0 | const OID domain_oid = domain().get_curve_oid(); |
59 | |
|
60 | 0 | DER_Encoder(params).start_sequence().encode(domain_oid).end_cons(); |
61 | |
|
62 | 0 | return AlgorithmIdentifier(gost_oid, params); |
63 | 0 | } |
64 | | |
65 | | GOST_3410_PublicKey::GOST_3410_PublicKey(const AlgorithmIdentifier& alg_id, |
66 | | const std::vector<uint8_t>& key_bits) |
67 | 90 | { |
68 | 90 | OID ecc_param_id; |
69 | | |
70 | | // The parameters also includes hash and cipher OIDs |
71 | 90 | BER_Decoder(alg_id.get_parameters()).start_sequence().decode(ecc_param_id); |
72 | | |
73 | 90 | m_domain_params = EC_Group(ecc_param_id); |
74 | | |
75 | 90 | const size_t p_bits = m_domain_params.get_p_bits(); |
76 | 90 | if(p_bits != 256 && p_bits != 512) |
77 | 3 | throw Decoding_Error("GOST-34.10-2012 is not defined for parameters of size " + |
78 | 3 | std::to_string(p_bits)); |
79 | | |
80 | 87 | secure_vector<uint8_t> bits; |
81 | 87 | BER_Decoder(key_bits).decode(bits, ASN1_Type::OctetString); |
82 | | |
83 | 87 | if(bits.size() != 2*(p_bits/8)) |
84 | 3 | throw Decoding_Error("GOST-34.10-2020 invalid encoding of public key"); |
85 | | |
86 | 84 | const size_t part_size = bits.size() / 2; |
87 | | |
88 | | // Keys are stored in little endian format (WTF) |
89 | 1.33k | for(size_t i = 0; i != part_size / 2; ++i) |
90 | 1.24k | { |
91 | 1.24k | std::swap(bits[i], bits[part_size-1-i]); |
92 | 1.24k | std::swap(bits[part_size+i], bits[2*part_size-1-i]); |
93 | 1.24k | } |
94 | | |
95 | 84 | BigInt x(bits.data(), part_size); |
96 | 84 | BigInt y(&bits[part_size], part_size); |
97 | | |
98 | 84 | m_public_key = domain().point(x, y); |
99 | | |
100 | 84 | BOTAN_ASSERT(m_public_key.on_the_curve(), |
101 | 84 | "Loaded GOST 34.10 public key is on the curve"); |
102 | 84 | } Unexecuted instantiation: Botan::GOST_3410_PublicKey::GOST_3410_PublicKey(Botan::AlgorithmIdentifier const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > const&) Botan::GOST_3410_PublicKey::GOST_3410_PublicKey(Botan::AlgorithmIdentifier const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > const&) Line | Count | Source | 67 | 90 | { | 68 | 90 | OID ecc_param_id; | 69 | | | 70 | | // The parameters also includes hash and cipher OIDs | 71 | 90 | BER_Decoder(alg_id.get_parameters()).start_sequence().decode(ecc_param_id); | 72 | | | 73 | 90 | m_domain_params = EC_Group(ecc_param_id); | 74 | | | 75 | 90 | const size_t p_bits = m_domain_params.get_p_bits(); | 76 | 90 | if(p_bits != 256 && p_bits != 512) | 77 | 3 | throw Decoding_Error("GOST-34.10-2012 is not defined for parameters of size " + | 78 | 3 | std::to_string(p_bits)); | 79 | | | 80 | 87 | secure_vector<uint8_t> bits; | 81 | 87 | BER_Decoder(key_bits).decode(bits, ASN1_Type::OctetString); | 82 | | | 83 | 87 | if(bits.size() != 2*(p_bits/8)) | 84 | 3 | throw Decoding_Error("GOST-34.10-2020 invalid encoding of public key"); | 85 | | | 86 | 84 | const size_t part_size = bits.size() / 2; | 87 | | | 88 | | // Keys are stored in little endian format (WTF) | 89 | 1.33k | for(size_t i = 0; i != part_size / 2; ++i) | 90 | 1.24k | { | 91 | 1.24k | std::swap(bits[i], bits[part_size-1-i]); | 92 | 1.24k | std::swap(bits[part_size+i], bits[2*part_size-1-i]); | 93 | 1.24k | } | 94 | | | 95 | 84 | BigInt x(bits.data(), part_size); | 96 | 84 | BigInt y(&bits[part_size], part_size); | 97 | | | 98 | 84 | m_public_key = domain().point(x, y); | 99 | | | 100 | 84 | BOTAN_ASSERT(m_public_key.on_the_curve(), | 101 | 84 | "Loaded GOST 34.10 public key is on the curve"); | 102 | 84 | } |
|
103 | | |
104 | | GOST_3410_PrivateKey::GOST_3410_PrivateKey(RandomNumberGenerator& rng, |
105 | | const EC_Group& domain, |
106 | | const BigInt& x) : |
107 | | EC_PrivateKey(rng, domain, x) |
108 | 0 | { |
109 | 0 | const size_t p_bits = m_domain_params.get_p_bits(); |
110 | 0 | if(p_bits != 256 && p_bits != 512) |
111 | 0 | throw Decoding_Error("GOST-34.10-2012 is not defined for parameters of size " + |
112 | 0 | std::to_string(p_bits)); |
113 | 0 | } Unexecuted instantiation: Botan::GOST_3410_PrivateKey::GOST_3410_PrivateKey(Botan::RandomNumberGenerator&, Botan::EC_Group const&, Botan::BigInt const&) Unexecuted instantiation: Botan::GOST_3410_PrivateKey::GOST_3410_PrivateKey(Botan::RandomNumberGenerator&, Botan::EC_Group const&, Botan::BigInt const&) |
114 | | |
115 | | std::unique_ptr<Public_Key> GOST_3410_PrivateKey::public_key() const |
116 | 0 | { |
117 | 0 | return std::make_unique<GOST_3410_PublicKey>(domain(), public_point()); |
118 | 0 | } |
119 | | |
120 | | namespace { |
121 | | |
122 | | BigInt decode_le(const uint8_t msg[], size_t msg_len) |
123 | 69 | { |
124 | 69 | secure_vector<uint8_t> msg_le(msg, msg + msg_len); |
125 | | |
126 | 1.17k | for(size_t i = 0; i != msg_le.size() / 2; ++i) |
127 | 1.10k | std::swap(msg_le[i], msg_le[msg_le.size()-1-i]); |
128 | | |
129 | 69 | return BigInt(msg_le.data(), msg_le.size()); |
130 | 69 | } |
131 | | |
132 | | /** |
133 | | * GOST-34.10 signature operation |
134 | | */ |
135 | | class GOST_3410_Signature_Operation final : public PK_Ops::Signature_with_EMSA |
136 | | { |
137 | | public: |
138 | | GOST_3410_Signature_Operation(const GOST_3410_PrivateKey& gost_3410, |
139 | | const std::string& emsa) : |
140 | | PK_Ops::Signature_with_EMSA(emsa), |
141 | | m_group(gost_3410.domain()), |
142 | | m_x(gost_3410.private_value()) |
143 | 0 | {} |
144 | | |
145 | 0 | size_t signature_length() const override { return 2*m_group.get_order_bytes(); } |
146 | | |
147 | 0 | size_t max_input_bits() const override { return m_group.get_order_bits(); } |
148 | | |
149 | | secure_vector<uint8_t> raw_sign(const uint8_t msg[], size_t msg_len, |
150 | | RandomNumberGenerator& rng) override; |
151 | | |
152 | | private: |
153 | | const EC_Group m_group; |
154 | | const BigInt& m_x; |
155 | | std::vector<BigInt> m_ws; |
156 | | }; |
157 | | |
158 | | secure_vector<uint8_t> |
159 | | GOST_3410_Signature_Operation::raw_sign(const uint8_t msg[], size_t msg_len, |
160 | | RandomNumberGenerator& rng) |
161 | 0 | { |
162 | 0 | const BigInt k = m_group.random_scalar(rng); |
163 | |
|
164 | 0 | BigInt e = decode_le(msg, msg_len); |
165 | |
|
166 | 0 | e = m_group.mod_order(e); |
167 | 0 | if(e.is_zero()) |
168 | 0 | e = BigInt::one(); |
169 | |
|
170 | 0 | const BigInt r = m_group.mod_order( |
171 | 0 | m_group.blinded_base_point_multiply_x(k, rng, m_ws)); |
172 | |
|
173 | 0 | const BigInt s = m_group.mod_order( |
174 | 0 | m_group.multiply_mod_order(r, m_x) + |
175 | 0 | m_group.multiply_mod_order(k, e)); |
176 | |
|
177 | 0 | if(r == 0 || s == 0) |
178 | 0 | throw Internal_Error("GOST 34.10 signature generation failed, r/s equal to zero"); |
179 | | |
180 | 0 | return BigInt::encode_fixed_length_int_pair(s, r, m_group.get_order_bytes()); |
181 | 0 | } |
182 | | |
183 | | /** |
184 | | * GOST-34.10 verification operation |
185 | | */ |
186 | | class GOST_3410_Verification_Operation final : public PK_Ops::Verification_with_EMSA |
187 | | { |
188 | | public: |
189 | | |
190 | | GOST_3410_Verification_Operation(const GOST_3410_PublicKey& gost, |
191 | | const std::string& emsa) : |
192 | | PK_Ops::Verification_with_EMSA(emsa), |
193 | | m_group(gost.domain()), |
194 | | m_gy_mul(m_group.get_base_point(), gost.public_point()) |
195 | 75 | {} |
196 | | |
197 | 75 | size_t max_input_bits() const override { return m_group.get_order_bits(); } |
198 | | |
199 | 75 | bool with_recovery() const override { return false; } |
200 | | |
201 | | bool verify(const uint8_t msg[], size_t msg_len, |
202 | | const uint8_t sig[], size_t sig_len) override; |
203 | | private: |
204 | | const EC_Group m_group; |
205 | | const PointGFp_Multi_Point_Precompute m_gy_mul; |
206 | | }; |
207 | | |
208 | | bool GOST_3410_Verification_Operation::verify(const uint8_t msg[], size_t msg_len, |
209 | | const uint8_t sig[], size_t sig_len) |
210 | 75 | { |
211 | 75 | if(sig_len != m_group.get_order_bytes() * 2) |
212 | 1 | return false; |
213 | | |
214 | 74 | const BigInt s(sig, sig_len / 2); |
215 | 74 | const BigInt r(sig + sig_len / 2, sig_len / 2); |
216 | | |
217 | 74 | const BigInt& order = m_group.get_order(); |
218 | | |
219 | 74 | if(r <= 0 || r >= order || s <= 0 || s >= order) |
220 | 5 | return false; |
221 | | |
222 | 69 | BigInt e = decode_le(msg, msg_len); |
223 | 69 | e = m_group.mod_order(e); |
224 | 69 | if(e.is_zero()) |
225 | 0 | e = BigInt::one(); |
226 | | |
227 | 69 | const BigInt v = m_group.inverse_mod_order(e); |
228 | | |
229 | 69 | const BigInt z1 = m_group.multiply_mod_order(s, v); |
230 | 69 | const BigInt z2 = m_group.multiply_mod_order(-r, v); |
231 | | |
232 | 69 | const PointGFp R = m_gy_mul.multi_exp(z1, z2); |
233 | | |
234 | 69 | if(R.is_zero()) |
235 | 0 | return false; |
236 | | |
237 | 69 | return (R.get_affine_x() == r); |
238 | 69 | } |
239 | | |
240 | | } |
241 | | |
242 | | std::unique_ptr<PK_Ops::Verification> |
243 | | GOST_3410_PublicKey::create_verification_op(const std::string& params, |
244 | | const std::string& provider) const |
245 | 75 | { |
246 | 75 | if(provider == "base" || provider.empty()) |
247 | 75 | return std::make_unique<GOST_3410_Verification_Operation>(*this, params); |
248 | 0 | throw Provider_Not_Found(algo_name(), provider); |
249 | 75 | } |
250 | | |
251 | | std::unique_ptr<PK_Ops::Signature> |
252 | | GOST_3410_PrivateKey::create_signature_op(RandomNumberGenerator& /*rng*/, |
253 | | const std::string& params, |
254 | | const std::string& provider) const |
255 | 0 | { |
256 | 0 | if(provider == "base" || provider.empty()) |
257 | 0 | return std::make_unique<GOST_3410_Signature_Operation>(*this, params); |
258 | 0 | throw Provider_Not_Found(algo_name(), provider); |
259 | 0 | } |
260 | | |
261 | | } |