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