Botan 3.6.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
10#include <botan/ber_dec.h>
11#include <botan/der_enc.h>
12#include <botan/hash.h>
13#include <botan/kdf.h>
14#include <botan/pk_ops.h>
15#include <botan/internal/ct_utils.h>
16#include <botan/internal/fmt.h>
17
18namespace Botan {
19
20namespace {
21
22class SM2_Encryption_Operation final : public PK_Ops::Encryption {
23 public:
24 SM2_Encryption_Operation(const SM2_Encryption_PublicKey& key, std::string_view kdf_hash) :
25 m_group(key.domain()), m_peer(key._public_key()), m_ws(EC_Point::WORKSPACE_SIZE) {
26 m_hash = HashFunction::create_or_throw(kdf_hash);
27 m_kdf = KDF::create_or_throw(fmt("KDF2({})", kdf_hash));
28 }
29
30 size_t max_input_bits() const override {
31 // This is arbitrary, but assumes SM2 is used for key encapsulation
32 return 512;
33 }
34
35 size_t ciphertext_length(size_t ptext_len) const override {
36 const size_t elem_size = m_group.get_order_bytes();
37 const size_t der_overhead = 16;
38
39 return der_overhead + 2 * elem_size + m_hash->output_length() + ptext_len;
40 }
41
42 std::vector<uint8_t> encrypt(std::span<const uint8_t> msg, RandomNumberGenerator& rng) override {
43 const auto k = EC_Scalar::random(m_group, rng);
44
45 const EC_AffinePoint C1 = EC_AffinePoint::g_mul(k, rng, m_ws);
46
47 const EC_AffinePoint kPB = m_peer.mul(k, rng, m_ws);
48
49 const auto x2_bytes = kPB.x_bytes();
50 const auto y2_bytes = kPB.y_bytes();
51
52 secure_vector<uint8_t> kdf_input;
53 kdf_input += x2_bytes;
54 kdf_input += y2_bytes;
55
56 const auto kdf_output = m_kdf->derive_key(msg.size(), kdf_input);
57
58 std::vector<uint8_t> masked_msg(msg.size());
59 xor_buf(masked_msg, msg, kdf_output);
60
61 m_hash->update(x2_bytes);
62 m_hash->update(msg);
63 m_hash->update(y2_bytes);
64 const auto C3 = m_hash->final<std::vector<uint8_t>>();
65
66 std::vector<uint8_t> ctext;
67 DER_Encoder(ctext)
68 .start_sequence()
69 .encode(BigInt(C1.x_bytes()))
70 .encode(BigInt(C1.y_bytes()))
71 .encode(C3, ASN1_Type::OctetString)
72 .encode(masked_msg, ASN1_Type::OctetString)
73 .end_cons();
74
75 return ctext;
76 }
77
78 private:
79 const EC_Group m_group;
80 const EC_AffinePoint m_peer;
81 std::unique_ptr<HashFunction> m_hash;
82 std::unique_ptr<KDF> m_kdf;
83 std::vector<BigInt> m_ws;
84};
85
86class SM2_Decryption_Operation final : public PK_Ops::Decryption {
87 public:
88 SM2_Decryption_Operation(const SM2_Encryption_PrivateKey& key,
89 RandomNumberGenerator& rng,
90 std::string_view kdf_hash) :
91 m_group(key.domain()), m_x(key._private_key()), m_rng(rng) {
92 m_hash = HashFunction::create_or_throw(kdf_hash);
93
94 const std::string kdf_name = fmt("KDF2({})", kdf_hash);
95 m_kdf = KDF::create_or_throw(kdf_name);
96 }
97
98 size_t plaintext_length(size_t ptext_len) const override {
99 /*
100 * This ignores the DER encoding and so overestimates the
101 * plaintext length by 12 bytes or so
102 */
103 const size_t elem_size = m_group.get_order_bytes();
104
105 if(ptext_len < 2 * elem_size + m_hash->output_length()) {
106 return 0;
107 }
108
109 return ptext_len - (2 * elem_size + m_hash->output_length());
110 }
111
112 secure_vector<uint8_t> decrypt(uint8_t& valid_mask, std::span<const uint8_t> ctext) override {
113 const size_t p_bytes = m_group.get_p_bytes();
114
115 valid_mask = 0x00;
116
117 // Too short to be valid - no timing problem from early return
118 if(ctext.size() < 1 + p_bytes * 2 + m_hash->output_length()) {
119 return secure_vector<uint8_t>();
120 }
121
122 BigInt x1, y1;
123 secure_vector<uint8_t> C3, masked_msg;
124
125 BER_Decoder(ctext)
126 .start_sequence()
127 .decode(x1)
128 .decode(y1)
129 .decode(C3, ASN1_Type::OctetString)
130 .decode(masked_msg, ASN1_Type::OctetString)
131 .end_cons()
132 .verify_end();
133
134 std::vector<uint8_t> recode_ctext;
135 DER_Encoder(recode_ctext)
136 .start_sequence()
137 .encode(x1)
138 .encode(y1)
139 .encode(C3, ASN1_Type::OctetString)
140 .encode(masked_msg, ASN1_Type::OctetString)
141 .end_cons();
142
143 if(recode_ctext.size() != ctext.size()) {
144 return secure_vector<uint8_t>();
145 }
146
147 if(CT::is_equal(recode_ctext.data(), ctext.data(), ctext.size()).as_bool() == false) {
148 return secure_vector<uint8_t>();
149 }
150
151 auto C1 = EC_AffinePoint::from_bigint_xy(m_group, x1, y1);
152
153 // Here C1 is publically invalid, so no problem with early return:
154 if(!C1) {
155 return secure_vector<uint8_t>();
156 }
157
158 const auto dbC1 = C1->mul(m_x, m_rng, m_ws);
159 const auto x2_bytes = dbC1.x_bytes();
160 const auto y2_bytes = dbC1.y_bytes();
161
162 const auto kdf_output = m_kdf->derive_key(masked_msg.size(), dbC1.xy_bytes());
163
164 xor_buf(masked_msg.data(), kdf_output.data(), kdf_output.size());
165
166 m_hash->update(x2_bytes);
167 m_hash->update(masked_msg);
168 m_hash->update(y2_bytes);
169 const auto u = m_hash->final();
170
171 if(!CT::is_equal(u.data(), C3.data(), m_hash->output_length()).as_bool()) {
172 return secure_vector<uint8_t>();
173 }
174
175 valid_mask = 0xFF;
176 return masked_msg;
177 }
178
179 private:
180 const EC_Group m_group;
181 const EC_Scalar m_x;
182 RandomNumberGenerator& m_rng;
183 std::vector<BigInt> m_ws;
184 std::unique_ptr<HashFunction> m_hash;
185 std::unique_ptr<KDF> m_kdf;
186};
187
188} // namespace
189
190std::unique_ptr<PK_Ops::Encryption> SM2_PublicKey::create_encryption_op(RandomNumberGenerator& rng,
191 std::string_view params,
192 std::string_view provider) const {
193 BOTAN_UNUSED(rng);
194
195 if(provider == "base" || provider.empty()) {
196 if(params.empty()) {
197 return std::make_unique<SM2_Encryption_Operation>(*this, "SM3");
198 } else {
199 return std::make_unique<SM2_Encryption_Operation>(*this, params);
200 }
201 }
202
203 throw Provider_Not_Found(algo_name(), provider);
204}
205
206std::unique_ptr<PK_Ops::Decryption> SM2_PrivateKey::create_decryption_op(RandomNumberGenerator& rng,
207 std::string_view params,
208 std::string_view provider) const {
209 if(provider == "base" || provider.empty()) {
210 if(params.empty()) {
211 return std::make_unique<SM2_Decryption_Operation>(*this, rng, "SM3");
212 } else {
213 return std::make_unique<SM2_Decryption_Operation>(*this, rng, params);
214 }
215 }
216
217 throw Provider_Not_Found(algo_name(), provider);
218}
219
220} // namespace Botan
#define BOTAN_UNUSED
Definition assert.h:118
static std::optional< EC_AffinePoint > from_bigint_xy(const EC_Group &group, const BigInt &x, const BigInt &y)
Definition ec_apoint.cpp:54
static EC_AffinePoint g_mul(const EC_Scalar &scalar, RandomNumberGenerator &rng, std::vector< BigInt > &ws)
static EC_Scalar random(const EC_Group &group, RandomNumberGenerator &rng)
Definition ec_scalar.cpp:57
static std::unique_ptr< HashFunction > create_or_throw(std::string_view algo_spec, std::string_view provider="")
Definition hash.cpp:298
static std::unique_ptr< KDF > create_or_throw(std::string_view algo_spec, std::string_view provider="")
Definition kdf.cpp:199
std::unique_ptr< PK_Ops::Decryption > create_decryption_op(RandomNumberGenerator &rng, std::string_view params, std::string_view provider) const override
Definition sm2_enc.cpp:206
std::unique_ptr< PK_Ops::Encryption > create_encryption_op(RandomNumberGenerator &rng, std::string_view params, std::string_view provider) const override
Definition sm2_enc.cpp:190
std::string algo_name() const override
Definition sm2.cpp:20
int(* final)(unsigned char *, CTX *)
constexpr CT::Mask< T > is_equal(const T x[], const T y[], size_t len)
Definition ct_utils.h:759
std::string encrypt(const uint8_t input[], size_t input_len, std::string_view passphrase, RandomNumberGenerator &rng)
Definition cryptobox.cpp:42
std::string decrypt(const uint8_t input[], size_t input_len, std::string_view passphrase)
SM2_PublicKey SM2_Encryption_PublicKey
Definition sm2.h:123
std::string fmt(std::string_view format, const T &... args)
Definition fmt.h:53
SM2_PrivateKey SM2_Encryption_PrivateKey
Definition sm2.h:126
constexpr void xor_buf(ranges::contiguous_output_range< uint8_t > auto &&out, ranges::contiguous_range< uint8_t > auto &&in)
Definition mem_ops.h:341
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:61