esp32_crypto_pkc.c
Go to the documentation of this file.
1 /**
2  * @file esp32_crypto_pkc.c
3  * @brief ESP32 public-key hardware accelerator
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 "soc/hwcrypto_reg.h"
36 #include "soc/dport_access.h"
37 #include "esp_private/periph_ctrl.h"
40 #include "pkc/rsa.h"
41 #include "ecc/ec.h"
42 #include "ecc/ec_misc.h"
43 #include "debug.h"
44 
45 //Check crypto library configuration
46 #if (ESP32_CRYPTO_PKC_SUPPORT == ENABLED)
47 
48 
49 /**
50  * @brief RSA module initialization
51  **/
52 
53 void esp32RsaInit(void)
54 {
55  //Enable RSA module
56  periph_module_enable(PERIPH_RSA_MODULE);
57 
58  //Software should query RSA_CLEAN_REG after being released from reset, and
59  //before writing to any RSA Accelerator memory blocks or registers for the
60  //first time
61  while(DPORT_REG_READ(RSA_CLEAN_REG) == 0)
62  {
63  }
64 }
65 
66 
67 #if (MPI_SUPPORT == ENABLED)
68 
69 /**
70  * @brief Multiple precision multiplication
71  * @param[out] r Resulting integer R = A * B
72  * @param[in] a First operand A
73  * @param[in] b Second operand B
74  * @return Error code
75  **/
76 
77 error_t mpiMul(Mpi *r, const Mpi *a, const Mpi *b)
78 {
79  error_t error;
80  size_t i;
81  size_t n;
82  size_t aLen;
83  size_t bLen;
84 
85  //Get the length of the first operand, in 32-bit words
86  aLen = mpiGetLength(a);
87  //Get the length of the second operand, in 32-bit words
88  bLen = mpiGetLength(b);
89 
90  //The accelerator supports large-number multiplication up to 2048 bits
91  if(aLen <= 64 && bLen <= 64)
92  {
93  //All numbers in calculation must be of the same length
94  n = 1;
95  n = MAX(n, aLen);
96  n = MAX(n, bLen);
97  n = (n + 7) & ~7U;
98 
99  //Acquire exclusive access to the RSA module
101 
102  //Clear the interrupt flag
103  DPORT_REG_WRITE(RSA_INTERRUPT_REG, 1);
104  //Set mode register
105  DPORT_REG_WRITE(RSA_MULT_MODE_REG, (n / 8) - 1 + 8);
106 
107  //Copy the first operand to RSA_X_MEM
108  for(i = 0; i < n; i++)
109  {
110  if(i < a->size)
111  {
112  DPORT_REG_WRITE(RSA_MEM_X_BLOCK_BASE + i * 4, a->data[i]);
113  }
114  else
115  {
116  DPORT_REG_WRITE(RSA_MEM_X_BLOCK_BASE + i * 4, 0);
117  }
118  }
119 
120  //The second operand will not be written to the base address of the
121  //RSA_Z_MEM memory. This area must be filled with zeroes
122  for(i = 0; i < n; i++)
123  {
124  DPORT_REG_WRITE(RSA_MEM_Z_BLOCK_BASE + i * 4, 0);
125  }
126 
127  //The second operand must be written to the base address of the RSA_Z_MEM
128  //memory plus the address offset N
129  for(i = 0; i < n; i++)
130  {
131  if(i < b->size)
132  {
133  DPORT_REG_WRITE(RSA_MEM_Z_BLOCK_BASE + (n + i) * 4, b->data[i]);
134  }
135  else
136  {
137  DPORT_REG_WRITE(RSA_MEM_Z_BLOCK_BASE + (n + i) * 4, 0);
138  }
139  }
140 
141  //Start large-number multiplication
142  DPORT_REG_WRITE(RSA_MULT_START_REG, 1);
143 
144  //Wait for the operation to complete
145  while(DPORT_REG_READ(RSA_INTERRUPT_REG) == 0)
146  {
147  }
148 
149  //Set the sign of the result
150  r->sign = (a->sign == b->sign) ? 1 : -1;
151 
152  //The length of the result is 2 x N bits
153  error = mpiGrow(r, n * 2);
154 
155  //Check status code
156  if(!error)
157  {
158  //Disable interrupts only on current CPU
159  DPORT_INTERRUPT_DISABLE();
160 
161  //Read the result from RSA_Z_MEM
162  for(i = 0; i < r->size; i++)
163  {
164  if(i < (n * 2))
165  {
166  r->data[i] = DPORT_SEQUENCE_REG_READ(RSA_MEM_Z_BLOCK_BASE + i * 4);
167  }
168  else
169  {
170  r->data[i] = 0;
171  }
172  }
173 
174  //Restore the previous interrupt level
175  DPORT_INTERRUPT_RESTORE();
176  }
177 
178  //Clear the interrupt flag
179  DPORT_REG_WRITE(RSA_INTERRUPT_REG, 1);
180 
181  //Release exclusive access to the RSA module
183  }
184  else
185  {
186  //Report an error
187  error = ERROR_FAILURE;
188  }
189 
190  //Return status code
191  return error;
192 }
193 
194 
195 /**
196  * @brief Modular exponentiation
197  * @param[out] r Resulting integer R = A ^ E mod P
198  * @param[in] a Pointer to a multiple precision integer
199  * @param[in] e Exponent
200  * @param[in] p Modulus
201  * @return Error code
202  **/
203 
204 error_t mpiExpMod(Mpi *r, const Mpi *a, const Mpi *e, const Mpi *p)
205 {
206  error_t error;
207  size_t i;
208  size_t n;
209  size_t modLen;
210  size_t expLen;
211  uint32_t m;
212  Mpi t;
213  Mpi r2;
214 
215  //Initialize multiple precision integers
216  mpiInit(&t);
217  mpiInit(&r2);
218 
219  //Get the length of the modulus, in 32-bit words
220  modLen = mpiGetLength(p);
221  //Get the length of the exponent, in 32-bit words
222  expLen = mpiGetLength(e);
223 
224  //The accelerator supports operand lengths up to 4096 bits
225  if(modLen > 0 && modLen <= 128 && expLen > 0 && expLen <= 128)
226  {
227  //All numbers in calculation must be of the same length
228  n = MAX(modLen, expLen);
229  n = (n + 15) & ~15U;
230 
231  //Reduce the operand first
232  error = mpiMod(&t, a, p);
233 
234  //Let R = b^n and pre-compute the quantity R^2 mod M
235  if(!error)
236  {
237  error = mpiSetValue(&r2, 1);
238  }
239 
240  if(!error)
241  {
242  error = mpiShiftLeft(&r2, n * 2 * 32);
243  }
244 
245  if(!error)
246  {
247  error = mpiMod(&r2, &r2, p);
248  }
249 
250  //Check status code
251  if(!error)
252  {
253  //Acquire exclusive access to the RSA module
255 
256  //Clear the interrupt flag
257  DPORT_REG_WRITE(RSA_INTERRUPT_REG, 1);
258  //Set mode register
259  DPORT_REG_WRITE(RSA_MODEXP_MODE_REG, (n / 16) - 1);
260 
261  //Copy the operand to RSA_X_MEM
262  for(i = 0; i < n; i++)
263  {
264  if(i < t.size)
265  {
266  DPORT_REG_WRITE(RSA_MEM_X_BLOCK_BASE + i * 4, t.data[i]);
267  }
268  else
269  {
270  DPORT_REG_WRITE(RSA_MEM_X_BLOCK_BASE + i * 4, 0);
271  }
272  }
273 
274  //Copy the exponent to RSA_Y_MEM
275  for(i = 0; i < n; i++)
276  {
277  if(i < e->size)
278  {
279  DPORT_REG_WRITE(RSA_MEM_Y_BLOCK_BASE + i * 4, e->data[i]);
280  }
281  else
282  {
283  DPORT_REG_WRITE(RSA_MEM_Y_BLOCK_BASE + i * 4, 0);
284  }
285  }
286 
287  //Copy the modulus to RSA_M_MEM
288  for(i = 0; i < n; i++)
289  {
290  if(i < p->size)
291  {
292  DPORT_REG_WRITE(RSA_MEM_M_BLOCK_BASE + i * 4, p->data[i]);
293  }
294  else
295  {
296  DPORT_REG_WRITE(RSA_MEM_M_BLOCK_BASE + i * 4, 0);
297  }
298  }
299 
300  //Copy the pre-calculated value of R^2 mod M to RSA_Z_MEM
301  for(i = 0; i < n; i++)
302  {
303  if(i < r2.size)
304  {
305  DPORT_REG_WRITE(RSA_MEM_RB_BLOCK_BASE + i * 4, r2.data[i]);
306  }
307  else
308  {
309  DPORT_REG_WRITE(RSA_MEM_RB_BLOCK_BASE + i * 4, 0);
310  }
311  }
312 
313  //Use Newton's method to compute the inverse of M[0] mod 2^32
314  for(m = p->data[0], i = 0; i < 4; i++)
315  {
316  m = m * (2U - m * p->data[0]);
317  }
318 
319  //Precompute M' = -1/M[0] mod 2^32;
320  m = ~m + 1U;
321 
322  //Write the value of M' to RSA_M_PRIME_REG
323  DPORT_REG_WRITE(RSA_M_DASH_REG, m);
324 
325  //Start modular exponentiation
326  DPORT_REG_WRITE(RSA_MODEXP_START_REG, 1);
327 
328  //Wait for the operation to complete
329  while(DPORT_REG_READ(RSA_INTERRUPT_REG) == 0)
330  {
331  }
332 
333  //Adjust the size of the result if necessary
334  error = mpiGrow(r, n);
335 
336  //Check status code
337  if(!error)
338  {
339  //Disable interrupts only on current CPU
340  DPORT_INTERRUPT_DISABLE();
341 
342  //Read the result from RSA_Z_MEM
343  for(i = 0; i < r->size; i++)
344  {
345  if(i < n)
346  {
347  r->data[i] = DPORT_SEQUENCE_REG_READ(RSA_MEM_Z_BLOCK_BASE + i * 4);
348  }
349  else
350  {
351  r->data[i] = 0;
352  }
353  }
354 
355  //Restore the previous interrupt level
356  DPORT_INTERRUPT_RESTORE();
357  }
358 
359  //Clear the interrupt flag
360  DPORT_REG_WRITE(RSA_INTERRUPT_REG, 1);
361 
362  //Release exclusive access to the RSA module
364  }
365  }
366  else
367  {
368  //Report an error
369  error = ERROR_FAILURE;
370  }
371 
372  //Release previously allocated memory
373  mpiFree(&t);
374  mpiFree(&r2);
375 
376  //Return status code
377  return error;
378 }
379 
380 #endif
381 #if (EC_SUPPORT == ENABLED)
382 
383 /**
384  * @brief Multiplication of two integers
385  * @param[out] rl Low part of the result R = (A * B) mod (2^32)^n
386  * @param[out] rh High part of the result R = (A * B) / (2^32)^n
387  * @param[in] a An integer such as 0 <= A < (2^32)^n
388  * @param[in] b An integer such as 0 <= B < (2^32)^n
389  * @param[in] n Size of the operands, in words
390  **/
391 
392 void ecScalarMul(uint32_t *rl, uint32_t *rh, const uint32_t *a,
393  const uint32_t *b, uint_t n)
394 {
395  uint_t i;
396  uint_t m;
397 
398  //The accelerator supports large-number multiplication with only four
399  //operand lengths
400  m = (n + 7) & ~7U;
401 
402  //Acquire exclusive access to the RSA module
404 
405  //Clear the interrupt flag
406  DPORT_REG_WRITE(RSA_INTERRUPT_REG, 1);
407  //Set mode register
408  DPORT_REG_WRITE(RSA_MULT_MODE_REG, (m / 8) - 1 + 8);
409 
410  //Copy the first operand to RSA_X_MEM
411  for(i = 0; i < m; i++)
412  {
413  if(i < n)
414  {
415  DPORT_REG_WRITE(RSA_MEM_X_BLOCK_BASE + i * 4, a[i]);
416  }
417  else
418  {
419  DPORT_REG_WRITE(RSA_MEM_X_BLOCK_BASE + i * 4, 0);
420  }
421  }
422 
423  //The second operand will not be written to the base address of the
424  //RSA_Z_MEM memory. This area must be filled with zeroes
425  for(i = 0; i < m; i++)
426  {
427  DPORT_REG_WRITE(RSA_MEM_Z_BLOCK_BASE + i * 4, 0);
428  }
429 
430  //The second operand must be written to the base address of the RSA_Z_MEM
431  //memory plus the address offset N
432  for(i = 0; i < m; i++)
433  {
434  if(i < n)
435  {
436  DPORT_REG_WRITE(RSA_MEM_Z_BLOCK_BASE + (m + i) * 4, b[i]);
437  }
438  else
439  {
440  DPORT_REG_WRITE(RSA_MEM_Z_BLOCK_BASE + (m + i) * 4, 0);
441  }
442  }
443 
444  //Start large-number multiplication
445  DPORT_REG_WRITE(RSA_MULT_START_REG, 1);
446 
447  //Wait for the operation to complete
448  while(DPORT_REG_READ(RSA_INTERRUPT_REG) == 0)
449  {
450  }
451 
452  //Disable interrupts only on current CPU
453  DPORT_INTERRUPT_DISABLE();
454 
455  //Check whether the low part of the multiplication should be calculated
456  if(rl != NULL)
457  {
458  //Read the result from RSA_Z_MEM
459  for(i = 0; i < n; i++)
460  {
461  rl[i] = DPORT_SEQUENCE_REG_READ(RSA_MEM_Z_BLOCK_BASE + i * 4);
462  }
463  }
464 
465  //Check whether the high part of the multiplication should be calculated
466  if(rh != NULL)
467  {
468  //Read the result from RSA_Z_MEM
469  for(i = 0; i < n; i++)
470  {
471  rh[i] = DPORT_SEQUENCE_REG_READ(RSA_MEM_Z_BLOCK_BASE + (n + i) * 4);
472  }
473  }
474 
475  //Restore the previous interrupt level
476  DPORT_INTERRUPT_RESTORE();
477  //Clear the interrupt flag
478  DPORT_REG_WRITE(RSA_INTERRUPT_REG, 1);
479 
480  //Release exclusive access to the RSA module
482 }
483 
484 
485 /**
486  * @brief Squaring operation
487  * @param[out] r Result R = A ^ 2
488  * @param[in] a An integer such as 0 <= A < (2^32)^n
489  * @param[in] n Size of the integer A, in words
490  **/
491 
492 void ecScalarSqr(uint32_t *r, const uint32_t *a, uint_t n)
493 {
494  //Compute R = A ^ 2
495  ecScalarMul(r, r + n, a, a, n);
496 }
497 
498 #endif
499 #endif
error_t mpiShiftLeft(Mpi *r, uint_t n)
Left shift operation.
Definition: mpi.c:1243
uint8_t b
Definition: nbns_common.h:104
uint8_t a
Definition: ndp.h:411
Arbitrary precision integer.
Definition: mpi.h:102
uint8_t p
Definition: ndp.h:300
uint8_t t
Definition: lldp_ext_med.h:212
void mpiInit(Mpi *r)
Initialize a multiple precision integer.
Definition: mpi.c:48
ESP32 hardware cryptographic accelerator.
uint8_t r
Definition: ndp.h:346
error_t mpiMod(Mpi *r, const Mpi *a, const Mpi *p)
Modulo operation.
Definition: mpi.c:1587
OsMutex esp32CryptoMutex
Definition: esp32_crypto.c:45
error_t mpiMul(Mpi *r, const Mpi *a, const Mpi *b)
Multiple precision multiplication.
error_t
Error codes.
Definition: error.h:43
error_t mpiSetValue(Mpi *r, mpi_sword_t a)
Set the value of a multiple precision integer.
Definition: mpi.c:562
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
void esp32RsaInit(void)
RSA module initialization.
Helper routines for ECC.
void ecScalarMul(uint32_t *rl, uint32_t *rh, const uint32_t *a, const uint32_t *b, uint_t n)
Multiplication of two integers.
RSA public-key cryptography standard.
ESP32 public-key hardware accelerator.
#define MAX(a, b)
Definition: os_port.h:67
uint_t mpiGetLength(const Mpi *a)
Get the actual length in words.
Definition: mpi.c:188
uint8_t m
Definition: ndp.h:304
uint8_t n
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
uint_t size
Definition: mpi.h:104
void ecScalarSqr(uint32_t *r, const uint32_t *a, uint_t n)
Squaring operation.
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
unsigned int uint_t
Definition: compiler_port.h:57
ECC (Elliptic Curve Cryptography)
mpi_word_t * data
Definition: mpi.h:106
error_t mpiGrow(Mpi *r, uint_t size)
Adjust the size of multiple precision integer.
Definition: mpi.c:102
error_t mpiExpMod(Mpi *r, const Mpi *a, const Mpi *e, const Mpi *p)
Modular exponentiation.
Debugging facilities.
void mpiFree(Mpi *r)
Release a multiple precision integer.
Definition: mpi.c:64