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-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 "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 #endif
1239 #if (ECDSA_SUPPORT == ENABLED)
1240 
1241 /**
1242  * @brief ECDSA signature generation
1243  * @param[in] prngAlgo PRNG algorithm
1244  * @param[in] prngContext Pointer to the PRNG context
1245  * @param[in] privateKey Signer's EC private key
1246  * @param[in] digest Digest of the message to be signed
1247  * @param[in] digestLen Length in octets of the digest
1248  * @param[out] signature (R, S) integer pair
1249  * @return Error code
1250  **/
1251 
1252 error_t ecdsaGenerateSignature(const PrngAlgo *prngAlgo, void *prngContext,
1253  const EcPrivateKey *privateKey, const uint8_t *digest, size_t digestLen,
1254  EcdsaSignature *signature)
1255 {
1256  error_t error;
1257  size_t modLen;
1258  size_t orderLen;
1259  uint8_t *pos;
1260  uint32_t k[EC_MAX_ORDER_SIZE];
1261  const EcCurve *curve;
1262  PukccZpEcDsaGenerateParams params = {0};
1263 
1264  //Check parameters
1265  if(privateKey == NULL || digest == NULL || signature == NULL)
1266  return ERROR_INVALID_PARAMETER;
1267 
1268  //Invalid elliptic curve?
1269  if(privateKey->curve == NULL)
1271 
1272  //Get elliptic curve parameters
1273  curve = privateKey->curve;
1274 
1275  //Get the length of the modulus, in bytes
1276  modLen = (curve->fieldSize + 7) / 8;
1277  modLen = (modLen + 3U) & ~3U;
1278 
1279  //Get the length of the order, in bytes
1280  orderLen = (curve->orderSize + 7) / 8;
1281  orderLen = (orderLen + 3U) & ~3U;
1282 
1283  //Keep the leftmost bits of the hash value
1284  digestLen = MIN(digestLen, (curve->orderSize + 7) / 8);
1285 
1286  //Generate a random number k such as 0 < k < q - 1
1287  error = ecScalarRand(curve, k, prngAlgo, prngContext);
1288 
1289  //Acquire exclusive access to the CPKCC accelerator
1291 
1292  //Check error code
1293  if(!error)
1294  {
1295  //Point to the crypto memory
1296  pos = (uint8_t *) CPKCC_CRYPTO_RAM_BASE;
1297 
1298  //Copy modulus
1299  params.mod = cpkccImportScalar(&pos, curve->p, modLen + 4);
1300  //Initialize reduction constant
1301  params.cns = cpkccWorkspace(&pos, orderLen + 12);
1302  //Initialize workspace R
1303  params.r = cpkccWorkspace(&pos, 64);
1304  //Initialize workspace X
1305  params.x = cpkccWorkspace(&pos, 2 * modLen + 8);
1306 
1307  //Set RedMod service parameters
1308  CPKCL(u2Option) = CPKCL_REDMOD_SETUP;
1309  CPKCL(Specific).CarryIn = 0;
1310  CPKCL(Specific).Gf2n = 0;
1311  CPKCL_RedMod(u2ModLength) = modLen;
1312  CPKCL_RedMod(nu1ModBase) = CPKCC_FAR_TO_NEAR(params.mod);
1313  CPKCL_RedMod(nu1CnsBase) = CPKCC_FAR_TO_NEAR(params.cns);
1314  CPKCL_RedMod(nu1RBase) = CPKCC_FAR_TO_NEAR(params.r);
1315  CPKCL_RedMod(nu1XBase) = CPKCC_FAR_TO_NEAR(params.x);
1316 
1317  //Perform modular reduction setup
1318  vCPKCL_Process(RedMod, pvCPKCLParam);
1319 
1320  //Check status code
1321  if(CPKCL(u2Status) != CPKCL_OK)
1322  error = ERROR_FAILURE;
1323  }
1324 
1325  //Check error code
1326  if(!error)
1327  {
1328  //Point to the crypto memory
1329  pos = params.r;
1330 
1331  //Copy base point coordinates
1332  params.basePoint.x = cpkccImportScalar(&pos, curve->g.x, modLen + 4);
1333  params.basePoint.y = cpkccImportScalar(&pos, curve->g.y, modLen + 4);
1334  params.basePoint.z = cpkccImportScalar(&pos, curve->g.z, modLen + 4);
1335 
1336  //Copy base point order
1337  params.order = cpkccImportScalar(&pos, curve->q, orderLen + 4);
1338  //Copy curve parameter a
1339  params.a = cpkccImportScalar(&pos, curve->a, modLen + 4);
1340  //Copy private key
1341  params.privateKey = cpkccImportScalar(&pos, privateKey->d, orderLen + 4);
1342  //Copy random scalar
1343  params.k = cpkccImportScalar(&pos, k, orderLen + 4);
1344  //Copy digest
1345  params.h = cpkccImportArray(&pos, digest, digestLen, orderLen + 4);
1346  //Initialize workspace
1347  params.w = cpkccWorkspace(&pos, 8 * modLen + 44);
1348 
1349  //Set ZpEcDsaGenerateFast service parameters
1350  CPKCL_ZpEcDsaGenerate(u2ModLength) = modLen;
1351  CPKCL_ZpEcDsaGenerate(nu1ModBase) = CPKCC_FAR_TO_NEAR(params.mod);
1352  CPKCL_ZpEcDsaGenerate(nu1CnsBase) = CPKCC_FAR_TO_NEAR(params.cns);
1353  CPKCL_ZpEcDsaGenerate(nu1PointABase) = CPKCC_FAR_TO_NEAR(params.basePoint.x);
1354  CPKCL_ZpEcDsaGenerate(nu1OrderPointBase) = CPKCC_FAR_TO_NEAR(params.order);
1355  CPKCL_ZpEcDsaGenerate(nu1ABase) = CPKCC_FAR_TO_NEAR(params.a);
1356  CPKCL_ZpEcDsaGenerate(nu1PrivateKey) = CPKCC_FAR_TO_NEAR(params.privateKey);
1357  CPKCL_ZpEcDsaGenerate(u2ScalarLength) = orderLen;
1358  CPKCL_ZpEcDsaGenerate(nu1ScalarNumber) = CPKCC_FAR_TO_NEAR(params.k);
1359  CPKCL_ZpEcDsaGenerate(nu1HashBase) = CPKCC_FAR_TO_NEAR(params.h);
1360  CPKCL_ZpEcDsaGenerate(nu1Workspace) = CPKCC_FAR_TO_NEAR(params.w);
1361 
1362  //Perform ECDSA signature generation
1363  vCPKCL_Process(ZpEcDsaGenerateFast, pvCPKCLParam);
1364 
1365  //Check status code
1366  if(CPKCL(u2Status) != CPKCL_OK)
1367  error = ERROR_FAILURE;
1368  }
1369 
1370  //Check error code
1371  if(!error)
1372  {
1373  //Save elliptic curve parameters
1374  signature->curve = curve;
1375 
1376  //Copy the first part of the ECDSA signature
1377  error = ecScalarImport(signature->r, EC_MAX_ORDER_SIZE,
1378  params.basePoint.x, orderLen, EC_SCALAR_FORMAT_LITTLE_ENDIAN);
1379  }
1380 
1381  //Check error code
1382  if(!error)
1383  {
1384  //Copy the second part of the ECDSA signature
1385  error = ecScalarImport(signature->s, EC_MAX_ORDER_SIZE,
1386  params.basePoint.x + orderLen + 4, orderLen,
1388  }
1389 
1390  //Release exclusive access to the CPKCC accelerator
1392 
1393  //Return error code
1394  return error;
1395 }
1396 
1397 
1398 /**
1399  * @brief ECDSA signature verification
1400  * @param[in] publicKey Signer's EC public key
1401  * @param[in] digest Digest of the message whose signature is to be verified
1402  * @param[in] digestLen Length in octets of the digest
1403  * @param[in] signature (R, S) integer pair
1404  * @return Error code
1405  **/
1406 
1408  const uint8_t *digest, size_t digestLen, const EcdsaSignature *signature)
1409 {
1410  error_t error;
1411  size_t modLen;
1412  size_t orderLen;
1413  uint8_t *pos;
1414  const EcCurve *curve;
1415  PukccZpEcDsaVerifyParams params = {0};
1416 
1417  //Check parameters
1418  if(publicKey == NULL || digest == NULL || signature == NULL)
1419  return ERROR_INVALID_PARAMETER;
1420 
1421  //Invalid elliptic curve?
1422  if(publicKey->curve == NULL)
1424 
1425  //Verify that the public key is on the curve
1426  if(!ecIsPointAffine(publicKey->curve, &publicKey->q))
1427  {
1428  return ERROR_INVALID_SIGNATURE;
1429  }
1430 
1431  //The verifier shall check that 0 < r < q
1432  if(ecScalarCompInt(signature->r, 0, EC_MAX_ORDER_SIZE) <= 0 ||
1433  ecScalarComp(signature->r, publicKey->curve->q, EC_MAX_ORDER_SIZE) >= 0)
1434  {
1435  //If the condition is violated, the signature shall be rejected as invalid
1436  return ERROR_INVALID_SIGNATURE;
1437  }
1438 
1439  //The verifier shall check that 0 < s < q
1440  if(ecScalarCompInt(signature->s, 0, EC_MAX_ORDER_SIZE) <= 0 ||
1441  ecScalarComp(signature->s, publicKey->curve->q, EC_MAX_ORDER_SIZE) >= 0)
1442  {
1443  //If the condition is violated, the signature shall be rejected as invalid
1444  return ERROR_INVALID_SIGNATURE;
1445  }
1446 
1447  //Get elliptic curve parameters
1448  curve = publicKey->curve;
1449 
1450  //Get the length of the modulus, in bytes
1451  modLen = (curve->fieldSize + 7) / 8;
1452  modLen = (modLen + 3U) & ~3U;
1453 
1454  //Get the length of the order, in bytes
1455  orderLen = (curve->orderSize + 7) / 8;
1456  orderLen = (orderLen + 3U) & ~3U;
1457 
1458  //Keep the leftmost bits of the hash value
1459  digestLen = MIN(digestLen, (curve->orderSize + 7) / 8);
1460 
1461  //Acquire exclusive access to the CPKCC accelerator
1463 
1464  //Point to the crypto memory
1465  pos = (uint8_t *) CPKCC_CRYPTO_RAM_BASE;
1466 
1467  //Copy modulus
1468  params.mod = cpkccImportScalar(&pos, curve->p, modLen + 4);
1469  //Initialize reduction constant
1470  params.cns = cpkccWorkspace(&pos, orderLen + 12);
1471  //Initialize workspace R
1472  params.r = cpkccWorkspace(&pos, 64);
1473  //Initialize workspace X
1474  params.x = cpkccWorkspace(&pos, 2 * modLen + 8);
1475 
1476  //Set RedMod service parameters
1477  CPKCL(u2Option) = CPKCL_REDMOD_SETUP;
1478  CPKCL(Specific).CarryIn = 0;
1479  CPKCL(Specific).Gf2n = 0;
1480  CPKCL_RedMod(u2ModLength) = modLen;
1481  CPKCL_RedMod(nu1ModBase) = CPKCC_FAR_TO_NEAR(params.mod);
1482  CPKCL_RedMod(nu1CnsBase) = CPKCC_FAR_TO_NEAR(params.cns);
1483  CPKCL_RedMod(nu1RBase) = CPKCC_FAR_TO_NEAR(params.r);
1484  CPKCL_RedMod(nu1XBase) = CPKCC_FAR_TO_NEAR(params.x);
1485 
1486  //Perform modular reduction setup
1487  vCPKCL_Process(RedMod, pvCPKCLParam);
1488 
1489  //Check status code
1490  if(CPKCL(u2Status) == CPKCL_OK)
1491  {
1492  //Point to the crypto memory
1493  pos = params.r;
1494 
1495  //Copy base point coordinates
1496  params.basePoint.x = cpkccImportScalar(&pos, curve->g.x, modLen + 4);
1497  params.basePoint.y = cpkccImportScalar(&pos, curve->g.y, modLen + 4);
1498  params.basePoint.z = cpkccImportScalar(&pos, curve->g.z, modLen + 4);
1499 
1500  //Copy base point order
1501  params.order = cpkccImportScalar(&pos, curve->q, orderLen + 4);
1502  //Copy curve parameter a
1503  params.a = cpkccImportScalar(&pos, curve->a, modLen + 4);
1504 
1505  //Copy public key
1506  params.publicKey.x = cpkccImportScalar(&pos, publicKey->q.x, modLen + 4);
1507  params.publicKey.y = cpkccImportScalar(&pos, publicKey->q.y, modLen + 4);
1508  params.publicKey.z = cpkccWorkspace(&pos, modLen + 4);
1509  params.publicKey.z[0] = 1;
1510 
1511  //Copy digest
1512  params.h = cpkccImportArray(&pos, digest, digestLen, orderLen + 4);
1513 
1514  //Copy signature
1515  params.r = cpkccImportScalar(&pos, signature->r, orderLen + 4);
1516  params.s = cpkccImportScalar(&pos, signature->s, orderLen + 4);
1517 
1518  //Initialize workspace
1519  params.w = cpkccWorkspace(&pos, 8 * modLen + 44);
1520 
1521  //Set ZpEcDsaVerifyFast service parameters
1522  CPKCL(u2Option) = 0;
1523  CPKCL_ZpEcDsaVerify(u2ModLength) = modLen;
1524  CPKCL_ZpEcDsaVerify(nu1ModBase) = CPKCC_FAR_TO_NEAR(params.mod);
1525  CPKCL_ZpEcDsaVerify(nu1CnsBase) = CPKCC_FAR_TO_NEAR(params.cns);
1526  CPKCL_ZpEcDsaVerify(nu1PointABase) = CPKCC_FAR_TO_NEAR(params.basePoint.x);
1527  CPKCL_ZpEcDsaVerify(nu1OrderPointBase) = CPKCC_FAR_TO_NEAR(params.order);
1528  CPKCL_ZpEcDsaVerify(nu1ABase) = CPKCC_FAR_TO_NEAR(params.a);
1529  CPKCL_ZpEcDsaVerify(nu1PointPublicKeyGen) = CPKCC_FAR_TO_NEAR(params.publicKey.x);
1530  CPKCL_ZpEcDsaVerify(u2ScalarLength) = orderLen;
1531  CPKCL_ZpEcDsaVerify(nu1HashBase) = CPKCC_FAR_TO_NEAR(params.h);
1532  CPKCL_ZpEcDsaVerify(nu1PointSignature) = CPKCC_FAR_TO_NEAR(params.r);
1533  CPKCL_ZpEcDsaVerify(nu1Workspace) = CPKCC_FAR_TO_NEAR(params.w);
1534 
1535  //Perform ECDSA signature verification
1536  vCPKCL_Process(ZpEcDsaVerifyFast, pvCPKCLParam);
1537  }
1538 
1539  //Check status code
1540  if(CPKCL(u2Status) == CPKCL_OK)
1541  {
1542  //The ECDSA signature is valid
1543  error = NO_ERROR;
1544  }
1545  else if(CPKCL(u2Status) == CPKCL_WRONG_SIGNATURE)
1546  {
1547  //The ECDSA signature is not valid
1548  error = ERROR_INVALID_SIGNATURE;
1549  }
1550  else
1551  {
1552  //Report an error
1553  error = ERROR_FAILURE;
1554  }
1555 
1556  //Release exclusive access to the CPKCC accelerator
1558 
1559  //Return status code
1560  return error;
1561 }
1562 
1563 #endif
1564 #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.
int bool_t
Definition: compiler_port.h:61
uint8_t b
Definition: nbns_common.h:104
@ 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:973
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
#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:310
#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.
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:712
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
error_t mpiExport(const Mpi *a, uint8_t *output, size_t length, MpiFormat format)
Integer to octet string conversion.
Definition: mpi.c:809
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:254
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
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
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
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: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
#define osMemset(p, value, length)
Definition: os_port.h:138
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:215