pic32cx_mt_crypto_pkc.c
Go to the documentation of this file.
1 /**
2  * @file pic32cx_mt_crypto_pkc.c
3  * @brief PIC32CX MTC/MTG/MTSH public-key hardware accelerator (CPKCC)
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.4
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
33 
34 //Dependencies
35 #include "pic32c.h"
36 #include "cpkcc/CryptoLib_cf.h"
37 #include "cpkcc/CryptoLib_JumpTable_Addr_pb.h"
38 #include "core/crypto.h"
41 #include "pkc/rsa.h"
42 #include "ecc/ec.h"
43 #include "ecc/ec_misc.h"
44 #include "ecc/ecdsa.h"
45 #include "mpi/mpi.h"
46 #include "debug.h"
47 
48 //Check crypto library configuration
49 #if (PIC32CX_MT_CRYPTO_PKC_SUPPORT == ENABLED)
50 
51 //Global variables
52 PCPKCL_PARAM pvCPKCLParam;
53 CPKCL_PARAM CPKCLParam;
54 
55 
56 /**
57  * @brief Initialize CPKCC module
58  **/
59 
61 {
62  uint32_t temp;
63 
64  //Enable CPKCC peripheral clock
65  PMC_REGS->PMC_PCR = PMC_PCR_PID(ID_CPKCC);
66  temp = PMC_REGS->PMC_PCR;
67  PMC_REGS->PMC_PCR = temp | PMC_PCR_CMD_Msk | PMC_PCR_EN_Msk;
68 
69  //Delay
70  sleep(10);
71 
72  //Clear CPKCLParam structure
73  osMemset(&CPKCLParam, 0, sizeof(CPKCL_PARAM));
75 
76  //Initialize CPKCC
77  vCPKCL_Process(SelfTest, pvCPKCLParam);
78 
79  //Check status code
80  if(CPKCL(u2Status) != CPKCL_OK)
81  return ERROR_FAILURE;
82 
83  //Check version number
84  if(pvCPKCLParam->P.CPKCL_SelfTest_s.u4Version != CPKCL_VERSION)
85  return ERROR_FAILURE;
86 
87  //The return values from the SelfTest service must be compared against
88  //known values mentioned in the service description
89  if(pvCPKCLParam->P.CPKCL_SelfTest_s.u4CheckNum1 != 0x6E70DDD2)
90  return ERROR_FAILURE;
91 
92  if(pvCPKCLParam->P.CPKCL_SelfTest_s.u4CheckNum2 != 0x25C8D64F)
93  return ERROR_FAILURE;
94 
95  if(pvCPKCLParam->P.CPKCL_SelfTest_s.u1Step != 0x03)
96  return ERROR_FAILURE;
97 
98  //Successful initialization
99  return NO_ERROR;
100 }
101 
102 
103 /**
104  * @brief Import byte array
105  * @param[in,out] dest Pointer to the crypto memory
106  * @param[in] src Pointer to the byte array
107  * @param[in] srcLen Length of the array to be copied
108  * @param[in] totalLen Desired length of the area, in bytes
109  * @return Pointer to the initialized area
110  **/
111 
112 uint8_t *cpkccImportArray(uint8_t **dest, const uint8_t *src, size_t srcLen,
113  size_t totalLen)
114 {
115  size_t i;
116  uint8_t *p;
117 
118  //Point to the crypto memory
119  p = *dest;
120 
121  //Copy the byte array to the crypto memory
122  for(i = 0; i < srcLen; i++)
123  {
124  p[i] = src[srcLen - 1 - i];
125  }
126 
127  //Pad the data with zeroes
128  while(i < totalLen)
129  {
130  p[i++] = 0;
131  }
132 
133  //Advance data pointer
134  *dest = p + i;
135 
136  //Return a pointer to the initialized area
137  return p;
138 }
139 
140 
141 /**
142  * @brief Import scalar
143  * @param[in,out] dest Pointer to the crypto memory
144  * @param[in] src Pointer to the scalar
145  * @param[in] totalLen Desired length of the area, in bytes
146  * @return Pointer to the initialized area
147  **/
148 
149 uint8_t *cpkccImportScalar(uint8_t **dest, const uint32_t *src, size_t totalLen)
150 {
151  uint8_t *p;
152 
153  //Point to the crypto memory
154  p = *dest;
155 
156  //Copy the scalar to the crypto memory
157  ecScalarExport(src, (totalLen - 1) / 4, p, totalLen, EC_SCALAR_FORMAT_LITTLE_ENDIAN);
158 
159  //Advance data pointer
160  *dest = p + totalLen;
161 
162  //Return a pointer to the initialized area
163  return p;
164 }
165 
166 
167 /**
168  * @brief Import multiple-precision integer
169  * @param[in,out] dest Pointer to the crypto memory
170  * @param[in] src Pointer to the multiple-precision integer
171  * @param[in] totalLen Desired length of the area, in bytes
172  * @return Pointer to the initialized area
173  **/
174 
175 uint8_t *cpkccImportMpi(uint8_t **dest, const Mpi *src, size_t totalLen)
176 {
177  uint8_t *p;
178 
179  //Point to the crypto memory
180  p = *dest;
181 
182  //Copy the multiple-precision integer to the crypto memory
183  mpiExport(src, p, totalLen, MPI_FORMAT_LITTLE_ENDIAN);
184 
185  //Advance data pointer
186  *dest = p + totalLen;
187 
188  //Return a pointer to the initialized area
189  return p;
190 }
191 
192 
193 /**
194  * @brief Initialize workspace area
195  * @param[in,out] dest Pointer to the crypto memory
196  * @param[in] totalLen Desired length of the area, in bytes
197  * @return Pointer to the initialized area
198  **/
199 
200 uint8_t *cpkccWorkspace(uint8_t **dest, size_t totalLen)
201 {
202  size_t i;
203  uint8_t *p;
204 
205  //Point to the crypto memory
206  p = *dest;
207 
208  //Initialize workspace area
209  for(i = 0; i < totalLen; i++)
210  {
211  p[i] = 0;
212  }
213 
214  //Advance data pointer
215  *dest = p + i;
216 
217  //Return a pointer to the initialized area
218  return p;
219 }
220 
221 
222 #if (MPI_SUPPORT == ENABLED)
223 
224 /**
225  * @brief Multiple precision multiplication
226  * @param[out] r Resulting integer R = A * B
227  * @param[in] a First operand A
228  * @param[in] b Second operand B
229  * @return Error code
230  **/
231 
232 error_t mpiMul(Mpi *r, const Mpi *a, const Mpi *b)
233 {
234  error_t error;
235  size_t m;
236  size_t n;
237  uint8_t *pos;
238  PukccFmultParams params = {0};
239 
240  //Get the length of the input integer, in bytes
241  m = mpiGetByteLength(a);
242  m = (m + 3U) & ~3U;
243 
244  //Get the length of the modulus, in bytes
245  n = mpiGetByteLength(b);
246  n = (n + 3U) & ~3U;
247 
248  //Acquire exclusive access to the CPKCC accelerator
250 
251  //Point to the crypto memory
252  pos = (uint8_t *) CPKCC_CRYPTO_RAM_BASE;
253 
254  //Copy input integer X
255  params.x = cpkccImportMpi(&pos, a, m);
256  //Copy input integer Y
257  params.y = cpkccImportMpi(&pos, b, n);
258 
259  //Unused parameters
260  params.z = 0;
261  params.mod = 0;
262  params.cns = 0;
263 
264  //Initialize output integer R
265  params.r = cpkccWorkspace(&pos, m + n);
266 
267  //Set Fmult service parameters
268  CPKCL(u2Option) = SET_MULTIPLIEROPTION(CPKCL_FMULT_ONLY) |
269  SET_CARRYOPTION(CARRY_NONE);
270  CPKCL(Specific).CarryIn = 0;
271  CPKCL(Specific).Gf2n = 0;
272  CPKCL_Fmult(u2ModLength) = 0;
273  CPKCL_Fmult(nu1ModBase) = CPKCC_FAR_TO_NEAR(params.mod);
274  CPKCL_Fmult(nu1CnsBase) = CPKCC_FAR_TO_NEAR(params.cns);
275  CPKCL_Fmult(u2XLength) = m;
276  CPKCL_Fmult(nu1XBase) = CPKCC_FAR_TO_NEAR(params.x);
277  CPKCL_Fmult(u2YLength) = n;
278  CPKCL_Fmult(nu1YBase) = CPKCC_FAR_TO_NEAR(params.y);
279  CPKCL_Fmult(nu1ZBase) = CPKCC_FAR_TO_NEAR(params.z);
280  CPKCL_Fmult(nu1RBase) = CPKCC_FAR_TO_NEAR(params.r);
281 
282  //Perform multiplication
283  vCPKCL_Process(Fmult, pvCPKCLParam);
284 
285  //Check status code
286  if(CPKCL(u2Status) == CPKCL_OK)
287  {
288  //If FMult is without reduction, R is filled with the final result
289  error = mpiImport(r, params.r, m + n, MPI_FORMAT_LITTLE_ENDIAN);
290 
291  //Check status code
292  if(!error)
293  {
294  //Set the sign of the result
295  r->sign = (a->sign == b->sign) ? 1 : -1;
296  }
297  }
298  else
299  {
300  //Report an error
301  error = ERROR_FAILURE;
302  }
303 
304  //Release exclusive access to the CPKCC accelerator
306 
307  //Return error code
308  return error;
309 }
310 
311 
312 /**
313  * @brief Modulo operation
314  * @param[out] r Resulting integer R = A mod P
315  * @param[in] a The multiple precision integer to be reduced
316  * @param[in] p The modulus P
317  * @return Error code
318  **/
319 
320 error_t mpiMod2(Mpi *r, const Mpi *a, const Mpi *p)
321 {
322  error_t error;
323  size_t n;
324  size_t modLen;
325  uint8_t *pos;
326  PukccRedModParams params = {0};
327 
328  //Get the length of the input integer, in bytes
329  n = mpiGetByteLength(a);
330 
331  //Get the length of the modulus, in bytes
332  modLen = mpiGetByteLength(p);
333  modLen = (modLen + 3U) & ~3U;
334 
335  //Check the length of the input integer
336  if(n > (2 * modLen + 4))
337  return ERROR_INVALID_LENGTH;
338 
339  //Acquire exclusive access to the CPKCC accelerator
341 
342  //Point to the crypto memory
343  pos = (uint8_t *) CPKCC_CRYPTO_RAM_BASE;
344 
345  //Copy modulus
346  params.mod = cpkccImportMpi(&pos, p, modLen + 4);
347  //Initialize workspace CNS
348  params.cns = cpkccWorkspace(&pos, 68);
349  //Initialize output integer R
350  params.r = cpkccWorkspace(&pos, modLen + 4);
351  //Copy input integer X
352  params.x = cpkccImportMpi(&pos, a, 2 * modLen + 8);
353 
354  //Set RedMod service parameters
355  CPKCL(u2Option) = CPKCL_REDMOD_REDUCTION | CPKCL_REDMOD_USING_DIVISION;
356  CPKCL(Specific).CarryIn = 0;
357  CPKCL(Specific).Gf2n = 0;
358  CPKCL_RedMod(u2ModLength) = modLen;
359  CPKCL_RedMod(nu1ModBase) = CPKCC_FAR_TO_NEAR(params.mod);
360  CPKCL_RedMod(nu1CnsBase) = CPKCC_FAR_TO_NEAR(params.cns);
361  CPKCL_RedMod(nu1RBase) = CPKCC_FAR_TO_NEAR(params.r);
362  CPKCL_RedMod(nu1XBase) = CPKCC_FAR_TO_NEAR(params.x);
363 
364  //Perform modular reduction setup
365  vCPKCL_Process(RedMod, pvCPKCLParam);
366 
367  //Check status code
368  if(CPKCL(u2Status) == CPKCL_OK)
369  {
370  //If FMult is without reduction, R is filled with the final result
371  error = mpiImport(r, params.r, modLen, MPI_FORMAT_LITTLE_ENDIAN);
372  }
373  else
374  {
375  //Report an error
376  error = ERROR_FAILURE;
377  }
378 
379  //Release exclusive access to the CPKCC accelerator
381 
382  //Return error code
383  return error;
384 }
385 
386 
387 /**
388  * @brief Modular inverse
389  * @param[out] r Resulting integer R = A^-1 mod P
390  * @param[in] a The multiple precision integer A
391  * @param[in] p The modulus P
392  * @return Error code
393  **/
394 
395 error_t mpiInvMod(Mpi *r, const Mpi *a, const Mpi *p)
396 {
397  error_t error;
398  size_t m;
399  size_t n;
400  uint8_t *pos;
401  PukccGcdParams params = {0};
402 
403  //Get the length of the input integer, in bytes
404  m = mpiGetByteLength(a);
405  //Get the length of the modulus, in bytes
406  n = mpiGetByteLength(p);
407 
408  //Compute the length of the areas X, Y, A and Z
409  n = MAX(n, m);
410  n = (n + 7U) & ~3U;
411 
412  //Acquire exclusive access to the CPKCC accelerator
414 
415  //Point to the crypto memory
416  pos = (uint8_t *) CPKCC_CRYPTO_RAM_BASE;
417 
418  //Copy input integer
419  params.x = cpkccImportMpi(&pos, a, n);
420  //Copy modulus
421  params.y = cpkccImportMpi(&pos, p, n);
422  //Initialize output integer A
423  params.a = cpkccWorkspace(&pos, n);
424  //Initialize output integer Z
425  params.z = cpkccWorkspace(&pos, n + 4);
426  //Initialize workspace >
427  params.w = cpkccWorkspace(&pos, 32);
428 
429  //Set GCD service parameters
430  CPKCL(Specific).Gf2n = 0;
431  CPKCL_GCD(nu1XBase) = CPKCC_FAR_TO_NEAR(params.x);
432  CPKCL_GCD(nu1YBase) = CPKCC_FAR_TO_NEAR(params.y);
433  CPKCL_GCD(nu1ABase) = CPKCC_FAR_TO_NEAR(params.a);
434  CPKCL_GCD(nu1ZBase) = CPKCC_FAR_TO_NEAR(params.z);
435  CPKCL_GCD(nu1WorkSpace) = CPKCC_FAR_TO_NEAR(params.w);
436  CPKCL_GCD(u2Length) = n;
437 
438  //Calculate the modular inverse
439  vCPKCL_Process(GCD, pvCPKCLParam);
440 
441  //Check status code
442  if(CPKCL(u2Status) == CPKCL_OK)
443  {
444  //Copy output integer Z
445  error = mpiImport(r, params.a, n, MPI_FORMAT_LITTLE_ENDIAN);
446  }
447  else
448  {
449  //Report an error
450  error = ERROR_FAILURE;
451  }
452 
453  //Release exclusive access to the CPKCC accelerator
455 
456  //Return error code
457  return error;
458 }
459 
460 
461 /**
462  * @brief Modular exponentiation
463  * @param[out] r Resulting integer R = A ^ E mod P
464  * @param[in] a Pointer to a multiple precision integer
465  * @param[in] e Exponent
466  * @param[in] p Modulus
467  * @return Error code
468  **/
469 
470 error_t mpiExpMod(Mpi *r, const Mpi *a, const Mpi *e, const Mpi *p)
471 {
472  error_t error;
473  size_t n;
474  size_t modLen;
475  size_t expLen;
476  uint8_t *pos;
477  PukccExpModParams params = {0};
478 
479  //Get the length of the input integer, in bytes
480  n = mpiGetByteLength(a);
481 
482  //Get the length of the modulus, in bytes
483  modLen = mpiGetByteLength(p);
484  modLen = (modLen + 3U) & ~3U;
485 
486  //Get the length of the exponent, in bytes
487  expLen = mpiGetByteLength(e);
488  expLen = (expLen + 3U) & ~3U;
489 
490  //Check the length of the input integer
491  if(n > (2 * modLen + 4))
492  return ERROR_INVALID_LENGTH;
493 
494  //Acquire exclusive access to the CPKCC accelerator
496 
497  //Point to the crypto memory
498  pos = (uint8_t *) CPKCC_CRYPTO_RAM_BASE;
499 
500  //Copy modulus
501  params.mod = cpkccImportMpi(&pos, p, modLen + 4);
502  //Initialize reduction constant
503  params.cns = cpkccWorkspace(&pos, modLen + 12);
504  //Initialize workspace R
505  params.r = cpkccWorkspace(&pos, 64);
506  //Initialize workspace X
507  params.x = cpkccWorkspace(&pos, 2 * modLen + 8);
508 
509  //Set RedMod service parameters
510  CPKCL(u2Option) = CPKCL_REDMOD_SETUP;
511  CPKCL(Specific).CarryIn = 0;
512  CPKCL(Specific).Gf2n = 0;
513  CPKCL_RedMod(u2ModLength) = modLen;
514  CPKCL_RedMod(nu1ModBase) = CPKCC_FAR_TO_NEAR(params.mod);
515  CPKCL_RedMod(nu1CnsBase) = CPKCC_FAR_TO_NEAR(params.cns);
516  CPKCL_RedMod(nu1RBase) = CPKCC_FAR_TO_NEAR(params.r);
517  CPKCL_RedMod(nu1XBase) = CPKCC_FAR_TO_NEAR(params.x);
518 
519  //Perform modular reduction setup
520  vCPKCL_Process(RedMod, pvCPKCLParam);
521 
522  //Check status code
523  if(CPKCL(u2Status) == CPKCL_OK)
524  {
525  //Point to the crypto memory
526  pos = params.r;
527 
528  //Copy input number
529  params.x = cpkccImportMpi(&pos, a, 2 * modLen + 8);
530 
531  //Set RedMod service parameters
532  CPKCL(u2Option) = CPKCL_REDMOD_REDUCTION | CPKCL_REDMOD_USING_FASTRED;
533  CPKCL(Specific).CarryIn = 0;
534  CPKCL(Specific).Gf2n = 0;
535  CPKCL_RedMod(u2ModLength) = modLen;
536  CPKCL_RedMod(nu1ModBase) = CPKCC_FAR_TO_NEAR(params.mod);
537  CPKCL_RedMod(nu1CnsBase) = CPKCC_FAR_TO_NEAR(params.cns);
538  CPKCL_RedMod(nu1RBase) = CPKCC_FAR_TO_NEAR(params.x);
539  CPKCL_RedMod(nu1XBase) = CPKCC_FAR_TO_NEAR(params.x);
540 
541  //Perform fast modular reduction
542  vCPKCL_Process(RedMod, pvCPKCLParam);
543  }
544 
545  //Check status code
546  if(CPKCL(u2Status) == CPKCL_OK)
547  {
548  //Set RedMod service parameters
549  CPKCL(u2Option) = CPKCL_REDMOD_NORMALIZE;
550  CPKCL(Specific).CarryIn = 0;
551  CPKCL(Specific).Gf2n = 0;
552  CPKCL_RedMod(u2ModLength) = modLen;
553  CPKCL_RedMod(nu1ModBase) = CPKCC_FAR_TO_NEAR(params.mod);
554  CPKCL_RedMod(nu1CnsBase) = CPKCC_FAR_TO_NEAR(params.cns);
555  CPKCL_RedMod(nu1RBase) = CPKCC_FAR_TO_NEAR(params.x);
556  CPKCL_RedMod(nu1XBase) = CPKCC_FAR_TO_NEAR(params.x);
557 
558  //Normalize the result
559  vCPKCL_Process(RedMod, pvCPKCLParam);
560  }
561 
562  //Check status code
563  if(CPKCL(u2Status) == CPKCL_OK)
564  {
565  //The number to be exponentiated is followed by four 32-bit words
566  //that are used during the computations as a workspace
567  pos = params.x + modLen;
568  cpkccWorkspace(&pos, 16);
569 
570  //The exponent must be given with a supplemental word on the LSB
571  //side (low addresses). This word shall be set to zero
572  params.exp = cpkccWorkspace(&pos, 4);
573  cpkccImportMpi(&pos, e, expLen);
574 
575  //Initialize workspace
576  params.w = cpkccWorkspace(&pos, 3 * (modLen + 4) + 8);
577 
578  //Set ExpMod service parameters
579  CPKCL(u2Option) = CPKCL_EXPMOD_REGULARRSA | CPKCL_EXPMOD_WINDOWSIZE_1 |
580  CPKCL_EXPMOD_EXPINPKCCRAM;
581  CPKCL_ExpMod(u2ModLength) = modLen;
582  CPKCL_ExpMod(nu1ModBase) = CPKCC_FAR_TO_NEAR(params.mod);
583  CPKCL_ExpMod(nu1CnsBase) = CPKCC_FAR_TO_NEAR(params.cns);
584  CPKCL_ExpMod(nu1XBase) = CPKCC_FAR_TO_NEAR(params.x);
585  CPKCL_ExpMod(nu1PrecompBase) = CPKCC_FAR_TO_NEAR(params.w);
586  CPKCL_ExpMod(u2ExpLength) = expLen;
587  CPKCL_ExpMod(pfu1ExpBase) = params.exp;
588  CPKCL_ExpMod(u1Blinding) = 0;
589 
590  //Perform modular exponentiation
591  vCPKCL_Process(ExpMod, pvCPKCLParam);
592  }
593 
594  //Check status code
595  if(CPKCL(u2Status) == CPKCL_OK)
596  {
597  //Copy resulting integer
598  error = mpiImport(r, params.x, modLen, MPI_FORMAT_LITTLE_ENDIAN);
599  }
600  else
601  {
602  //Report an error
603  error = ERROR_FAILURE;
604  }
605 
606  //Release exclusive access to the CPKCC accelerator
608 
609  //Return error code
610  return error;
611 }
612 
613 
614 /**
615  * @brief Test whether a number is probable prime
616  * @param[in] a Pointer to a multiple precision integer
617  * @return Error code
618  **/
619 
621 {
622  error_t error;
623  uint_t k;
624  size_t n;
625  uint8_t *pos;
626  PukccPrimeGenParams params = {0};
627 
628  //Get the length of the input integer, in bits
629  n = mpiGetBitLength(a);
630 
631  //Prime numbers of a size lower than 96 bits cannot be tested by this
632  //service
633  if(n < 96)
634  return ERROR_INVALID_LENGTH;
635 
636  //The number of repetitions controls the error probability
637  if(n >= 1300)
638  {
639  k = 2;
640  }
641  else if(n >= 850)
642  {
643  k = 3;
644  }
645  else if(n >= 650)
646  {
647  k = 4;
648  }
649  else if(n >= 550)
650  {
651  k = 5;
652  }
653  else if(n >= 450)
654  {
655  k = 6;
656  }
657  else if(n >= 400)
658  {
659  k = 7;
660  }
661  else if(n >= 350)
662  {
663  k = 8;
664  }
665  else if(n >= 300)
666  {
667  k = 9;
668  }
669  else if(n >= 250)
670  {
671  k = 12;
672  }
673  else if(n >= 200)
674  {
675  k = 15;
676  }
677  else if(n >= 150)
678  {
679  k = 18;
680  }
681  else
682  {
683  k = 27;
684  }
685 
686  //Get the length of the input integer, in bytes
687  n = mpiGetByteLength(a);
688  n = (n + 3U) & ~3U;
689 
690  //Acquire exclusive access to the CPKCC accelerator
692 
693  //Point to the crypto memory
694  pos = (uint8_t *) CPKCC_CRYPTO_RAM_BASE;
695 
696  //One additional word is used on the LSB side of the NBase parameter. As
697  //a consequence, the parameter nu1NBase must never be at the beginning of
698  //the crypto RAM, but at least at one word from the beginning
699  cpkccWorkspace(&pos, 4);
700 
701  //Copy the number to test
702  params.n = cpkccImportMpi(&pos, a, n + 4);
703  //Cns is used as a workspace
704  params.cns = cpkccWorkspace(&pos, n + 12);
705  //Rnd is used as a workspace
706  params.rnd = cpkccWorkspace(&pos, MAX(n + 16, 64));
707  //Precomp is used as a precomputation workspace
708  params.w = cpkccWorkspace(&pos, MAX(3 * (n + 4), n + 72) + 8);
709  //Exp is used as a workspace
710  params.exp = cpkccWorkspace(&pos, n + 4);
711 
712  //Unused parameter
713  params.r = 0;
714 
715  //Set PrimeGen service parameters
716  CPKCL(u2Option) = CPKCL_PRIMEGEN_TEST | CPKCL_EXPMOD_FASTRSA |
717  CPKCL_EXPMOD_WINDOWSIZE_1;
718  CPKCL_PrimeGen(u2NLength) = n;
719  CPKCL_PrimeGen(nu1NBase) = CPKCC_FAR_TO_NEAR(params.n);
720  CPKCL_PrimeGen(nu1CnsBase) = CPKCC_FAR_TO_NEAR(params.cns);
721  CPKCL_PrimeGen(nu1RndBase) = CPKCC_FAR_TO_NEAR(params.rnd);
722  CPKCL_PrimeGen(nu1PrecompBase) = CPKCC_FAR_TO_NEAR(params.w);
723  CPKCL_PrimeGen(nu1RBase) = CPKCC_FAR_TO_NEAR(params.r);
724  CPKCL_PrimeGen(nu1ExpBase) = CPKCC_FAR_TO_NEAR(params.exp);
725  CPKCL_PrimeGen(u1MillerRabinIterations) = k;
726  CPKCL_PrimeGen(u2MaxIncrement) = 1;
727 
728  //Perform probable prime testing
729  vCPKCL_Process(PrimeGen, pvCPKCLParam);
730 
731  //Check status code
732  switch(CPKCL(u2Status))
733  {
734  case CPKCL_NUMBER_IS_PRIME:
735  //The number is probably prime
736  error = NO_ERROR;
737  break;
738  case CPKCL_NUMBER_IS_NOT_PRIME:
739  //The number is not prime
740  error = ERROR_INVALID_VALUE;
741  break;
742  default:
743  //Report an error
744  error = ERROR_FAILURE;
745  break;
746  }
747 
748  //Release exclusive access to the CPKCC accelerator
750 
751  //Return error code
752  return error;
753 }
754 
755 #endif
756 #if (RSA_SUPPORT == ENABLED)
757 
758 /**
759  * @brief RSA decryption primitive
760  * @param[in] key RSA private key
761  * @param[in] c Ciphertext representative
762  * @param[out] m Message representative
763  * @return Error code
764  **/
765 
766 error_t rsadp(const RsaPrivateKey *key, const Mpi *c, Mpi *m)
767 {
768  error_t error;
769  size_t nLen;
770  size_t dLen;
771  size_t pLen;
772  size_t qLen;
773  size_t dpLen;
774  size_t dqLen;
775  size_t qinvLen;
776 
777  //Get the length of the private key
778  nLen = mpiGetByteLength(&key->n);
779  dLen = mpiGetByteLength(&key->d);
780  pLen = mpiGetByteLength(&key->p);
781  qLen = mpiGetByteLength(&key->q);
782  dpLen = mpiGetByteLength(&key->dp);
783  dqLen = mpiGetByteLength(&key->dq);
784  qinvLen = mpiGetByteLength(&key->qinv);
785 
786  //Sanity check
787  if(nLen == 0)
789 
790  //The ciphertext representative c shall be between 0 and n - 1
791  if(mpiCompInt(c, 0) < 0 || mpiComp(c, &key->n) >= 0)
792  return ERROR_OUT_OF_RANGE;
793 
794  //Use the Chinese remainder algorithm?
795  if(nLen > 0 && pLen > 0 && qLen > 0 && dpLen > 0 && dqLen > 0 && qinvLen > 0)
796  {
797  size_t cLen;
798  size_t modLen;
799  size_t expLen;
800  uint8_t *pos;
801  PukccCrtParams params = {0};
802 
803  //Get the length of the ciphertext, in bytes
804  cLen = mpiGetByteLength(c);
805 
806  //Get the length of the modulus, in bytes
807  modLen = MAX(pLen, qLen);
808  modLen = MAX(modLen, 12);
809  modLen = (modLen + 3U) & ~3U;
810 
811  //Get the length of the reduced exponents, in bytes
812  expLen = MAX(dpLen, dqLen);
813  expLen = (expLen + 3U) & ~3U;
814 
815  //Check the length of the ciphertext
816  if(cLen > (2 * modLen))
817  return ERROR_INVALID_LENGTH;
818 
819  //Acquire exclusive access to the CPKCC accelerator
821 
822  //Point to the crypto memory
823  pos = (uint8_t *) CPKCC_CRYPTO_RAM_BASE;
824 
825  //Copy primes
826  params.q = cpkccImportMpi(&pos, &key->q, modLen + 4);
827  params.p = cpkccImportMpi(&pos, &key->p, modLen + 4);
828 
829  //Copy input number
830  params.x = cpkccImportMpi(&pos, c, 2 * modLen + 16);
831 
832  //The reduced exponents must be given with a supplemental word on the
833  //LSB side (low addresses). This word shall be set to zero
834  params.dq = cpkccWorkspace(&pos, 4);
835  cpkccImportMpi(&pos, &key->dq, expLen);
836  params.dp = cpkccWorkspace(&pos, 4);
837  cpkccImportMpi(&pos, &key->dp, expLen);
838 
839  //Copy R value
840  params.r = cpkccImportMpi(&pos, &key->qinv, modLen + 4);
841  //Initialize workspace
842  cpkccWorkspace(&pos, 3 * (modLen + 4) + MAX(64, 1 * (modLen + 4)) + 8);
843 
844  //Set CRT service parameters
845  CPKCL(u2Option) = CPKCL_EXPMOD_REGULARRSA | CPKCL_EXPMOD_WINDOWSIZE_1 |
846  CPKCL_EXPMOD_EXPINPKCCRAM;
847  CPKCL_CRT(u2ModLength) = modLen;
848  CPKCL_CRT(nu1ModBase) = CPKCC_FAR_TO_NEAR(params.q);
849  CPKCL_CRT(nu1XBase) = CPKCC_FAR_TO_NEAR(params.x);
850  CPKCL_CRT(nu1PrecompBase) = CPKCC_FAR_TO_NEAR(params.r);
851  CPKCL_CRT(u2ExpLength) = expLen;
852  CPKCL_CRT(pfu1ExpBase) = params.dq;
853  CPKCL_CRT(u1Blinding) = 0;
854 
855  //Perform modular exponentiation (with CRT)
856  vCPKCL_Process(CRT, pvCPKCLParam);
857 
858  //Check status code
859  if(CPKCL(u2Status) == CPKCL_OK)
860  {
861  //Copy resulting integer
862  error = mpiImport(m, params.x, 2 * modLen, MPI_FORMAT_LITTLE_ENDIAN);
863  }
864  else
865  {
866  //Report an error
867  error = ERROR_FAILURE;
868  }
869 
870  //Release exclusive access to the CPKCC accelerator
872  }
873  else if(nLen > 0 && dLen > 0)
874  {
875  //Perform modular exponentiation (without CRT)
876  error = mpiExpMod(m, c, &key->d, &key->n);
877  }
878  else
879  {
880  //Invalid parameters
881  error = ERROR_INVALID_PARAMETER;
882  }
883 
884  //Return status code
885  return error;
886 }
887 
888 #endif
889 #if (EC_SUPPORT == ENABLED)
890 
891 /**
892  * @brief Check whether the affine point S is on the curve
893  * @param[in] curve Elliptic curve parameters
894  * @param[in] s Affine representation of the point
895  * @return TRUE if the affine point S is on the curve, else FALSE
896  **/
897 
898 bool_t ecIsPointAffine(const EcCurve *curve, const EcPoint *s)
899 {
900  bool_t valid;
901  size_t modLen;
902  uint8_t *pos;
903  PukccZpEcPointIsOnCurveParams params = {0};
904 
905  //Get the length of the modulus, in bytes
906  modLen = (curve->fieldSize + 7) / 8;
907  modLen = (modLen + 3U) & ~3U;
908 
909  //Acquire exclusive access to the CPKCC accelerator
911 
912  //Point to the crypto memory
913  pos = (uint8_t *) CPKCC_CRYPTO_RAM_BASE;
914 
915  //Copy modulus
916  params.mod = cpkccImportScalar(&pos, curve->p, modLen + 4);
917  //Initialize reduction constant
918  params.cns = cpkccWorkspace(&pos, modLen + 12);
919  //Initialize workspace R
920  params.r = cpkccWorkspace(&pos, 64);
921  //Initialize workspace X
922  params.x = cpkccWorkspace(&pos, 2 * modLen + 8);
923 
924  //Set RedMod service parameters
925  CPKCL(u2Option) = CPKCL_REDMOD_SETUP;
926  CPKCL(Specific).CarryIn = 0;
927  CPKCL(Specific).Gf2n = 0;
928  CPKCL_RedMod(u2ModLength) = modLen;
929  CPKCL_RedMod(nu1ModBase) = CPKCC_FAR_TO_NEAR(params.mod);
930  CPKCL_RedMod(nu1CnsBase) = CPKCC_FAR_TO_NEAR(params.cns);
931  CPKCL_RedMod(nu1RBase) = CPKCC_FAR_TO_NEAR(params.r);
932  CPKCL_RedMod(nu1XBase) = CPKCC_FAR_TO_NEAR(params.x);
933 
934  //Perform modular reduction setup
935  vCPKCL_Process(RedMod, pvCPKCLParam);
936 
937  //Check status code
938  if(CPKCL(u2Status) == CPKCL_OK)
939  {
940  //Point to the crypto memory
941  pos = params.r;
942 
943  //Copy point coordinates
944  params.point.x = cpkccImportScalar(&pos, s->x, modLen + 4);
945  params.point.y = cpkccImportScalar(&pos, s->y, modLen + 4);
946  params.point.z = cpkccWorkspace(&pos, modLen + 4);
947  params.point.z[0] = 1;
948 
949  //Copy curve parameter a
950  params.a = cpkccImportScalar(&pos, curve->a, modLen + 4);
951  //Copy curve parameter b
952  params.b = cpkccImportScalar(&pos, curve->b, modLen + 4);
953  //Initialize workspace
954  params.w = cpkccWorkspace(&pos, 4 * modLen + 28);
955 
956  //Set ZpEcPointIsOnCurve service parameters
957  CPKCL_ZpEcPointIsOnCurve(u2ModLength) = modLen;
958  CPKCL_ZpEcPointIsOnCurve(nu1ModBase) = CPKCC_FAR_TO_NEAR(params.mod);
959  CPKCL_ZpEcPointIsOnCurve(nu1CnsBase) = CPKCC_FAR_TO_NEAR(params.cns);
960  CPKCL_ZpEcPointIsOnCurve(nu1PointBase) = CPKCC_FAR_TO_NEAR(params.point.x);
961  CPKCL_ZpEcPointIsOnCurve(nu1AParam) = CPKCC_FAR_TO_NEAR(params.a);
962  CPKCL_ZpEcPointIsOnCurve(nu1BParam) = CPKCC_FAR_TO_NEAR(params.b);
963  CPKCL_ZpEcPointIsOnCurve(nu1Workspace) = CPKCC_FAR_TO_NEAR(params.w);
964 
965  //Test whether the point is on the curve
966  vCPKCL_Process(ZpEcPointIsOnCurve, pvCPKCLParam);
967  }
968 
969  //Check status code
970  if(CPKCL(u2Status) == CPKCL_OK)
971  {
972  //The point S is on the elliptic curve
973  valid = TRUE;
974  }
975  else
976  {
977  //The point S is not on the elliptic curve
978  valid = FALSE;
979  }
980 
981  //Release exclusive access to the CPKCC accelerator
983 
984  //Return TRUE if the affine point S is on the curve, else FALSE
985  return valid;
986 }
987 
988 
989 /**
990  * @brief Recover affine representation
991  * @param[in] curve Elliptic curve parameters
992  * @param[out] r Affine representation of the point
993  * @param[in] s Projective representation of the point
994  * @return Error code
995  **/
996 
997 error_t ecAffinify(const EcCurve *curve, EcPoint3 *r, const EcPoint3 *s)
998 {
999  error_t error;
1000  size_t modLen;
1001  uint8_t *pos;
1002  PukccZpEcConvProjToAffineParams params = {0};
1003 
1004  //Get the length of the modulus, in bytes
1005  modLen = (curve->fieldSize + 7) / 8;
1006  modLen = (modLen + 3U) & ~3U;
1007 
1008  //Acquire exclusive access to the CPKCC accelerator
1010 
1011  //Point to the crypto memory
1012  pos = (uint8_t *) CPKCC_CRYPTO_RAM_BASE;
1013 
1014  //Copy modulus
1015  params.mod = cpkccImportScalar(&pos, curve->p, modLen + 4);
1016  //Initialize reduction constant
1017  params.cns = cpkccWorkspace(&pos, modLen + 12);
1018  //Initialize workspace R
1019  params.r = cpkccWorkspace(&pos, 64);
1020  //Initialize workspace X
1021  params.x = cpkccWorkspace(&pos, 2 * modLen + 8);
1022 
1023  //Set RedMod service parameters
1024  CPKCL(u2Option) = CPKCL_REDMOD_SETUP;
1025  CPKCL(Specific).CarryIn = 0;
1026  CPKCL(Specific).Gf2n = 0;
1027  CPKCL_RedMod(u2ModLength) = modLen;
1028  CPKCL_RedMod(nu1ModBase) = CPKCC_FAR_TO_NEAR(params.mod);
1029  CPKCL_RedMod(nu1CnsBase) = CPKCC_FAR_TO_NEAR(params.cns);
1030  CPKCL_RedMod(nu1RBase) = CPKCC_FAR_TO_NEAR(params.r);
1031  CPKCL_RedMod(nu1XBase) = CPKCC_FAR_TO_NEAR(params.x);
1032 
1033  //Perform modular reduction setup
1034  vCPKCL_Process(RedMod, pvCPKCLParam);
1035 
1036  //Check status code
1037  if(CPKCL(u2Status) == CPKCL_OK)
1038  {
1039  //Point to the crypto memory
1040  pos = params.r;
1041 
1042  //Copy point coordinates
1043  params.point.x = cpkccImportScalar(&pos, s->x, modLen + 4);
1044  params.point.y = cpkccImportScalar(&pos, s->y, modLen + 4);
1045  params.point.z = cpkccImportScalar(&pos, s->z, modLen + 4);
1046  //Initialize workspace
1047  params.w = cpkccWorkspace(&pos, 4 * modLen + 48);
1048 
1049  //Set ZpEccConvAffineToProjective service parameters
1050  CPKCL_ZpEcConvProjToAffine(u2ModLength) = modLen;
1051  CPKCL_ZpEcConvProjToAffine(nu1ModBase) = CPKCC_FAR_TO_NEAR(params.mod);
1052  CPKCL_ZpEcConvProjToAffine(nu1CnsBase) = CPKCC_FAR_TO_NEAR(params.cns);
1053  CPKCL_ZpEcConvProjToAffine(nu1PointABase) = CPKCC_FAR_TO_NEAR(params.point.x);
1054  CPKCL_ZpEcConvProjToAffine(nu1Workspace) = CPKCC_FAR_TO_NEAR(params.w);
1055 
1056  //Convert point coordinates from projective to affine representation
1057  vCPKCL_Process(ZpEcConvProjToAffine, pvCPKCLParam);
1058  }
1059 
1060  //Check status code
1061  if(CPKCL(u2Status) == CPKCL_OK)
1062  {
1063  //Copy the x-coordinate of the result
1064  error = ecScalarImport(r->x, EC_MAX_MODULUS_SIZE, params.point.x, modLen,
1066 
1067  //Check error code
1068  if(!error)
1069  {
1070  //Copy the y-coordinate of the result
1071  error = ecScalarImport(r->y, EC_MAX_MODULUS_SIZE, params.point.y, modLen,
1073  }
1074 
1075  //Check error code
1076  if(!error)
1077  {
1078  //Copy the z-coordinate of the result
1079  error = ecScalarImport(r->z, EC_MAX_MODULUS_SIZE, params.point.z, modLen,
1081  }
1082  }
1083  else
1084  {
1085  //Report an error
1086  error = ERROR_FAILURE;
1087  }
1088 
1089  //Release exclusive access to the CPKCC accelerator
1091 
1092  //Return error code
1093  return error;
1094 }
1095 
1096 
1097 /**
1098  * @brief Scalar multiplication (fast calculation)
1099  * @param[in] curve Elliptic curve parameters
1100  * @param[out] r Resulting point R = d.S
1101  * @param[in] d An integer d such as 0 <= d < p
1102  * @param[in] s EC point
1103  * @return Error code
1104  **/
1105 
1106 error_t ecMulFast(const EcCurve *curve, EcPoint3 *r, const uint32_t *d,
1107  const EcPoint3 *s)
1108 {
1109  //Compute R = d.S
1110  return ecMulRegular(curve, r, d, s);
1111 }
1112 
1113 
1114 /**
1115  * @brief Scalar multiplication (regular calculation)
1116  * @param[in] curve Elliptic curve parameters
1117  * @param[out] r Resulting point R = d.S
1118  * @param[in] d An integer d such as 0 <= d < q
1119  * @param[in] s EC point
1120  * @return Error code
1121  **/
1122 
1123 error_t ecMulRegular(const EcCurve *curve, EcPoint3 *r, const uint32_t *d,
1124  const EcPoint3 *s)
1125 {
1126  error_t error;
1127  size_t modLen;
1128  size_t orderLen;
1129  uint8_t *pos;
1130  PukccZpEccMulParams params = {0};
1131 
1132  //Get the length of the modulus, in bytes
1133  modLen = (curve->fieldSize + 7) / 8;
1134  modLen = (modLen + 3U) & ~3U;
1135 
1136  //Get the length of the order, in bytes
1137  orderLen = (curve->orderSize + 7) / 8;
1138  orderLen = (orderLen + 3U) & ~3U;
1139 
1140  //Acquire exclusive access to the CPKCC accelerator
1142 
1143  //Point to the crypto memory
1144  pos = (uint8_t *) CPKCC_CRYPTO_RAM_BASE;
1145 
1146  //Copy modulus
1147  params.mod = cpkccImportScalar(&pos, curve->p, modLen + 4);
1148  //Initialize reduction constant
1149  params.cns = cpkccWorkspace(&pos, modLen + 12);
1150  //Initialize workspace R
1151  params.r = cpkccWorkspace(&pos, 64);
1152  //Initialize workspace X
1153  params.x = cpkccWorkspace(&pos, 2 * modLen + 8);
1154 
1155  //Set RedMod service parameters
1156  CPKCL(u2Option) = CPKCL_REDMOD_SETUP;
1157  CPKCL(Specific).CarryIn = 0;
1158  CPKCL(Specific).Gf2n = 0;
1159  CPKCL_RedMod(u2ModLength) = modLen;
1160  CPKCL_RedMod(nu1ModBase) = CPKCC_FAR_TO_NEAR(params.mod);
1161  CPKCL_RedMod(nu1CnsBase) = CPKCC_FAR_TO_NEAR(params.cns);
1162  CPKCL_RedMod(nu1RBase) = CPKCC_FAR_TO_NEAR(params.r);
1163  CPKCL_RedMod(nu1XBase) = CPKCC_FAR_TO_NEAR(params.x);
1164 
1165  //Perform modular reduction setup
1166  vCPKCL_Process(RedMod, pvCPKCLParam);
1167 
1168  //Check status code
1169  if(CPKCL(u2Status) == CPKCL_OK)
1170  {
1171  //Point to the crypto memory
1172  pos = params.r;
1173 
1174  //Copy scalar number
1175  params.k = cpkccImportScalar(&pos, d, orderLen + 4);
1176 
1177  //Copy point coordinates
1178  params.point.x = cpkccImportScalar(&pos, s->x, modLen + 4);
1179  params.point.y = cpkccImportScalar(&pos, s->y, modLen + 4);
1180  params.point.z = cpkccWorkspace(&pos, modLen + 4);
1181  params.point.z[0] = 1;
1182 
1183  //Copy curve parameter a
1184  params.a = cpkccImportScalar(&pos, curve->a, modLen + 4);
1185  //Initialize workspace
1186  params.w = cpkccWorkspace(&pos, 8 * modLen + 44);
1187 
1188  //Set ZpEccMulFast service parameters
1189  CPKCL_ZpEccMul(u2ModLength) = modLen;
1190  CPKCL_ZpEccMul(nu1ModBase) = CPKCC_FAR_TO_NEAR(params.mod);
1191  CPKCL_ZpEccMul(nu1CnsBase) = CPKCC_FAR_TO_NEAR(params.cns);
1192  CPKCL_ZpEccMul(u2KLength) = orderLen;
1193  CPKCL_ZpEccMul(nu1KBase) = CPKCC_FAR_TO_NEAR(params.k);
1194  CPKCL_ZpEccMul(nu1PointBase) = CPKCC_FAR_TO_NEAR(params.point.x);
1195  CPKCL_ZpEccMul(nu1ABase) = CPKCC_FAR_TO_NEAR(params.a);
1196  CPKCL_ZpEccMul(nu1Workspace) = CPKCC_FAR_TO_NEAR(params.w);
1197 
1198  //Perform scalar multiplication over GF(p)
1199  vCPKCL_Process(ZpEccMulFast, pvCPKCLParam);
1200  }
1201 
1202  //Check status code
1203  if(CPKCL(u2Status) == CPKCL_OK)
1204  {
1205  //Copy the x-coordinate of the result
1206  error = ecScalarImport(r->x, EC_MAX_MODULUS_SIZE, params.point.x, modLen,
1208 
1209  //Check error code
1210  if(!error)
1211  {
1212  //Copy the y-coordinate of the result
1213  error = ecScalarImport(r->y, EC_MAX_MODULUS_SIZE, params.point.y, modLen,
1215  }
1216 
1217  //Check error code
1218  if(!error)
1219  {
1220  //Copy the z-coordinate of the result
1221  error = ecScalarImport(r->z, EC_MAX_MODULUS_SIZE, params.point.z, modLen,
1223  }
1224  }
1225  else
1226  {
1227  //Report an error
1228  error = ERROR_FAILURE;
1229  }
1230 
1231  //Release exclusive access to the CPKCC accelerator
1233 
1234  //Return error code
1235  return error;
1236 }
1237 
1238 
1239 /**
1240  * @brief Twin multiplication
1241  * @param[in] curve Elliptic curve parameters
1242  * @param[out] r Resulting point R = d0.S + d1.T
1243  * @param[in] d0 An integer d such as 0 <= d0 < p
1244  * @param[in] s EC point
1245  * @param[in] d1 An integer d such as 0 <= d1 < p
1246  * @param[in] t EC point
1247  * @return Error code
1248  **/
1249 
1250 error_t ecTwinMul(const EcCurve *curve, EcPoint3 *r, const uint32_t *d0,
1251  const EcPoint3 *s, const uint32_t *d1, const EcPoint3 *t)
1252 {
1253  error_t error;
1254  EcPoint3 u;
1255 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
1256  EcState *state;
1257 #else
1258  EcState state[1];
1259 #endif
1260 
1261 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
1262  //Allocate working state
1263  state = cryptoAllocMem(sizeof(EcState));
1264  //Failed to allocate memory?
1265  if(state == NULL)
1266  return ERROR_OUT_OF_MEMORY;
1267 #endif
1268 
1269  //Initialize working state
1270  osMemset(state, 0, sizeof(EcState));
1271  //Save elliptic curve parameters
1272  state->curve = curve;
1273 
1274  //Compute d0.S
1275  error = ecMulFast(curve, r, d0, s);
1276 
1277  //Check status code
1278  if(!error)
1279  {
1280  //Compute d1.T
1281  error = ecMulFast(curve, &u, d1, t);
1282  }
1283 
1284  //Check status code
1285  if(!error)
1286  {
1287  //Compute d0.S + d1.T
1288  ecFullAdd(state, r, r, &u);
1289  }
1290 
1291  //Return status code
1292  return error;
1293 }
1294 
1295 #endif
1296 #if (ECDSA_SUPPORT == ENABLED)
1297 
1298 /**
1299  * @brief ECDSA signature generation
1300  * @param[in] prngAlgo PRNG algorithm
1301  * @param[in] prngContext Pointer to the PRNG context
1302  * @param[in] privateKey Signer's EC private key
1303  * @param[in] digest Digest of the message to be signed
1304  * @param[in] digestLen Length in octets of the digest
1305  * @param[out] signature (R, S) integer pair
1306  * @return Error code
1307  **/
1308 
1309 error_t ecdsaGenerateSignature(const PrngAlgo *prngAlgo, void *prngContext,
1310  const EcPrivateKey *privateKey, const uint8_t *digest, size_t digestLen,
1311  EcdsaSignature *signature)
1312 {
1313  error_t error;
1314  size_t modLen;
1315  size_t orderLen;
1316  uint8_t *pos;
1317  uint32_t k[EC_MAX_ORDER_SIZE];
1318  const EcCurve *curve;
1319  PukccZpEcDsaGenerateParams params = {0};
1320 
1321  //Check parameters
1322  if(privateKey == NULL || digest == NULL || signature == NULL)
1323  return ERROR_INVALID_PARAMETER;
1324 
1325  //Invalid elliptic curve?
1326  if(privateKey->curve == NULL)
1328 
1329  //Get elliptic curve parameters
1330  curve = privateKey->curve;
1331 
1332  //Get the length of the modulus, in bytes
1333  modLen = (curve->fieldSize + 7) / 8;
1334  modLen = (modLen + 3U) & ~3U;
1335 
1336  //Get the length of the order, in bytes
1337  orderLen = (curve->orderSize + 7) / 8;
1338  orderLen = (orderLen + 3U) & ~3U;
1339 
1340  //Keep the leftmost bits of the hash value
1341  digestLen = MIN(digestLen, (curve->orderSize + 7) / 8);
1342 
1343  //Generate a random number k such as 0 < k < q - 1
1344  error = ecScalarRand(curve, k, prngAlgo, prngContext);
1345 
1346  //Acquire exclusive access to the CPKCC accelerator
1348 
1349  //Check error code
1350  if(!error)
1351  {
1352  //Point to the crypto memory
1353  pos = (uint8_t *) CPKCC_CRYPTO_RAM_BASE;
1354 
1355  //Copy modulus
1356  params.mod = cpkccImportScalar(&pos, curve->p, modLen + 4);
1357  //Initialize reduction constant
1358  params.cns = cpkccWorkspace(&pos, orderLen + 12);
1359  //Initialize workspace R
1360  params.r = cpkccWorkspace(&pos, 64);
1361  //Initialize workspace X
1362  params.x = cpkccWorkspace(&pos, 2 * modLen + 8);
1363 
1364  //Set RedMod service parameters
1365  CPKCL(u2Option) = CPKCL_REDMOD_SETUP;
1366  CPKCL(Specific).CarryIn = 0;
1367  CPKCL(Specific).Gf2n = 0;
1368  CPKCL_RedMod(u2ModLength) = modLen;
1369  CPKCL_RedMod(nu1ModBase) = CPKCC_FAR_TO_NEAR(params.mod);
1370  CPKCL_RedMod(nu1CnsBase) = CPKCC_FAR_TO_NEAR(params.cns);
1371  CPKCL_RedMod(nu1RBase) = CPKCC_FAR_TO_NEAR(params.r);
1372  CPKCL_RedMod(nu1XBase) = CPKCC_FAR_TO_NEAR(params.x);
1373 
1374  //Perform modular reduction setup
1375  vCPKCL_Process(RedMod, pvCPKCLParam);
1376 
1377  //Check status code
1378  if(CPKCL(u2Status) != CPKCL_OK)
1379  error = ERROR_FAILURE;
1380  }
1381 
1382  //Check error code
1383  if(!error)
1384  {
1385  //Point to the crypto memory
1386  pos = params.r;
1387 
1388  //Copy base point coordinates
1389  params.basePoint.x = cpkccImportScalar(&pos, curve->g.x, modLen + 4);
1390  params.basePoint.y = cpkccImportScalar(&pos, curve->g.y, modLen + 4);
1391  params.basePoint.z = cpkccImportScalar(&pos, curve->g.z, modLen + 4);
1392 
1393  //Copy base point order
1394  params.order = cpkccImportScalar(&pos, curve->q, orderLen + 4);
1395  //Copy curve parameter a
1396  params.a = cpkccImportScalar(&pos, curve->a, modLen + 4);
1397  //Copy private key
1398  params.privateKey = cpkccImportScalar(&pos, privateKey->d, orderLen + 4);
1399  //Copy random scalar
1400  params.k = cpkccImportScalar(&pos, k, orderLen + 4);
1401  //Copy digest
1402  params.h = cpkccImportArray(&pos, digest, digestLen, orderLen + 4);
1403  //Initialize workspace
1404  params.w = cpkccWorkspace(&pos, 8 * modLen + 44);
1405 
1406  //Set ZpEcDsaGenerateFast service parameters
1407  CPKCL_ZpEcDsaGenerate(u2ModLength) = modLen;
1408  CPKCL_ZpEcDsaGenerate(nu1ModBase) = CPKCC_FAR_TO_NEAR(params.mod);
1409  CPKCL_ZpEcDsaGenerate(nu1CnsBase) = CPKCC_FAR_TO_NEAR(params.cns);
1410  CPKCL_ZpEcDsaGenerate(nu1PointABase) = CPKCC_FAR_TO_NEAR(params.basePoint.x);
1411  CPKCL_ZpEcDsaGenerate(nu1OrderPointBase) = CPKCC_FAR_TO_NEAR(params.order);
1412  CPKCL_ZpEcDsaGenerate(nu1ABase) = CPKCC_FAR_TO_NEAR(params.a);
1413  CPKCL_ZpEcDsaGenerate(nu1PrivateKey) = CPKCC_FAR_TO_NEAR(params.privateKey);
1414  CPKCL_ZpEcDsaGenerate(u2ScalarLength) = orderLen;
1415  CPKCL_ZpEcDsaGenerate(nu1ScalarNumber) = CPKCC_FAR_TO_NEAR(params.k);
1416  CPKCL_ZpEcDsaGenerate(nu1HashBase) = CPKCC_FAR_TO_NEAR(params.h);
1417  CPKCL_ZpEcDsaGenerate(nu1Workspace) = CPKCC_FAR_TO_NEAR(params.w);
1418 
1419  //Perform ECDSA signature generation
1420  vCPKCL_Process(ZpEcDsaGenerateFast, pvCPKCLParam);
1421 
1422  //Check status code
1423  if(CPKCL(u2Status) != CPKCL_OK)
1424  error = ERROR_FAILURE;
1425  }
1426 
1427  //Check error code
1428  if(!error)
1429  {
1430  //Save elliptic curve parameters
1431  signature->curve = curve;
1432 
1433  //Copy the first part of the ECDSA signature
1434  error = ecScalarImport(signature->r, EC_MAX_ORDER_SIZE,
1435  params.basePoint.x, orderLen, EC_SCALAR_FORMAT_LITTLE_ENDIAN);
1436  }
1437 
1438  //Check error code
1439  if(!error)
1440  {
1441  //Copy the second part of the ECDSA signature
1442  error = ecScalarImport(signature->s, EC_MAX_ORDER_SIZE,
1443  params.basePoint.x + orderLen + 4, orderLen,
1445  }
1446 
1447  //Release exclusive access to the CPKCC accelerator
1449 
1450  //Return error code
1451  return error;
1452 }
1453 
1454 
1455 /**
1456  * @brief ECDSA signature verification
1457  * @param[in] publicKey Signer's EC public key
1458  * @param[in] digest Digest of the message whose signature is to be verified
1459  * @param[in] digestLen Length in octets of the digest
1460  * @param[in] signature (R, S) integer pair
1461  * @return Error code
1462  **/
1463 
1465  const uint8_t *digest, size_t digestLen, const EcdsaSignature *signature)
1466 {
1467  error_t error;
1468  size_t modLen;
1469  size_t orderLen;
1470  uint8_t *pos;
1471  const EcCurve *curve;
1472  PukccZpEcDsaVerifyParams params = {0};
1473 
1474  //Check parameters
1475  if(publicKey == NULL || digest == NULL || signature == NULL)
1476  return ERROR_INVALID_PARAMETER;
1477 
1478  //Invalid elliptic curve?
1479  if(publicKey->curve == NULL)
1481 
1482  //Verify that the public key is on the curve
1483  if(!ecIsPointAffine(publicKey->curve, &publicKey->q))
1484  {
1485  return ERROR_INVALID_SIGNATURE;
1486  }
1487 
1488  //The verifier shall check that 0 < r < q
1489  if(ecScalarCompInt(signature->r, 0, EC_MAX_ORDER_SIZE) <= 0 ||
1490  ecScalarComp(signature->r, publicKey->curve->q, EC_MAX_ORDER_SIZE) >= 0)
1491  {
1492  //If the condition is violated, the signature shall be rejected as invalid
1493  return ERROR_INVALID_SIGNATURE;
1494  }
1495 
1496  //The verifier shall check that 0 < s < q
1497  if(ecScalarCompInt(signature->s, 0, EC_MAX_ORDER_SIZE) <= 0 ||
1498  ecScalarComp(signature->s, publicKey->curve->q, EC_MAX_ORDER_SIZE) >= 0)
1499  {
1500  //If the condition is violated, the signature shall be rejected as invalid
1501  return ERROR_INVALID_SIGNATURE;
1502  }
1503 
1504  //Get elliptic curve parameters
1505  curve = publicKey->curve;
1506 
1507  //Get the length of the modulus, in bytes
1508  modLen = (curve->fieldSize + 7) / 8;
1509  modLen = (modLen + 3U) & ~3U;
1510 
1511  //Get the length of the order, in bytes
1512  orderLen = (curve->orderSize + 7) / 8;
1513  orderLen = (orderLen + 3U) & ~3U;
1514 
1515  //Keep the leftmost bits of the hash value
1516  digestLen = MIN(digestLen, (curve->orderSize + 7) / 8);
1517 
1518  //Acquire exclusive access to the CPKCC accelerator
1520 
1521  //Point to the crypto memory
1522  pos = (uint8_t *) CPKCC_CRYPTO_RAM_BASE;
1523 
1524  //Copy modulus
1525  params.mod = cpkccImportScalar(&pos, curve->p, modLen + 4);
1526  //Initialize reduction constant
1527  params.cns = cpkccWorkspace(&pos, orderLen + 12);
1528  //Initialize workspace R
1529  params.r = cpkccWorkspace(&pos, 64);
1530  //Initialize workspace X
1531  params.x = cpkccWorkspace(&pos, 2 * modLen + 8);
1532 
1533  //Set RedMod service parameters
1534  CPKCL(u2Option) = CPKCL_REDMOD_SETUP;
1535  CPKCL(Specific).CarryIn = 0;
1536  CPKCL(Specific).Gf2n = 0;
1537  CPKCL_RedMod(u2ModLength) = modLen;
1538  CPKCL_RedMod(nu1ModBase) = CPKCC_FAR_TO_NEAR(params.mod);
1539  CPKCL_RedMod(nu1CnsBase) = CPKCC_FAR_TO_NEAR(params.cns);
1540  CPKCL_RedMod(nu1RBase) = CPKCC_FAR_TO_NEAR(params.r);
1541  CPKCL_RedMod(nu1XBase) = CPKCC_FAR_TO_NEAR(params.x);
1542 
1543  //Perform modular reduction setup
1544  vCPKCL_Process(RedMod, pvCPKCLParam);
1545 
1546  //Check status code
1547  if(CPKCL(u2Status) == CPKCL_OK)
1548  {
1549  //Point to the crypto memory
1550  pos = params.r;
1551 
1552  //Copy base point coordinates
1553  params.basePoint.x = cpkccImportScalar(&pos, curve->g.x, modLen + 4);
1554  params.basePoint.y = cpkccImportScalar(&pos, curve->g.y, modLen + 4);
1555  params.basePoint.z = cpkccImportScalar(&pos, curve->g.z, modLen + 4);
1556 
1557  //Copy base point order
1558  params.order = cpkccImportScalar(&pos, curve->q, orderLen + 4);
1559  //Copy curve parameter a
1560  params.a = cpkccImportScalar(&pos, curve->a, modLen + 4);
1561 
1562  //Copy public key
1563  params.publicKey.x = cpkccImportScalar(&pos, publicKey->q.x, modLen + 4);
1564  params.publicKey.y = cpkccImportScalar(&pos, publicKey->q.y, modLen + 4);
1565  params.publicKey.z = cpkccWorkspace(&pos, modLen + 4);
1566  params.publicKey.z[0] = 1;
1567 
1568  //Copy digest
1569  params.h = cpkccImportArray(&pos, digest, digestLen, orderLen + 4);
1570 
1571  //Copy signature
1572  params.r = cpkccImportScalar(&pos, signature->r, orderLen + 4);
1573  params.s = cpkccImportScalar(&pos, signature->s, orderLen + 4);
1574 
1575  //Initialize workspace
1576  params.w = cpkccWorkspace(&pos, 8 * modLen + 44);
1577 
1578  //Set ZpEcDsaVerifyFast service parameters
1579  CPKCL(u2Option) = 0;
1580  CPKCL_ZpEcDsaVerify(u2ModLength) = modLen;
1581  CPKCL_ZpEcDsaVerify(nu1ModBase) = CPKCC_FAR_TO_NEAR(params.mod);
1582  CPKCL_ZpEcDsaVerify(nu1CnsBase) = CPKCC_FAR_TO_NEAR(params.cns);
1583  CPKCL_ZpEcDsaVerify(nu1PointABase) = CPKCC_FAR_TO_NEAR(params.basePoint.x);
1584  CPKCL_ZpEcDsaVerify(nu1OrderPointBase) = CPKCC_FAR_TO_NEAR(params.order);
1585  CPKCL_ZpEcDsaVerify(nu1ABase) = CPKCC_FAR_TO_NEAR(params.a);
1586  CPKCL_ZpEcDsaVerify(nu1PointPublicKeyGen) = CPKCC_FAR_TO_NEAR(params.publicKey.x);
1587  CPKCL_ZpEcDsaVerify(u2ScalarLength) = orderLen;
1588  CPKCL_ZpEcDsaVerify(nu1HashBase) = CPKCC_FAR_TO_NEAR(params.h);
1589  CPKCL_ZpEcDsaVerify(nu1PointSignature) = CPKCC_FAR_TO_NEAR(params.r);
1590  CPKCL_ZpEcDsaVerify(nu1Workspace) = CPKCC_FAR_TO_NEAR(params.w);
1591 
1592  //Perform ECDSA signature verification
1593  vCPKCL_Process(ZpEcDsaVerifyFast, pvCPKCLParam);
1594  }
1595 
1596  //Check status code
1597  if(CPKCL(u2Status) == CPKCL_OK)
1598  {
1599  //The ECDSA signature is valid
1600  error = NO_ERROR;
1601  }
1602  else if(CPKCL(u2Status) == CPKCL_WRONG_SIGNATURE)
1603  {
1604  //The ECDSA signature is not valid
1605  error = ERROR_INVALID_SIGNATURE;
1606  }
1607  else
1608  {
1609  //Report an error
1610  error = ERROR_FAILURE;
1611  }
1612 
1613  //Release exclusive access to the CPKCC accelerator
1615 
1616  //Return status code
1617  return error;
1618 }
1619 
1620 #endif
1621 #endif
error_t ecScalarImport(uint32_t *r, uint_t n, const uint8_t *input, size_t length, EcScalarFormat format)
Octet string to integer conversion.
Definition: ec_misc.c:54
ECDSA signature.
Definition: ecdsa.h:63
ZpEccMul service parameters.
ZpEcPointIsOnCurve service parameters.
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 bool_t
Definition: compiler_port.h:63
uint8_t b
Definition: nbns_common.h:122
@ ERROR_OUT_OF_RANGE
Definition: error.h:138
error_t mpiMod2(Mpi *r, const Mpi *a, const Mpi *p)
Modulo operation.
error_t mpiExpMod(Mpi *r, const Mpi *a, const Mpi *e, const Mpi *p)
Modular exponentiation.
Mpi p
First factor.
Definition: rsa.h:72
error_t mpiMul(Mpi *r, const Mpi *a, const Mpi *b)
Multiple precision multiplication.
uint8_t a
Definition: ndp.h:411
error_t ecScalarExport(const uint32_t *a, uint_t n, uint8_t *output, size_t length, EcScalarFormat format)
Integer to octet string conversion.
Definition: ec_misc.c:150
Arbitrary precision integer.
Definition: mpi.h:102
#define PrngAlgo
Definition: crypto.h:1049
PrimeGen service parameters.
bool_t ecIsPointAffine(const EcCurve *curve, const EcPoint *s)
Check whether the affine point S is on the curve.
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 TRUE
Definition: os_port.h:50
uint8_t * cpkccWorkspace(uint8_t **dest, size_t totalLen)
Initialize workspace area.
error_t ecAffinify(const EcCurve *curve, EcPoint3 *r, const EcPoint3 *s)
Recover affine representation.
#define sleep(delay)
Definition: os_port.h:313
#define EC_MAX_ORDER_SIZE
Definition: ec.h:315
Mpi n
Modulus.
Definition: rsa.h:69
error_t ecdsaVerifySignature(const EcPublicKey *publicKey, const uint8_t *digest, size_t digestLen, const EcdsaSignature *signature)
ECDSA signature verification.
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
Fmult service parameters.
uint32_t y[EC_MAX_MODULUS_SIZE]
y-coordinate
Definition: ec.h:400
ExpMod service parameters.
error_t cpkccInit(void)
Initialize CPKCC module.
CPKCL_PARAM CPKCLParam
Mpi d
Private exponent.
Definition: rsa.h:71
uint8_t r
Definition: ndp.h:346
@ ERROR_INVALID_ELLIPTIC_CURVE
Definition: error.h:134
error_t ecMulFast(const EcCurve *curve, EcPoint3 *r, const uint32_t *d, const EcPoint3 *s)
Scalar multiplication (fast calculation)
#define FALSE
Definition: os_port.h:46
error_t ecMulRegular(const EcCurve *curve, EcPoint3 *r, const uint32_t *d, const EcPoint3 *s)
Scalar multiplication (regular calculation)
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
@ MPI_FORMAT_LITTLE_ENDIAN
Definition: mpi.h:92
error_t
Error codes.
Definition: error.h:43
error_t mpiCheckProbablePrime(const Mpi *a)
Test whether a number is probable prime.
uint8_t * cpkccImportMpi(uint8_t **dest, const Mpi *src, size_t totalLen)
Import multiple-precision integer.
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
uint8_t * cpkccImportScalar(uint8_t **dest, const uint32_t *src, size_t totalLen)
Import scalar.
Mpi q
Second factor.
Definition: rsa.h:73
Helper routines for ECC.
ZpEcConvProjToAffine service parameters.
error_t rsadp(const RsaPrivateKey *key, const Mpi *c, Mpi *m)
RSA decryption primitive.
error_t mpiImport(Mpi *r, const uint8_t *input, size_t length, MpiFormat format)
Octet string to integer conversion.
Definition: mpi.c:714
ZpEcDsaVerify service parameters.
uint32_t r[EC_MAX_ORDER_SIZE]
Integer R.
Definition: ecdsa.h:65
MPI (Multiple Precision Integer Arithmetic)
@ ERROR_INVALID_LENGTH
Definition: error.h:111
@ EC_SCALAR_FORMAT_LITTLE_ENDIAN
Definition: ec_misc.h:50
General definitions for cryptographic algorithms.
RSA public-key cryptography standard.
EC private key.
Definition: ec.h:432
uint8_t u
Definition: lldp_ext_med.h:213
error_t mpiExport(const Mpi *a, uint8_t *output, size_t length, MpiFormat format)
Integer to octet string conversion.
Definition: mpi.c:811
EC point (affine coordinates)
Definition: ec.h:398
uint8_t * cpkccImportArray(uint8_t **dest, const uint8_t *src, size_t srcLen, size_t totalLen)
Import byte array.
#define MIN(a, b)
Definition: os_port.h:63
PIC32CX MTC/MTG/MTSH hardware cryptographic accelerator.
RedMod service parameters.
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
PIC32CX MTC/MTG/MTSH public-key hardware accelerator (CPKCC)
error_t mpiInvMod(Mpi *r, const Mpi *a, const Mpi *p)
Modular inverse.
EC public key.
Definition: ec.h:421
#define MAX(a, b)
Definition: os_port.h:67
const EcCurve * curve
Definition: ec.h:446
GCD service parameters.
CRT service parameters.
@ ERROR_INVALID_VALUE
Definition: error.h:116
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
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
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
EC point (projective coordinates)
Definition: ec.h:409
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
EcPoint q
Public key.
Definition: ec.h:423
ZpEcDsaGenerate service parameters.
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:870
uint8_t s
Definition: igmp_common.h:234
error_t ecdsaGenerateSignature(const PrngAlgo *prngAlgo, void *prngContext, const EcPrivateKey *privateKey, const uint8_t *digest, size_t digestLen, EcdsaSignature *signature)
ECDSA signature generation.
OsMutex pic32cxmtCryptoMutex
#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
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
ECC (Elliptic Curve Cryptography)
@ ERROR_INVALID_SIGNATURE
Definition: error.h:228
PCPKCL_PARAM pvCPKCLParam
const EcCurve * curve
Elliptic curve parameters.
Definition: ec.h:422
#define CPKCC_FAR_TO_NEAR(p)
#define CPKCC_CRYPTO_RAM_BASE
#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.
uint_t mpiGetByteLength(const Mpi *a)
Get the actual length in bytes.
Definition: mpi.c:216