sama5d4_crypto_pkc.c
Go to the documentation of this file.
1 /**
2  * @file sama5d4_crypto_pkc.c
3  * @brief SAMA5D4 public-key hardware accelerator (CPKCC)
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2026 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneCRYPTO Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.6.0
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
33 
34 //Dependencies
35 #include "chip.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 "mpi/mpi.h"
43 #include "debug.h"
44 
45 //Check crypto library configuration
46 #if (SAMA5D4_CRYPTO_PKC_SUPPORT == ENABLED)
47 
48 //Global variables
49 PCPKCL_PARAM pvCPKCLParam;
50 CPKCL_PARAM CPKCLParam;
51 
52 
53 /**
54  * @brief Initialize CPKCC module
55  **/
56 
58 {
59  //Enable CPKCC peripheral clock
60  PMC->PMC_PCER0 = (1U << ID_CPKCC);
61 
62  //Delay
63  sleep(10);
64 
65  //Clear CPKCLParam structure
66  osMemset(&CPKCLParam, 0, sizeof(CPKCL_PARAM));
68 
69  //Initialize CPKCC
70  vCPKCL_Process(SelfTest, pvCPKCLParam);
71 
72  //Check status code
73  if(CPKCL(u2Status) != CPKCL_OK)
74  return ERROR_FAILURE;
75 
76  //Check version number
77  if(pvCPKCLParam->P.CPKCL_SelfTest_s.u4Version != CPKCL_VERSION)
78  return ERROR_FAILURE;
79 
80  //The return values from the SelfTest service must be compared against
81  //known values mentioned in the service description
82  if(pvCPKCLParam->P.CPKCL_SelfTest_s.u4CheckNum1 != 0x6E70DDD2)
83  return ERROR_FAILURE;
84 
85  if(pvCPKCLParam->P.CPKCL_SelfTest_s.u4CheckNum2 != 0x25C8D64F)
86  return ERROR_FAILURE;
87 
88  if(pvCPKCLParam->P.CPKCL_SelfTest_s.u1Step != 0x03)
89  return ERROR_FAILURE;
90 
91  //Successful initialization
92  return NO_ERROR;
93 }
94 
95 
96 /**
97  * @brief Import multiple-precision integer
98  * @param[in,out] dest Pointer to the crypto memory
99  * @param[in] src Pointer to the multiple-precision integer
100  * @param[in] totalLen Desired length of the area, in bytes
101  * @return Pointer to the initialized area
102  **/
103 
104 uint8_t *cpkccImportMpi(uint8_t **dest, const Mpi *src, size_t totalLen)
105 {
106  uint8_t *p;
107 
108  //Point to the crypto memory
109  p = *dest;
110 
111  //Copy the multiple-precision integer to the crypto memory
112  mpiExport(src, p, totalLen, MPI_FORMAT_LITTLE_ENDIAN);
113 
114  //Advance data pointer
115  *dest = p + totalLen;
116 
117  //Return a pointer to the initialized area
118  return p;
119 }
120 
121 
122 /**
123  * @brief Initialize workspace area
124  * @param[in,out] dest Pointer to the crypto memory
125  * @param[in] totalLen Desired length of the area, in bytes
126  * @return Pointer to the initialized area
127  **/
128 
129 uint8_t *cpkccWorkspace(uint8_t **dest, size_t totalLen)
130 {
131  size_t i;
132  uint8_t *p;
133 
134  //Point to the crypto memory
135  p = *dest;
136 
137  //Initialize workspace area
138  for(i = 0; i < totalLen; i++)
139  {
140  p[i] = 0;
141  }
142 
143  //Advance data pointer
144  *dest = p + i;
145 
146  //Return a pointer to the initialized area
147  return p;
148 }
149 
150 
151 #if (MPI_SUPPORT == ENABLED)
152 
153 /**
154  * @brief Multiple precision multiplication
155  * @param[out] r Resulting integer R = A * B
156  * @param[in] a First operand A
157  * @param[in] b Second operand B
158  * @return Error code
159  **/
160 
161 error_t mpiMul(Mpi *r, const Mpi *a, const Mpi *b)
162 {
163  error_t error;
164  size_t m;
165  size_t n;
166  uint8_t *pos;
167  PukccFmultParams params = {0};
168 
169  //Get the length of the input integer, in bytes
170  m = mpiGetByteLength(a);
171  m = (m + 3U) & ~3U;
172 
173  //Get the length of the modulus, in bytes
174  n = mpiGetByteLength(b);
175  n = (n + 3U) & ~3U;
176 
177  //Acquire exclusive access to the CPKCC accelerator
179 
180  //Point to the crypto memory
181  pos = (uint8_t *) CPKCC_CRYPTO_RAM_BASE;
182 
183  //Copy input integer X
184  params.x = cpkccImportMpi(&pos, a, m);
185  //Copy input integer Y
186  params.y = cpkccImportMpi(&pos, b, n);
187 
188  //Unused parameters
189  params.z = 0;
190  params.mod = 0;
191  params.cns = 0;
192 
193  //Initialize output integer R
194  params.r = cpkccWorkspace(&pos, m + n);
195 
196  //Set Fmult service parameters
197  CPKCL(u2Option) = SET_MULTIPLIEROPTION(CPKCL_FMULT_ONLY) |
198  SET_CARRYOPTION(CARRY_NONE);
199  CPKCL(Specific).CarryIn = 0;
200  CPKCL(Specific).Gf2n = 0;
201  CPKCL_Fmult(u2ModLength) = 0;
202  CPKCL_Fmult(nu1ModBase) = CPKCC_FAR_TO_NEAR(params.mod);
203  CPKCL_Fmult(nu1CnsBase) = CPKCC_FAR_TO_NEAR(params.cns);
204  CPKCL_Fmult(u2XLength) = m;
205  CPKCL_Fmult(nu1XBase) = CPKCC_FAR_TO_NEAR(params.x);
206  CPKCL_Fmult(u2YLength) = n;
207  CPKCL_Fmult(nu1YBase) = CPKCC_FAR_TO_NEAR(params.y);
208  CPKCL_Fmult(nu1ZBase) = CPKCC_FAR_TO_NEAR(params.z);
209  CPKCL_Fmult(nu1RBase) = CPKCC_FAR_TO_NEAR(params.r);
210 
211  //Perform multiplication
212  vCPKCL_Process(Fmult, pvCPKCLParam);
213 
214  //Check status code
215  if(CPKCL(u2Status) == CPKCL_OK)
216  {
217  //If FMult is without reduction, R is filled with the final result
218  error = mpiImport(r, params.r, m + n, MPI_FORMAT_LITTLE_ENDIAN);
219 
220  //Check status code
221  if(!error)
222  {
223  //Set the sign of the result
224  r->sign = (a->sign == b->sign) ? 1 : -1;
225  }
226  }
227  else
228  {
229  //Report an error
230  error = ERROR_FAILURE;
231  }
232 
233  //Release exclusive access to the CPKCC accelerator
235 
236  //Return error code
237  return error;
238 }
239 
240 
241 /**
242  * @brief Modulo operation
243  * @param[out] r Resulting integer R = A mod P
244  * @param[in] a The multiple precision integer to be reduced
245  * @param[in] p The modulus P
246  * @return Error code
247  **/
248 
249 error_t mpiMod2(Mpi *r, const Mpi *a, const Mpi *p)
250 {
251  error_t error;
252  size_t n;
253  size_t modLen;
254  uint8_t *pos;
255  PukccRedModParams params = {0};
256 
257  //Get the length of the input integer, in bytes
258  n = mpiGetByteLength(a);
259 
260  //Get the length of the modulus, in bytes
261  modLen = mpiGetByteLength(p);
262  modLen = (modLen + 3U) & ~3U;
263 
264  //Check the length of the input integer
265  if(n > (2 * modLen + 4))
266  return ERROR_INVALID_LENGTH;
267 
268  //Acquire exclusive access to the CPKCC accelerator
270 
271  //Point to the crypto memory
272  pos = (uint8_t *) CPKCC_CRYPTO_RAM_BASE;
273 
274  //Copy modulus
275  params.mod = cpkccImportMpi(&pos, p, modLen + 4);
276  //Initialize workspace CNS
277  params.cns = cpkccWorkspace(&pos, 68);
278  //Initialize output integer R
279  params.r = cpkccWorkspace(&pos, modLen + 4);
280  //Copy input integer X
281  params.x = cpkccImportMpi(&pos, a, 2 * modLen + 8);
282 
283  //Set RedMod service parameters
284  CPKCL(u2Option) = CPKCL_REDMOD_REDUCTION | CPKCL_REDMOD_USING_DIVISION;
285  CPKCL(Specific).CarryIn = 0;
286  CPKCL(Specific).Gf2n = 0;
287  CPKCL_RedMod(u2ModLength) = modLen;
288  CPKCL_RedMod(nu1ModBase) = CPKCC_FAR_TO_NEAR(params.mod);
289  CPKCL_RedMod(nu1CnsBase) = CPKCC_FAR_TO_NEAR(params.cns);
290  CPKCL_RedMod(nu1RBase) = CPKCC_FAR_TO_NEAR(params.r);
291  CPKCL_RedMod(nu1XBase) = CPKCC_FAR_TO_NEAR(params.x);
292 
293  //Perform modular reduction setup
294  vCPKCL_Process(RedMod, pvCPKCLParam);
295 
296  //Check status code
297  if(CPKCL(u2Status) == CPKCL_OK)
298  {
299  //If FMult is without reduction, R is filled with the final result
300  error = mpiImport(r, params.r, modLen, MPI_FORMAT_LITTLE_ENDIAN);
301  }
302  else
303  {
304  //Report an error
305  error = ERROR_FAILURE;
306  }
307 
308  //Release exclusive access to the CPKCC accelerator
310 
311  //Return error code
312  return error;
313 }
314 
315 
316 /**
317  * @brief Modular inverse
318  * @param[out] r Resulting integer R = A^-1 mod P
319  * @param[in] a The multiple precision integer A
320  * @param[in] p The modulus P
321  * @return Error code
322  **/
323 
324 error_t mpiInvMod(Mpi *r, const Mpi *a, const Mpi *p)
325 {
326  error_t error;
327  size_t m;
328  size_t n;
329  uint8_t *pos;
330  PukccGcdParams params = {0};
331 
332  //Get the length of the input integer, in bytes
333  m = mpiGetByteLength(a);
334  //Get the length of the modulus, in bytes
335  n = mpiGetByteLength(p);
336 
337  //Compute the length of the areas X, Y, A and Z
338  n = MAX(n, m);
339  n = (n + 7U) & ~3U;
340 
341  //Acquire exclusive access to the CPKCC accelerator
343 
344  //Point to the crypto memory
345  pos = (uint8_t *) CPKCC_CRYPTO_RAM_BASE;
346 
347  //Copy input integer
348  params.x = cpkccImportMpi(&pos, a, n);
349  //Copy modulus
350  params.y = cpkccImportMpi(&pos, p, n);
351  //Initialize output integer A
352  params.a = cpkccWorkspace(&pos, n);
353  //Initialize output integer Z
354  params.z = cpkccWorkspace(&pos, n + 4);
355  //Initialize workspace >
356  params.w = cpkccWorkspace(&pos, 32);
357 
358  //Set GCD service parameters
359  CPKCL(Specific).Gf2n = 0;
360  CPKCL_GCD(nu1XBase) = CPKCC_FAR_TO_NEAR(params.x);
361  CPKCL_GCD(nu1YBase) = CPKCC_FAR_TO_NEAR(params.y);
362  CPKCL_GCD(nu1ABase) = CPKCC_FAR_TO_NEAR(params.a);
363  CPKCL_GCD(nu1ZBase) = CPKCC_FAR_TO_NEAR(params.z);
364  CPKCL_GCD(nu1WorkSpace) = CPKCC_FAR_TO_NEAR(params.w);
365  CPKCL_GCD(u2Length) = n;
366 
367  //Calculate the modular inverse
368  vCPKCL_Process(GCD, pvCPKCLParam);
369 
370  //Check status code
371  if(CPKCL(u2Status) == CPKCL_OK)
372  {
373  //Copy output integer Z
374  error = mpiImport(r, params.a, n, MPI_FORMAT_LITTLE_ENDIAN);
375  }
376  else
377  {
378  //Report an error
379  error = ERROR_FAILURE;
380  }
381 
382  //Release exclusive access to the CPKCC accelerator
384 
385  //Return error code
386  return error;
387 }
388 
389 
390 /**
391  * @brief Modular exponentiation
392  * @param[out] r Resulting integer R = A ^ E mod P
393  * @param[in] a Pointer to a multiple precision integer
394  * @param[in] e Exponent
395  * @param[in] p Modulus
396  * @return Error code
397  **/
398 
399 error_t mpiExpMod(Mpi *r, const Mpi *a, const Mpi *e, const Mpi *p)
400 {
401  error_t error;
402  size_t n;
403  size_t modLen;
404  size_t expLen;
405  uint8_t *pos;
406  PukccExpModParams params = {0};
407 
408  //Get the length of the input integer, in bytes
409  n = mpiGetByteLength(a);
410 
411  //Get the length of the modulus, in bytes
412  modLen = mpiGetByteLength(p);
413  modLen = (modLen + 3U) & ~3U;
414 
415  //Get the length of the exponent, in bytes
416  expLen = mpiGetByteLength(e);
417  expLen = (expLen + 3U) & ~3U;
418 
419  //Check the length of the input integer
420  if(n > (2 * modLen + 4))
421  return ERROR_INVALID_LENGTH;
422 
423  //Acquire exclusive access to the CPKCC accelerator
425 
426  //Point to the crypto memory
427  pos = (uint8_t *) CPKCC_CRYPTO_RAM_BASE;
428 
429  //Copy modulus
430  params.mod = cpkccImportMpi(&pos, p, modLen + 4);
431  //Initialize reduction constant
432  params.cns = cpkccWorkspace(&pos, modLen + 12);
433  //Initialize workspace R
434  params.r = cpkccWorkspace(&pos, 64);
435  //Initialize workspace X
436  params.x = cpkccWorkspace(&pos, 2 * modLen + 8);
437 
438  //Set RedMod service parameters
439  CPKCL(u2Option) = CPKCL_REDMOD_SETUP;
440  CPKCL(Specific).CarryIn = 0;
441  CPKCL(Specific).Gf2n = 0;
442  CPKCL_RedMod(u2ModLength) = modLen;
443  CPKCL_RedMod(nu1ModBase) = CPKCC_FAR_TO_NEAR(params.mod);
444  CPKCL_RedMod(nu1CnsBase) = CPKCC_FAR_TO_NEAR(params.cns);
445  CPKCL_RedMod(nu1RBase) = CPKCC_FAR_TO_NEAR(params.r);
446  CPKCL_RedMod(nu1XBase) = CPKCC_FAR_TO_NEAR(params.x);
447 
448  //Perform modular reduction setup
449  vCPKCL_Process(RedMod, pvCPKCLParam);
450 
451  //Check status code
452  if(CPKCL(u2Status) == CPKCL_OK)
453  {
454  //Point to the crypto memory
455  pos = params.r;
456 
457  //Copy input number
458  params.x = cpkccImportMpi(&pos, a, 2 * modLen + 8);
459 
460  //Set RedMod service parameters
461  CPKCL(u2Option) = CPKCL_REDMOD_REDUCTION | CPKCL_REDMOD_USING_FASTRED;
462  CPKCL(Specific).CarryIn = 0;
463  CPKCL(Specific).Gf2n = 0;
464  CPKCL_RedMod(u2ModLength) = modLen;
465  CPKCL_RedMod(nu1ModBase) = CPKCC_FAR_TO_NEAR(params.mod);
466  CPKCL_RedMod(nu1CnsBase) = CPKCC_FAR_TO_NEAR(params.cns);
467  CPKCL_RedMod(nu1RBase) = CPKCC_FAR_TO_NEAR(params.x);
468  CPKCL_RedMod(nu1XBase) = CPKCC_FAR_TO_NEAR(params.x);
469 
470  //Perform fast modular reduction
471  vCPKCL_Process(RedMod, pvCPKCLParam);
472  }
473 
474  //Check status code
475  if(CPKCL(u2Status) == CPKCL_OK)
476  {
477  //Set RedMod service parameters
478  CPKCL(u2Option) = CPKCL_REDMOD_NORMALIZE;
479  CPKCL(Specific).CarryIn = 0;
480  CPKCL(Specific).Gf2n = 0;
481  CPKCL_RedMod(u2ModLength) = modLen;
482  CPKCL_RedMod(nu1ModBase) = CPKCC_FAR_TO_NEAR(params.mod);
483  CPKCL_RedMod(nu1CnsBase) = CPKCC_FAR_TO_NEAR(params.cns);
484  CPKCL_RedMod(nu1RBase) = CPKCC_FAR_TO_NEAR(params.x);
485  CPKCL_RedMod(nu1XBase) = CPKCC_FAR_TO_NEAR(params.x);
486 
487  //Normalize the result
488  vCPKCL_Process(RedMod, pvCPKCLParam);
489  }
490 
491  //Check status code
492  if(CPKCL(u2Status) == CPKCL_OK)
493  {
494  //The number to be exponentiated is followed by four 32-bit words
495  //that are used during the computations as a workspace
496  pos = params.x + modLen;
497  cpkccWorkspace(&pos, 16);
498 
499  //The exponent must be given with a supplemental word on the LSB
500  //side (low addresses). This word shall be set to zero
501  params.exp = cpkccWorkspace(&pos, 4);
502  cpkccImportMpi(&pos, e, expLen);
503 
504  //Initialize workspace
505  params.w = cpkccWorkspace(&pos, 3 * (modLen + 4) + 8);
506 
507  //Set ExpMod service parameters
508  CPKCL(u2Option) = CPKCL_EXPMOD_REGULARRSA | CPKCL_EXPMOD_WINDOWSIZE_1 |
509  CPKCL_EXPMOD_EXPINPKCCRAM;
510  CPKCL_ExpMod(u2ModLength) = modLen;
511  CPKCL_ExpMod(nu1ModBase) = CPKCC_FAR_TO_NEAR(params.mod);
512  CPKCL_ExpMod(nu1CnsBase) = CPKCC_FAR_TO_NEAR(params.cns);
513  CPKCL_ExpMod(nu1XBase) = CPKCC_FAR_TO_NEAR(params.x);
514  CPKCL_ExpMod(nu1PrecompBase) = CPKCC_FAR_TO_NEAR(params.w);
515  CPKCL_ExpMod(u2ExpLength) = expLen;
516  CPKCL_ExpMod(pfu1ExpBase) = params.exp;
517  CPKCL_ExpMod(u1Blinding) = 0;
518 
519  //Perform modular exponentiation
520  vCPKCL_Process(ExpMod, pvCPKCLParam);
521  }
522 
523  //Check status code
524  if(CPKCL(u2Status) == CPKCL_OK)
525  {
526  //Copy resulting integer
527  error = mpiImport(r, params.x, modLen, MPI_FORMAT_LITTLE_ENDIAN);
528  }
529  else
530  {
531  //Report an error
532  error = ERROR_FAILURE;
533  }
534 
535  //Release exclusive access to the CPKCC accelerator
537 
538  //Return error code
539  return error;
540 }
541 
542 
543 /**
544  * @brief Test whether a number is probable prime
545  * @param[in] a Pointer to a multiple precision integer
546  * @return Error code
547  **/
548 
550 {
551  error_t error;
552  uint_t k;
553  size_t n;
554  uint8_t *pos;
555  PukccPrimeGenParams params = {0};
556 
557  //Get the length of the input integer, in bits
558  n = mpiGetBitLength(a);
559 
560  //Prime numbers of a size lower than 96 bits cannot be tested by this
561  //service
562  if(n < 96)
563  return ERROR_INVALID_LENGTH;
564 
565  //The number of repetitions controls the error probability
566  if(n >= 1300)
567  {
568  k = 2;
569  }
570  else if(n >= 850)
571  {
572  k = 3;
573  }
574  else if(n >= 650)
575  {
576  k = 4;
577  }
578  else if(n >= 550)
579  {
580  k = 5;
581  }
582  else if(n >= 450)
583  {
584  k = 6;
585  }
586  else if(n >= 400)
587  {
588  k = 7;
589  }
590  else if(n >= 350)
591  {
592  k = 8;
593  }
594  else if(n >= 300)
595  {
596  k = 9;
597  }
598  else if(n >= 250)
599  {
600  k = 12;
601  }
602  else if(n >= 200)
603  {
604  k = 15;
605  }
606  else if(n >= 150)
607  {
608  k = 18;
609  }
610  else
611  {
612  k = 27;
613  }
614 
615  //Get the length of the input integer, in bytes
616  n = mpiGetByteLength(a);
617  n = (n + 3U) & ~3U;
618 
619  //Acquire exclusive access to the CPKCC accelerator
621 
622  //Point to the crypto memory
623  pos = (uint8_t *) CPKCC_CRYPTO_RAM_BASE;
624 
625  //One additional word is used on the LSB side of the NBase parameter. As
626  //a consequence, the parameter nu1NBase must never be at the beginning of
627  //the crypto RAM, but at least at one word from the beginning
628  cpkccWorkspace(&pos, 4);
629 
630  //Copy the number to test
631  params.n = cpkccImportMpi(&pos, a, n + 4);
632  //Cns is used as a workspace
633  params.cns = cpkccWorkspace(&pos, n + 12);
634  //Rnd is used as a workspace
635  params.rnd = cpkccWorkspace(&pos, MAX(n + 16, 64));
636  //Precomp is used as a precomputation workspace
637  params.w = cpkccWorkspace(&pos, MAX(3 * (n + 4), n + 72) + 8);
638  //Exp is used as a workspace
639  params.exp = cpkccWorkspace(&pos, n + 4);
640 
641  //Unused parameter
642  params.r = 0;
643 
644  //Set PrimeGen service parameters
645  CPKCL(u2Option) = CPKCL_PRIMEGEN_TEST | CPKCL_EXPMOD_FASTRSA |
646  CPKCL_EXPMOD_WINDOWSIZE_1;
647  CPKCL_PrimeGen(u2NLength) = n;
648  CPKCL_PrimeGen(nu1NBase) = CPKCC_FAR_TO_NEAR(params.n);
649  CPKCL_PrimeGen(nu1CnsBase) = CPKCC_FAR_TO_NEAR(params.cns);
650  CPKCL_PrimeGen(nu1RndBase) = CPKCC_FAR_TO_NEAR(params.rnd);
651  CPKCL_PrimeGen(nu1PrecompBase) = CPKCC_FAR_TO_NEAR(params.w);
652  CPKCL_PrimeGen(nu1RBase) = CPKCC_FAR_TO_NEAR(params.r);
653  CPKCL_PrimeGen(nu1ExpBase) = CPKCC_FAR_TO_NEAR(params.exp);
654  CPKCL_PrimeGen(u1MillerRabinIterations) = k;
655  CPKCL_PrimeGen(u2MaxIncrement) = 1;
656 
657  //Perform probable prime testing
658  vCPKCL_Process(PrimeGen, pvCPKCLParam);
659 
660  //Check status code
661  switch(CPKCL(u2Status))
662  {
663  case CPKCL_NUMBER_IS_PRIME:
664  //The number is probably prime
665  error = NO_ERROR;
666  break;
667  case CPKCL_NUMBER_IS_NOT_PRIME:
668  //The number is not prime
669  error = ERROR_INVALID_VALUE;
670  break;
671  default:
672  //Report an error
673  error = ERROR_FAILURE;
674  break;
675  }
676 
677  //Release exclusive access to the CPKCC accelerator
679 
680  //Return error code
681  return error;
682 }
683 
684 #endif
685 #if (RSA_SUPPORT == ENABLED)
686 
687 /**
688  * @brief RSA decryption primitive
689  * @param[in] key RSA private key
690  * @param[in] c Ciphertext representative
691  * @param[out] m Message representative
692  * @return Error code
693  **/
694 
695 error_t rsadp(const RsaPrivateKey *key, const Mpi *c, Mpi *m)
696 {
697  error_t error;
698  size_t nLen;
699  size_t dLen;
700  size_t pLen;
701  size_t qLen;
702  size_t dpLen;
703  size_t dqLen;
704  size_t qinvLen;
705 
706  //Get the length of the private key
707  nLen = mpiGetByteLength(&key->n);
708  dLen = mpiGetByteLength(&key->d);
709  pLen = mpiGetByteLength(&key->p);
710  qLen = mpiGetByteLength(&key->q);
711  dpLen = mpiGetByteLength(&key->dp);
712  dqLen = mpiGetByteLength(&key->dq);
713  qinvLen = mpiGetByteLength(&key->qinv);
714 
715  //Sanity check
716  if(nLen == 0)
718 
719  //The ciphertext representative c shall be between 0 and n - 1
720  if(mpiCompInt(c, 0) < 0 || mpiComp(c, &key->n) >= 0)
721  return ERROR_OUT_OF_RANGE;
722 
723  //Use the Chinese remainder algorithm?
724  if(nLen > 0 && pLen > 0 && qLen > 0 && dpLen > 0 && dqLen > 0 && qinvLen > 0)
725  {
726  size_t cLen;
727  size_t modLen;
728  size_t expLen;
729  uint8_t *pos;
730  PukccCrtParams params = {0};
731 
732  //Get the length of the ciphertext, in bytes
733  cLen = mpiGetByteLength(c);
734 
735  //Get the length of the modulus, in bytes
736  modLen = MAX(pLen, qLen);
737  modLen = MAX(modLen, 12);
738  modLen = (modLen + 3U) & ~3U;
739 
740  //Get the length of the reduced exponents, in bytes
741  expLen = MAX(dpLen, dqLen);
742  expLen = (expLen + 3U) & ~3U;
743 
744  //Check the length of the ciphertext
745  if(cLen > (2 * modLen))
746  return ERROR_INVALID_LENGTH;
747 
748  //Acquire exclusive access to the CPKCC accelerator
750 
751  //Point to the crypto memory
752  pos = (uint8_t *) CPKCC_CRYPTO_RAM_BASE;
753 
754  //Copy primes
755  params.q = cpkccImportMpi(&pos, &key->q, modLen + 4);
756  params.p = cpkccImportMpi(&pos, &key->p, modLen + 4);
757 
758  //Copy input number
759  params.x = cpkccImportMpi(&pos, c, 2 * modLen + 16);
760 
761  //The reduced exponents must be given with a supplemental word on the
762  //LSB side (low addresses). This word shall be set to zero
763  params.dq = cpkccWorkspace(&pos, 4);
764  cpkccImportMpi(&pos, &key->dq, expLen);
765  params.dp = cpkccWorkspace(&pos, 4);
766  cpkccImportMpi(&pos, &key->dp, expLen);
767 
768  //Copy R value
769  params.r = cpkccImportMpi(&pos, &key->qinv, modLen + 4);
770  //Initialize workspace
771  cpkccWorkspace(&pos, 3 * (modLen + 4) + MAX(64, 1 * (modLen + 4)) + 8);
772 
773  //Set CRT service parameters
774  CPKCL(u2Option) = CPKCL_EXPMOD_REGULARRSA | CPKCL_EXPMOD_WINDOWSIZE_1 |
775  CPKCL_EXPMOD_EXPINPKCCRAM;
776  CPKCL_CRT(u2ModLength) = modLen;
777  CPKCL_CRT(nu1ModBase) = CPKCC_FAR_TO_NEAR(params.q);
778  CPKCL_CRT(nu1XBase) = CPKCC_FAR_TO_NEAR(params.x);
779  CPKCL_CRT(nu1PrecompBase) = CPKCC_FAR_TO_NEAR(params.r);
780  CPKCL_CRT(u2ExpLength) = expLen;
781  CPKCL_CRT(pfu1ExpBase) = params.dq;
782  CPKCL_CRT(u1Blinding) = 0;
783 
784  //Perform modular exponentiation (with CRT)
785  vCPKCL_Process(CRT, pvCPKCLParam);
786 
787  //Check status code
788  if(CPKCL(u2Status) == CPKCL_OK)
789  {
790  //Copy resulting integer
791  error = mpiImport(m, params.x, 2 * modLen, MPI_FORMAT_LITTLE_ENDIAN);
792  }
793  else
794  {
795  //Report an error
796  error = ERROR_FAILURE;
797  }
798 
799  //Release exclusive access to the CPKCC accelerator
801  }
802  else if(nLen > 0 && dLen > 0)
803  {
804  //Perform modular exponentiation (without CRT)
805  error = mpiExpMod(m, c, &key->d, &key->n);
806  }
807  else
808  {
809  //Invalid parameters
810  error = ERROR_INVALID_PARAMETER;
811  }
812 
813  //Return status code
814  return error;
815 }
816 
817 #endif
818 #endif
uint8_t b
Definition: nbns_common.h:122
@ ERROR_OUT_OF_RANGE
Definition: error.h:138
Mpi p
First factor.
Definition: rsa.h:72
uint8_t a
Definition: ndp.h:411
Arbitrary precision integer.
Definition: mpi.h:102
error_t mpiMul(Mpi *r, const Mpi *a, const Mpi *b)
Multiple precision multiplication.
PrimeGen service parameters.
uint8_t p
Definition: ndp.h:300
#define sleep(delay)
Definition: os_port.h:310
SAMA5D4 hardware cryptographic accelerator.
Mpi n
Modulus.
Definition: rsa.h:69
error_t cpkccInit(void)
Initialize CPKCC module.
Fmult service parameters.
uint8_t * cpkccImportMpi(uint8_t **dest, const Mpi *src, size_t totalLen)
Import multiple-precision integer.
ExpMod service parameters.
Mpi d
Private exponent.
Definition: rsa.h:71
error_t rsadp(const RsaPrivateKey *key, const Mpi *c, Mpi *m)
RSA decryption primitive.
uint8_t r
Definition: ndp.h:346
SAMA5D4 public-key hardware accelerator (CPKCC)
error_t mpiMod2(Mpi *r, const Mpi *a, const Mpi *p)
Modulo operation.
@ 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 mpiExpMod(Mpi *r, const Mpi *a, const Mpi *e, const Mpi *p)
Modular exponentiation.
error_t mpiInvMod(Mpi *r, const Mpi *a, const Mpi *p)
Modular inverse.
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
Mpi q
Second factor.
Definition: rsa.h:73
OsMutex sama5d4CryptoMutex
error_t mpiImport(Mpi *r, const uint8_t *input, size_t length, MpiFormat format)
Octet string to integer conversion.
Definition: mpi.c:714
MPI (Multiple Precision Integer Arithmetic)
@ ERROR_INVALID_LENGTH
Definition: error.h:111
General definitions for cryptographic algorithms.
RSA public-key cryptography standard.
PCPKCL_PARAM pvCPKCLParam
uint8_t * cpkccWorkspace(uint8_t **dest, size_t totalLen)
Initialize workspace area.
error_t mpiExport(const Mpi *a, uint8_t *output, size_t length, MpiFormat format)
Integer to octet string conversion.
Definition: mpi.c:811
RedMod service parameters.
uint_t mpiGetBitLength(const Mpi *a)
Get the actual length in bits.
Definition: mpi.c:255
Mpi qinv
CRT coefficient.
Definition: rsa.h:76
Mpi dq
Second factor's CRT exponent.
Definition: rsa.h:75
#define MAX(a, b)
Definition: os_port.h:67
GCD service parameters.
CRT service parameters.
@ ERROR_INVALID_VALUE
Definition: error.h:116
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.
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
error_t mpiCheckProbablePrime(const Mpi *a)
Test whether a number is probable prime.
int_t mpiComp(const Mpi *a, const Mpi *b)
Compare two multiple precision integers.
Definition: mpi.c:359
Mpi dp
First factor's CRT exponent.
Definition: rsa.h:74
int_t mpiCompInt(const Mpi *a, mpi_sword_t b)
Compare a multiple precision integer with an integer.
Definition: mpi.c:430
unsigned int uint_t
Definition: compiler_port.h:57
#define osMemset(p, value, length)
Definition: os_port.h:138
CPKCL_PARAM CPKCLParam
#define CPKCC_FAR_TO_NEAR(p)
#define CPKCC_CRYPTO_RAM_BASE
@ NO_ERROR
Success.
Definition: error.h:44
uint8_t c
Definition: ndp.h:514
Debugging facilities.
uint_t mpiGetByteLength(const Mpi *a)
Get the actual length in bytes.
Definition: mpi.c:216