esp32_c3_crypto_hash.c
Go to the documentation of this file.
1 /**
2  * @file esp32_c3_crypto_hash.c
3  * @brief ESP32-C3 hash 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 "esp_crypto_lock.h"
36 #include "hal/sha_types.h"
37 #include "soc/hwcrypto_reg.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_C3_CRYPTO_HASH_SUPPORT == ENABLED)
47 
48 //Padding string
49 static const uint8_t padding[64] =
50 {
51  0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
52  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
53  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
54  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
55 };
56 
57 
58 /**
59  * @brief SHA module initialization
60  **/
61 
62 void esp32c3ShaInit(void)
63 {
64 }
65 
66 
67 /**
68  * @brief Update hash value
69  * @param[in] algo Hash algorithm
70  * @param[in] data Pointer to the input buffer
71  * @param[in] length Length of the input buffer
72  * @param[in,out] h Hash value
73  **/
74 
75 void hashProcessData(uint32_t algo, const uint8_t *data, size_t length,
76  uint32_t *h)
77 {
78  uint32_t temp;
79  size_t blockSize;
80 
81  //Get block size
82  blockSize = (algo <= SHA_MODE_SHA256) ? 64 : 128;
83 
84  //Acquire exclusive access to the SHA module
85  esp_crypto_sha_aes_lock_acquire();
86  //Enable SHA module
87  periph_module_enable(PERIPH_SHA_MODULE);
88 
89  //Select the relevant hash algorithm
90  REG_WRITE(SHA_MODE_REG, algo);
91 
92  //Restore initial hash value
93  REG_WRITE(SHA_H_BASE, h[0]);
94  REG_WRITE(SHA_H_BASE + 4, h[1]);
95  REG_WRITE(SHA_H_BASE + 8, h[2]);
96  REG_WRITE(SHA_H_BASE + 12, h[3]);
97  REG_WRITE(SHA_H_BASE + 16, h[4]);
98 
99  //SHA-224 or SHA-256 algorithm?
100  if(algo >= SHA_MODE_SHA224)
101  {
102  REG_WRITE(SHA_H_BASE + 20, h[5]);
103  REG_WRITE(SHA_H_BASE + 24, h[6]);
104  REG_WRITE(SHA_H_BASE + 28, h[7]);
105  }
106 
107  //Input data are processed in a block-by-block fashion
108  while(length >= blockSize)
109  {
110  //Write the block to be processed in the data registers
111  temp = LOAD32LE(data);
112  REG_WRITE(SHA_TEXT_BASE, temp);
113  temp = LOAD32LE(data + 4);
114  REG_WRITE(SHA_TEXT_BASE + 4, temp);
115  temp = LOAD32LE(data + 8);
116  REG_WRITE(SHA_TEXT_BASE + 8, temp);
117  temp = LOAD32LE(data + 12);
118  REG_WRITE(SHA_TEXT_BASE + 12, temp);
119  temp = LOAD32LE(data + 16);
120  REG_WRITE(SHA_TEXT_BASE + 16, temp);
121  temp = LOAD32LE(data + 20);
122  REG_WRITE(SHA_TEXT_BASE + 20, temp);
123  temp = LOAD32LE(data + 24);
124  REG_WRITE(SHA_TEXT_BASE + 24, temp);
125  temp = LOAD32LE(data + 28);
126  REG_WRITE(SHA_TEXT_BASE + 28, temp);
127  temp = LOAD32LE(data + 32);
128  REG_WRITE(SHA_TEXT_BASE + 32, temp);
129  temp = LOAD32LE(data + 36);
130  REG_WRITE(SHA_TEXT_BASE + 36, temp);
131  temp = LOAD32LE(data + 40);
132  REG_WRITE(SHA_TEXT_BASE + 40, temp);
133  temp = LOAD32LE(data + 44);
134  REG_WRITE(SHA_TEXT_BASE + 44, temp);
135  temp = LOAD32LE(data + 48);
136  REG_WRITE(SHA_TEXT_BASE + 48, temp);
137  temp = LOAD32LE(data + 52);
138  REG_WRITE(SHA_TEXT_BASE + 52, temp);
139  temp = LOAD32LE(data + 56);
140  REG_WRITE(SHA_TEXT_BASE + 56, temp);
141  temp = LOAD32LE(data + 60);
142  REG_WRITE(SHA_TEXT_BASE + 60, temp);
143 
144  //Start the SHA accelerator
145  REG_WRITE(SHA_CONTINUE_REG, 1);
146 
147  //Wait for the operation to complete
148  while(REG_READ(SHA_BUSY_REG) != 0)
149  {
150  }
151 
152  //Advance data pointer
153  data += blockSize;
154  length -= blockSize;
155  }
156 
157  //Save intermediate hash value
158  h[0] = REG_READ(SHA_H_BASE);
159  h[1] = REG_READ(SHA_H_BASE + 4);
160  h[2] = REG_READ(SHA_H_BASE + 8);
161  h[3] = REG_READ(SHA_H_BASE + 12);
162  h[4] = REG_READ(SHA_H_BASE + 16);
163 
164  //SHA-224 or SHA-256 algorithm?
165  if(algo >= SHA_MODE_SHA224)
166  {
167  h[5] = REG_READ(SHA_H_BASE + 20);
168  h[6] = REG_READ(SHA_H_BASE + 24);
169  h[7] = REG_READ(SHA_H_BASE + 28);
170  }
171 
172  //Disable SHA module
173  periph_module_disable(PERIPH_SHA_MODULE);
174  //Release exclusive access to the SHA module
175  esp_crypto_sha_aes_lock_release();
176 }
177 
178 
179 #if (SHA1_SUPPORT == ENABLED)
180 
181 /**
182  * @brief Initialize SHA-1 message digest context
183  * @param[in] context Pointer to the SHA-1 context to initialize
184  **/
185 
186 void sha1Init(Sha1Context *context)
187 {
188  //Set initial hash value
189  context->h[0] = BETOH32(0x67452301);
190  context->h[1] = BETOH32(0xEFCDAB89);
191  context->h[2] = BETOH32(0x98BADCFE);
192  context->h[3] = BETOH32(0x10325476);
193  context->h[4] = BETOH32(0xC3D2E1F0);
194 
195  //Number of bytes in the buffer
196  context->size = 0;
197  //Total length of the message
198  context->totalSize = 0;
199 }
200 
201 
202 /**
203  * @brief Update the SHA-1 context with a portion of the message being hashed
204  * @param[in] context Pointer to the SHA-1 context
205  * @param[in] data Pointer to the buffer being hashed
206  * @param[in] length Length of the buffer
207  **/
208 
209 void sha1Update(Sha1Context *context, const void *data, size_t length)
210 {
211  size_t n;
212 
213  //Process the incoming data
214  while(length > 0)
215  {
216  //Check whether some data is pending in the buffer
217  if(context->size == 0 && length >= 64)
218  {
219  //The length must be a multiple of 64 bytes
220  n = length - (length % 64);
221 
222  //Update hash value
223  hashProcessData(SHA_MODE_SHA1, data, n, context->h);
224 
225  //Update the SHA-1 context
226  context->totalSize += n;
227  //Advance the data pointer
228  data = (uint8_t *) data + n;
229  //Remaining bytes to process
230  length -= n;
231  }
232  else
233  {
234  //The buffer can hold at most 64 bytes
235  n = MIN(length, 64 - context->size);
236 
237  //Copy the data to the buffer
238  osMemcpy(context->buffer + context->size, data, n);
239 
240  //Update the SHA-1 context
241  context->size += n;
242  context->totalSize += n;
243  //Advance the data pointer
244  data = (uint8_t *) data + n;
245  //Remaining bytes to process
246  length -= n;
247 
248  //Check whether the buffer is full
249  if(context->size == 64)
250  {
251  //Update hash value
252  hashProcessData(SHA_MODE_SHA1, context->buffer, context->size,
253  context->h);
254 
255  //Empty the buffer
256  context->size = 0;
257  }
258  }
259  }
260 }
261 
262 
263 /**
264  * @brief Finish the SHA-1 message digest
265  * @param[in] context Pointer to the SHA-1 context
266  * @param[out] digest Calculated digest
267  **/
268 
269 void sha1Final(Sha1Context *context, uint8_t *digest)
270 {
271  uint_t i;
272  size_t paddingSize;
273  uint64_t totalSize;
274 
275  //Length of the original message (before padding)
276  totalSize = context->totalSize * 8;
277 
278  //Pad the message so that its length is congruent to 56 modulo 64
279  if(context->size < 56)
280  {
281  paddingSize = 56 - context->size;
282  }
283  else
284  {
285  paddingSize = 64 + 56 - context->size;
286  }
287 
288  //Append padding
289  sha1Update(context, padding, paddingSize);
290 
291  //Append the length of the original message
292  for(i = 0; i < 8; i++)
293  {
294  context->buffer[63 - i] = totalSize & 0xFF;
295  totalSize >>= 8;
296  }
297 
298  //Calculate the message digest
299  hashProcessData(SHA_MODE_SHA1, context->buffer, 64, context->h);
300 
301  //Copy the resulting digest
302  for(i = 0; i < (SHA1_DIGEST_SIZE / 4); i++)
303  {
304  STORE32LE(context->h[i], digest + i * 4);
305  }
306 }
307 
308 
309 /**
310  * @brief Finish the SHA-1 message digest (no padding added)
311  * @param[in] context Pointer to the SHA-1 context
312  * @param[out] digest Calculated digest
313  **/
314 
315 void sha1FinalRaw(Sha1Context *context, uint8_t *digest)
316 {
317  uint_t i;
318 
319  //Copy the resulting digest
320  for(i = 0; i < (SHA1_DIGEST_SIZE / 4); i++)
321  {
322  STORE32LE(context->h[i], digest + i * 4);
323  }
324 }
325 
326 #endif
327 #if (SHA224_SUPPORT == ENABLED)
328 
329 /**
330  * @brief Initialize SHA-224 message digest context
331  * @param[in] context Pointer to the SHA-224 context to initialize
332  **/
333 
334 void sha224Init(Sha224Context *context)
335 {
336  //Set initial hash value
337  context->h[0] = BETOH32(0xC1059ED8);
338  context->h[1] = BETOH32(0x367CD507);
339  context->h[2] = BETOH32(0x3070DD17);
340  context->h[3] = BETOH32(0xF70E5939);
341  context->h[4] = BETOH32(0xFFC00B31);
342  context->h[5] = BETOH32(0x68581511);
343  context->h[6] = BETOH32(0x64F98FA7);
344  context->h[7] = BETOH32(0xBEFA4FA4);
345 
346  //Number of bytes in the buffer
347  context->size = 0;
348  //Total length of the message
349  context->totalSize = 0;
350 }
351 
352 #endif
353 #if (SHA256_SUPPORT == ENABLED)
354 
355 /**
356  * @brief Initialize SHA-256 message digest context
357  * @param[in] context Pointer to the SHA-256 context to initialize
358  **/
359 
360 void sha256Init(Sha256Context *context)
361 {
362  //Set initial hash value
363  context->h[0] = BETOH32(0x6A09E667);
364  context->h[1] = BETOH32(0xBB67AE85);
365  context->h[2] = BETOH32(0x3C6EF372);
366  context->h[3] = BETOH32(0xA54FF53A);
367  context->h[4] = BETOH32(0x510E527F);
368  context->h[5] = BETOH32(0x9B05688C);
369  context->h[6] = BETOH32(0x1F83D9AB);
370  context->h[7] = BETOH32(0x5BE0CD19);
371 
372  //Number of bytes in the buffer
373  context->size = 0;
374  //Total length of the message
375  context->totalSize = 0;
376 }
377 
378 
379 /**
380  * @brief Update the SHA-256 context with a portion of the message being hashed
381  * @param[in] context Pointer to the SHA-256 context
382  * @param[in] data Pointer to the buffer being hashed
383  * @param[in] length Length of the buffer
384  **/
385 
386 void sha256Update(Sha256Context *context, const void *data, size_t length)
387 {
388  size_t n;
389 
390  //Process the incoming data
391  while(length > 0)
392  {
393  //Check whether some data is pending in the buffer
394  if(context->size == 0 && length >= 64)
395  {
396  //The length must be a multiple of 64 bytes
397  n = length - (length % 64);
398 
399  //Update hash value
400  hashProcessData(SHA_MODE_SHA256, data, n, context->h);
401 
402  //Update the SHA-256 context
403  context->totalSize += n;
404  //Advance the data pointer
405  data = (uint8_t *) data + n;
406  //Remaining bytes to process
407  length -= n;
408  }
409  else
410  {
411  //The buffer can hold at most 64 bytes
412  n = MIN(length, 64 - context->size);
413 
414  //Copy the data to the buffer
415  osMemcpy(context->buffer + context->size, data, n);
416 
417  //Update the SHA-256 context
418  context->size += n;
419  context->totalSize += n;
420  //Advance the data pointer
421  data = (uint8_t *) data + n;
422  //Remaining bytes to process
423  length -= n;
424 
425  //Check whether the buffer is full
426  if(context->size == 64)
427  {
428  //Update hash value
429  hashProcessData(SHA_MODE_SHA256, context->buffer, context->size,
430  context->h);
431 
432  //Empty the buffer
433  context->size = 0;
434  }
435  }
436  }
437 }
438 
439 
440 /**
441  * @brief Finish the SHA-256 message digest
442  * @param[in] context Pointer to the SHA-256 context
443  * @param[out] digest Calculated digest
444  **/
445 
446 void sha256Final(Sha256Context *context, uint8_t *digest)
447 {
448  uint_t i;
449  size_t paddingSize;
450  uint64_t totalSize;
451 
452  //Length of the original message (before padding)
453  totalSize = context->totalSize * 8;
454 
455  //Pad the message so that its length is congruent to 56 modulo 64
456  if(context->size < 56)
457  {
458  paddingSize = 56 - context->size;
459  }
460  else
461  {
462  paddingSize = 64 + 56 - context->size;
463  }
464 
465  //Append padding
466  sha256Update(context, padding, paddingSize);
467 
468  //Append the length of the original message
469  for(i = 0; i < 8; i++)
470  {
471  context->buffer[63 - i] = totalSize & 0xFF;
472  totalSize >>= 8;
473  }
474 
475  //Calculate the message digest
476  hashProcessData(SHA_MODE_SHA256, context->buffer, 64, context->h);
477 
478  //Copy the resulting digest
479  for(i = 0; i < (SHA256_DIGEST_SIZE / 4); i++)
480  {
481  STORE32LE(context->h[i], digest + i * 4);
482  }
483 }
484 
485 
486 /**
487  * @brief Finish the SHA-256 message digest (no padding added)
488  * @param[in] context Pointer to the SHA-256 context
489  * @param[out] digest Calculated digest
490  **/
491 
492 void sha256FinalRaw(Sha256Context *context, uint8_t *digest)
493 {
494  uint_t i;
495 
496  //Copy the resulting digest
497  for(i = 0; i < (SHA256_DIGEST_SIZE / 4); i++)
498  {
499  STORE32LE(context->h[i], digest + i * 4);
500  }
501 }
502 
503 #endif
504 #endif
#define SHA_MODE_SHA256
SHA-256 algorithm context.
Definition: sha256.h:62
uint8_t data[]
Definition: ethernet.h:222
#define STORE32LE(a, p)
Definition: cpu_endian.h:279
size_t size
Definition: sha256.h:69
void sha224Init(Sha224Context *context)
Initialize SHA-224 message digest context.
uint32_t h[8]
Definition: sha256.h:63
#define BETOH32(value)
Definition: cpu_endian.h:451
void sha256FinalRaw(Sha256Context *context, uint8_t *digest)
Finish the SHA-256 message digest (no padding added)
ESP32-C3 hash hardware accelerator.
#define SHA_MODE_SHA1
uint64_t totalSize
Definition: sha1.h:70
uint8_t h
Definition: ndp.h:302
void sha1Init(Sha1Context *context)
Initialize SHA-1 message digest context.
#define osMemcpy(dest, src, length)
Definition: os_port.h:144
void hashProcessData(uint32_t algo, const uint8_t *data, size_t length, uint32_t *h)
Update hash value.
void sha1FinalRaw(Sha1Context *context, uint8_t *digest)
Finish the SHA-1 message digest (no padding added)
#define SHA_MODE_SHA224
uint32_t h[5]
Definition: sha1.h:63
General definitions for cryptographic algorithms.
uint8_t length
Definition: tcp.h:375
uint8_t buffer[64]
Definition: sha256.h:67
#define MIN(a, b)
Definition: os_port.h:63
void sha256Init(Sha256Context *context)
Initialize SHA-256 message digest context.
void esp32c3ShaInit(void)
SHA module initialization.
Collection of hash algorithms.
void sha1Update(Sha1Context *context, const void *data, size_t length)
Update the SHA-1 context with a portion of the message being hashed.
void sha256Final(Sha256Context *context, uint8_t *digest)
Finish the SHA-256 message digest.
#define SHA1_DIGEST_SIZE
Definition: sha1.h:45
uint8_t n
size_t size
Definition: sha1.h:69
SHA-1 algorithm context.
Definition: sha1.h:62
uint8_t buffer[64]
Definition: sha1.h:67
#define LOAD32LE(p)
Definition: cpu_endian.h:203
uint64_t totalSize
Definition: sha256.h:70
void sha256Update(Sha256Context *context, const void *data, size_t length)
Update the SHA-256 context with a portion of the message being hashed.
unsigned int uint_t
Definition: compiler_port.h:57
void sha1Final(Sha1Context *context, uint8_t *digest)
Finish the SHA-1 message digest.
#define SHA256_DIGEST_SIZE
Definition: sha256.h:45
ESP32-C3 hardware cryptographic accelerator.
Debugging facilities.