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-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 "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 (optional parameter)
267  **/
268 
269 void sha1Final(Sha1Context *context, uint8_t *digest)
270 {
271  size_t paddingSize;
272  uint64_t totalSize;
273 
274  //Length of the original message (before padding)
275  totalSize = context->totalSize * 8;
276 
277  //Pad the message so that its length is congruent to 56 modulo 64
278  if(context->size < 56)
279  {
280  paddingSize = 56 - context->size;
281  }
282  else
283  {
284  paddingSize = 64 + 56 - context->size;
285  }
286 
287  //Append padding
288  sha1Update(context, padding, paddingSize);
289 
290  //Append the length of the original message
291  context->w[14] = htobe32((uint32_t) (totalSize >> 32));
292  context->w[15] = htobe32((uint32_t) totalSize);
293 
294  //Calculate the message digest
295  hashProcessData(SHA_MODE_SHA1, context->buffer, 64, context->h);
296 
297  //Copy the resulting digest
298  if(digest != NULL)
299  {
300  osMemcpy(digest, context->digest, SHA1_DIGEST_SIZE);
301  }
302 }
303 
304 
305 /**
306  * @brief Finish the SHA-1 message digest (no padding added)
307  * @param[in] context Pointer to the SHA-1 context
308  * @param[out] digest Calculated digest
309  **/
310 
311 void sha1FinalRaw(Sha1Context *context, uint8_t *digest)
312 {
313  //Copy the resulting digest
314  osMemcpy(digest, context->digest, SHA1_DIGEST_SIZE);
315 }
316 
317 #endif
318 #if (SHA224_SUPPORT == ENABLED)
319 
320 /**
321  * @brief Initialize SHA-224 message digest context
322  * @param[in] context Pointer to the SHA-224 context to initialize
323  **/
324 
325 void sha224Init(Sha224Context *context)
326 {
327  //Set initial hash value
328  context->h[0] = BETOH32(0xC1059ED8);
329  context->h[1] = BETOH32(0x367CD507);
330  context->h[2] = BETOH32(0x3070DD17);
331  context->h[3] = BETOH32(0xF70E5939);
332  context->h[4] = BETOH32(0xFFC00B31);
333  context->h[5] = BETOH32(0x68581511);
334  context->h[6] = BETOH32(0x64F98FA7);
335  context->h[7] = BETOH32(0xBEFA4FA4);
336 
337  //Number of bytes in the buffer
338  context->size = 0;
339  //Total length of the message
340  context->totalSize = 0;
341 }
342 
343 #endif
344 #if (SHA256_SUPPORT == ENABLED)
345 
346 /**
347  * @brief Initialize SHA-256 message digest context
348  * @param[in] context Pointer to the SHA-256 context to initialize
349  **/
350 
351 void sha256Init(Sha256Context *context)
352 {
353  //Set initial hash value
354  context->h[0] = BETOH32(0x6A09E667);
355  context->h[1] = BETOH32(0xBB67AE85);
356  context->h[2] = BETOH32(0x3C6EF372);
357  context->h[3] = BETOH32(0xA54FF53A);
358  context->h[4] = BETOH32(0x510E527F);
359  context->h[5] = BETOH32(0x9B05688C);
360  context->h[6] = BETOH32(0x1F83D9AB);
361  context->h[7] = BETOH32(0x5BE0CD19);
362 
363  //Number of bytes in the buffer
364  context->size = 0;
365  //Total length of the message
366  context->totalSize = 0;
367 }
368 
369 
370 /**
371  * @brief Update the SHA-256 context with a portion of the message being hashed
372  * @param[in] context Pointer to the SHA-256 context
373  * @param[in] data Pointer to the buffer being hashed
374  * @param[in] length Length of the buffer
375  **/
376 
377 void sha256Update(Sha256Context *context, const void *data, size_t length)
378 {
379  size_t n;
380 
381  //Process the incoming data
382  while(length > 0)
383  {
384  //Check whether some data is pending in the buffer
385  if(context->size == 0 && length >= 64)
386  {
387  //The length must be a multiple of 64 bytes
388  n = length - (length % 64);
389 
390  //Update hash value
391  hashProcessData(SHA_MODE_SHA256, data, n, context->h);
392 
393  //Update the SHA-256 context
394  context->totalSize += n;
395  //Advance the data pointer
396  data = (uint8_t *) data + n;
397  //Remaining bytes to process
398  length -= n;
399  }
400  else
401  {
402  //The buffer can hold at most 64 bytes
403  n = MIN(length, 64 - context->size);
404 
405  //Copy the data to the buffer
406  osMemcpy(context->buffer + context->size, data, n);
407 
408  //Update the SHA-256 context
409  context->size += n;
410  context->totalSize += n;
411  //Advance the data pointer
412  data = (uint8_t *) data + n;
413  //Remaining bytes to process
414  length -= n;
415 
416  //Check whether the buffer is full
417  if(context->size == 64)
418  {
419  //Update hash value
420  hashProcessData(SHA_MODE_SHA256, context->buffer, context->size,
421  context->h);
422 
423  //Empty the buffer
424  context->size = 0;
425  }
426  }
427  }
428 }
429 
430 
431 /**
432  * @brief Finish the SHA-256 message digest
433  * @param[in] context Pointer to the SHA-256 context
434  * @param[out] digest Calculated digest (optional parameter)
435  **/
436 
437 void sha256Final(Sha256Context *context, uint8_t *digest)
438 {
439  size_t paddingSize;
440  uint64_t totalSize;
441 
442  //Length of the original message (before padding)
443  totalSize = context->totalSize * 8;
444 
445  //Pad the message so that its length is congruent to 56 modulo 64
446  if(context->size < 56)
447  {
448  paddingSize = 56 - context->size;
449  }
450  else
451  {
452  paddingSize = 64 + 56 - context->size;
453  }
454 
455  //Append padding
456  sha256Update(context, padding, paddingSize);
457 
458  //Append the length of the original message
459  context->w[14] = htobe32((uint32_t) (totalSize >> 32));
460  context->w[15] = htobe32((uint32_t) totalSize);
461 
462  //Calculate the message digest
463  hashProcessData(SHA_MODE_SHA256, context->buffer, 64, context->h);
464 
465  //Copy the resulting digest
466  if(digest != NULL)
467  {
468  osMemcpy(digest, context->digest, SHA256_DIGEST_SIZE);
469  }
470 }
471 
472 
473 /**
474  * @brief Finish the SHA-256 message digest (no padding added)
475  * @param[in] context Pointer to the SHA-256 context
476  * @param[out] digest Calculated digest
477  **/
478 
479 void sha256FinalRaw(Sha256Context *context, uint8_t *digest)
480 {
481  //Copy the resulting digest
482  osMemcpy(digest, context->digest, SHA256_DIGEST_SIZE);
483 }
484 
485 #endif
486 #endif
#define BETOH32(value)
Definition: cpu_endian.h:451
#define LOAD32LE(p)
Definition: cpu_endian.h:203
#define htobe32(value)
Definition: cpu_endian.h:446
General definitions for cryptographic algorithms.
Debugging facilities.
uint8_t n
ESP32-C3 hardware cryptographic accelerator.
void sha224Init(Sha224Context *context)
Initialize SHA-224 message digest context.
void sha256FinalRaw(Sha256Context *context, uint8_t *digest)
Finish the SHA-256 message digest (no padding added)
void sha1Final(Sha1Context *context, uint8_t *digest)
Finish the SHA-1 message digest.
void esp32c3ShaInit(void)
SHA module initialization.
void sha256Update(Sha256Context *context, const void *data, size_t length)
Update the SHA-256 context with a portion of the message being hashed.
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.
void sha1Init(Sha1Context *context)
Initialize SHA-1 message digest context.
void hashProcessData(uint32_t algo, const uint8_t *data, size_t length, uint32_t *h)
Update hash value.
void sha256Init(Sha256Context *context)
Initialize SHA-256 message digest context.
void sha1FinalRaw(Sha1Context *context, uint8_t *digest)
Finish the SHA-1 message digest (no padding added)
ESP32-C3 hash hardware accelerator.
#define SHA_MODE_SHA1
#define SHA_MODE_SHA224
#define SHA_MODE_SHA256
uint8_t data[]
Definition: ethernet.h:222
Collection of hash algorithms.
uint8_t h
Definition: ndp.h:302
#define osMemcpy(dest, src, length)
Definition: os_port.h:141
#define MIN(a, b)
Definition: os_port.h:63
#define SHA1_DIGEST_SIZE
Definition: sha1.h:45
#define SHA256_DIGEST_SIZE
Definition: sha256.h:45
SHA-1 algorithm context.
Definition: sha1.h:62
uint8_t digest[20]
Definition: sha1.h:66
uint64_t totalSize
Definition: sha1.h:74
size_t size
Definition: sha1.h:73
uint32_t h[5]
Definition: sha1.h:65
uint8_t buffer[64]
Definition: sha1.h:71
uint32_t w[16]
Definition: sha1.h:70
SHA-256 algorithm context.
Definition: sha256.h:62
uint8_t digest[32]
Definition: sha256.h:66
uint64_t totalSize
Definition: sha256.h:74
size_t size
Definition: sha256.h:73
uint8_t buffer[64]
Definition: sha256.h:71
uint32_t h[8]
Definition: sha256.h:65
uint32_t w[16]
Definition: sha256.h:70
uint8_t length
Definition: tcp.h:368