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