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