• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 12805544433

16 Jan 2025 09:08AM UTC coverage: 90.876% (-0.4%) from 91.245%
12805544433

Pull #4540

github

web-flow
Merge cc1ceff51 into 9b798efbb
Pull Request #4540: PKCS #11 Version 3.2 Support

93425 of 102805 relevant lines covered (90.88%)

11409241.89 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.33
/src/lib/pubkey/sm2/sm2_enc.cpp
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

18
namespace Botan {
19

20
namespace {
21

22
class SM2_Encryption_Operation final : public PK_Ops::Encryption {
×
23
   public:
24
      SM2_Encryption_Operation(const SM2_Encryption_PublicKey& key, std::string_view kdf_hash) :
6✔
25
            m_group(key.domain()), m_peer(key._public_ec_point()) {
6✔
26
         m_hash = HashFunction::create_or_throw(kdf_hash);
6✔
27
         m_kdf = KDF::create_or_throw(fmt("KDF2({})", kdf_hash));
6✔
28
      }
6✔
29

30
      size_t max_input_bits() const override {
5✔
31
         // This is arbitrary, but assumes SM2 is used for key encapsulation
32
         return 512;
5✔
33
      }
34

35
      size_t ciphertext_length(size_t ptext_len) const override {
6✔
36
         const size_t elem_size = m_group.get_order_bytes();
6✔
37
         const size_t der_overhead = 16;
6✔
38

39
         return der_overhead + 2 * elem_size + m_hash->output_length() + ptext_len;
6✔
40
      }
41

42
      std::vector<uint8_t> encrypt(std::span<const uint8_t> msg, RandomNumberGenerator& rng) override {
6✔
43
         const auto k = EC_Scalar::random(m_group, rng);
6✔
44

45
         const EC_AffinePoint C1 = EC_AffinePoint::g_mul(k, rng, m_ws);
6✔
46

47
         const EC_AffinePoint kPB = m_peer.mul(k, rng, m_ws);
6✔
48

49
         const auto x2_bytes = kPB.x_bytes();
6✔
50
         const auto y2_bytes = kPB.y_bytes();
6✔
51

52
         secure_vector<uint8_t> kdf_input;
6✔
53
         kdf_input += x2_bytes;
6✔
54
         kdf_input += y2_bytes;
6✔
55

56
         const auto kdf_output = m_kdf->derive_key(msg.size(), kdf_input);
6✔
57

58
         std::vector<uint8_t> masked_msg(msg.size());
6✔
59
         xor_buf(masked_msg, msg, kdf_output);
6✔
60

61
         m_hash->update(x2_bytes);
6✔
62
         m_hash->update(msg);
6✔
63
         m_hash->update(y2_bytes);
6✔
64
         const auto C3 = m_hash->final<std::vector<uint8_t>>();
6✔
65

66
         std::vector<uint8_t> ctext;
6✔
67
         DER_Encoder(ctext)
6✔
68
            .start_sequence()
6✔
69
            .encode(BigInt(C1.x_bytes()))
18✔
70
            .encode(BigInt(C1.y_bytes()))
18✔
71
            .encode(C3, ASN1_Type::OctetString)
6✔
72
            .encode(masked_msg, ASN1_Type::OctetString)
6✔
73
            .end_cons();
6✔
74

75
         return ctext;
12✔
76
      }
36✔
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

86
class SM2_Decryption_Operation final : public PK_Ops::Decryption {
×
87
   public:
88
      SM2_Decryption_Operation(const SM2_Encryption_PrivateKey& key,
6✔
89
                               RandomNumberGenerator& rng,
90
                               std::string_view kdf_hash) :
6✔
91
            m_group(key.domain()), m_x(key._private_key()), m_rng(rng) {
6✔
92
         m_hash = HashFunction::create_or_throw(kdf_hash);
6✔
93

94
         const std::string kdf_name = fmt("KDF2({})", kdf_hash);
6✔
95
         m_kdf = KDF::create_or_throw(kdf_name);
6✔
96
      }
6✔
97

98
      size_t plaintext_length(size_t ptext_len) const override {
5✔
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();
5✔
104

105
         if(ptext_len < 2 * elem_size + m_hash->output_length()) {
5✔
106
            return 0;
107
         }
108

109
         return ptext_len - (2 * elem_size + m_hash->output_length());
5✔
110
      }
111

112
      secure_vector<uint8_t> decrypt(uint8_t& valid_mask, std::span<const uint8_t> ctext) override {
106✔
113
         const size_t p_bytes = m_group.get_p_bytes();
106✔
114

115
         valid_mask = 0x00;
106✔
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()) {
106✔
119
            return secure_vector<uint8_t>();
×
120
         }
121

122
         BigInt x1, y1;
106✔
123
         secure_vector<uint8_t> C3, masked_msg;
106✔
124

125
         BER_Decoder(ctext)
211✔
126
            .start_sequence()
218✔
127
            .decode(x1)
104✔
128
            .decode(y1)
102✔
129
            .decode(C3, ASN1_Type::OctetString)
99✔
130
            .decode(masked_msg, ASN1_Type::OctetString)
97✔
131
            .end_cons()
97✔
132
            .verify_end();
97✔
133

134
         std::vector<uint8_t> recode_ctext;
97✔
135
         DER_Encoder(recode_ctext)
194✔
136
            .start_sequence()
97✔
137
            .encode(x1)
97✔
138
            .encode(y1)
97✔
139
            .encode(C3, ASN1_Type::OctetString)
97✔
140
            .encode(masked_msg, ASN1_Type::OctetString)
97✔
141
            .end_cons();
97✔
142

143
         if(recode_ctext.size() != ctext.size()) {
97✔
144
            return secure_vector<uint8_t>();
×
145
         }
146

147
         if(CT::is_equal(recode_ctext.data(), ctext.data(), ctext.size()).as_bool() == false) {
194✔
148
            return secure_vector<uint8_t>();
×
149
         }
150

151
         auto C1 = EC_AffinePoint::from_bigint_xy(m_group, x1, y1);
97✔
152

153
         // Here C1 is publically invalid, so no problem with early return:
154
         if(!C1) {
97✔
155
            return secure_vector<uint8_t>();
62✔
156
         }
157

158
         const auto dbC1 = C1->mul(m_x, m_rng, m_ws);
35✔
159
         const auto x2_bytes = dbC1.x_bytes();
35✔
160
         const auto y2_bytes = dbC1.y_bytes();
35✔
161

162
         const auto kdf_output = m_kdf->derive_key(masked_msg.size(), dbC1.xy_bytes());
35✔
163

164
         xor_buf(masked_msg.data(), kdf_output.data(), kdf_output.size());
35✔
165

166
         m_hash->update(x2_bytes);
35✔
167
         m_hash->update(masked_msg);
35✔
168
         m_hash->update(y2_bytes);
35✔
169
         const auto u = m_hash->final();
35✔
170

171
         if(!CT::is_equal(u.data(), C3.data(), m_hash->output_length()).as_bool()) {
70✔
172
            return secure_vector<uint8_t>();
29✔
173
         }
174

175
         valid_mask = 0xFF;
6✔
176
         return masked_msg;
6✔
177
      }
743✔
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

190
std::unique_ptr<PK_Ops::Encryption> SM2_PublicKey::create_encryption_op(RandomNumberGenerator& rng,
21✔
191
                                                                        std::string_view params,
192
                                                                        std::string_view provider) const {
193
   BOTAN_UNUSED(rng);
21✔
194

195
   if(provider == "base" || provider.empty()) {
26✔
196
      if(params.empty()) {
6✔
197
         return std::make_unique<SM2_Encryption_Operation>(*this, "SM3");
1✔
198
      } else {
199
         return std::make_unique<SM2_Encryption_Operation>(*this, params);
5✔
200
      }
201
   }
202

203
   throw Provider_Not_Found(algo_name(), provider);
30✔
204
}
205

206
std::unique_ptr<PK_Ops::Decryption> SM2_PrivateKey::create_decryption_op(RandomNumberGenerator& rng,
21✔
207
                                                                         std::string_view params,
208
                                                                         std::string_view provider) const {
209
   if(provider == "base" || provider.empty()) {
26✔
210
      if(params.empty()) {
6✔
211
         return std::make_unique<SM2_Decryption_Operation>(*this, rng, "SM3");
1✔
212
      } else {
213
         return std::make_unique<SM2_Decryption_Operation>(*this, rng, params);
5✔
214
      }
215
   }
216

217
   throw Provider_Not_Found(algo_name(), provider);
30✔
218
}
219

220
}  // namespace Botan
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc