m460_crypto_hash.c
Go to the documentation of this file.
1 /**
2  * @file m460_crypto_hash.c
3  * @brief M460 hash hardware accelerator
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.6
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
33 
34 //Dependencies
35 #include "m460.h"
36 #include "core/crypto.h"
39 #include "hash/hash_algorithms.h"
40 #include "xof/keccak.h"
41 #include "debug.h"
42 
43 //Check crypto library configuration
44 #if (M460_CRYPTO_HASH_SUPPORT == ENABLED)
45 
46 
47 /**
48  * @brief Update hash value
49  * @param[in] opmode Hash algorithm
50  * @param[in] data Pointer to the input buffer
51  * @param[in] length Length of the input buffer
52  * @param[in,out] h Intermediate hash value
53  * @param[in] hLen Length of the intermediate hash value, in words
54  **/
55 
56 void hashProcessData(uint32_t opmode, const uint8_t *data,
57  size_t length, uint32_t *h, size_t hLen)
58 {
59  uint_t i;
60 
61  //Acquire exclusive access to the CRYPTO module
63 
64  //Reset CRYPTO controller
65  SYS->IPRST0 |= SYS_IPRST0_CRPTRST_Msk;
66  SYS->IPRST0 &= ~SYS_IPRST0_CRPTRST_Msk;
67 
68  //Select the relevant hash algorithm
69  CRPT->HMAC_CTL = CRPT_HMAC_CTL_INSWAP_Msk | CRPT_HMAC_CTL_OUTSWAP_Msk |
70  CRPT_HMAC_CTL_DMACSCAD_Msk | opmode;
71 
72  //SHA-1, SHA-224 or SHA-256 algorithm?
73  if(opmode == CRPT_HMAC_CTL_OPMODE_SHA1 ||
74  opmode == CRPT_HMAC_CTL_OPMODE_SHA224 ||
76  {
77  //Restore initial hash value
78  for(i = 0; i < hLen; i++)
79  {
80  CRPT->HMAC_FDBCK[2 * i] = h[i];
81  }
82  }
83  else
84  {
85  //Restore initial hash value
86  for(i = 0; i < hLen; i++)
87  {
88  CRPT->HMAC_FDBCK[i] = h[i];
89  }
90  }
91 
92  //Start SHA engine
93  CRPT->HMAC_CTL |= CRPT_HMAC_CTL_START_Msk;
94 
95  //Process input data
96  for(i = 0; i < length; i += 4)
97  {
98  //Wait for the DATINREQ bit to be set
99  while((CRPT->HMAC_STS & CRPT_HMAC_STS_DATINREQ_Msk) == 0)
100  {
101  }
102 
103  //Write one word of data
104  CRPT->HMAC_DATIN = __UNALIGNED_UINT32_READ(data + i);
105  }
106 
107  //Wait for the processing to complete
108  while((CRPT->HMAC_STS & CRPT_HMAC_STS_DATINREQ_Msk) == 0)
109  {
110  }
111 
112  //SHA-1, SHA-224 or SHA-256 algorithm?
113  if(opmode == CRPT_HMAC_CTL_OPMODE_SHA1 ||
114  opmode == CRPT_HMAC_CTL_OPMODE_SHA224 ||
115  opmode == CRPT_HMAC_CTL_OPMODE_SHA256)
116  {
117  //Save intermediate hash value
118  for(i = 0; i < hLen; i++)
119  {
120  h[i] = CRPT->HMAC_FDBCK[2 * i];
121  }
122  }
123  else
124  {
125  //Save intermediate hash value
126  for(i = 0; i < hLen; i++)
127  {
128  h[i] = CRPT->HMAC_FDBCK[i];
129  }
130  }
131 
132  //Stop SHA engine
133  CRPT->HMAC_CTL |= CRPT_HMAC_CTL_STOP_Msk;
134 
135  //Release exclusive access to the CRYPTO module
137 }
138 
139 
140 #if (SHA1_SUPPORT == ENABLED)
141 
142 /**
143  * @brief Update the SHA-1 context with a portion of the message being hashed
144  * @param[in] context Pointer to the SHA-1 context
145  * @param[in] data Pointer to the buffer being hashed
146  * @param[in] length Length of the buffer
147  **/
148 
149 void sha1Update(Sha1Context *context, const void *data, size_t length)
150 {
151  size_t n;
152 
153  //Process the incoming data
154  while(length > 0)
155  {
156  //Check whether some data is pending in the buffer
157  if(context->size == 0 && length >= 64)
158  {
159  //The length must be a multiple of 64 bytes
160  n = length - (length % 64);
161 
162  //Update hash value
164  SHA1_DIGEST_SIZE / 4);
165 
166  //Update the SHA-1 context
167  context->totalSize += n;
168  //Advance the data pointer
169  data = (uint8_t *) data + n;
170  //Remaining bytes to process
171  length -= n;
172  }
173  else
174  {
175  //The buffer can hold at most 64 bytes
176  n = MIN(length, 64 - context->size);
177 
178  //Copy the data to the buffer
179  osMemcpy(context->buffer + context->size, data, n);
180 
181  //Update the SHA-1 context
182  context->size += n;
183  context->totalSize += n;
184  //Advance the data pointer
185  data = (uint8_t *) data + n;
186  //Remaining bytes to process
187  length -= n;
188 
189  //Check whether the buffer is full
190  if(context->size == 64)
191  {
192  //Update hash value
194  context->size, context->h, SHA1_DIGEST_SIZE / 4);
195 
196  //Empty the buffer
197  context->size = 0;
198  }
199  }
200  }
201 }
202 
203 
204 /**
205  * @brief Process message in 16-word blocks
206  * @param[in] context Pointer to the SHA-1 context
207  **/
208 
210 {
211  //Update hash value
213  context->h, SHA1_DIGEST_SIZE / 4);
214 }
215 
216 #endif
217 #if (SHA256_SUPPORT == ENABLED)
218 
219 /**
220  * @brief Update the SHA-256 context with a portion of the message being hashed
221  * @param[in] context Pointer to the SHA-256 context
222  * @param[in] data Pointer to the buffer being hashed
223  * @param[in] length Length of the buffer
224  **/
225 
226 void sha256Update(Sha256Context *context, const void *data, size_t length)
227 {
228  size_t n;
229 
230  //Process the incoming data
231  while(length > 0)
232  {
233  //Check whether some data is pending in the buffer
234  if(context->size == 0 && length >= 64)
235  {
236  //The length must be a multiple of 64 bytes
237  n = length - (length % 64);
238 
239  //Update hash value
241  SHA256_DIGEST_SIZE / 4);
242 
243  //Update the SHA-256 context
244  context->totalSize += n;
245  //Advance the data pointer
246  data = (uint8_t *) data + n;
247  //Remaining bytes to process
248  length -= n;
249  }
250  else
251  {
252  //The buffer can hold at most 64 bytes
253  n = MIN(length, 64 - context->size);
254 
255  //Copy the data to the buffer
256  osMemcpy(context->buffer + context->size, data, n);
257 
258  //Update the SHA-256 context
259  context->size += n;
260  context->totalSize += n;
261  //Advance the data pointer
262  data = (uint8_t *) data + n;
263  //Remaining bytes to process
264  length -= n;
265 
266  //Check whether the buffer is full
267  if(context->size == 64)
268  {
269  //Update hash value
271  context->size, context->h, SHA256_DIGEST_SIZE / 4);
272 
273  //Empty the buffer
274  context->size = 0;
275  }
276  }
277  }
278 }
279 
280 
281 /**
282  * @brief Process message in 16-word blocks
283  * @param[in] context Pointer to the SHA-256 context
284  **/
285 
287 {
288  //Update hash value
290  context->h, SHA256_DIGEST_SIZE / 4);
291 }
292 
293 #endif
294 #if (SHA512_SUPPORT == ENABLED)
295 
296 /**
297  * @brief Update the SHA-512 context with a portion of the message being hashed
298  * @param[in] context Pointer to the SHA-512 context
299  * @param[in] data Pointer to the buffer being hashed
300  * @param[in] length Length of the buffer
301  **/
302 
303 void sha512Update(Sha512Context *context, const void *data, size_t length)
304 {
305  size_t n;
306 
307  //Process the incoming data
308  while(length > 0)
309  {
310  //Check whether some data is pending in the buffer
311  if(context->size == 0 && length >= 128)
312  {
313  //The length must be a multiple of 128 bytes
314  n = length - (length % 128);
315 
316  //Update hash value
318  (uint32_t *) context->h, SHA512_DIGEST_SIZE / 4);
319 
320  //Update the SHA-512 context
321  context->totalSize += n;
322  //Advance the data pointer
323  data = (uint8_t *) data + n;
324  //Remaining bytes to process
325  length -= n;
326  }
327  else
328  {
329  //The buffer can hold at most 128 bytes
330  n = MIN(length, 128 - context->size);
331 
332  //Copy the data to the buffer
333  osMemcpy(context->buffer + context->size, data, n);
334 
335  //Update the SHA-512 context
336  context->size += n;
337  context->totalSize += n;
338  //Advance the data pointer
339  data = (uint8_t *) data + n;
340  //Remaining bytes to process
341  length -= n;
342 
343  //Check whether the buffer is full
344  if(context->size == 128)
345  {
346  //Update hash value
348  context->size, (uint32_t *) context->h, SHA512_DIGEST_SIZE / 4);
349 
350  //Empty the buffer
351  context->size = 0;
352  }
353  }
354  }
355 }
356 
357 
358 /**
359  * @brief Process message in 16-word blocks
360  * @param[in] context Pointer to the SHA-512 context
361  **/
362 
364 {
365  //Update hash value
367  (uint32_t *) context->h, SHA512_DIGEST_SIZE / 4);
368 }
369 
370 #endif
371 #if (KECCAK_SUPPORT == ENABLED)
372 
373 /**
374  * @brief Update state array
375  * @param[in] data Pointer to the input buffer
376  * @param[in] length Length of the input buffer
377  * @param[in] blockSize Block size
378  * @param[in,out] a State array
379  **/
380 
381 void keccakProcessData(const uint8_t *data, size_t length, size_t blockSize,
382  uint32_t *a)
383 {
384  uint_t i;
385  uint32_t opmode;
386 
387  //Check block size
388  if(blockSize == 72)
389  {
391  }
392  else if(blockSize == 104)
393  {
395  }
396  else if(blockSize == 136)
397  {
399  }
400  else
401  {
403  }
404 
405  //Acquire exclusive access to the CRYPTO module
407 
408  //Reset CRYPTO controller
409  SYS->IPRST0 |= SYS_IPRST0_CRPTRST_Msk;
410  SYS->IPRST0 &= ~SYS_IPRST0_CRPTRST_Msk;
411 
412  //Select the relevant hash algorithm
413  CRPT->HMAC_CTL = CRPT_HMAC_CTL_INSWAP_Msk | CRPT_HMAC_CTL_OUTSWAP_Msk |
414  CRPT_HMAC_CTL_SHA3EN_Msk | CRPT_HMAC_CTL_DMACSCAD_Msk | opmode;
415 
416  //Restore state array
417  for(i = 0; i < 16; i++)
418  {
419  CRPT->HMAC_FDBCK[i] = reverseInt32(a[49 - i]);
420  }
421 
422  for(i = 0; i < 34; i++)
423  {
424  CRPT->HMAC_FDBCK[54 + i] = reverseInt32(a[33 - i]);
425  }
426 
427  //Start SHA engine
428  CRPT->HMAC_CTL |= CRPT_HMAC_CTL_START_Msk;
429 
430  //Valid buffer?
431  if(data != NULL)
432  {
433  //Process input data
434  for(i = 0; i < length; i += 4)
435  {
436  //Wait for the DATINREQ bit to be set
437  while((CRPT->HMAC_STS & CRPT_HMAC_STS_DATINREQ_Msk) == 0)
438  {
439  }
440 
441  //Write one word of data
442  CRPT->HMAC_DATIN = __UNALIGNED_UINT32_READ(data + i);
443  }
444  }
445  else
446  {
447  //Process input data
448  for(i = 0; i < length; i += 4)
449  {
450  //Wait for the DATINREQ bit to be set
451  while((CRPT->HMAC_STS & CRPT_HMAC_STS_DATINREQ_Msk) == 0)
452  {
453  }
454 
455  //Write one word of data
456  CRPT->HMAC_DATIN = 0;
457  }
458  }
459 
460  //Wait for the processing to complete
461  while((CRPT->HMAC_STS & CRPT_HMAC_STS_DATINREQ_Msk) == 0)
462  {
463  }
464 
465  //Save state array
466  for(i = 0; i < 34; i++)
467  {
468  a[i] = reverseInt32(CRPT->HMAC_FDBCK[87 - i]);
469  }
470 
471  for(i = 0; i < 16; i++)
472  {
473  a[34 + i] = reverseInt32(CRPT->HMAC_FDBCK[15 - i]);
474  }
475 
476  //Stop SHA engine
477  CRPT->HMAC_CTL |= CRPT_HMAC_CTL_STOP_Msk;
478 
479  //Release exclusive access to the CRYPTO module
481 }
482 
483 
484 /**
485  * @brief Absorb data
486  * @param[in] context Pointer to the Keccak context
487  * @param[in] input Pointer to the buffer being hashed
488  * @param[in] length Length of the buffer
489  **/
490 
491 void keccakAbsorb(KeccakContext *context, const void *input, size_t length)
492 {
493  size_t n;
494 
495  //Process the incoming data
496  while(length > 0)
497  {
498  //Check whether some data is pending in the buffer
499  if(context->length == 0 && length >= context->blockSize)
500  {
501  //The length must be a multiple of the block size
502  n = length - (length % context->blockSize);
503 
504  //Absorb the current block
505  keccakProcessData(input, n, context->blockSize,
506  (uint32_t *) context->a);
507 
508  //Advance the data pointer
509  input = (uint8_t *) input + n;
510  //Remaining bytes to process
511  length -= n;
512  }
513  else
514  {
515  //The buffer can hold at most one block
516  n = MIN(length, context->blockSize - context->length);
517 
518  //Copy the data to the buffer
519  osMemcpy(context->buffer + context->length, input, n);
520  //Update the length of the buffer
521  context->length += n;
522 
523  //Advance the data pointer
524  input = (uint8_t *) input + n;
525  //Remaining bytes to process
526  length -= n;
527 
528  //Check whether the buffer is full
529  if(context->length == context->blockSize)
530  {
531  //Absorb the current block
532  keccakProcessData(context->buffer, context->length,
533  context->blockSize, (uint32_t *) context->a);
534 
535  //Empty the buffer
536  context->length = 0;
537  }
538  }
539  }
540 }
541 
542 
543 /**
544  * @brief Block permutation
545  * @param[in] context Pointer to the Keccak context
546  **/
547 
549 {
550  //Perform block permutation
551  keccakProcessData(NULL, context->blockSize, context->blockSize,
552  (uint32_t *) context->a);
553 }
554 
555 #endif
556 #endif
void hashProcessData(uint32_t opmode, const uint8_t *data, size_t length, uint32_t *h, size_t hLen)
Update hash value.
keccak_lane_t a[5][5]
Definition: keccak.h:117
#define CRPT_HMAC_CTL_OPMODE_SHA3_512
uint8_t a
Definition: ndp.h:411
SHA-256 algorithm context.
Definition: sha256.h:62
void sha256ProcessBlock(Sha256Context *context)
Process message in 16-word blocks.
#define CRPT_HMAC_CTL_OPMODE_SHA256
uint8_t data[]
Definition: ethernet.h:224
Keccak context.
Definition: keccak.h:116
size_t size
Definition: sha256.h:69
uint32_t h[8]
Definition: sha256.h:63
void sha512ProcessBlock(Sha512Context *context)
Process message in 16-word blocks.
uint64_t totalSize
Definition: sha1.h:70
void keccakPermutBlock(KeccakContext *context)
Block permutation.
size_t size
Definition: sha512.h:69
void sha1Update(Sha1Context *context, const void *data, size_t length)
Update the SHA-1 context with a portion of the message being hashed.
uint8_t buffer[24 *KECCAK_W_BYTES]
Definition: keccak.h:118
uint8_t h
Definition: ndp.h:302
#define osMemcpy(dest, src, length)
Definition: os_port.h:147
M460 hash hardware accelerator.
#define CRPT_HMAC_CTL_OPMODE_SHA3_256
void keccakProcessData(const uint8_t *data, size_t length, size_t blockSize, uint32_t *a)
Update state array.
SHA-512 algorithm context.
Definition: sha512.h:62
uint32_t h[5]
Definition: sha1.h:63
General definitions for cryptographic algorithms.
uint8_t buffer[128]
Definition: sha512.h:67
uint8_t length
Definition: tcp.h:375
uint8_t buffer[64]
Definition: sha256.h:67
#define MIN(a, b)
Definition: os_port.h:63
Collection of hash algorithms.
#define CRPT_HMAC_CTL_OPMODE_SHA512
#define SHA1_DIGEST_SIZE
Definition: sha1.h:45
Keccak sponge function.
void keccakAbsorb(KeccakContext *context, const void *input, size_t length)
Absorb data.
uint64_t h[8]
Definition: sha512.h:63
uint8_t n
uint_t blockSize
Definition: keccak.h:119
#define CRPT_HMAC_CTL_OPMODE_SHA1
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
size_t length
Definition: keccak.h:120
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
void sha1ProcessBlock(Sha1Context *context)
Process message in 16-word blocks.
#define CRPT_HMAC_CTL_OPMODE_SHA3_384
M460 hardware cryptographic accelerator.
size_t size
Definition: sha1.h:69
#define CRPT_HMAC_CTL_OPMODE_SHA224
#define CRPT_HMAC_CTL_OPMODE_SHA3_224
SHA-1 algorithm context.
Definition: sha1.h:62
uint32_t reverseInt32(uint32_t value)
Reverse bit order in a 32-bit word.
Definition: cpu_endian.c:123
uint8_t buffer[64]
Definition: sha1.h:67
uint64_t totalSize
Definition: sha512.h:70
uint64_t totalSize
Definition: sha256.h:70
unsigned int uint_t
Definition: compiler_port.h:57
#define SHA256_DIGEST_SIZE
Definition: sha256.h:45
OsMutex m460CryptoMutex
Definition: m460_crypto.c:42
#define SHA512_DIGEST_SIZE
Definition: sha512.h:45
Debugging facilities.
void sha512Update(Sha512Context *context, const void *data, size_t length)
Update the SHA-512 context with a portion of the message being hashed.
void sha256Update(Sha256Context *context, const void *data, size_t length)
Update the SHA-256 context with a portion of the message being hashed.