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

randombit / botan / 11087146043

28 Sep 2024 09:28PM UTC coverage: 92.003% (+0.7%) from 91.274%
11087146043

push

github

web-flow
Create terraform.yml

82959 of 90170 relevant lines covered (92.0%)

9376319.11 hits per line

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

96.64
/src/lib/pubkey/sm2/sm2.cpp
1
/*
2
* SM2 Signatures
3
* (C) 2017,2018 Ribose Inc
4
* (C) 2018 Jack Lloyd
5
*
6
* Botan is released under the Simplified BSD License (see license.txt)
7
*/
8

9
#include <botan/sm2.h>
10

11
#include <botan/hash.h>
12
#include <botan/numthry.h>
13
#include <botan/internal/keypair.h>
14
#include <botan/internal/loadstor.h>
15
#include <botan/internal/parsing.h>
16
#include <botan/internal/pk_ops_impl.h>
17
#include <botan/internal/point_mul.h>
18

19
namespace Botan {
20

21
std::string SM2_PublicKey::algo_name() const {
203✔
22
   return "SM2";
203✔
23
}
24

25
std::unique_ptr<Public_Key> SM2_PrivateKey::public_key() const {
7✔
26
   return std::make_unique<SM2_Signature_PublicKey>(domain(), public_point());
7✔
27
}
28

29
bool SM2_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const {
4✔
30
   if(!EC_PrivateKey::check_key(rng, strong)) {
4✔
31
      return false;
32
   }
33

34
   // SM2 has an oddity in private key generation when compared to
35
   // other EC*DSA style signature algorithms described in ISO14888-3:
36
   // the private key x MUST be in ]0, q-1[ instead of ]0, q[.
37
   if(m_private_key < 1 || m_private_key >= m_domain_params.get_order() - 1) {
8✔
38
      return false;
39
   }
40

41
   if(!strong) {
4✔
42
      return true;
43
   }
44

45
   return KeyPair::signature_consistency_check(rng, *this, "user@example.com,SM3");
2✔
46
}
47

48
SM2_PrivateKey::SM2_PrivateKey(const AlgorithmIdentifier& alg_id, std::span<const uint8_t> key_bits) :
20✔
49
      EC_PrivateKey(alg_id, key_bits) {
20✔
50
   m_da_inv = domain().inverse_mod_order(m_private_key + 1);
40✔
51
}
20✔
52

53
SM2_PrivateKey::SM2_PrivateKey(RandomNumberGenerator& rng, const EC_Group& domain, const BigInt& x) :
30✔
54
      EC_PrivateKey(rng, domain, x) {
30✔
55
   m_da_inv = domain.inverse_mod_order(m_private_key + 1);
60✔
56
}
30✔
57

58
std::vector<uint8_t> sm2_compute_za(HashFunction& hash,
38✔
59
                                    std::string_view user_id,
60
                                    const EC_Group& domain,
61
                                    const EC_Point& pubkey) {
62
   if(user_id.size() >= 8192) {
38✔
63
      throw Invalid_Argument("SM2 user id too long to represent");
×
64
   }
65

66
   const uint16_t uid_len = static_cast<uint16_t>(8 * user_id.size());
38✔
67

68
   hash.update(get_byte<0>(uid_len));
38✔
69
   hash.update(get_byte<1>(uid_len));
38✔
70
   hash.update(user_id);
38✔
71

72
   const size_t p_bytes = domain.get_p_bytes();
38✔
73

74
   hash.update(BigInt::encode_1363(domain.get_a(), p_bytes));
38✔
75
   hash.update(BigInt::encode_1363(domain.get_b(), p_bytes));
38✔
76
   hash.update(BigInt::encode_1363(domain.get_g_x(), p_bytes));
38✔
77
   hash.update(BigInt::encode_1363(domain.get_g_y(), p_bytes));
38✔
78
   hash.update(BigInt::encode_1363(pubkey.get_affine_x(), p_bytes));
76✔
79
   hash.update(BigInt::encode_1363(pubkey.get_affine_y(), p_bytes));
76✔
80

81
   std::vector<uint8_t> za(hash.output_length());
38✔
82
   hash.final(za.data());
38✔
83

84
   return za;
38✔
85
}
×
86

87
namespace {
88

89
/**
90
* SM2 signature operation
91
*/
92
class SM2_Signature_Operation final : public PK_Ops::Signature {
×
93
   public:
94
      SM2_Signature_Operation(const SM2_PrivateKey& sm2, std::string_view ident, std::string_view hash) :
20✔
95
            m_group(sm2.domain()), m_x(sm2.private_value()), m_da_inv(sm2.get_da_inv()) {
20✔
96
         if(hash == "Raw") {
37✔
97
            // m_hash is null, m_za is empty
98
         } else {
99
            m_hash = HashFunction::create_or_throw(hash);
18✔
100
            // ZA=H256(ENTLA || IDA || a || b || xG || yG || xA || yA)
101
            m_za = sm2_compute_za(*m_hash, ident, m_group, sm2.public_point());
18✔
102
            m_hash->update(m_za);
18✔
103
         }
104
      }
20✔
105

106
      size_t signature_length() const override { return 2 * m_group.get_order_bytes(); }
10✔
107

108
      void update(const uint8_t msg[], size_t msg_len) override {
28✔
109
         if(m_hash) {
28✔
110
            m_hash->update(msg, msg_len);
26✔
111
         } else {
112
            m_digest.insert(m_digest.end(), msg, msg + msg_len);
2✔
113
         }
114
      }
28✔
115

116
      secure_vector<uint8_t> sign(RandomNumberGenerator& rng) override;
117

118
      std::string hash_function() const override { return m_hash ? m_hash->name() : "Raw"; }
4✔
119

120
   private:
121
      const EC_Group m_group;
122
      const BigInt m_x;
123
      const BigInt m_da_inv;
124

125
      std::vector<uint8_t> m_za;
126
      secure_vector<uint8_t> m_digest;
127
      std::unique_ptr<HashFunction> m_hash;
128
      std::vector<BigInt> m_ws;
129
};
130

131
secure_vector<uint8_t> SM2_Signature_Operation::sign(RandomNumberGenerator& rng) {
29✔
132
   BigInt e;
29✔
133
   if(m_hash) {
29✔
134
      e = BigInt::decode(m_hash->final());
54✔
135
      // prepend ZA for next signature if any
136
      m_hash->update(m_za);
27✔
137
   } else {
138
      e = BigInt::decode(m_digest);
4✔
139
      m_digest.clear();
2✔
140
   }
141

142
   const BigInt k = m_group.random_scalar(rng);
29✔
143

144
   const BigInt r = m_group.mod_order(m_group.blinded_base_point_multiply_x(k, rng, m_ws) + e);
58✔
145
   const BigInt s = m_group.multiply_mod_order(m_da_inv, m_group.mod_order(k - r * m_x));
87✔
146

147
   return BigInt::encode_fixed_length_int_pair(r, s, m_group.get_order().bytes());
58✔
148
}
149

150
/**
151
* SM2 verification operation
152
*/
153
class SM2_Verification_Operation final : public PK_Ops::Verification {
×
154
   public:
155
      SM2_Verification_Operation(const SM2_PublicKey& sm2, std::string_view ident, std::string_view hash) :
20✔
156
            m_group(sm2.domain()), m_gy_mul(m_group.get_base_point(), sm2.public_point()) {
20✔
157
         if(hash == "Raw") {
37✔
158
            // m_hash is null, m_za is empty
159
         } else {
160
            m_hash = HashFunction::create_or_throw(hash);
18✔
161
            // ZA=H256(ENTLA || IDA || a || b || xG || yG || xA || yA)
162
            m_za = sm2_compute_za(*m_hash, ident, m_group, sm2.public_point());
18✔
163
            m_hash->update(m_za);
18✔
164
         }
165
      }
20✔
166

167
      void update(const uint8_t msg[], size_t msg_len) override {
186✔
168
         if(m_hash) {
186✔
169
            m_hash->update(msg, msg_len);
162✔
170
         } else {
171
            m_digest.insert(m_digest.end(), msg, msg + msg_len);
24✔
172
         }
173
      }
186✔
174

175
      bool is_valid_signature(const uint8_t sig[], size_t sig_len) override;
176

177
      std::string hash_function() const override { return m_hash ? m_hash->name() : "Raw"; }
4✔
178

179
   private:
180
      const EC_Group m_group;
181
      const EC_Point_Multi_Point_Precompute m_gy_mul;
182
      secure_vector<uint8_t> m_digest;
183
      std::vector<uint8_t> m_za;
184
      std::unique_ptr<HashFunction> m_hash;
185
};
186

187
bool SM2_Verification_Operation::is_valid_signature(const uint8_t sig[], size_t sig_len) {
187✔
188
   BigInt e;
187✔
189
   if(m_hash) {
187✔
190
      e = BigInt::decode(m_hash->final());
326✔
191
      // prepend ZA for next signature if any
192
      m_hash->update(m_za);
163✔
193
   } else {
194
      e = BigInt::decode(m_digest);
48✔
195
      m_digest.clear();
24✔
196
   }
197

198
   if(sig_len != m_group.get_order().bytes() * 2) {
187✔
199
      return false;
200
   }
201

202
   const BigInt r(sig, sig_len / 2);
187✔
203
   const BigInt s(sig + sig_len / 2, sig_len / 2);
187✔
204

205
   if(r <= 0 || r >= m_group.get_order() || s <= 0 || s >= m_group.get_order()) {
366✔
206
      return false;
9✔
207
   }
208

209
   const BigInt t = m_group.mod_order(r + s);
178✔
210

211
   if(t == 0) {
178✔
212
      return false;
213
   }
214

215
   const EC_Point R = m_gy_mul.multi_exp(s, t);
178✔
216

217
   // ???
218
   if(R.is_zero()) {
356✔
219
      return false;
220
   }
221

222
   return (m_group.mod_order(R.get_affine_x() + e) == r);
890✔
223
}
926✔
224

225
void parse_sm2_param_string(std::string_view params, std::string& userid, std::string& hash) {
40✔
226
   // GM/T 0009-2012 specifies this as the default userid
227
   const std::string default_userid = "1234567812345678";
40✔
228

229
   // defaults:
230
   userid = default_userid;
40✔
231
   hash = "SM3";
40✔
232

233
   /*
234
   * SM2 parameters have the following possible formats:
235
   * Ident [since 2.2.0]
236
   * Ident,Hash [since 2.3.0]
237
   */
238

239
   auto comma = params.find(',');
40✔
240
   if(comma == std::string::npos) {
40✔
241
      userid = params;
58✔
242
   } else {
243
      userid = params.substr(0, comma);
22✔
244
      hash = params.substr(comma + 1, std::string::npos);
44✔
245
   }
246
}
40✔
247

248
}  // namespace
249

250
std::unique_ptr<Private_Key> SM2_PublicKey::generate_another(RandomNumberGenerator& rng) const {
2✔
251
   return std::make_unique<SM2_PrivateKey>(rng, domain());
4✔
252
}
253

254
std::unique_ptr<PK_Ops::Verification> SM2_PublicKey::create_verification_op(std::string_view params,
41✔
255
                                                                            std::string_view provider) const {
256
   if(provider == "base" || provider.empty()) {
50✔
257
      std::string userid, hash;
20✔
258
      parse_sm2_param_string(params, userid, hash);
20✔
259
      return std::make_unique<SM2_Verification_Operation>(*this, userid, hash);
20✔
260
   }
40✔
261

262
   throw Provider_Not_Found(algo_name(), provider);
42✔
263
}
264

265
std::unique_ptr<PK_Ops::Signature> SM2_PrivateKey::create_signature_op(RandomNumberGenerator& /*rng*/,
41✔
266
                                                                       std::string_view params,
267
                                                                       std::string_view provider) const {
268
   if(provider == "base" || provider.empty()) {
50✔
269
      std::string userid, hash;
20✔
270
      parse_sm2_param_string(params, userid, hash);
20✔
271
      return std::make_unique<SM2_Signature_Operation>(*this, userid, hash);
20✔
272
   }
40✔
273

274
   throw Provider_Not_Found(algo_name(), provider);
42✔
275
}
276

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

© 2026 Coveralls, Inc