mcxn547_crypto_hash.c
Go to the documentation of this file.
1 /**
2  * @file mcxn547_crypto_hash.c
3  * @brief NXP MCX N547 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.4
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
33 
34 //Dependencies
35 #include <mcuxClEls.h>
36 #include "core/crypto.h"
39 #include "hash/hash_algorithms.h"
40 #include "debug.h"
41 
42 //Check crypto library configuration
43 #if (MCXN547_CRYPTO_HASH_SUPPORT == ENABLED)
44 
45 //Padding string
46 static const uint8_t padding[128] =
47 {
48  0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
49  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
50  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
51  0x00, 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  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
56 };
57 
58 
59 /**
60  * @brief Update hash value
61  * @param[in] algo Hash algorithm
62  * @param[in] data Pointer to the input buffer
63  * @param[in] length Length of the input buffer
64  * @param[in,out] h Intermediate hash value
65  * @return Error code
66  **/
67 
68 error_t hashProcessData(uint32_t algo, const uint8_t *data, size_t length,
69  uint32_t *h)
70 {
71  error_t error;
72  size_t blockSize;
73  uint8_t temp[64];
74  mcuxClEls_HashOption_t options;
75 
76  //Initialize status code
77  error = NO_ERROR;
78 
79  //Get block size
80  blockSize = (algo == MCUXCLELS_HASH_MODE_SHA_256) ? 64 : 128;
81 
82  //Acquire exclusive access to the ELS module
84 
85  //Configure hash operation
86  options.word.value = 0;
87  options.bits.hashini = MCUXCLELS_HASH_INIT_ENABLE;
88  options.bits.hashld = MCUXCLELS_HASH_LOAD_DISABLE;
89  options.bits.hashmd = algo;
90  options.bits.hashoe = MCUXCLELS_HASH_OUTPUT_ENABLE;
91  options.bits.rtfupd = MCUXCLELS_HASH_RTF_UPDATE_DISABLE;
92  options.bits.rtfoe = MCUXCLELS_HASH_RTF_OUTPUT_DISABLE;
93 
94  //Initialize hash computation
95  MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(status, token, mcuxClEls_Hash_Async(
96  options, padding, blockSize, temp));
97 
98  //Check the protection token and the return value
99  if(token != MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClEls_Hash_Async) ||
100  status != MCUXCLELS_STATUS_OK_WAIT)
101  {
102  error = ERROR_FAILURE;
103  }
104 
105  //End of function call
106  MCUX_CSSL_FP_FUNCTION_CALL_END();
107 
108  //Check status code
109  if(!error)
110  {
111  //Wait for the operation to complete
112  MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(status, token, mcuxClEls_WaitForOperation(
113  MCUXCLELS_ERROR_FLAGS_CLEAR));
114 
115  //Check the protection token and the return value
116  if(token != MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClEls_WaitForOperation) ||
117  status != MCUXCLELS_STATUS_OK)
118  {
119  error = ERROR_FAILURE;
120  }
121 
122  //End of function call
123  MCUX_CSSL_FP_FUNCTION_CALL_END();
124  }
125 
126  //Check status code
127  if(!error)
128  {
129  //Configure hash operation
130  options.bits.hashini = MCUXCLELS_HASH_INIT_DISABLE;
131  options.bits.hashld = MCUXCLELS_HASH_LOAD_ENABLE;
132 
133  //Update hash value
134  MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(status, token, mcuxClEls_Hash_Async(
135  options, data, length, (uint8_t *) h));
136 
137  //Check the protection token and the return value
138  if(token != MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClEls_Hash_Async) ||
139  status != MCUXCLELS_STATUS_OK_WAIT)
140  {
141  error = ERROR_FAILURE;
142  }
143 
144  //End of function call
145  MCUX_CSSL_FP_FUNCTION_CALL_END();
146  }
147 
148  //Check status code
149  if(!error)
150  {
151  //Wait for the operation to complete
152  MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(status, token, mcuxClEls_WaitForOperation(
153  MCUXCLELS_ERROR_FLAGS_CLEAR));
154 
155  //Check the protection token and the return value
156  if(token != MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClEls_WaitForOperation) ||
157  status != MCUXCLELS_STATUS_OK)
158  {
159  error = ERROR_FAILURE;
160  }
161 
162  //End of function call
163  MCUX_CSSL_FP_FUNCTION_CALL_END();
164  }
165 
166  //Release exclusive access to the ELS module
168 
169  //Return status code
170  return error;
171 }
172 
173 
174 #if (SHA224_SUPPORT == ENABLED)
175 
176 /**
177  * @brief Initialize SHA-224 message digest context
178  * @param[in] context Pointer to the SHA-224 context to initialize
179  **/
180 
181 void sha224Init(Sha224Context *context)
182 {
183  //Set initial hash value
184  context->h[0] = BETOH32(0xC1059ED8);
185  context->h[1] = BETOH32(0x367CD507);
186  context->h[2] = BETOH32(0x3070DD17);
187  context->h[3] = BETOH32(0xF70E5939);
188  context->h[4] = BETOH32(0xFFC00B31);
189  context->h[5] = BETOH32(0x68581511);
190  context->h[6] = BETOH32(0x64F98FA7);
191  context->h[7] = BETOH32(0xBEFA4FA4);
192 
193  //Number of bytes in the buffer
194  context->size = 0;
195  //Total length of the message
196  context->totalSize = 0;
197 }
198 
199 #endif
200 #if (SHA256_SUPPORT == ENABLED)
201 
202 /**
203  * @brief Initialize SHA-256 message digest context
204  * @param[in] context Pointer to the SHA-256 context to initialize
205  **/
206 
207 void sha256Init(Sha256Context *context)
208 {
209  //Set initial hash value
210  context->h[0] = BETOH32(0x6A09E667);
211  context->h[1] = BETOH32(0xBB67AE85);
212  context->h[2] = BETOH32(0x3C6EF372);
213  context->h[3] = BETOH32(0xA54FF53A);
214  context->h[4] = BETOH32(0x510E527F);
215  context->h[5] = BETOH32(0x9B05688C);
216  context->h[6] = BETOH32(0x1F83D9AB);
217  context->h[7] = BETOH32(0x5BE0CD19);
218 
219  //Number of bytes in the buffer
220  context->size = 0;
221  //Total length of the message
222  context->totalSize = 0;
223 }
224 
225 /**
226  * @brief Update the SHA-256 context with a portion of the message being hashed
227  * @param[in] context Pointer to the SHA-256 context
228  * @param[in] data Pointer to the buffer being hashed
229  * @param[in] length Length of the buffer
230  **/
231 
232 void sha256Update(Sha256Context *context, const void *data, size_t length)
233 {
234  size_t n;
235 
236  //Process the incoming data
237  while(length > 0)
238  {
239  //Check whether some data is pending in the buffer
240  if(context->size == 0 && length >= 64)
241  {
242  //The length must be a multiple of 64 bytes
243  n = length - (length % 64);
244 
245  //Update hash value
246  hashProcessData(MCUXCLELS_HASH_MODE_SHA_256, data, n, context->h);
247 
248  //Update the SHA-256 context
249  context->totalSize += n;
250  //Advance the data pointer
251  data = (uint8_t *) data + n;
252  //Remaining bytes to process
253  length -= n;
254  }
255  else
256  {
257  //The buffer can hold at most 64 bytes
258  n = MIN(length, 64 - context->size);
259 
260  //Copy the data to the buffer
261  osMemcpy(context->buffer + context->size, data, n);
262 
263  //Update the SHA-256 context
264  context->size += n;
265  context->totalSize += n;
266  //Advance the data pointer
267  data = (uint8_t *) data + n;
268  //Remaining bytes to process
269  length -= n;
270 
271  //Check whether the buffer is full
272  if(context->size == 64)
273  {
274  //Update hash value
275  hashProcessData(MCUXCLELS_HASH_MODE_SHA_256, context->buffer,
276  context->size, context->h);
277 
278  //Empty the buffer
279  context->size = 0;
280  }
281  }
282  }
283 }
284 
285 
286 /**
287  * @brief Finish the SHA-256 message digest
288  * @param[in] context Pointer to the SHA-256 context
289  * @param[out] digest Calculated digest
290  **/
291 
292 void sha256Final(Sha256Context *context, uint8_t *digest)
293 {
294  uint_t i;
295  size_t paddingSize;
296  uint64_t totalSize;
297 
298  //Length of the original message (before padding)
299  totalSize = context->totalSize * 8;
300 
301  //Pad the message so that its length is congruent to 56 modulo 64
302  if(context->size < 56)
303  {
304  paddingSize = 56 - context->size;
305  }
306  else
307  {
308  paddingSize = 64 + 56 - context->size;
309  }
310 
311  //Append padding
312  sha256Update(context, padding, paddingSize);
313 
314  //Append the length of the original message
315  for(i = 0; i < 8; i++)
316  {
317  context->buffer[63 - i] = totalSize & 0xFF;
318  totalSize >>= 8;
319  }
320 
321  //Calculate the message digest
322  hashProcessData(MCUXCLELS_HASH_MODE_SHA_256, context->buffer, 64,
323  context->h);
324 
325  //Copy the resulting digest
326  for(i = 0; i < (SHA256_DIGEST_SIZE / 4); i++)
327  {
328  STORE32LE(context->h[i], digest + i * 4);
329  }
330 }
331 
332 
333 /**
334  * @brief Finish the SHA-256 message digest (no padding added)
335  * @param[in] context Pointer to the SHA-256 context
336  * @param[out] digest Calculated digest
337  **/
338 
339 void sha256FinalRaw(Sha256Context *context, uint8_t *digest)
340 {
341  uint_t i;
342 
343  //Copy the resulting digest
344  for(i = 0; i < (SHA256_DIGEST_SIZE / 4); i++)
345  {
346  STORE32LE(context->h[i], digest + i * 4);
347  }
348 }
349 
350 #endif
351 #if (SHA384_SUPPORT == ENABLED)
352 
353 /**
354  * @brief Initialize SHA-384 message digest context
355  * @param[in] context Pointer to the SHA-384 context to initialize
356  **/
357 
358 void sha384Init(Sha384Context *context)
359 {
360  //Set initial hash value
361  context->h[0] = BETOH64(0xCBBB9D5DC1059ED8);
362  context->h[1] = BETOH64(0x629A292A367CD507);
363  context->h[2] = BETOH64(0x9159015A3070DD17);
364  context->h[3] = BETOH64(0x152FECD8F70E5939);
365  context->h[4] = BETOH64(0x67332667FFC00B31);
366  context->h[5] = BETOH64(0x8EB44A8768581511);
367  context->h[6] = BETOH64(0xDB0C2E0D64F98FA7);
368  context->h[7] = BETOH64(0x47B5481DBEFA4FA4);
369 
370  //Number of bytes in the buffer
371  context->size = 0;
372  //Total length of the message
373  context->totalSize = 0;
374 }
375 
376 
377 /**
378  * @brief Finish the SHA-384 message digest (no padding added)
379  * @param[in] context Pointer to the SHA-384 context
380  * @param[out] digest Calculated digest
381  **/
382 
383 void sha384FinalRaw(Sha384Context *context, uint8_t *digest)
384 {
385  uint_t i;
386 
387  //Copy the resulting digest
388  for(i = 0; i < (SHA384_DIGEST_SIZE / 8); i++)
389  {
390  STORE64LE(context->h[i], digest + i * 8);
391  }
392 }
393 
394 #endif
395 #if (SHA512_SUPPORT == ENABLED)
396 
397 /**
398  * @brief Initialize SHA-512 message digest context
399  * @param[in] context Pointer to the SHA-512 context to initialize
400  **/
401 
402 void sha512Init(Sha512Context *context)
403 {
404  //Set initial hash value
405  context->h[0] = BETOH64(0x6A09E667F3BCC908);
406  context->h[1] = BETOH64(0xBB67AE8584CAA73B);
407  context->h[2] = BETOH64(0x3C6EF372FE94F82B);
408  context->h[3] = BETOH64(0xA54FF53A5F1D36F1);
409  context->h[4] = BETOH64(0x510E527FADE682D1);
410  context->h[5] = BETOH64(0x9B05688C2B3E6C1F);
411  context->h[6] = BETOH64(0x1F83D9ABFB41BD6B);
412  context->h[7] = BETOH64(0x5BE0CD19137E2179);
413 
414  //Number of bytes in the buffer
415  context->size = 0;
416  //Total length of the message
417  context->totalSize = 0;
418 }
419 
420 
421 /**
422  * @brief Update the SHA-512 context with a portion of the message being hashed
423  * @param[in] context Pointer to the SHA-512 context
424  * @param[in] data Pointer to the buffer being hashed
425  * @param[in] length Length of the buffer
426  **/
427 
428 void sha512Update(Sha512Context *context, const void *data, size_t length)
429 {
430  size_t n;
431 
432  //Process the incoming data
433  while(length > 0)
434  {
435  //Check whether some data is pending in the buffer
436  if(context->size == 0 && length >= 128)
437  {
438  //The length must be a multiple of 128 bytes
439  n = length - (length % 128);
440 
441  //Update hash value
442  hashProcessData(MCUXCLELS_HASH_MODE_SHA_512, data, n,
443  (uint32_t *) context->h);
444 
445  //Update the SHA-512 context
446  context->totalSize += n;
447  //Advance the data pointer
448  data = (uint8_t *) data + n;
449  //Remaining bytes to process
450  length -= n;
451  }
452  else
453  {
454  //The buffer can hold at most 128 bytes
455  n = MIN(length, 128 - context->size);
456 
457  //Copy the data to the buffer
458  osMemcpy(context->buffer + context->size, data, n);
459 
460  //Update the SHA-512 context
461  context->size += n;
462  context->totalSize += n;
463  //Advance the data pointer
464  data = (uint8_t *) data + n;
465  //Remaining bytes to process
466  length -= n;
467 
468  //Check whether the buffer is full
469  if(context->size == 128)
470  {
471  //Update hash value
472  hashProcessData(MCUXCLELS_HASH_MODE_SHA_512, context->buffer,
473  context->size, (uint32_t *) context->h);
474 
475  //Empty the buffer
476  context->size = 0;
477  }
478  }
479  }
480 }
481 
482 
483 /**
484  * @brief Finish the SHA-512 message digest
485  * @param[in] context Pointer to the SHA-512 context
486  * @param[out] digest Calculated digest
487  **/
488 
489 void sha512Final(Sha512Context *context, uint8_t *digest)
490 {
491  uint_t i;
492  size_t paddingSize;
493  uint64_t totalSize;
494 
495  //Length of the original message (before padding)
496  totalSize = context->totalSize * 8;
497 
498  //Pad the message so that its length is congruent to 112 modulo 128
499  if(context->size < 112)
500  {
501  paddingSize = 112 - context->size;
502  }
503  else
504  {
505  paddingSize = 128 + 112 - context->size;
506  }
507 
508  //Append padding
509  sha512Update(context, padding, paddingSize);
510 
511  //Append the length of the original message
512  for(i = 0; i < 16; i++)
513  {
514  context->buffer[127 - i] = totalSize & 0xFF;
515  totalSize >>= 8;
516  }
517 
518  //Calculate the message digest
519  hashProcessData(MCUXCLELS_HASH_MODE_SHA_512, context->buffer, 128,
520  (uint32_t *) context->h);
521 
522  //Copy the resulting digest
523  for(i = 0; i < (SHA512_DIGEST_SIZE / 8); i++)
524  {
525  STORE64LE(context->h[i], digest + i * 8);
526  }
527 }
528 
529 #endif
530 #if (SHA512_224_SUPPORT == ENABLED)
531 
532 /**
533  * @brief Initialize SHA-512/224 message digest context
534  * @param[in] context Pointer to the SHA-512/224 context to initialize
535  **/
536 
538 {
539  //Set initial hash value
540  context->h[0] = BETOH64(0x8C3D37C819544DA2);
541  context->h[1] = BETOH64(0x73E1996689DCD4D6);
542  context->h[2] = BETOH64(0x1DFAB7AE32FF9C82);
543  context->h[3] = BETOH64(0x679DD514582F9FCF);
544  context->h[4] = BETOH64(0x0F6D2B697BD44DA8);
545  context->h[5] = BETOH64(0x77E36F7304C48942);
546  context->h[6] = BETOH64(0x3F9D85A86A1D36C8);
547  context->h[7] = BETOH64(0x1112E6AD91D692A1);
548 
549  //Number of bytes in the buffer
550  context->size = 0;
551  //Total length of the message
552  context->totalSize = 0;
553 }
554 
555 #endif
556 #if (SHA512_256_SUPPORT == ENABLED)
557 
558 /**
559  * @brief Initialize SHA-512/256 message digest context
560  * @param[in] context Pointer to the SHA-512/256 context to initialize
561  **/
562 
564 {
565  //Set initial hash value
566  context->h[0] = BETOH64(0x22312194FC2BF72C);
567  context->h[1] = BETOH64(0x9F555FA3C84C64C2);
568  context->h[2] = BETOH64(0x2393B86B6F53B151);
569  context->h[3] = BETOH64(0x963877195940EABD);
570  context->h[4] = BETOH64(0x96283EE2A88EFFE3);
571  context->h[5] = BETOH64(0xBE5E1E2553863992);
572  context->h[6] = BETOH64(0x2B0199FC2C85B8AA);
573  context->h[7] = BETOH64(0x0EB72DDC81C52CA2);
574 
575  //Number of bytes in the buffer
576  context->size = 0;
577  //Total length of the message
578  context->totalSize = 0;
579 }
580 
581 #endif
582 #endif
SHA-256 algorithm context.
Definition: sha256.h:62
uint8_t data[]
Definition: ethernet.h:224
#define STORE32LE(a, p)
Definition: cpu_endian.h:279
error_t hashProcessData(uint32_t algo, const uint8_t *data, size_t length, uint32_t *h)
Update hash value.
size_t size
Definition: sha256.h:69
uint32_t h[8]
Definition: sha256.h:63
#define BETOH32(value)
Definition: cpu_endian.h:451
void sha224Init(Sha224Context *context)
Initialize SHA-224 message digest context.
void sha512_256Init(Sha512_256Context *context)
Initialize SHA-512/256 message digest context.
void sha512_224Init(Sha512_224Context *context)
Initialize SHA-512/224 message digest context.
size_t size
Definition: sha512.h:69
void sha256Init(Sha256Context *context)
Initialize SHA-256 message digest context.
uint8_t h
Definition: ndp.h:302
void sha384FinalRaw(Sha384Context *context, uint8_t *digest)
Finish the SHA-384 message digest (no padding added)
#define osMemcpy(dest, src, length)
Definition: os_port.h:144
error_t
Error codes.
Definition: error.h:43
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
void sha512Init(Sha512Context *context)
Initialize SHA-512 message digest context.
void sha256Final(Sha256Context *context, uint8_t *digest)
Finish the SHA-256 message digest.
SHA-512 algorithm context.
Definition: sha512.h:62
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
#define SHA384_DIGEST_SIZE
Definition: sha384.h:41
Collection of hash algorithms.
void sha384Init(Sha384Context *context)
Initialize SHA-384 message digest context.
void sha512Final(Sha512Context *context, uint8_t *digest)
Finish the SHA-512 message digest.
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.
uint64_t h[8]
Definition: sha512.h:63
OsMutex mcxn547CryptoMutex
uint8_t n
#define STORE64LE(a, p)
Definition: cpu_endian.h:311
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
NXP MCX N547 hash hardware accelerator.
#define BETOH64(value)
Definition: cpu_endian.h:452
uint8_t options[]
Definition: tcp.h:364
uint64_t totalSize
Definition: sha512.h:70
NXP MCX N547 hardware cryptographic accelerator.
uint64_t totalSize
Definition: sha256.h:70
void sha256FinalRaw(Sha256Context *context, uint8_t *digest)
Finish the SHA-256 message digest (no padding added)
unsigned int uint_t
Definition: compiler_port.h:57
#define SHA256_DIGEST_SIZE
Definition: sha256.h:45
#define SHA512_DIGEST_SIZE
Definition: sha512.h:45
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
uint8_t token[]
Definition: coap_common.h:181