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

randombit / botan / 14732017105

29 Apr 2025 01:07PM UTC coverage: 90.895% (-0.01%) from 90.907%
14732017105

Pull #4776

github

web-flow
Merge f137f1d27 into dbe524bf5
Pull Request #4776: Add support for null ciphers

95954 of 105566 relevant lines covered (90.89%)

12971514.27 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/mem_ops.h>
15
#include <botan/pk_ops.h>
16
#include <botan/internal/ct_utils.h>
17
#include <botan/internal/fmt.h>
18

19
namespace Botan {
20

21
namespace {
22

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

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

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

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

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

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

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

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

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

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

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

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

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

76
         return ctext;
12✔
77
      }
36✔
78

79
   private:
80
      const EC_Group m_group;
81
      const EC_AffinePoint m_peer;
82
      std::unique_ptr<HashFunction> m_hash;
83
      std::unique_ptr<KDF> m_kdf;
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)
102✔
128
            .decode(y1)
100✔
129
            .decode(C3, ASN1_Type::OctetString)
97✔
130
            .decode(masked_msg, ASN1_Type::OctetString)
95✔
131
            .end_cons()
95✔
132
            .verify_end();
95✔
133

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

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

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

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

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

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

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

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

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

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

175
         valid_mask = 0xFF;
6✔
176
         return masked_msg;
6✔
177
      }
563✔
178

179
   private:
180
      const EC_Group m_group;
181
      const EC_Scalar m_x;
182
      RandomNumberGenerator& m_rng;
183
      std::unique_ptr<HashFunction> m_hash;
184
      std::unique_ptr<KDF> m_kdf;
185
};
186

187
}  // namespace
188

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

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

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

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

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

219
}  // 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