sm2.c
Go to the documentation of this file.
1 /**
2  * @file sm2.c
3  * @brief SM2 signature algorithm
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneCRYPTO Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.4.0
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
33 
34 //Dependencies
35 #include "core/crypto.h"
36 #include "hash/hash_algorithms.h"
37 #include "ecc/sm2.h"
38 #include "debug.h"
39 
40 //Check crypto library configuration
41 #if (SM2_SUPPORT == ENABLED)
42 
43 //SM2 with SM3 OID (1.2.156.10197.1.501)
44 const uint8_t SM2_WITH_SM3_OID[8] = {0x2A, 0x81, 0x1C, 0xCF, 0x55, 0x01, 0x83, 0x75};
45 
46 
47 /**
48  * @brief SM2 signature generation
49  * @param[in] prngAlgo PRNG algorithm
50  * @param[in] prngContext Pointer to the PRNG context
51  * @param[in] params EC domain parameters
52  * @param[in] privateKey Signer's EC private key
53  * @param[in] hashAlgo Underlying hash function
54  * @param[in] id User's identity
55  * @param[in] idLen Length of the user's identity
56  * @param[in] message Message to be signed
57  * @param[in] messageLen Length of the message, in bytes
58  * @param[out] signature (r, s) integer pair
59  * @return Error code
60  **/
61 
62 error_t sm2GenerateSignature(const PrngAlgo *prngAlgo, void *prngContext,
63  const EcDomainParameters *params, const EcPrivateKey *privateKey,
64  const HashAlgo *hashAlgo, const char_t *id, size_t idLen,
65  const void *message, size_t messageLen, EcdsaSignature *signature)
66 {
67  error_t error;
68  Mpi e;
69  Mpi k;
70  Mpi t;
71  EcPoint p1;
72  EcPublicKey pa;
73  uint8_t buffer[32];
74 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
75  HashContext *hashContext;
76 #else
77  HashContext hashContext[1];
78 #endif
79 
80  //Check parameters
81  if(params == NULL || privateKey == NULL || hashAlgo == NULL || id == NULL ||
82  message == NULL || signature == NULL)
83  {
85  }
86 
87  //Sanity check
88  if(hashAlgo->digestSize > sizeof(buffer))
90 
91  //Debug message
92  TRACE_DEBUG("SM2 signature generation...\r\n");
93  TRACE_DEBUG(" private key:\r\n");
94  TRACE_DEBUG_MPI(" ", &privateKey->d);
95  TRACE_DEBUG(" identifier:\r\n");
96  TRACE_DEBUG_ARRAY(" ", id, idLen);
97  TRACE_DEBUG(" message:\r\n");
98  TRACE_DEBUG_ARRAY(" ", message, messageLen);
99 
100 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
101  //Allocate a memory buffer to hold the hash context
102  hashContext = cryptoAllocMem(hashAlgo->contextSize);
103  //Failed to allocate memory?
104  if(hashContext == NULL)
105  return ERROR_OUT_OF_MEMORY;
106 #endif
107 
108  //Initialize multiple precision integers
109  mpiInit(&e);
110  mpiInit(&k);
111  mpiInit(&t);
112  //Initialize EC points
113  ecInit(&p1);
114  //Initialize EC public key
115  ecInitPublicKey(&pa);
116 
117  //Derive the public key from the signer's EC private key
118  EC_CHECK(ecGeneratePublicKey(params, privateKey, &pa));
119 
120  //Calculate ZA = H256(ENTLA || IDA || a || b || xG || yG || xA || yA)
121  EC_CHECK(sm2ComputeZa(hashAlgo, hashContext, params, &pa, id, idLen,
122  buffer));
123 
124  //Let M~ = ZA || M and calculate Hv(M~)
125  hashAlgo->init(hashContext);
126  hashAlgo->update(hashContext, buffer, hashAlgo->digestSize);
127  hashAlgo->update(hashContext, message, messageLen);
128  hashAlgo->final(hashContext, buffer);
129 
130  //Let e = Hv(M~)
131  MPI_CHECK(mpiImport(&e, buffer, hashAlgo->digestSize,
133 
134  //SM2 signature generation process
135  do
136  {
137  do
138  {
139  //Pick a random number k in [1, q-1]
140  MPI_CHECK(mpiRandRange(&k, &params->q, prngAlgo, prngContext));
141 
142  //Debug message
143  TRACE_DEBUG(" k:\r\n");
144  TRACE_DEBUG_MPI(" ", &k);
145 
146  //Calculate the elliptic curve point (x1, y1) = [k]G
147  EC_CHECK(ecMult(params, &p1, &k, &params->g));
148  EC_CHECK(ecAffinify(params, &p1, &p1));
149 
150  //Calculate r = (e + x1) mod q
151  MPI_CHECK(mpiAddMod(&signature->r, &e, &p1.x, &params->q));
152 
153  //Calculate r + k
154  MPI_CHECK(mpiAdd(&t, &signature->r, &k));
155 
156  //If r = 0 or r + k = n, then generate a new random number
157  } while(mpiCompInt(&signature->r, 0) == 0 || mpiComp(&t, &params->q) == 0);
158 
159  //Calculate s = ((1 + dA)^-1 * (k - r * dA)) mod q
160  MPI_CHECK(mpiAddInt(&t, &privateKey->d, 1));
161  MPI_CHECK(mpiInvMod(&signature->s, &t, &params->q));
162  MPI_CHECK(mpiMulMod(&t, &signature->r, &privateKey->d, &params->q));
163  MPI_CHECK(mpiSubMod(&t, &k, &t, &params->q));
164  MPI_CHECK(mpiMulMod(&signature->s, &signature->s, &t, &params->q));
165 
166  //If s = 0, then generate a new random number
167  } while(mpiCompInt(&signature->s, 0) == 0);
168 
169  //Debug message
170  TRACE_DEBUG(" r:\r\n");
171  TRACE_DEBUG_MPI(" ", &signature->r);
172  TRACE_DEBUG(" s:\r\n");
173  TRACE_DEBUG_MPI(" ", &signature->s);
174 
175 end:
176  //Release multiple precision integers
177  mpiFree(&e);
178  mpiFree(&k);
179  mpiFree(&t);
180  //Release EC points
181  ecFree(&p1);
182  //Release EC public key
183  ecFreePublicKey(&pa);
184 
185 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
186  //Release hash context
187  cryptoFreeMem(hashContext);
188 #endif
189 
190  //Clean up side effects if necessary
191  if(error)
192  {
193  //Release (r, r) integer pair
194  mpiFree(&signature->r);
195  mpiFree(&signature->s);
196  }
197 
198  //Return status code
199  return error;
200 }
201 
202 
203 /**
204  * @brief SM2 signature verification
205  * @param[in] params EC domain parameters
206  * @param[in] publicKey Signer's SM2 public key
207  * @param[in] hashAlgo Underlying hash function
208  * @param[in] id User's identity
209  * @param[in] idLen Length of the user's identity
210  * @param[in] message Message whose signature is to be verified
211  * @param[in] messageLen Length of the message, in bytes
212  * @param[in] signature (r, s) integer pair
213  * @return Error code
214  **/
215 
217  const EcPublicKey *publicKey, const HashAlgo *hashAlgo,
218  const char_t *id, size_t idLen, const void *message, size_t messageLen,
219  const EcdsaSignature *signature)
220 {
221  error_t error;
222  Mpi e;
223  Mpi t;
224  Mpi r;
225  EcPoint pa;
226  EcPoint p1;
227  uint8_t buffer[32];
228 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
229  HashContext *hashContext;
230 #else
231  HashContext hashContext[1];
232 #endif
233 
234  //Check parameters
235  if(params == NULL || publicKey == NULL || hashAlgo == NULL || id == NULL ||
236  message == NULL || signature == NULL)
237  {
239  }
240 
241  //Sanity check
242  if(hashAlgo->digestSize > sizeof(buffer))
244 
245  //Debug message
246  TRACE_DEBUG("SM2 signature verification...\r\n");
247  TRACE_DEBUG(" public key X:\r\n");
248  TRACE_DEBUG_MPI(" ", &publicKey->q.x);
249  TRACE_DEBUG(" public key Y:\r\n");
250  TRACE_DEBUG_MPI(" ", &publicKey->q.y);
251  TRACE_DEBUG(" identifier:\r\n");
252  TRACE_DEBUG_ARRAY(" ", id, idLen);
253  TRACE_DEBUG(" message:\r\n");
254  TRACE_DEBUG_ARRAY(" ", message, messageLen);
255  TRACE_DEBUG(" r:\r\n");
256  TRACE_DEBUG_MPI(" ", &signature->r);
257  TRACE_DEBUG(" s:\r\n");
258  TRACE_DEBUG_MPI(" ", &signature->s);
259 
260  //The verifier shall check that 0 < r < q
261  if(mpiCompInt(&signature->r, 0) <= 0 ||
262  mpiComp(&signature->r, &params->q) >= 0)
263  {
264  //If the condition is violated, the signature shall be rejected as invalid
266  }
267 
268  //The verifier shall check that 0 < s < q
269  if(mpiCompInt(&signature->s, 0) <= 0 ||
270  mpiComp(&signature->s, &params->q) >= 0)
271  {
272  //If the condition is violated, the signature shall be rejected as invalid
274  }
275 
276 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
277  //Allocate a memory buffer to hold the hash context
278  hashContext = cryptoAllocMem(hashAlgo->contextSize);
279  //Failed to allocate memory?
280  if(hashContext == NULL)
281  return ERROR_OUT_OF_MEMORY;
282 #endif
283 
284  //Initialize multiple precision integers
285  mpiInit(&e);
286  mpiInit(&t);
287  mpiInit(&r);
288  //Initialize EC points
289  ecInit(&pa);
290  ecInit(&p1);
291 
292  //Calculate ZA = H256(ENTLA || IDA || a || b || xG || yG || xA || yA)
293  EC_CHECK(sm2ComputeZa(hashAlgo, hashContext, params, publicKey, id, idLen,
294  buffer));
295 
296  //Let M~ = ZA || M and calculate Hv(M~)
297  hashAlgo->init(hashContext);
298  hashAlgo->update(hashContext, buffer, hashAlgo->digestSize);
299  hashAlgo->update(hashContext, message, messageLen);
300  hashAlgo->final(hashContext, buffer);
301 
302  //Let e = Hv(M~)
303  MPI_CHECK(mpiImport(&e, buffer, hashAlgo->digestSize,
305 
306  //Calculate t = (r + s) mod q
307  MPI_CHECK(mpiAddMod(&t, &signature->r, &signature->s, &params->q));
308 
309  //Test if t = 0
310  if(mpiCompInt(&t, 0) == 0)
311  {
312  //Verification failed
313  error = ERROR_INVALID_SIGNATURE;
314  }
315  else
316  {
317  //Calculate the point (x1, y1)=[s]G + [t]PA
318  EC_CHECK(ecProjectify(params, &pa, &publicKey->q));
319  EC_CHECK(ecTwinMult(params, &p1, &signature->s, &params->g, &t, &pa));
320  EC_CHECK(ecAffinify(params, &p1, &p1));
321 
322  //Calculate R = (e + x1) mod q
323  MPI_CHECK(mpiAddMod(&r, &e, &p1.x, &params->q));
324 
325  //Verify that R = r
326  if(mpiComp(&r, &signature->r) == 0)
327  {
328  //Verification succeeded
329  error = NO_ERROR;
330  }
331  else
332  {
333  //Verification failed
334  error = ERROR_INVALID_SIGNATURE;
335  }
336  }
337 
338 end:
339  //Release multiple precision integers
340  mpiFree(&e);
341  mpiFree(&t);
342  mpiFree(&r);
343  //Release EC points
344  ecFree(&pa);
345  ecFree(&p1);
346 
347 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
348  //Release hash context
349  cryptoFreeMem(hashContext);
350 #endif
351 
352  //Return status code
353  return error;
354 }
355 
356 
357 /**
358  * @brief Calculate ZA
359  * @param[in] hashAlgo Hash function
360  * @param[in] hashContext Hash function context
361  * @param[in] params EC domain parameters
362  * @param[in] pa Public key of user A
363  * @param[in] ida Distinguishing identifier of user A
364  * @param[in] idaLen Length of the identifier
365  * @param[out] za Hash value of the distinguishing identifier of user A
366  **/
367 
368 error_t sm2ComputeZa(const HashAlgo *hashAlgo, HashContext *hashContext,
369  const EcDomainParameters *params, const EcPublicKey *pa, const char_t *ida,
370  size_t idaLen, uint8_t *za)
371 {
372  error_t error;
373  size_t n;
374  uint8_t buffer[32];
375 
376  //Get the length in octets of the prime modulus
377  n = mpiGetByteLength(&params->p);
378 
379  //Sanity check
380  if(n > sizeof(buffer))
382 
383  //Format ENTLA
384  STORE16BE(idaLen * 8, buffer);
385 
386  //Calculate ZA = H256(ENTLA || IDA || a || b || xG || yG || xA || yA)
387  hashAlgo->init(hashContext);
388 
389  //Digest ENTLA || IDA
390  hashAlgo->update(hashContext, buffer, sizeof(uint16_t));
391  hashAlgo->update(hashContext, ida, idaLen);
392 
393  //Convert the parameter a to bit string
394  error = mpiExport(&params->a, buffer, n, MPI_FORMAT_BIG_ENDIAN);
395  //Any error to report?
396  if(error)
397  return error;
398 
399  //Digest the parameter a
400  hashAlgo->update(hashContext, buffer, n);
401 
402  //Convert the parameter b to bit string
403  error = mpiExport(&params->b, buffer, n, MPI_FORMAT_BIG_ENDIAN);
404  //Any error to report?
405  if(error)
406  return error;
407 
408  //Digest the parameter b
409  hashAlgo->update(hashContext, buffer, n);
410 
411  //Convert the coordinate xG to bit string
412  error = mpiExport(&params->g.x, buffer, n, MPI_FORMAT_BIG_ENDIAN);
413  //Any error to report?
414  if(error)
415  return error;
416 
417  //Digest the coordinate xG
418  hashAlgo->update(hashContext, buffer, n);
419 
420  //Convert the coordinate yG to bit string
421  error = mpiExport(&params->g.y, buffer, n, MPI_FORMAT_BIG_ENDIAN);
422  //Any error to report?
423  if(error)
424  return error;
425 
426  //Digest the coordinate yG
427  hashAlgo->update(hashContext, buffer, n);
428 
429  //Convert the public key's coordinate xA to bit string
430  error = mpiExport(&pa->q.x, buffer, n, MPI_FORMAT_BIG_ENDIAN);
431  //Any error to report?
432  if(error)
433  return error;
434 
435  //Digest the public key's coordinate xA
436  hashAlgo->update(hashContext, buffer, n);
437 
438  //Convert the public key's coordinate yA to bit string
439  error = mpiExport(&pa->q.y, buffer, n, MPI_FORMAT_BIG_ENDIAN);
440  //Any error to report?
441  if(error)
442  return error;
443 
444  //Digest the public key's coordinate yA
445  hashAlgo->update(hashContext, buffer, n);
446 
447  //Finalize ZA calculation
448  hashAlgo->final(hashContext, za);
449 
450  //Debug message
451  TRACE_DEBUG(" ZA:\r\n");
452  TRACE_DEBUG_ARRAY(" ", za, hashAlgo->digestSize);
453 
454  //Return status code
455  return error;
456 }
457 
458 #endif
uint8_t message[]
Definition: chap.h:154
char char_t
Definition: compiler_port.h:48
#define STORE16BE(a, p)
Definition: cpu_endian.h:262
General definitions for cryptographic algorithms.
#define cryptoAllocMem(size)
Definition: crypto.h:765
#define cryptoFreeMem(p)
Definition: crypto.h:770
#define PrngAlgo
Definition: crypto.h:917
Debugging facilities.
#define TRACE_DEBUG_ARRAY(p, a, n)
Definition: debug.h:108
#define TRACE_DEBUG(...)
Definition: debug.h:107
#define TRACE_DEBUG_MPI(p, a)
Definition: debug.h:110
uint8_t n
error_t ecProjectify(const EcDomainParameters *params, EcPoint *r, const EcPoint *s)
Compute projective representation.
Definition: ec.c:495
__weak_func error_t ecAffinify(const EcDomainParameters *params, EcPoint *r, const EcPoint *s)
Recover affine representation.
Definition: ec.c:519
void ecInitPublicKey(EcPublicKey *key)
Initialize an EC public key.
Definition: ec.c:153
__weak_func error_t ecMult(const EcDomainParameters *params, EcPoint *r, const Mpi *d, const EcPoint *s)
Scalar multiplication.
Definition: ec.c:986
error_t ecTwinMult(const EcDomainParameters *params, EcPoint *r, const Mpi *d0, const EcPoint *s, const Mpi *d1, const EcPoint *t)
Twin multiplication.
Definition: ec.c:1135
void ecInit(EcPoint *r)
Initialize elliptic curve point.
Definition: ec.c:307
void ecFreePublicKey(EcPublicKey *key)
Release an EC public key.
Definition: ec.c:165
void ecFree(EcPoint *r)
Release an elliptic curve point.
Definition: ec.c:321
error_t ecGeneratePublicKey(const EcDomainParameters *params, const EcPrivateKey *privateKey, EcPublicKey *publicKey)
Derive the public key from an EC private key.
Definition: ec.c:275
#define EC_CHECK(f)
Definition: ec.h:39
error_t
Error codes.
Definition: error.h:43
@ ERROR_INVALID_SIGNATURE
Definition: error.h:226
@ NO_ERROR
Success.
Definition: error.h:44
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
Collection of hash algorithms.
uint8_t t
Definition: lldp_ext_med.h:212
error_t mpiMulMod(Mpi *r, const Mpi *a, const Mpi *b, const Mpi *p)
Modular multiplication.
error_t mpiRandRange(Mpi *r, const Mpi *p, const PrngAlgo *prngAlgo, void *prngContext)
Generate a random value in the range 1 to p-1.
Definition: mpi.c:564
error_t mpiSubMod(Mpi *r, const Mpi *a, const Mpi *b, const Mpi *p)
Modular subtraction.
Definition: mpi.c:1532
error_t mpiAddMod(Mpi *r, const Mpi *a, const Mpi *b, const Mpi *p)
Modular addition.
Definition: mpi.c:1509
int_t mpiCompInt(const Mpi *a, int_t b)
Compare a multiple precision integer with an integer.
Definition: mpi.c:382
int_t mpiComp(const Mpi *a, const Mpi *b)
Compare two multiple precision integers.
Definition: mpi.c:338
error_t mpiAddInt(Mpi *r, const Mpi *a, int_t b)
Add an integer to a multiple precision integer.
Definition: mpi.c:836
void mpiInit(Mpi *r)
Initialize a multiple precision integer.
Definition: mpi.c:48
error_t mpiImport(Mpi *r, const uint8_t *data, uint_t length, MpiFormat format)
Octet string to integer conversion.
Definition: mpi.c:624
uint_t mpiGetByteLength(const Mpi *a)
Get the actual length in bytes.
Definition: mpi.c:195
void mpiFree(Mpi *r)
Release a multiple precision integer.
Definition: mpi.c:64
error_t mpiExport(const Mpi *a, uint8_t *data, uint_t length, MpiFormat format)
Integer to octet string conversion.
Definition: mpi.c:709
error_t mpiAdd(Mpi *r, const Mpi *a, const Mpi *b)
Multiple precision addition.
Definition: mpi.c:787
#define MPI_CHECK(f)
Definition: mpi.h:52
@ MPI_FORMAT_BIG_ENDIAN
Definition: mpi.h:71
uint8_t r
Definition: ndp.h:346
error_t mpiInvMod(Mpi *r, const Mpi *a, const Mpi *p)
Modular inverse.
error_t sm2GenerateSignature(const PrngAlgo *prngAlgo, void *prngContext, const EcDomainParameters *params, const EcPrivateKey *privateKey, const HashAlgo *hashAlgo, const char_t *id, size_t idLen, const void *message, size_t messageLen, EcdsaSignature *signature)
SM2 signature generation.
Definition: sm2.c:62
error_t sm2ComputeZa(const HashAlgo *hashAlgo, HashContext *hashContext, const EcDomainParameters *params, const EcPublicKey *pa, const char_t *ida, size_t idaLen, uint8_t *za)
Calculate ZA.
Definition: sm2.c:368
const uint8_t SM2_WITH_SM3_OID[8]
Definition: sm2.c:44
error_t sm2VerifySignature(const EcDomainParameters *params, const EcPublicKey *publicKey, const HashAlgo *hashAlgo, const char_t *id, size_t idLen, const void *message, size_t messageLen, const EcdsaSignature *signature)
SM2 signature verification.
Definition: sm2.c:216
SM2 signature algorithm.
EC domain parameters.
Definition: ec.h:76
Mpi p
Prime.
Definition: ec.h:79
EcPoint g
Base point G.
Definition: ec.h:82
Mpi q
Order of the point G.
Definition: ec.h:83
Mpi a
Curve parameter a.
Definition: ec.h:80
Mpi b
Curve parameter b.
Definition: ec.h:81
EC point.
Definition: ec.h:64
Mpi y
y-coordinate
Definition: ec.h:66
Mpi x
x-coordinate
Definition: ec.h:65
EC private key.
Definition: ec.h:104
Mpi d
Private key.
Definition: ec.h:105
EC public key.
Definition: ec.h:94
EcPoint q
Public key.
Definition: ec.h:95
ECDSA signature.
Definition: ecdsa.h:49
Common interface for hash algorithms.
Definition: crypto.h:1014
HashAlgoFinal final
Definition: crypto.h:1026
size_t contextSize
Definition: crypto.h:1018
HashAlgoUpdate update
Definition: crypto.h:1025
size_t digestSize
Definition: crypto.h:1020
HashAlgoInit init
Definition: crypto.h:1024
Arbitrary precision integer.
Definition: mpi.h:80
Generic hash algorithm context.