Botan  2.4.0
Crypto and TLS for C++11
sm2.cpp
Go to the documentation of this file.
1 /*
2 * SM2 Signatures
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 #include <botan/internal/pk_ops_impl.h>
10 #include <botan/keypair.h>
11 #include <botan/reducer.h>
12 #include <botan/hash.h>
13 
14 namespace Botan {
15 
17  bool strong) const
18  {
19  if(!public_point().on_the_curve())
20  return false;
21 
22  if(!strong)
23  return true;
24 
25  return KeyPair::signature_consistency_check(rng, *this, "SM3");
26  }
27 
29  const secure_vector<uint8_t>& key_bits) :
30  EC_PrivateKey(alg_id, key_bits)
31  {
32  m_da_inv = inverse_mod(m_private_key + 1, domain().get_order());
33  }
34 
36  const EC_Group& domain,
37  const BigInt& x) :
38  EC_PrivateKey(rng, domain, x)
39  {
40  m_da_inv = inverse_mod(m_private_key + 1, domain.get_order());
41  }
42 
43 std::vector<uint8_t> sm2_compute_za(HashFunction& hash,
44  const std::string& user_id,
45  const EC_Group& domain,
46  const PointGFp& pubkey)
47  {
48  if(user_id.size() >= 8192)
49  throw Invalid_Argument("SM2 user id too long to represent");
50 
51  const uint16_t uid_len = static_cast<uint16_t>(8 * user_id.size());
52 
53  hash.update(get_byte(0, uid_len));
54  hash.update(get_byte(1, uid_len));
55  hash.update(user_id);
56 
57  const size_t p_bytes = domain.get_curve().get_p().bytes();
58 
59  hash.update(BigInt::encode_1363(domain.get_curve().get_a(), p_bytes));
60  hash.update(BigInt::encode_1363(domain.get_curve().get_b(), p_bytes));
61  hash.update(BigInt::encode_1363(domain.get_base_point().get_affine_x(), p_bytes));
62  hash.update(BigInt::encode_1363(domain.get_base_point().get_affine_y(), p_bytes));
63  hash.update(BigInt::encode_1363(pubkey.get_affine_x(), p_bytes));
64  hash.update(BigInt::encode_1363(pubkey.get_affine_y(), p_bytes));
65 
66  std::vector<uint8_t> za(hash.output_length());
67  hash.final(za.data());
68 
69  return za;
70  }
71 
72 namespace {
73 
74 /**
75 * SM2 signature operation
76 */
77 class SM2_Signature_Operation final : public PK_Ops::Signature
78  {
79  public:
80 
81  SM2_Signature_Operation(const SM2_Signature_PrivateKey& sm2,
82  const std::string& ident,
83  const std::string& hash) :
84  m_order(sm2.domain().get_order()),
85  m_base_point(sm2.domain().get_base_point(), m_order),
86  m_x(sm2.private_value()),
87  m_da_inv(sm2.get_da_inv()),
88  m_mod_order(m_order),
89  m_hash(HashFunction::create_or_throw(hash))
90  {
91  // ZA=H256(ENTLA || IDA || a || b || xG || yG || xA || yA)
92  m_za = sm2_compute_za(*m_hash, ident, sm2.domain(), sm2.public_point());
93  m_hash->update(m_za);
94  }
95 
96  void update(const uint8_t msg[], size_t msg_len) override
97  {
98  m_hash->update(msg, msg_len);
99  }
100 
101  secure_vector<uint8_t> sign(RandomNumberGenerator& rng) override;
102 
103  private:
104  const BigInt& m_order;
105  Blinded_Point_Multiply m_base_point;
106  const BigInt& m_x;
107  const BigInt& m_da_inv;
108  Modular_Reducer m_mod_order;
109 
110  std::vector<uint8_t> m_za;
111  std::unique_ptr<HashFunction> m_hash;
112  };
113 
115 SM2_Signature_Operation::sign(RandomNumberGenerator& rng)
116  {
117  const BigInt k = BigInt::random_integer(rng, 1, m_order);
118 
119  const PointGFp k_times_P = m_base_point.blinded_multiply(k, rng);
120 
121  const BigInt e = BigInt::decode(m_hash->final());
122  const BigInt r = m_mod_order.reduce(k_times_P.get_affine_x() + e);
123  const BigInt s = m_mod_order.multiply(m_da_inv, (k - r*m_x));
124 
125  // prepend ZA for next signature if any
126  m_hash->update(m_za);
127 
128  return BigInt::encode_fixed_length_int_pair(r, s, m_order.bytes());
129  }
130 
131 /**
132 * SM2 verification operation
133 */
134 class SM2_Verification_Operation final : public PK_Ops::Verification
135  {
136  public:
137  SM2_Verification_Operation(const SM2_Signature_PublicKey& sm2,
138  const std::string& ident,
139  const std::string& hash) :
140  m_base_point(sm2.domain().get_base_point()),
141  m_public_point(sm2.public_point()),
142  m_order(sm2.domain().get_order()),
143  m_mod_order(m_order),
144  m_hash(HashFunction::create_or_throw(hash))
145  {
146  // ZA=H256(ENTLA || IDA || a || b || xG || yG || xA || yA)
147  m_za = sm2_compute_za(*m_hash, ident, sm2.domain(), sm2.public_point());
148  m_hash->update(m_za);
149  }
150 
151  void update(const uint8_t msg[], size_t msg_len) override
152  {
153  m_hash->update(msg, msg_len);
154  }
155 
156  bool is_valid_signature(const uint8_t sig[], size_t sig_len) override;
157  private:
158  const PointGFp& m_base_point;
159  const PointGFp& m_public_point;
160  const BigInt& m_order;
161  // FIXME: should be offered by curve
162  Modular_Reducer m_mod_order;
163  std::vector<uint8_t> m_za;
164  std::unique_ptr<HashFunction> m_hash;
165  };
166 
167 bool SM2_Verification_Operation::is_valid_signature(const uint8_t sig[], size_t sig_len)
168  {
169  const BigInt e = BigInt::decode(m_hash->final());
170 
171  // Update for next verification
172  m_hash->update(m_za);
173 
174  if(sig_len != m_order.bytes()*2)
175  return false;
176 
177  const BigInt r(sig, sig_len / 2);
178  const BigInt s(sig + sig_len / 2, sig_len / 2);
179 
180  if(r <= 0 || r >= m_order || s <= 0 || s >= m_order)
181  return false;
182 
183  const BigInt t = m_mod_order.reduce(r + s);
184 
185  if(t == 0)
186  return false;
187 
188  const PointGFp R = multi_exponentiate(m_base_point, s, m_public_point, t);
189 
190  // ???
191  if(R.is_zero())
192  return false;
193 
194  return (m_mod_order.reduce(R.get_affine_x() + e) == r);
195  }
196 
197 }
198 
199 std::unique_ptr<PK_Ops::Verification>
201  const std::string& provider) const
202  {
203  if(provider == "base" || provider.empty())
204  {
205  std::string userid = "";
206  std::string hash = "SM3";
207 
208  auto comma = params.find(',');
209  if(comma == std::string::npos)
210  userid = params;
211  else
212  {
213  userid = params.substr(0, comma);
214  hash = params.substr(comma+1, std::string::npos);
215  }
216 
217  if (userid.empty())
218  {
219  // GM/T 0009-2012 specifies this as the default userid
220  userid = "1234567812345678";
221  }
222 
223  return std::unique_ptr<PK_Ops::Verification>(new SM2_Verification_Operation(*this, userid, hash));
224  }
225 
226  throw Provider_Not_Found(algo_name(), provider);
227  }
228 
229 std::unique_ptr<PK_Ops::Signature>
231  const std::string& params,
232  const std::string& provider) const
233  {
234  if(provider == "base" || provider.empty())
235  {
236  std::string userid = "";
237  std::string hash = "SM3";
238 
239  auto comma = params.find(',');
240  if(comma == std::string::npos)
241  userid = params;
242  else
243  {
244  userid = params.substr(0, comma);
245  hash = params.substr(comma+1, std::string::npos);
246  }
247 
248  if (userid.empty())
249  {
250  // GM/T 0009-2012 specifies this as the default userid
251  userid = "1234567812345678";
252  }
253 
254  return std::unique_ptr<PK_Ops::Signature>(new SM2_Signature_Operation(*this, userid, hash));
255  }
256 
257  throw Provider_Not_Found(algo_name(), provider);
258  }
259 
260 }
BigInt m_private_key
Definition: ecc_key.h:153
std::string algo_name() const override
Definition: sm2.h:44
const BigInt & private_value() const
Definition: ecc_key.cpp:112
const PointGFp & get_base_point() const
Definition: ec_group.h:96
static std::unique_ptr< HashFunction > create_or_throw(const std::string &algo_spec, const std::string &provider="")
Definition: hash.cpp:345
const PointGFp & public_point() const
Definition: ecc_key.h:57
const BigInt & get_da_inv() const
Definition: sm2.h:91
std::vector< uint8_t > sm2_compute_za(HashFunction &hash, const std::string &user_id, const EC_Group &domain, const PointGFp &pubkey)
Definition: sm2.cpp:43
static BigInt random_integer(RandomNumberGenerator &rng, const BigInt &min, const BigInt &max)
Definition: big_rand.cpp:45
BigInt get_affine_x() const
Definition: point_gfp.cpp:389
BigInt get_affine_y() const
Definition: point_gfp.cpp:401
void final(uint8_t out[])
Definition: buf_comp.h:89
bool signature_consistency_check(RandomNumberGenerator &rng, const Private_Key &private_key, const Public_Key &public_key, const std::string &padding)
Definition: keypair.cpp:49
const EC_Group & domain() const
Definition: ecc_key.h:72
BigInt inverse_mod(const BigInt &n, const BigInt &mod)
Definition: numthry.cpp:277
Definition: alg_id.cpp:13
size_t bytes() const
Definition: bigint.cpp:175
const BigInt & get_order() const
Definition: ec_group.h:102
const BigInt & get_b() const
Definition: curve_gfp.h:85
const BigInt & get_a() const
Definition: curve_gfp.h:80
std::unique_ptr< PK_Ops::Signature > create_signature_op(RandomNumberGenerator &rng, const std::string &params, const std::string &provider) const override
Definition: sm2.cpp:230
void update(const uint8_t in[], size_t length)
Definition: buf_comp.h:34
bool is_zero() const
Definition: point_gfp.h:179
static secure_vector< uint8_t > encode_1363(const BigInt &n, size_t bytes)
Definition: big_code.cpp:82
uint8_t get_byte(size_t byte_num, T input)
Definition: loadstor.h:39
const CurveGFp & get_curve() const
Definition: ec_group.h:90
SM2_Signature_PrivateKey(const AlgorithmIdentifier &alg_id, const secure_vector< uint8_t > &key_bits)
Definition: sm2.cpp:28
std::vector< T, secure_allocator< T > > secure_vector
Definition: secmem.h:88
static secure_vector< uint8_t > encode_fixed_length_int_pair(const BigInt &n1, const BigInt &n2, size_t bytes)
Definition: big_code.cpp:103
const BigInt & get_p() const
Definition: curve_gfp.h:91
bool check_key(RandomNumberGenerator &rng, bool) const override
Definition: sm2.cpp:16
std::unique_ptr< PK_Ops::Verification > create_verification_op(const std::string &params, const std::string &provider) const override
Definition: sm2.cpp:200
virtual size_t output_length() const =0
MechanismType hash
PointGFp multi_exponentiate(const PointGFp &p1, const BigInt &z1, const PointGFp &p2, const BigInt &z2)
Definition: point_gfp.cpp:247
static BigInt decode(const uint8_t buf[], size_t length, Base base=Binary)
Definition: big_code.cpp:114