Botan 2.19.1
Crypto and TLS for C&
sm2_enc.cpp
Go to the documentation of this file.
1/*
2* SM2 Encryption
3* (C) 2017 Ribose Inc
4*
5* Botan is released under the Simplified BSD License (see license.txt)
6*/
7
8#include <botan/sm2.h>
9#include <botan/internal/point_mul.h>
10#include <botan/pk_ops.h>
11#include <botan/der_enc.h>
12#include <botan/ber_dec.h>
13#include <botan/kdf.h>
14#include <botan/hash.h>
15
16namespace Botan {
17
18namespace {
19
20class SM2_Encryption_Operation final : public PK_Ops::Encryption
21 {
22 public:
23 SM2_Encryption_Operation(const SM2_Encryption_PublicKey& key,
24 RandomNumberGenerator& rng,
25 const std::string& kdf_hash) :
26 m_group(key.domain()),
27 m_kdf_hash(kdf_hash),
28 m_ws(PointGFp::WORKSPACE_SIZE),
29 m_mul_public_point(key.public_point(), rng, m_ws)
30 {
31 std::unique_ptr<HashFunction> hash = HashFunction::create_or_throw(m_kdf_hash);
32 m_hash_size = hash->output_length();
33 }
34
35 size_t max_input_bits() const override
36 {
37 // This is arbitrary, but assumes SM2 is used for key encapsulation
38 return 512;
39 }
40
41 size_t ciphertext_length(size_t ptext_len) const override
42 {
43 const size_t elem_size = m_group.get_order_bytes();
44 const size_t der_overhead = 16;
45
46 return der_overhead + 2*elem_size + m_hash_size + ptext_len;
47 }
48
49 secure_vector<uint8_t> encrypt(const uint8_t msg[],
50 size_t msg_len,
51 RandomNumberGenerator& rng) override
52 {
53 std::unique_ptr<HashFunction> hash = HashFunction::create_or_throw(m_kdf_hash);
54 std::unique_ptr<KDF> kdf = KDF::create_or_throw("KDF2(" + m_kdf_hash + ")");
55
56 const size_t p_bytes = m_group.get_p_bytes();
57
58 const BigInt k = m_group.random_scalar(rng);
59
60 const PointGFp C1 = m_group.blinded_base_point_multiply(k, rng, m_ws);
61 const BigInt x1 = C1.get_affine_x();
62 const BigInt y1 = C1.get_affine_y();
63 std::vector<uint8_t> x1_bytes(p_bytes);
64 std::vector<uint8_t> y1_bytes(p_bytes);
65 BigInt::encode_1363(x1_bytes.data(), x1_bytes.size(), x1);
66 BigInt::encode_1363(y1_bytes.data(), y1_bytes.size(), y1);
67
68 const PointGFp kPB = m_mul_public_point.mul(k, rng, m_group.get_order(), m_ws);
69
70 const BigInt x2 = kPB.get_affine_x();
71 const BigInt y2 = kPB.get_affine_y();
72 std::vector<uint8_t> x2_bytes(p_bytes);
73 std::vector<uint8_t> y2_bytes(p_bytes);
74 BigInt::encode_1363(x2_bytes.data(), x2_bytes.size(), x2);
75 BigInt::encode_1363(y2_bytes.data(), y2_bytes.size(), y2);
76
77 secure_vector<uint8_t> kdf_input;
78 kdf_input += x2_bytes;
79 kdf_input += y2_bytes;
80
81 const secure_vector<uint8_t> kdf_output =
82 kdf->derive_key(msg_len, kdf_input.data(), kdf_input.size());
83
84 secure_vector<uint8_t> masked_msg(msg_len);
85 xor_buf(masked_msg.data(), msg, kdf_output.data(), msg_len);
86
87 hash->update(x2_bytes);
88 hash->update(msg, msg_len);
89 hash->update(y2_bytes);
90 std::vector<uint8_t> C3(hash->output_length());
91 hash->final(C3.data());
92
93 return DER_Encoder()
94 .start_cons(SEQUENCE)
95 .encode(x1)
96 .encode(y1)
97 .encode(C3, OCTET_STRING)
98 .encode(masked_msg, OCTET_STRING)
99 .end_cons()
100 .get_contents();
101 }
102
103 private:
104 const EC_Group m_group;
105 const std::string m_kdf_hash;
106
107 std::vector<BigInt> m_ws;
108 PointGFp_Var_Point_Precompute m_mul_public_point;
109 size_t m_hash_size;
110 };
111
112class SM2_Decryption_Operation final : public PK_Ops::Decryption
113 {
114 public:
115 SM2_Decryption_Operation(const SM2_Encryption_PrivateKey& key,
116 RandomNumberGenerator& rng,
117 const std::string& kdf_hash) :
118 m_key(key),
119 m_rng(rng),
120 m_kdf_hash(kdf_hash)
121 {
122 std::unique_ptr<HashFunction> hash = HashFunction::create_or_throw(m_kdf_hash);
123 m_hash_size = hash->output_length();
124 }
125
126 size_t plaintext_length(size_t ptext_len) const override
127 {
128 /*
129 * This ignores the DER encoding and so overestimates the
130 * plaintext length by 12 bytes or so
131 */
132 const size_t elem_size = m_key.domain().get_order_bytes();
133
134 if(ptext_len < 2*elem_size + m_hash_size)
135 return 0;
136
137 return ptext_len - (2*elem_size + m_hash_size);
138 }
139
140 secure_vector<uint8_t> decrypt(uint8_t& valid_mask,
141 const uint8_t ciphertext[],
142 size_t ciphertext_len) override
143 {
144 const EC_Group& group = m_key.domain();
145 const BigInt& cofactor = group.get_cofactor();
146 const size_t p_bytes = group.get_p_bytes();
147
148 valid_mask = 0x00;
149
150 std::unique_ptr<HashFunction> hash = HashFunction::create_or_throw(m_kdf_hash);
151 std::unique_ptr<KDF> kdf = KDF::create_or_throw("KDF2(" + m_kdf_hash + ")");
152
153 // Too short to be valid - no timing problem from early return
154 if(ciphertext_len < 1 + p_bytes*2 + hash->output_length())
155 {
156 return secure_vector<uint8_t>();
157 }
158
159 BigInt x1, y1;
160 secure_vector<uint8_t> C3, masked_msg;
161
162 BER_Decoder(ciphertext, ciphertext_len)
163 .start_cons(SEQUENCE)
164 .decode(x1)
165 .decode(y1)
166 .decode(C3, OCTET_STRING)
167 .decode(masked_msg, OCTET_STRING)
168 .end_cons()
169 .verify_end();
170
171 std::vector<uint8_t> recode_ctext;
172 DER_Encoder(recode_ctext)
173 .start_cons(SEQUENCE)
174 .encode(x1)
175 .encode(y1)
176 .encode(C3, OCTET_STRING)
177 .encode(masked_msg, OCTET_STRING)
178 .end_cons();
179
180 if(recode_ctext.size() != ciphertext_len)
181 return secure_vector<uint8_t>();
182
183 if(same_mem(recode_ctext.data(), ciphertext, ciphertext_len) == false)
184 return secure_vector<uint8_t>();
185
186 PointGFp C1 = group.point(x1, y1);
187 C1.randomize_repr(m_rng);
188
189 // Here C1 is publically invalid, so no problem with early return:
190 if(!C1.on_the_curve())
191 return secure_vector<uint8_t>();
192
193 if(cofactor > 1 && (C1 * cofactor).is_zero())
194 {
195 return secure_vector<uint8_t>();
196 }
197
198 const PointGFp dbC1 = group.blinded_var_point_multiply(
199 C1, m_key.private_value(), m_rng, m_ws);
200
201 const BigInt x2 = dbC1.get_affine_x();
202 const BigInt y2 = dbC1.get_affine_y();
203
204 secure_vector<uint8_t> x2_bytes(p_bytes);
205 secure_vector<uint8_t> y2_bytes(p_bytes);
206 BigInt::encode_1363(x2_bytes.data(), x2_bytes.size(), x2);
207 BigInt::encode_1363(y2_bytes.data(), y2_bytes.size(), y2);
208
209 secure_vector<uint8_t> kdf_input;
210 kdf_input += x2_bytes;
211 kdf_input += y2_bytes;
212
213 const secure_vector<uint8_t> kdf_output =
214 kdf->derive_key(masked_msg.size(), kdf_input.data(), kdf_input.size());
215
216 xor_buf(masked_msg.data(), kdf_output.data(), kdf_output.size());
217
218 hash->update(x2_bytes);
219 hash->update(masked_msg);
220 hash->update(y2_bytes);
221 secure_vector<uint8_t> u = hash->final();
222
223 if(constant_time_compare(u.data(), C3.data(), hash->output_length()) == false)
224 return secure_vector<uint8_t>();
225
226 valid_mask = 0xFF;
227 return masked_msg;
228 }
229 private:
230 const SM2_Encryption_PrivateKey& m_key;
231 RandomNumberGenerator& m_rng;
232 const std::string m_kdf_hash;
233 std::vector<BigInt> m_ws;
234 size_t m_hash_size;
235 };
236
237}
238
239std::unique_ptr<PK_Ops::Encryption>
241 const std::string& params,
242 const std::string& provider) const
243 {
244 if(provider == "base" || provider.empty())
245 {
246 const std::string kdf_hash = (params.empty() ? "SM3" : params);
247 return std::unique_ptr<PK_Ops::Encryption>(new SM2_Encryption_Operation(*this, rng, kdf_hash));
248 }
249
250 throw Provider_Not_Found(algo_name(), provider);
251 }
252
253std::unique_ptr<PK_Ops::Decryption>
255 const std::string& params,
256 const std::string& provider) const
257 {
258 if(provider == "base" || provider.empty())
259 {
260 const std::string kdf_hash = (params.empty() ? "SM3" : params);
261 return std::unique_ptr<PK_Ops::Decryption>(new SM2_Decryption_Operation(*this, rng, kdf_hash));
262 }
263
264 throw Provider_Not_Found(algo_name(), provider);
265 }
266
267}
static secure_vector< uint8_t > encode_1363(const BigInt &n, size_t bytes)
Definition: big_code.cpp:111
static std::unique_ptr< HashFunction > create_or_throw(const std::string &algo_spec, const std::string &provider="")
Definition: hash.cpp:344
static std::unique_ptr< KDF > create_or_throw(const std::string &algo_spec, const std::string &provider="")
Definition: kdf.cpp:226
std::unique_ptr< PK_Ops::Decryption > create_decryption_op(RandomNumberGenerator &rng, const std::string &params, const std::string &provider) const override
Definition: sm2_enc.cpp:254
std::string algo_name() const override
Definition: sm2.cpp:20
std::unique_ptr< PK_Ops::Encryption > create_encryption_op(RandomNumberGenerator &rng, const std::string &params, const std::string &provider) const override
Definition: sm2_enc.cpp:240
int(* final)(unsigned char *, CTX *)
std::string decrypt(const uint8_t input[], size_t input_len, const std::string &passphrase)
Definition: cryptobox.cpp:162
std::string encrypt(const uint8_t input[], size_t input_len, const std::string &passphrase, RandomNumberGenerator &rng)
Definition: cryptobox.cpp:43
Definition: alg_id.cpp:13
SM2_PublicKey SM2_Encryption_PublicKey
Definition: sm2.h:117
bool constant_time_compare(const uint8_t x[], const uint8_t y[], size_t len)
Definition: mem_ops.h:82
void xor_buf(uint8_t out[], const uint8_t in[], size_t length)
Definition: mem_ops.h:262
SM2_PrivateKey SM2_Encryption_PrivateKey
Definition: sm2.h:120
bool same_mem(const T *p1, const T *p2, size_t n)
Definition: mem_ops.h:217
@ SEQUENCE
Definition: asn1_obj.h:42
@ OCTET_STRING
Definition: asn1_obj.h:38
MechanismType hash