stm32wbxx_crypto_pkc.c
Go to the documentation of this file.
1 /**
2  * @file stm32wbxx_crypto_pkc.c
3  * @brief STM32WB public-key hardware accelerator (PKA)
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2025 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.5.0
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
33 
34 //Dependencies
35 #include "stm32wbxx.h"
36 #include "stm32wbxx_hal.h"
37 #include "core/crypto.h"
40 #include "pkc/rsa.h"
41 #include "ecc/ec.h"
42 #include "ecc/ec_misc.h"
43 #include "ecc/ecdsa.h"
44 #include "debug.h"
45 
46 //Check crypto library configuration
47 #if (STM32WBXX_CRYPTO_PKC_SUPPORT == ENABLED)
48 
49 
50 /**
51  * @brief PKA module initialization
52  * @return Error code
53  **/
54 
56 {
57  //Enable PKA peripheral clock
58  __HAL_RCC_PKA_CLK_ENABLE();
59 
60  //Reset the PKA peripheral
61  PKA->CR = 0;
62 
63  //Enable the PKA peripheral
64  while((PKA->CR & PKA_CR_EN) == 0)
65  {
66  PKA->CR = PKA_CR_EN;
67  }
68 
69  //Clear flags
70  PKA->CLRFR = PKA_CLRFR_ADDRERRFC | PKA_CLRFR_RAMERRFC | PKA_CLRFR_PROCENDFC;
71 
72  //Successful processing
73  return NO_ERROR;
74 }
75 
76 
77 /**
78  * @brief Import byte array
79  * @param[in] src Pointer to the byte array
80  * @param[in] srcLen Length of the array to be copied, in bytes
81  * @param[in] destLen Length of the operand, in bits
82  * @param[in] offset PKA ram offset
83  **/
84 
85 void pkaImportArray(const uint8_t *src, size_t srcLen, uint_t destLen,
86  uint_t offset)
87 {
88  uint_t i;
89  uint_t j;
90  uint32_t temp;
91 
92  //Get the length of the operand, in words
93  destLen = (destLen + 31) / 32;
94 
95  //Copy the array to the PKA RAM
96  for(i = 0, j = 0; i < srcLen; i++)
97  {
98  switch(i % 4)
99  {
100  case 0:
101  temp = src[srcLen - i - 1];
102  break;
103  case 1:
104  temp |= src[srcLen - i - 1] << 8;
105  break;
106  case 2:
107  temp |= src[srcLen - i - 1] << 16;
108  break;
109  default:
110  temp |= src[srcLen - i - 1] << 24;
111  PKA->RAM[offset + j] = temp;
112  j++;
113  break;
114  }
115  }
116 
117  //Pad the operand with zeroes
118  for(; i < (destLen * 4); i++)
119  {
120  switch(i % 4)
121  {
122  case 0:
123  temp = 0;
124  break;
125  case 3:
126  PKA->RAM[offset + j] = temp;
127  j++;
128  break;
129  default:
130  break;
131  }
132  }
133 
134  //An additional word with all bits equal to zero must be added
135  PKA->RAM[offset + j] = 0;
136 }
137 
138 
139 /**
140  * @brief Import scalar
141  * @param[in] src Pointer to the scalar
142  * @param[in] length Length of the operand, in bits
143  * @param[in] offset PKA ram offset
144  **/
145 
146 void pkaImportScalar(const uint32_t *src, uint_t length, uint_t offset)
147 {
148  uint_t i;
149 
150  //Get the length of the operand, in words
151  length = (length + 31) / 32;
152 
153  //Copy the scalar to the PKA RAM
154  for(i = 0; i < length; i++)
155  {
156  PKA->RAM[offset + i] = src[i];
157  }
158 
159  //An additional word with all bits equal to zero must be added
160  PKA->RAM[offset + i] = 0;
161 }
162 
163 
164 /**
165  * @brief Import multiple-precision integer
166  * @param[in] src Pointer to the multiple-precision integer
167  * @param[in] length Length of the operand, in bits
168  * @param[in] offset PKA ram offset
169  **/
170 
171 void pkaImportMpi(const Mpi *src, uint_t length, uint_t offset)
172 {
173  uint_t i;
174  uint_t n;
175 
176  //Get the length of the operand, in words
177  length = (length + 31) / 32;
178 
179  //Get the actual length of the multiple-precision integer, in words
180  n = mpiGetLength(src);
181 
182  //Copy the multiple-precision integer to the PKA RAM
183  for(i = 0; i < n && i < length; i++)
184  {
185  PKA->RAM[offset + i] = src->data[i];
186  }
187 
188  //Pad the operand with zeroes
189  for(; i < length; i++)
190  {
191  PKA->RAM[offset + i] = 0;
192  }
193 
194  //An additional word with all bits equal to zero must be added
195  PKA->RAM[offset + i] = 0;
196 }
197 
198 
199 /**
200  * @brief Export scalar
201  * @param[out] dest Pointer to the scalar
202  * @param[in] length Length of the operand, in bits
203  * @param[in] offset PKA ram offset
204  **/
205 
206 void pkaExportScalar(uint32_t *dest, uint_t length, uint_t offset)
207 {
208  uint_t i;
209 
210  //Get the length of the operand, in words
211  length = (length + 31) / 32;
212 
213  //Copy the scalar from the PKA RAM
214  for(i = 0; i < length; i++)
215  {
216  dest[i] = PKA->RAM[offset + i];
217  }
218 }
219 
220 
221 /**
222  * @brief Export multiple-precision integer
223  * @param[out] dest Pointer to the multiple-precision integer
224  * @param[in] length Length of the operand, in bits
225  * @param[in] offset PKA ram offset
226  * @return Error code
227  **/
228 
230 {
231  error_t error;
232  uint_t i;
233 
234  //Get the length of the operand, in words
235  length = (length + 31) / 32;
236 
237  //Skip trailing zeroes
238  while(length > 0 && PKA->RAM[offset + length - 1] == 0)
239  {
240  length--;
241  }
242 
243  //Ajust the size of the multiple precision integer
244  error = mpiGrow(dest, length);
245 
246  //Check status code
247  if(!error)
248  {
249  //Copy the multiple-precision integer from the PKA RAM
250  for(i = 0; i < length; i++)
251  {
252  dest->data[i] = PKA->RAM[offset + i];
253  }
254 
255  //Pad the resulting value with zeroes
256  for(; i < dest->size; i++)
257  {
258  dest->data[i] = 0;
259  }
260 
261  //Set the sign
262  dest->sign = 1;
263  }
264 
265  //Return status code
266  return error;
267 }
268 
269 
270 #if (MPI_SUPPORT == ENABLED)
271 
272 /**
273  * @brief Modular exponentiation
274  * @param[out] r Resulting integer R = A ^ E mod P
275  * @param[in] a Pointer to a multiple precision integer
276  * @param[in] e Exponent
277  * @param[in] p Modulus
278  * @return Error code
279  **/
280 
281 error_t pkaModExp(Mpi *r, const Mpi *a, const Mpi *e, const Mpi *p)
282 {
283  error_t error;
284  uint_t modLen;
285  uint_t expLen;
286  uint32_t temp;
287 
288  //Get the length of the modulus, in bits
289  modLen = mpiGetBitLength(p);
290  //Get the length of the exponent, in bits
291  expLen = mpiGetBitLength(e);
292 
293  //Check the length of the operands
294  if(modLen <= PKA_MAX_ROS && expLen <= PKA_MAX_ROS)
295  {
296  //Reduce the operand first
297  error = mpiMod(r, a, p);
298 
299  //Check status code
300  if(!error)
301  {
302  //Acquire exclusive access to the PKA module
304 
305  //Specify the length of the operand, in bits
306  PKA->RAM[PKA_MODULAR_EXP_IN_OP_NB_BITS] = modLen;
307  //Specify the length of the exponent, in bits
308  PKA->RAM[PKA_MODULAR_EXP_IN_EXP_NB_BITS] = expLen;
309 
310  //Load input arguments into the PKA internal RAM
311  pkaImportMpi(r, modLen, PKA_MODULAR_EXP_IN_EXPONENT_BASE);
312  pkaImportMpi(e, expLen, PKA_MODULAR_EXP_IN_EXPONENT);
313  pkaImportMpi(p, modLen, PKA_MODULAR_EXP_IN_MODULUS);
314 
315  //Disable interrupts
316  PKA->CR &= ~(PKA_CR_ADDRERRIE | PKA_CR_RAMERRIE | PKA_CR_PROCENDIE);
317 
318  //Write in the MODE field of PKA_CR register, specifying the operation
319  //which is to be executed
320  temp = PKA->CR & ~PKA_CR_MODE;
321  PKA->CR = temp | (PKA_CR_MODE_MODULAR_EXP << PKA_CR_MODE_Pos);
322 
323  //Then assert the START bit in PKA_CR register
324  PKA->CR |= PKA_CR_START;
325 
326  //Wait until the PROCENDF bit in the PKA_SR register is set to 1,
327  //indicating that the computation is complete
328  while((PKA->SR & PKA_SR_PROCENDF) == 0)
329  {
330  }
331 
332  //Read the result data from the PKA internal RAM
333  error = pkaExportMpi(r, modLen, PKA_MODULAR_EXP_OUT_SM_ALGO_ACC1);
334 
335  //Then clear PROCENDF bit by setting PROCENDFC bit in PKA_CLRFR
336  PKA->CLRFR = PKA_CLRFR_PROCENDFC;
337 
338  //Release exclusive access to the PKA module
340  }
341  }
342  else
343  {
344  //Perform modular exponentiation
345  error = mpiExpMod(r, a, e, p);
346  }
347 
348  //Return status code
349  return error;
350 }
351 
352 #endif
353 #if (RSA_SUPPORT == ENABLED)
354 
355 /**
356  * @brief Modular exponentiation with CRT
357  * @param[in] key RSA public key
358  * @param[in] m Message representative
359  * @param[out] c Ciphertext representative
360  * @return Error code
361  **/
362 
363 error_t pkaRsaCrtExp(const RsaPrivateKey *key, const Mpi *c, Mpi *m)
364 {
365  error_t error;
366  uint_t nLen;
367  uint_t pLen;
368  uint_t qLen;
369  uint_t dpLen;
370  uint_t dqLen;
371  uint_t qinvLen;
372  uint32_t temp;
373 
374  //Get the length of the private key
375  nLen = mpiGetBitLength(&key->n);
376  pLen = mpiGetBitLength(&key->p);
377  qLen = mpiGetBitLength(&key->q);
378  dpLen = mpiGetBitLength(&key->dp);
379  dqLen = mpiGetBitLength(&key->dq);
380  qinvLen = mpiGetBitLength(&key->qinv);
381 
382  //Check the length of the operands
383  if(nLen <= PKA_MAX_ROS && pLen <= (nLen / 2) && qLen <= (nLen / 2) &&
384  dpLen <= (nLen / 2) && dqLen <= (nLen / 2) && qinvLen <= (nLen / 2))
385  {
386  //Acquire exclusive access to the PKA module
388 
389  //Specify the length of the operand, in bits
390  PKA->RAM[PKA_RSA_CRT_EXP_IN_MOD_NB_BITS] = nLen;
391 
392  //Load input arguments into the PKA internal RAM
393  pkaImportMpi(&key->p, nLen / 2, PKA_RSA_CRT_EXP_IN_PRIME_P);
394  pkaImportMpi(&key->q, nLen / 2, PKA_RSA_CRT_EXP_IN_PRIME_Q);
395  pkaImportMpi(&key->dp, nLen / 2, PKA_RSA_CRT_EXP_IN_DP_CRT);
396  pkaImportMpi(&key->dq, nLen / 2, PKA_RSA_CRT_EXP_IN_DQ_CRT);
397  pkaImportMpi(&key->qinv, nLen / 2, PKA_RSA_CRT_EXP_IN_QINV_CRT);
398  pkaImportMpi(c, nLen, PKA_RSA_CRT_EXP_IN_EXPONENT_BASE);
399 
400  //Disable interrupts
401  PKA->CR &= ~(PKA_CR_ADDRERRIE | PKA_CR_RAMERRIE | PKA_CR_PROCENDIE);
402 
403  //Write in the MODE field of PKA_CR register, specifying the operation
404  //which is to be executed
405  temp = PKA->CR & ~PKA_CR_MODE;
406  PKA->CR = temp | (PKA_CR_MODE_RSA_CRT_EXP << PKA_CR_MODE_Pos);
407 
408  //Then assert the START bit in PKA_CR register
409  PKA->CR |= PKA_CR_START;
410 
411  //Wait until the PROCENDF bit in the PKA_SR register is set to 1,
412  //indicating that the computation is complete
413  while((PKA->SR & PKA_SR_PROCENDF) == 0)
414  {
415  }
416 
417  //Read the result data from the PKA internal RAM
418  error = pkaExportMpi(m, nLen, PKA_RSA_CRT_EXP_OUT_RESULT);
419 
420  //Then clear PROCENDF bit by setting PROCENDFC bit in PKA_CLRFR
421  PKA->CLRFR = PKA_CLRFR_PROCENDFC;
422 
423  //Release exclusive access to the PKA module
425  }
426  else
427  {
428  Mpi m1;
429  Mpi m2;
430  Mpi h;
431 
432  //Initialize multiple-precision integers
433  mpiInit(&m1);
434  mpiInit(&m2);
435  mpiInit(&h);
436 
437  //Compute m1 = c ^ dP mod p
438  error = pkaModExp(&m1, c, &key->dp, &key->p);
439 
440  //Check status code
441  if(!error)
442  {
443  //Compute m2 = c ^ dQ mod q
444  error = pkaModExp(&m2, c, &key->dq, &key->q);
445  }
446 
447  //Check status code
448  if(!error)
449  {
450  //Let h = (m1 - m2) * qInv mod p
451  error = mpiSub(&h, &m1, &m2);
452  }
453 
454  //Check status code
455  if(!error)
456  {
457  error = mpiMulMod(&h, &h, &key->qinv, &key->p);
458  }
459 
460  //Check status code
461  if(!error)
462  {
463  //Let m = m2 + q * h
464  error = mpiMul(m, &key->q, &h);
465  }
466 
467  //Check status code
468  if(!error)
469  {
470  error = mpiAdd(m, m, &m2);
471  }
472 
473  //Free previously allocated memory
474  mpiFree(&m1);
475  mpiFree(&m2);
476  mpiFree(&h);
477  }
478 
479  //Return status code
480  return error;
481 }
482 
483 
484 /**
485  * @brief RSA encryption primitive
486  * @param[in] key RSA public key
487  * @param[in] m Message representative
488  * @param[out] c Ciphertext representative
489  * @return Error code
490  **/
491 
492 error_t rsaep(const RsaPublicKey *key, const Mpi *m, Mpi *c)
493 {
494  size_t nLen;
495  size_t eLen;
496 
497  //Get the length of the public key
498  nLen = mpiGetLength(&key->n);
499  eLen = mpiGetLength(&key->e);
500 
501  //Sanity check
502  if(nLen == 0 || eLen == 0)
504 
505  //The message representative m shall be between 0 and n - 1
506  if(mpiCompInt(m, 0) < 0 || mpiComp(m, &key->n) >= 0)
507  return ERROR_OUT_OF_RANGE;
508 
509  //Perform modular exponentiation (c = m ^ e mod n)
510  return pkaModExp(c, m, &key->e, &key->n);
511 }
512 
513 
514 /**
515  * @brief RSA decryption primitive
516  * @param[in] key RSA private key
517  * @param[in] c Ciphertext representative
518  * @param[out] m Message representative
519  * @return Error code
520  **/
521 
522 error_t rsadp(const RsaPrivateKey *key, const Mpi *c, Mpi *m)
523 {
524  error_t error;
525 
526  //The ciphertext representative c shall be between 0 and n - 1
527  if(mpiCompInt(c, 0) < 0 || mpiComp(c, &key->n) >= 0)
528  return ERROR_OUT_OF_RANGE;
529 
530  //Use the Chinese remainder algorithm?
531  if(mpiGetLength(&key->n) > 0 && mpiGetLength(&key->p) > 0 &&
532  mpiGetLength(&key->q) > 0 && mpiGetLength(&key->dp) > 0 &&
533  mpiGetLength(&key->dq) > 0 && mpiGetLength(&key->qinv) > 0)
534  {
535  //Perform modular exponentiation (with CRT)
536  error = pkaRsaCrtExp(key, c, m);
537  }
538  else if(mpiGetLength(&key->n) > 0 && mpiGetLength(&key->d) > 0)
539  {
540  //Perform modular exponentiation (without CRT)
541  error = pkaModExp(m, c, &key->d, &key->n);
542  }
543  else
544  {
545  //Invalid parameters
546  error = ERROR_INVALID_PARAMETER;
547  }
548 
549  //Return status code
550  return error;
551 }
552 
553 #endif
554 #if (EC_SUPPORT == ENABLED)
555 
556 /**
557  * @brief Scalar multiplication (fast calculation)
558  * @param[in] curve Elliptic curve parameters
559  * @param[out] r Resulting point R = d.S
560  * @param[in] d An integer d such as 0 <= d < p
561  * @param[in] s EC point
562  * @return Error code
563  **/
564 
565 error_t ecMulFast(const EcCurve *curve, EcPoint3 *r, const uint32_t *d,
566  const EcPoint3 *s)
567 {
568  //Compute R = d.S
569  return ecMulRegular(curve, r, d, s);
570 }
571 
572 
573 /**
574  * @brief Scalar multiplication (regular calculation)
575  * @param[in] curve Elliptic curve parameters
576  * @param[out] r Resulting point R = d.S
577  * @param[in] d An integer d such as 0 <= d < q
578  * @param[in] s EC point
579  * @return Error code
580  **/
581 
582 error_t ecMulRegular(const EcCurve *curve, EcPoint3 *r, const uint32_t *d,
583  const EcPoint3 *s)
584 {
585  error_t error;
586  uint_t modLen;
587  uint_t orderLen;
588  uint32_t temp;
589 
590  //Get the length of the modulus, in bits
591  modLen = curve->fieldSize;
592  //Get the length of the order, in bits
593  orderLen = curve->orderSize;
594 
595  //Check the length of the operands
596  if(modLen <= PKA_MAX_EOS && orderLen <= PKA_MAX_EOS)
597  {
598  //Acquire exclusive access to the PKA module
600 
601  //Specify the length of the modulus, in bits
602  PKA->RAM[PKA_ECC_SCALAR_MUL_IN_OP_NB_BITS] = modLen;
603  //Specify the length of the scalar, in bits
604  PKA->RAM[PKA_ECC_SCALAR_MUL_IN_EXP_NB_BITS] = orderLen;
605  //Set the sign of the coefficient A
606  PKA->RAM[PKA_ECC_SCALAR_MUL_IN_A_COEFF_SIGN] = 0;
607 
608  //Load input arguments into the PKA internal RAM
609  pkaImportScalar(curve->p, modLen, PKA_ECC_SCALAR_MUL_IN_MOD_GF);
610  pkaImportScalar(curve->a, modLen, PKA_ECC_SCALAR_MUL_IN_A_COEFF);
611  pkaImportScalar(d, orderLen, PKA_ECC_SCALAR_MUL_IN_K);
612  pkaImportScalar(s->x, modLen, PKA_ECC_SCALAR_MUL_IN_INITIAL_POINT_X);
613  pkaImportScalar(s->y, modLen, PKA_ECC_SCALAR_MUL_IN_INITIAL_POINT_Y);
614 
615  //Disable interrupts
616  PKA->CR &= ~(PKA_CR_ADDRERRIE | PKA_CR_RAMERRIE | PKA_CR_PROCENDIE);
617 
618  //Write in the MODE field of PKA_CR register, specifying the operation
619  //which is to be executed
620  temp = PKA->CR & ~PKA_CR_MODE;
621  PKA->CR = temp | (PKA_CR_MODE_ECC_MUL << PKA_CR_MODE_Pos);
622 
623  //Then assert the START bit in PKA_CR register
624  PKA->CR |= PKA_CR_START;
625 
626  //Wait until the PROCENDF bit in the PKA_SR register is set to 1,
627  //indicating that the computation is complete
628  while((PKA->SR & PKA_SR_PROCENDF) == 0)
629  {
630  }
631 
632  //Copy the x-coordinate of the result
634  pkaExportScalar(r->x, modLen, PKA_ECC_SCALAR_MUL_OUT_RESULT_X);
635 
636  //Copy the y-coordinate of the result
638  pkaExportScalar(r->y, modLen, PKA_ECC_SCALAR_MUL_OUT_RESULT_Y);
639 
640  //Set the z-coordinate of the result
642 
643  //Then clear PROCENDF bit by setting PROCENDFC bit in PKA_CLRFR
644  PKA->CLRFR = PKA_CLRFR_PROCENDFC;
645 
646  //Release exclusive access to the PKA module
648 
649  //Successful processing
650  error = NO_ERROR;
651  }
652  else
653  {
654  //Report an error
655  error = ERROR_FAILURE;
656  }
657 
658  //Return status code
659  return error;
660 }
661 
662 #endif
663 #if (ECDSA_SUPPORT == ENABLED)
664 
665 /**
666  * @brief ECDSA signature generation
667  * @param[in] prngAlgo PRNG algorithm
668  * @param[in] prngContext Pointer to the PRNG context
669  * @param[in] privateKey Signer's EC private key
670  * @param[in] digest Digest of the message to be signed
671  * @param[in] digestLen Length in octets of the digest
672  * @param[out] signature (R, S) integer pair
673  * @return Error code
674  **/
675 
676 error_t ecdsaGenerateSignature(const PrngAlgo *prngAlgo, void *prngContext,
677  const EcPrivateKey *privateKey, const uint8_t *digest, size_t digestLen,
678  EcdsaSignature *signature)
679 {
680  error_t error;
681  uint_t modLen;
682  uint_t orderLen;
683  uint32_t temp;
684  uint32_t k[EC_MAX_ORDER_SIZE];
685  const EcCurve *curve;
686 
687  //Check parameters
688  if(privateKey == NULL || digest == NULL || signature == NULL)
690 
691  //Invalid elliptic curve?
692  if(privateKey->curve == NULL)
694 
695  //Get elliptic curve parameters
696  curve = privateKey->curve;
697 
698  //Get the length of the modulus, in bits
699  modLen = curve->fieldSize;
700  //Get the length of the order, in bits
701  orderLen = curve->orderSize;
702 
703  //Check the length of the operands
704  if(modLen > PKA_MAX_EOS || orderLen > PKA_MAX_EOS)
705  return ERROR_FAILURE;
706 
707  //Generate a random number k such as 0 < k < q - 1
708  error = ecScalarRand(curve, k, prngAlgo, prngContext);
709 
710  //Check status code
711  if(!error)
712  {
713  //Acquire exclusive access to the PKA module
715 
716  //Specify the length of the modulus, in bits
717  PKA->RAM[PKA_ECDSA_SIGN_IN_MOD_NB_BITS] = modLen;
718  //Specify the length of the base point order, in bits
719  PKA->RAM[PKA_ECDSA_SIGN_IN_ORDER_NB_BITS] = orderLen;
720  //Set the sign of the coefficient A
721  PKA->RAM[PKA_ECDSA_SIGN_IN_A_COEFF_SIGN] = 0;
722 
723  //Load input arguments into the PKA internal RAM
724  pkaImportScalar(curve->p, modLen, PKA_ECDSA_SIGN_IN_MOD_GF);
725  pkaImportScalar(curve->a, modLen, PKA_ECDSA_SIGN_IN_A_COEFF);
726  pkaImportScalar(curve->g.x, modLen, PKA_ECDSA_SIGN_IN_INITIAL_POINT_X);
727  pkaImportScalar(curve->g.y, modLen, PKA_ECDSA_SIGN_IN_INITIAL_POINT_Y);
728  pkaImportScalar(curve->q, orderLen, PKA_ECDSA_SIGN_IN_ORDER_N);
729  pkaImportScalar(privateKey->d, orderLen, PKA_ECDSA_SIGN_IN_PRIVATE_KEY_D);
730  pkaImportScalar(k, orderLen, PKA_ECDSA_SIGN_IN_K);
731 
732  //Keep the leftmost bits of the hash value
733  digestLen = MIN(digestLen, (orderLen + 7) / 8);
734  //Load the hash value into the PKA internal RAM
735  pkaImportArray(digest, digestLen, orderLen, PKA_ECDSA_SIGN_IN_HASH_E);
736 
737  //Clear error code
738  PKA->RAM[PKA_ECDSA_SIGN_OUT_ERROR] = PKA_STATUS_INVALID;
739 
740  //Disable interrupts
741  PKA->CR &= ~(PKA_CR_ADDRERRIE | PKA_CR_RAMERRIE | PKA_CR_PROCENDIE);
742 
743  //Write in the MODE field of PKA_CR register, specifying the operation
744  //which is to be executed
745  temp = PKA->CR & ~PKA_CR_MODE;
746  PKA->CR = temp | (PKA_CR_MODE_ECDSA_SIGN << PKA_CR_MODE_Pos);
747 
748  //Then assert the START bit in PKA_CR register
749  PKA->CR |= PKA_CR_START;
750 
751  //Wait until the PROCENDF bit in the PKA_SR register is set to 1,
752  //indicating that the computation is complete
753  while((PKA->SR & PKA_SR_PROCENDF) == 0)
754  {
755  }
756 
757  //Successful computation?
758  if(PKA->RAM[PKA_ECDSA_SIGN_OUT_ERROR] == PKA_STATUS_SUCCESS)
759  {
760  error = NO_ERROR;
761  }
762  else
763  {
764  error = ERROR_FAILURE;
765  }
766 
767  //Check status code
768  if(!error)
769  {
770  //Save elliptic curve parameters
771  signature->curve = curve;
772 
773  //Copy integer R
774  ecScalarSetInt(signature->r, 0, EC_MAX_ORDER_SIZE);
775  pkaExportScalar(signature->r, orderLen, PKA_ECDSA_SIGN_OUT_SIGNATURE_R);
776 
777  //Copy integer S
778  ecScalarSetInt(signature->s, 0, EC_MAX_ORDER_SIZE);
779  pkaExportScalar(signature->s, orderLen, PKA_ECDSA_SIGN_OUT_SIGNATURE_S);
780  }
781 
782  //Then clear PROCENDF bit by setting PROCENDFC bit in PKA_CLRFR
783  PKA->CLRFR = PKA_CLRFR_PROCENDFC;
784 
785  //Release exclusive access to the PKA module
787  }
788 
789  //Return status code
790  return error;
791 }
792 
793 
794 /**
795  * @brief ECDSA signature verification
796  * @param[in] publicKey Signer's EC public key
797  * @param[in] digest Digest of the message whose signature is to be verified
798  * @param[in] digestLen Length in octets of the digest
799  * @param[in] signature (R, S) integer pair
800  * @return Error code
801  **/
802 
804  const uint8_t *digest, size_t digestLen, const EcdsaSignature *signature)
805 {
806  error_t error;
807  uint_t modLen;
808  uint_t orderLen;
809  uint32_t temp;
810  const EcCurve *curve;
811 
812  //Check parameters
813  if(publicKey == NULL || digest == NULL || signature == NULL)
815 
816  //Invalid elliptic curve?
817  if(publicKey->curve == NULL)
819 
820  //Verify that the public key is on the curve
821  if(!ecIsPointAffine(publicKey->curve, &publicKey->q))
822  {
824  }
825 
826  //The verifier shall check that 0 < r < q
827  if(ecScalarCompInt(signature->r, 0, EC_MAX_ORDER_SIZE) <= 0 ||
828  ecScalarComp(signature->r, publicKey->curve->q, EC_MAX_ORDER_SIZE) >= 0)
829  {
830  //If the condition is violated, the signature shall be rejected as invalid
832  }
833 
834  //The verifier shall check that 0 < s < q
835  if(ecScalarCompInt(signature->s, 0, EC_MAX_ORDER_SIZE) <= 0 ||
836  ecScalarComp(signature->s, publicKey->curve->q, EC_MAX_ORDER_SIZE) >= 0)
837  {
838  //If the condition is violated, the signature shall be rejected as invalid
840  }
841 
842  //Get elliptic curve parameters
843  curve = publicKey->curve;
844 
845  //Get the length of the modulus, in bits
846  modLen = curve->fieldSize;
847  //Get the length of the order, in bits
848  orderLen = curve->orderSize;
849 
850  //Check the length of the operands
851  if(modLen > PKA_MAX_EOS || orderLen > PKA_MAX_EOS)
852  return ERROR_FAILURE;
853 
854  //Acquire exclusive access to the PKA module
856 
857  //Specify the length of the modulus, in bits
858  PKA->RAM[PKA_ECDSA_VERIF_IN_MOD_NB_BITS] = modLen;
859  //Specify the length of the base point order, in bits
860  PKA->RAM[PKA_ECDSA_VERIF_IN_ORDER_NB_BITS] = orderLen;
861  //Set the sign of the coefficient A
862  PKA->RAM[PKA_ECDSA_VERIF_IN_A_COEFF_SIGN] = 0;
863 
864  //Load input arguments into the PKA internal RAM
865  pkaImportScalar(curve->p, modLen, PKA_ECDSA_VERIF_IN_MOD_GF);
866  pkaImportScalar(curve->a, modLen, PKA_ECDSA_VERIF_IN_A_COEFF);
867  pkaImportScalar(curve->g.x, modLen, PKA_ECDSA_VERIF_IN_INITIAL_POINT_X);
868  pkaImportScalar(curve->g.y, modLen, PKA_ECDSA_VERIF_IN_INITIAL_POINT_Y);
869  pkaImportScalar(curve->q, orderLen, PKA_ECDSA_VERIF_IN_ORDER_N);
870  pkaImportScalar(publicKey->q.x, modLen, PKA_ECDSA_VERIF_IN_PUBLIC_KEY_POINT_X);
871  pkaImportScalar(publicKey->q.y, modLen, PKA_ECDSA_VERIF_IN_PUBLIC_KEY_POINT_Y);
872  pkaImportScalar(signature->r, orderLen, PKA_ECDSA_VERIF_IN_SIGNATURE_R);
873  pkaImportScalar(signature->s, orderLen, PKA_ECDSA_VERIF_IN_SIGNATURE_S);
874 
875  //Keep the leftmost bits of the hash value
876  digestLen = MIN(digestLen, (orderLen + 7) / 8);
877  //Load the hash value into the PKA internal RAM
878  pkaImportArray(digest, digestLen, orderLen, PKA_ECDSA_VERIF_IN_HASH_E);
879 
880  //Clear result
881  PKA->RAM[PKA_ECDSA_VERIF_OUT_RESULT] = PKA_STATUS_INVALID;
882 
883  //Disable interrupts
884  PKA->CR &= ~(PKA_CR_ADDRERRIE | PKA_CR_RAMERRIE | PKA_CR_PROCENDIE);
885 
886  //Write in the MODE field of PKA_CR register, specifying the operation
887  //which is to be executed
888  temp = PKA->CR & ~PKA_CR_MODE;
889  PKA->CR = temp | (PKA_CR_MODE_ECDSA_VERIFY << PKA_CR_MODE_Pos);
890 
891  //Then assert the START bit in PKA_CR register
892  PKA->CR |= PKA_CR_START;
893 
894  //Wait until the PROCENDF bit in the PKA_SR register is set to 1,
895  //indicating that the computation is complete
896  while((PKA->SR & PKA_SR_PROCENDF) == 0)
897  {
898  }
899 
900  //Test if the ECDSA signature is valid
901  if(PKA->RAM[PKA_ECDSA_VERIF_OUT_RESULT] == PKA_STATUS_SUCCESS)
902  {
903  error = NO_ERROR;
904  }
905  else
906  {
907  error = ERROR_INVALID_SIGNATURE;
908  }
909 
910  //Then clear PROCENDF bit by setting PROCENDFC bit in PKA_CLRFR
911  PKA->CLRFR = PKA_CLRFR_PROCENDFC;
912 
913  //Release exclusive access to the PKA module
915 
916  //Return status code
917  return error;
918 }
919 
920 #endif
921 #endif
error_t rsaep(const RsaPublicKey *key, const Mpi *m, Mpi *c)
RSA encryption primitive.
ECDSA signature.
Definition: ecdsa.h:63
void pkaImportScalar(const uint32_t *src, uint_t length, uint_t offset)
Import scalar.
@ ERROR_OUT_OF_RANGE
Definition: error.h:138
error_t rsadp(const RsaPrivateKey *key, const Mpi *c, Mpi *m)
RSA decryption primitive.
#define PKA_MAX_EOS
Mpi p
First factor.
Definition: rsa.h:72
uint8_t a
Definition: ndp.h:411
Arbitrary precision integer.
Definition: mpi.h:102
#define PrngAlgo
Definition: crypto.h:973
ECDSA (Elliptic Curve Digital Signature Algorithm)
uint8_t p
Definition: ndp.h:300
#define PKA_CR_MODE_ECDSA_VERIFY
const EcCurve * curve
Elliptic curve parameters.
Definition: ecdsa.h:64
const EcCurve * curve
Elliptic curve parameters.
Definition: ec.h:433
void pkaImportMpi(const Mpi *src, uint_t length, uint_t offset)
Import multiple-precision integer.
#define EC_MAX_ORDER_SIZE
Definition: ec.h:315
#define PKA_CR_MODE_RSA_CRT_EXP
Mpi n
Modulus.
Definition: rsa.h:69
Mpi e
Public exponent.
Definition: rsa.h:59
uint32_t y[EC_MAX_MODULUS_SIZE]
y-coordinate
Definition: ec.h:400
void mpiInit(Mpi *r)
Initialize a multiple precision integer.
Definition: mpi.c:48
Mpi d
Private exponent.
Definition: rsa.h:71
Mpi n
Modulus.
Definition: rsa.h:58
uint8_t r
Definition: ndp.h:346
error_t ecMulRegular(const EcCurve *curve, EcPoint3 *r, const uint32_t *d, const EcPoint3 *s)
Scalar multiplication (regular calculation)
error_t mpiMod(Mpi *r, const Mpi *a, const Mpi *p)
Modulo operation.
Definition: mpi.c:1587
STM32WB public-key hardware accelerator (PKA)
@ ERROR_INVALID_ELLIPTIC_CURVE
Definition: error.h:134
error_t mpiMul(Mpi *r, const Mpi *a, const Mpi *b)
Multiple precision multiplication.
uint8_t h
Definition: ndp.h:302
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
error_t mpiSub(Mpi *r, const Mpi *a, const Mpi *b)
Multiple precision subtraction.
Definition: mpi.c:969
error_t
Error codes.
Definition: error.h:43
STM32WB hardware cryptographic accelerator.
error_t mpiAdd(Mpi *r, const Mpi *a, const Mpi *b)
Multiple precision addition.
Definition: mpi.c:891
#define PKA_CR_MODE_MODULAR_EXP
#define PKA_CR_MODE_ECDSA_SIGN
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
#define PKA_CR_MODE_ECC_MUL
void ecScalarSetInt(uint32_t *a, uint32_t b, uint_t n)
Set integer value.
Definition: ec_misc.c:505
#define PKA_STATUS_INVALID
Mpi q
Second factor.
Definition: rsa.h:73
Helper routines for ECC.
RSA public key.
Definition: rsa.h:57
uint32_t r[EC_MAX_ORDER_SIZE]
Integer R.
Definition: ecdsa.h:65
General definitions for cryptographic algorithms.
RSA public-key cryptography standard.
#define PKA_MAX_ROS
EC private key.
Definition: ec.h:432
error_t pkaInit(void)
PKA module initialization.
uint8_t length
Definition: tcp.h:375
#define MIN(a, b)
Definition: os_port.h:63
error_t ecMulFast(const EcCurve *curve, EcPoint3 *r, const uint32_t *d, const EcPoint3 *s)
Scalar multiplication (fast calculation)
uint_t mpiGetBitLength(const Mpi *a)
Get the actual length in bits.
Definition: mpi.c:254
Mpi qinv
CRT coefficient.
Definition: rsa.h:76
Mpi dq
Second factor's CRT exponent.
Definition: rsa.h:75
void pkaImportArray(const uint8_t *src, size_t srcLen, uint_t destLen, uint_t offset)
Import byte array.
EC public key.
Definition: ec.h:421
__weak_func bool_t ecIsPointAffine(const EcCurve *curve, const EcPoint *s)
Check whether the affine point S is on the curve.
Definition: ec.c:798
uint_t mpiGetLength(const Mpi *a)
Get the actual length in words.
Definition: mpi.c:188
error_t pkaRsaCrtExp(const RsaPrivateKey *key, const Mpi *c, Mpi *m)
Modular exponentiation with CRT.
OsMutex stm32wbxxCryptoMutex
uint32_t d[EC_MAX_ORDER_SIZE]
Private key.
Definition: ec.h:434
int_t ecScalarCompInt(const uint32_t *a, uint32_t b, uint_t n)
Compare integers.
Definition: ec_misc.c:374
uint8_t m
Definition: ndp.h:304
uint8_t n
RSA private key.
Definition: rsa.h:68
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
uint_t size
Definition: mpi.h:104
EC point (projective coordinates)
Definition: ec.h:409
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
error_t ecdsaGenerateSignature(const PrngAlgo *prngAlgo, void *prngContext, const EcPrivateKey *privateKey, const uint8_t *digest, size_t digestLen, EcdsaSignature *signature)
ECDSA signature generation.
EcPoint q
Public key.
Definition: ec.h:423
uint32_t s[EC_MAX_ORDER_SIZE]
Integer S.
Definition: ecdsa.h:66
error_t ecScalarRand(const EcCurve *curve, uint32_t *r, const PrngAlgo *prngAlgo, void *prngContext)
Generate a random value.
Definition: ec_misc.c:603
uint8_t s
Definition: igmp_common.h:234
#define PKA_STATUS_SUCCESS
error_t pkaModExp(Mpi *r, const Mpi *a, const Mpi *e, const Mpi *p)
Modular exponentiation.
#define EcCurve
Definition: ec.h:346
int_t mpiComp(const Mpi *a, const Mpi *b)
Compare two multiple precision integers.
Definition: mpi.c:358
Mpi dp
First factor's CRT exponent.
Definition: rsa.h:74
int_t ecScalarComp(const uint32_t *a, const uint32_t *b, uint_t n)
Compare integers.
Definition: ec_misc.c:337
int_t mpiCompInt(const Mpi *a, mpi_sword_t b)
Compare a multiple precision integer with an integer.
Definition: mpi.c:429
unsigned int uint_t
Definition: compiler_port.h:57
uint32_t x[EC_MAX_MODULUS_SIZE]
x-coordinate
Definition: ec.h:399
error_t mpiMulMod(Mpi *r, const Mpi *a, const Mpi *b, const Mpi *p)
Modular multiplication.
error_t ecdsaVerifySignature(const EcPublicKey *publicKey, const uint8_t *digest, size_t digestLen, const EcdsaSignature *signature)
ECDSA signature verification.
ECC (Elliptic Curve Cryptography)
@ ERROR_INVALID_SIGNATURE
Definition: error.h:228
mpi_word_t * data
Definition: mpi.h:106
error_t mpiGrow(Mpi *r, uint_t size)
Adjust the size of multiple precision integer.
Definition: mpi.c:102
const EcCurve * curve
Elliptic curve parameters.
Definition: ec.h:422
error_t pkaExportMpi(Mpi *dest, uint_t length, uint_t offset)
Export multiple-precision integer.
error_t mpiExpMod(Mpi *r, const Mpi *a, const Mpi *e, const Mpi *p)
Modular exponentiation.
#define EC_MAX_MODULUS_SIZE
Definition: ec.h:284
@ NO_ERROR
Success.
Definition: error.h:44
uint8_t c
Definition: ndp.h:514
Debugging facilities.
int_t sign
Definition: mpi.h:103
void pkaExportScalar(uint32_t *dest, uint_t length, uint_t offset)
Export scalar.
void mpiFree(Mpi *r)
Release a multiple precision integer.
Definition: mpi.c:64