esp32_crypto_hash.c
Go to the documentation of this file.
1 /**
2  * @file esp32_crypto_hash.c
3  * @brief ESP32 hash hardware accelerator
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2024 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.4.0
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
33 
34 //Dependencies
35 #include "hal/sha_types.h"
36 #include "soc/hwcrypto_reg.h"
37 #include "soc/dport_access.h"
38 #include "esp_private/periph_ctrl.h"
39 #include "core/crypto.h"
42 #include "hash/hash_algorithms.h"
43 #include "debug.h"
44 
45 //Check crypto library configuration
46 #if (ESP32_CRYPTO_HASH_SUPPORT == ENABLED)
47 
48 
49 /**
50  * @brief SHA module initialization
51  **/
52 
53 void esp32ShaInit(void)
54 {
55  //Enable SHA module
56  periph_module_enable(PERIPH_SHA_MODULE);
57 }
58 
59 
60 /**
61  * @brief Process data block
62  * @param[in] algo Hash algorithm
63  * @param[in] data Pointer to the data block
64  * @param[in,out] first First message block
65  **/
66 
67 void hashProcessDataBlock(uint32_t algo, const uint8_t *data, bool_t *first)
68 {
69  uint32_t temp;
70 
71  //Write the block to be processed in the data registers
72  temp = LOAD32BE(data);
73  DPORT_REG_WRITE(SHA_TEXT_BASE, temp);
74  temp = LOAD32BE(data + 4);
75  DPORT_REG_WRITE(SHA_TEXT_BASE + 4, temp);
76  temp = LOAD32BE(data + 8);
77  DPORT_REG_WRITE(SHA_TEXT_BASE + 8, temp);
78  temp = LOAD32BE(data + 12);
79  DPORT_REG_WRITE(SHA_TEXT_BASE + 12, temp);
80  temp = LOAD32BE(data + 16);
81  DPORT_REG_WRITE(SHA_TEXT_BASE + 16, temp);
82  temp = LOAD32BE(data + 20);
83  DPORT_REG_WRITE(SHA_TEXT_BASE + 20, temp);
84  temp = LOAD32BE(data + 24);
85  DPORT_REG_WRITE(SHA_TEXT_BASE + 24, temp);
86  temp = LOAD32BE(data + 28);
87  DPORT_REG_WRITE(SHA_TEXT_BASE + 28, temp);
88  temp = LOAD32BE(data + 32);
89  DPORT_REG_WRITE(SHA_TEXT_BASE + 32, temp);
90  temp = LOAD32BE(data + 36);
91  DPORT_REG_WRITE(SHA_TEXT_BASE + 36, temp);
92  temp = LOAD32BE(data + 40);
93  DPORT_REG_WRITE(SHA_TEXT_BASE + 40, temp);
94  temp = LOAD32BE(data + 44);
95  DPORT_REG_WRITE(SHA_TEXT_BASE + 44, temp);
96  temp = LOAD32BE(data + 48);
97  DPORT_REG_WRITE(SHA_TEXT_BASE + 48, temp);
98  temp = LOAD32BE(data + 52);
99  DPORT_REG_WRITE(SHA_TEXT_BASE + 52, temp);
100  temp = LOAD32BE(data + 56);
101  DPORT_REG_WRITE(SHA_TEXT_BASE + 56, temp);
102  temp = LOAD32BE(data + 60);
103  DPORT_REG_WRITE(SHA_TEXT_BASE + 60, temp);
104 
105  //128-octet data block?
106  if(algo == SHA2_384 || algo == SHA2_512)
107  {
108  temp = LOAD32BE(data + 64);
109  DPORT_REG_WRITE(SHA_TEXT_BASE + 64, temp);
110  temp = LOAD32BE(data + 68);
111  DPORT_REG_WRITE(SHA_TEXT_BASE + 68, temp);
112  temp = LOAD32BE(data + 72);
113  DPORT_REG_WRITE(SHA_TEXT_BASE + 72, temp);
114  temp = LOAD32BE(data + 76);
115  DPORT_REG_WRITE(SHA_TEXT_BASE + 76, temp);
116  temp = LOAD32BE(data + 80);
117  DPORT_REG_WRITE(SHA_TEXT_BASE + 80, temp);
118  temp = LOAD32BE(data + 84);
119  DPORT_REG_WRITE(SHA_TEXT_BASE + 84, temp);
120  temp = LOAD32BE(data + 88);
121  DPORT_REG_WRITE(SHA_TEXT_BASE + 88, temp);
122  temp = LOAD32BE(data + 92);
123  DPORT_REG_WRITE(SHA_TEXT_BASE + 92, temp);
124  temp = LOAD32BE(data + 96);
125  DPORT_REG_WRITE(SHA_TEXT_BASE + 96, temp);
126  temp = LOAD32BE(data + 100);
127  DPORT_REG_WRITE(SHA_TEXT_BASE + 100, temp);
128  temp = LOAD32BE(data + 104);
129  DPORT_REG_WRITE(SHA_TEXT_BASE + 104, temp);
130  temp = LOAD32BE(data + 108);
131  DPORT_REG_WRITE(SHA_TEXT_BASE + 108, temp);
132  temp = LOAD32BE(data + 112);
133  DPORT_REG_WRITE(SHA_TEXT_BASE + 112, temp);
134  temp = LOAD32BE(data + 116);
135  DPORT_REG_WRITE(SHA_TEXT_BASE + 116, temp);
136  temp = LOAD32BE(data + 120);
137  DPORT_REG_WRITE(SHA_TEXT_BASE + 120, temp);
138  temp = LOAD32BE(data + 124);
139  DPORT_REG_WRITE(SHA_TEXT_BASE + 124, temp);
140  }
141 
142  //SHA-1, SHA-256, SHA-384 and SHA-512 algorithms use different control
143  //registers
144  if(algo == SHA1)
145  {
146  //Start SHA-1 operation
147  if(*first)
148  {
149  DPORT_REG_WRITE(SHA_1_START_REG, 1);
150  }
151  else
152  {
153  DPORT_REG_WRITE(SHA_1_CONTINUE_REG, 1);
154  }
155 
156  //Wait for the operation to complete
157  while(DPORT_REG_READ(SHA_1_BUSY_REG) != 0)
158  {
159  }
160  }
161  else if(algo == SHA2_256)
162  {
163  //Start SHA-256 operation
164  if(*first)
165  {
166  DPORT_REG_WRITE(SHA_256_START_REG, 1);
167  }
168  else
169  {
170  DPORT_REG_WRITE(SHA_256_CONTINUE_REG, 1);
171  }
172 
173  //Wait for the operation to complete
174  while(DPORT_REG_READ(SHA_256_BUSY_REG) != 0)
175  {
176  }
177  }
178  else if(algo == SHA2_384)
179  {
180  //Start SHA-384 operation
181  if(*first)
182  {
183  DPORT_REG_WRITE(SHA_384_START_REG, 1);
184  }
185  else
186  {
187  DPORT_REG_WRITE(SHA_384_CONTINUE_REG, 1);
188  }
189 
190  //Wait for the operation to complete
191  while(DPORT_REG_READ(SHA_384_BUSY_REG) != 0)
192  {
193  }
194  }
195  else
196  {
197  //Start SHA-512 operation
198  if(*first)
199  {
200  DPORT_REG_WRITE(SHA_512_START_REG, 1);
201  }
202  else
203  {
204  DPORT_REG_WRITE(SHA_512_CONTINUE_REG, 1);
205  }
206 
207  //Wait for the operation to complete
208  while(DPORT_REG_READ(SHA_512_BUSY_REG) != 0)
209  {
210  }
211  }
212 
213  //Process subsequent message blocks
214  *first = FALSE;
215 }
216 
217 
218 #if (SHA1_SUPPORT == ENABLED)
219 
220 /**
221  * @brief Digest a message using SHA-1
222  * @param[in] data Pointer to the message being hashed
223  * @param[in] length Length of the message
224  * @param[out] digest Pointer to the calculated digest
225  * @return Error code
226  **/
227 
228 error_t sha1Compute(const void *data, size_t length, uint8_t *digest)
229 {
230  bool_t first;
231  size_t n;
232  uint32_t temp;
233  uint8_t buffer[64];
234 
235  //Acquire exclusive access to the SHA module
237 
238  //Process the first message block
239  first = TRUE;
240 
241  //Digest the message
242  for(n = length; n >= 64; n -= 64)
243  {
244  //Update hash value
245  hashProcessDataBlock(SHA1, data, &first);
246  //Advance the data pointer
247  data = (uint8_t *) data + 64;
248  }
249 
250  //Copy the partial block, is any
251  osMemset(buffer, 0, 64);
252  osMemcpy(buffer, data, n);
253 
254  //Append the first byte of the padding string
255  buffer[n] = 0x80;
256 
257  //Pad the message so that its length is congruent to 56 modulo 64
258  if(n >= 56)
259  {
260  hashProcessDataBlock(SHA1, buffer, &first);
261  osMemset(buffer, 0, 64);
262  }
263 
264  //Append the length of the original message
265  STORE64BE(length * 8, buffer + 56);
266 
267  //Process the final block
268  hashProcessDataBlock(SHA1, buffer, &first);
269 
270  //Compute SHA-1 digest
271  DPORT_REG_WRITE(SHA_1_LOAD_REG, 1);
272 
273  //Wait for the operation to complete
274  while(DPORT_REG_READ(SHA_1_BUSY_REG) != 0)
275  {
276  }
277 
278  //Save the resulting hash value
279  DPORT_INTERRUPT_DISABLE();
280  temp = DPORT_SEQUENCE_REG_READ(SHA_TEXT_BASE);
281  STORE32BE(temp, digest);
282  temp = DPORT_SEQUENCE_REG_READ(SHA_TEXT_BASE + 4);
283  STORE32BE(temp, digest + 4);
284  temp = DPORT_SEQUENCE_REG_READ(SHA_TEXT_BASE + 8);
285  STORE32BE(temp, digest + 8);
286  temp = DPORT_SEQUENCE_REG_READ(SHA_TEXT_BASE + 12);
287  STORE32BE(temp, digest + 12);
288  temp = DPORT_SEQUENCE_REG_READ(SHA_TEXT_BASE + 16);
289  STORE32BE(temp, digest + 16);
290  DPORT_INTERRUPT_RESTORE();
291 
292  //Release exclusive access to the SHA module
294 
295  //Sucessful processing
296  return NO_ERROR;
297 }
298 
299 #endif
300 #if (SHA256_SUPPORT == ENABLED)
301 
302 /**
303  * @brief Digest a message using SHA-256
304  * @param[in] data Pointer to the message being hashed
305  * @param[in] length Length of the message
306  * @param[out] digest Pointer to the calculated digest
307  * @return Error code
308  **/
309 
310 error_t sha256Compute(const void *data, size_t length, uint8_t *digest)
311 {
312  bool_t first;
313  size_t n;
314  uint32_t temp;
315  uint8_t buffer[64];
316 
317  //Acquire exclusive access to the SHA module
319 
320  //Process the first message block
321  first = TRUE;
322 
323  //Digest the message
324  for(n = length; n >= 64; n -= 64)
325  {
326  //Update hash value
327  hashProcessDataBlock(SHA2_256, data, &first);
328  //Advance the data pointer
329  data = (uint8_t *) data + 64;
330  }
331 
332  //Copy the partial block, is any
333  osMemset(buffer, 0, 64);
334  osMemcpy(buffer, data, n);
335 
336  //Append the first byte of the padding string
337  buffer[n] = 0x80;
338 
339  //Pad the message so that its length is congruent to 56 modulo 64
340  if(n >= 56)
341  {
342  hashProcessDataBlock(SHA2_256, buffer, &first);
343  osMemset(buffer, 0, 64);
344  }
345 
346  //Append the length of the original message
347  STORE64BE(length * 8, buffer + 56);
348 
349  //Process the final block
350  hashProcessDataBlock(SHA2_256, buffer, &first);
351 
352  //Compute SHA-256 digest
353  DPORT_REG_WRITE(SHA_256_LOAD_REG, 1);
354 
355  //Wait for the operation to complete
356  while(DPORT_REG_READ(SHA_256_BUSY_REG) != 0)
357  {
358  }
359 
360  //Save the resulting hash value
361  DPORT_INTERRUPT_DISABLE();
362  temp = DPORT_SEQUENCE_REG_READ(SHA_TEXT_BASE);
363  STORE32BE(temp, digest);
364  temp = DPORT_SEQUENCE_REG_READ(SHA_TEXT_BASE + 4);
365  STORE32BE(temp, digest + 4);
366  temp = DPORT_SEQUENCE_REG_READ(SHA_TEXT_BASE + 8);
367  STORE32BE(temp, digest + 8);
368  temp = DPORT_SEQUENCE_REG_READ(SHA_TEXT_BASE + 12);
369  STORE32BE(temp, digest + 12);
370  temp = DPORT_SEQUENCE_REG_READ(SHA_TEXT_BASE + 16);
371  STORE32BE(temp, digest + 16);
372  temp = DPORT_SEQUENCE_REG_READ(SHA_TEXT_BASE + 20);
373  STORE32BE(temp, digest + 20);
374  temp = DPORT_SEQUENCE_REG_READ(SHA_TEXT_BASE + 24);
375  STORE32BE(temp, digest + 24);
376  temp = DPORT_SEQUENCE_REG_READ(SHA_TEXT_BASE + 28);
377  STORE32BE(temp, digest + 28);
378  DPORT_INTERRUPT_RESTORE();
379 
380  //Release exclusive access to the SHA module
382 
383  //Sucessful processing
384  return NO_ERROR;
385 }
386 
387 #endif
388 #if (SHA384_SUPPORT == ENABLED)
389 
390 /**
391  * @brief Digest a message using SHA-384
392  * @param[in] data Pointer to the message being hashed
393  * @param[in] length Length of the message
394  * @param[out] digest Pointer to the calculated digest
395  * @return Error code
396  **/
397 
398 error_t sha384Compute(const void *data, size_t length, uint8_t *digest)
399 {
400  bool_t first;
401  size_t n;
402  uint32_t temp;
403  uint8_t buffer[128];
404 
405  //Acquire exclusive access to the SHA module
407 
408  //Process the first message block
409  first = TRUE;
410 
411  //Digest the message
412  for(n = length; n >= 128; n -= 128)
413  {
414  //Update hash value
415  hashProcessDataBlock(SHA2_384, data, &first);
416  //Advance the data pointer
417  data = (uint8_t *) data + 128;
418  }
419 
420  //Copy the partial block, is any
421  osMemset(buffer, 0, 128);
422  osMemcpy(buffer, data, n);
423 
424  //Append the first byte of the padding string
425  buffer[n] = 0x80;
426 
427  //Pad the message so that its length is congruent to 112 modulo 128
428  if(n >= 112)
429  {
430  hashProcessDataBlock(SHA2_384, buffer, &first);
431  osMemset(buffer, 0, 128);
432  }
433 
434  //Append the length of the original message
435  STORE64BE(length * 8, buffer + 120);
436 
437  //Process the final block
438  hashProcessDataBlock(SHA2_384, buffer, &first);
439 
440  //Compute SHA-384 digest
441  DPORT_REG_WRITE(SHA_384_LOAD_REG, 1);
442 
443  //Wait for the operation to complete
444  while(DPORT_REG_READ(SHA_384_BUSY_REG) != 0)
445  {
446  }
447 
448  //Save the resulting hash value
449  DPORT_INTERRUPT_DISABLE();
450  temp = DPORT_SEQUENCE_REG_READ(SHA_TEXT_BASE);
451  STORE32BE(temp, digest);
452  temp = DPORT_SEQUENCE_REG_READ(SHA_TEXT_BASE + 4);
453  STORE32BE(temp, digest + 4);
454  temp = DPORT_SEQUENCE_REG_READ(SHA_TEXT_BASE + 8);
455  STORE32BE(temp, digest + 8);
456  temp = DPORT_SEQUENCE_REG_READ(SHA_TEXT_BASE + 12);
457  STORE32BE(temp, digest + 12);
458  temp = DPORT_SEQUENCE_REG_READ(SHA_TEXT_BASE + 16);
459  STORE32BE(temp, digest + 16);
460  temp = DPORT_SEQUENCE_REG_READ(SHA_TEXT_BASE + 20);
461  STORE32BE(temp, digest + 20);
462  temp = DPORT_SEQUENCE_REG_READ(SHA_TEXT_BASE + 24);
463  STORE32BE(temp, digest + 24);
464  temp = DPORT_SEQUENCE_REG_READ(SHA_TEXT_BASE + 28);
465  STORE32BE(temp, digest + 28);
466  temp = DPORT_SEQUENCE_REG_READ(SHA_TEXT_BASE + 32);
467  STORE32BE(temp, digest + 32);
468  temp = DPORT_SEQUENCE_REG_READ(SHA_TEXT_BASE + 36);
469  STORE32BE(temp, digest + 36);
470  temp = DPORT_SEQUENCE_REG_READ(SHA_TEXT_BASE + 40);
471  STORE32BE(temp, digest + 40);
472  temp = DPORT_SEQUENCE_REG_READ(SHA_TEXT_BASE + 44);
473  STORE32BE(temp, digest + 44);
474  DPORT_INTERRUPT_RESTORE();
475 
476  //Release exclusive access to the SHA module
478 
479  //Sucessful processing
480  return NO_ERROR;
481 }
482 
483 #endif
484 #if (SHA512_SUPPORT == ENABLED)
485 
486 /**
487  * @brief Digest a message using SHA-512
488  * @param[in] data Pointer to the message being hashed
489  * @param[in] length Length of the message
490  * @param[out] digest Pointer to the calculated digest
491  * @return Error code
492  **/
493 
494 error_t sha512Compute(const void *data, size_t length, uint8_t *digest)
495 {
496  bool_t first;
497  size_t n;
498  uint32_t temp;
499  uint8_t buffer[128];
500 
501  //Acquire exclusive access to the SHA module
503 
504  //Process the first message block
505  first = TRUE;
506 
507  //Digest the message
508  for(n = length; n >= 128; n -= 128)
509  {
510  //Update hash value
511  hashProcessDataBlock(SHA2_512, data, &first);
512  //Advance the data pointer
513  data = (uint8_t *) data + 128;
514  }
515 
516  //Copy the partial block, is any
517  osMemset(buffer, 0, 128);
518  osMemcpy(buffer, data, n);
519 
520  //Append the first byte of the padding string
521  buffer[n] = 0x80;
522 
523  //Pad the message so that its length is congruent to 112 modulo 128
524  if(n >= 112)
525  {
526  hashProcessDataBlock(SHA2_512, buffer, &first);
527  osMemset(buffer, 0, 128);
528  }
529 
530  //Append the length of the original message
531  STORE64BE(length * 8, buffer + 120);
532 
533  //Process the final block
534  hashProcessDataBlock(SHA2_512, buffer, &first);
535 
536  //Compute SHA-512 digest
537  DPORT_REG_WRITE(SHA_512_LOAD_REG, 1);
538 
539  //Wait for the operation to complete
540  while(DPORT_REG_READ(SHA_512_BUSY_REG) != 0)
541  {
542  }
543 
544  //Save the resulting hash value
545  DPORT_INTERRUPT_DISABLE();
546  temp = DPORT_SEQUENCE_REG_READ(SHA_TEXT_BASE);
547  STORE32BE(temp, digest);
548  temp = DPORT_SEQUENCE_REG_READ(SHA_TEXT_BASE + 4);
549  STORE32BE(temp, digest + 4);
550  temp = DPORT_SEQUENCE_REG_READ(SHA_TEXT_BASE + 8);
551  STORE32BE(temp, digest + 8);
552  temp = DPORT_SEQUENCE_REG_READ(SHA_TEXT_BASE + 12);
553  STORE32BE(temp, digest + 12);
554  temp = DPORT_SEQUENCE_REG_READ(SHA_TEXT_BASE + 16);
555  STORE32BE(temp, digest + 16);
556  temp = DPORT_SEQUENCE_REG_READ(SHA_TEXT_BASE + 20);
557  STORE32BE(temp, digest + 20);
558  temp = DPORT_SEQUENCE_REG_READ(SHA_TEXT_BASE + 24);
559  STORE32BE(temp, digest + 24);
560  temp = DPORT_SEQUENCE_REG_READ(SHA_TEXT_BASE + 28);
561  STORE32BE(temp, digest + 28);
562  temp = DPORT_SEQUENCE_REG_READ(SHA_TEXT_BASE + 32);
563  STORE32BE(temp, digest + 32);
564  temp = DPORT_SEQUENCE_REG_READ(SHA_TEXT_BASE + 36);
565  STORE32BE(temp, digest + 36);
566  temp = DPORT_SEQUENCE_REG_READ(SHA_TEXT_BASE + 40);
567  STORE32BE(temp, digest + 40);
568  temp = DPORT_SEQUENCE_REG_READ(SHA_TEXT_BASE + 44);
569  STORE32BE(temp, digest + 44);
570  temp = DPORT_SEQUENCE_REG_READ(SHA_TEXT_BASE + 48);
571  STORE32BE(temp, digest + 48);
572  temp = DPORT_SEQUENCE_REG_READ(SHA_TEXT_BASE + 52);
573  STORE32BE(temp, digest + 52);
574  temp = DPORT_SEQUENCE_REG_READ(SHA_TEXT_BASE + 56);
575  STORE32BE(temp, digest + 56);
576  temp = DPORT_SEQUENCE_REG_READ(SHA_TEXT_BASE + 60);
577  STORE32BE(temp, digest + 60);
578  DPORT_INTERRUPT_RESTORE();
579 
580  //Release exclusive access to the SHA module
582 
583  //Sucessful processing
584  return NO_ERROR;
585 }
586 
587 #endif
588 #endif
int bool_t
Definition: compiler_port.h:53
#define LOAD32BE(p)
Definition: cpu_endian.h:210
#define STORE32BE(a, p)
Definition: cpu_endian.h:286
#define STORE64BE(a, p)
Definition: cpu_endian.h:322
General definitions for cryptographic algorithms.
Debugging facilities.
uint8_t n
error_t
Error codes.
Definition: error.h:43
@ NO_ERROR
Success.
Definition: error.h:44
OsMutex esp32CryptoMutex
Definition: esp32_crypto.c:45
ESP32 hardware cryptographic accelerator.
error_t sha512Compute(const void *data, size_t length, uint8_t *digest)
Digest a message using SHA-512.
error_t sha256Compute(const void *data, size_t length, uint8_t *digest)
Digest a message using SHA-256.
error_t sha384Compute(const void *data, size_t length, uint8_t *digest)
Digest a message using SHA-384.
void hashProcessDataBlock(uint32_t algo, const uint8_t *data, bool_t *first)
Process data block.
void esp32ShaInit(void)
SHA module initialization.
error_t sha1Compute(const void *data, size_t length, uint8_t *digest)
Digest a message using SHA-1.
ESP32 hash hardware accelerator.
uint8_t data[]
Definition: ethernet.h:222
Collection of hash algorithms.
#define osMemset(p, value, length)
Definition: os_port.h:135
#define osMemcpy(dest, src, length)
Definition: os_port.h:141
#define TRUE
Definition: os_port.h:50
#define FALSE
Definition: os_port.h:46
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
uint8_t length
Definition: tcp.h:368