stm32h5xx_crypto_hash.c
Go to the documentation of this file.
1 /**
2  * @file stm32h5xx_crypto_hash.c
3  * @brief STM32H5 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 "stm32h5xx.h"
36 #include "stm32h5xx_hal.h"
37 #include "core/crypto.h"
40 #include "hash/hash_algorithms.h"
41 #include "debug.h"
42 
43 //Check crypto library configuration
44 #if (STM32H5XX_CRYPTO_HASH_SUPPORT == ENABLED)
45 
46 
47 /**
48  * @brief HASH module initialization
49  * @return Error code
50  **/
51 
53 {
54  //Enable HASH peripheral clock
55  __HAL_RCC_HASH_CLK_ENABLE();
56 
57  //Successful processing
58  return NO_ERROR;
59 }
60 
61 
62 /**
63  * @brief Update hash value
64  * @param[in] algo Hash algorithm
65  * @param[in] data Pointer to the input buffer
66  * @param[in] length Length of the input buffer
67  * @param[in,out] h Intermediate hash value
68  * @param[in] hLen Length of the intermediate hash value, in words
69  **/
70 
71 void hashProcessData(uint32_t algo, const uint8_t *data, size_t length,
72  uint32_t *h, size_t hLen)
73 {
74  uint_t i;
75  size_t blockSize;
76 
77  //Get block size
78  if(algo == HASH_CR_ALGO_SHA1 || algo == HASH_CR_ALGO_SHA224 ||
79  algo == HASH_CR_ALGO_SHA256)
80  {
81  blockSize = 64;
82  }
83  else
84  {
85  blockSize = 128;
86  }
87 
88  //Acquire exclusive access to the HASH module
90 
91  //Select the relevant hash algorithm
92  HASH->CR = HASH_CR_DATATYPE_8B | algo;
93  //Initialize the hash processor by setting the INIT bit
94  HASH->CR |= HASH_CR_INIT;
95 
96  //SHA-1, SHA-224 or SHA-256 algorithm?
97  if(blockSize == 64)
98  {
99  //Restore initial hash value
100  for(i = 0; i < hLen; i++)
101  {
102  HASH->CSR[6 + i] = h[i];
103  HASH->CSR[14 + i] = h[i];
104  }
105  }
106  else
107  {
108  //Restore initial hash value
109  for(i = 0; i < hLen; i += 2)
110  {
111  HASH->CSR[6 + i] = h[i + 1];
112  HASH->CSR[7 + i] = h[i];
113  HASH->CSR[39 + i / 2] = h[i];
114  HASH->CSR[47 + i / 2] = h[i + 1];
115  }
116  }
117 
118  //Input data are processed in a block-by-block fashion
119  while(length >= blockSize)
120  {
121  //Write the first byte of the block
122  HASH->DIN = __UNALIGNED_UINT32_READ(data);
123 
124  //Wait for the BUSY bit to be cleared
125  while((HASH->SR & HASH_SR_BUSY) != 0)
126  {
127  }
128 
129  //Write the rest of the block
130  HASH->DIN = __UNALIGNED_UINT32_READ(data + 4);
131  HASH->DIN = __UNALIGNED_UINT32_READ(data + 8);
132  HASH->DIN = __UNALIGNED_UINT32_READ(data + 12);
133  HASH->DIN = __UNALIGNED_UINT32_READ(data + 16);
134  HASH->DIN = __UNALIGNED_UINT32_READ(data + 20);
135  HASH->DIN = __UNALIGNED_UINT32_READ(data + 24);
136  HASH->DIN = __UNALIGNED_UINT32_READ(data + 28);
137  HASH->DIN = __UNALIGNED_UINT32_READ(data + 32);
138  HASH->DIN = __UNALIGNED_UINT32_READ(data + 36);
139  HASH->DIN = __UNALIGNED_UINT32_READ(data + 40);
140  HASH->DIN = __UNALIGNED_UINT32_READ(data + 44);
141  HASH->DIN = __UNALIGNED_UINT32_READ(data + 48);
142  HASH->DIN = __UNALIGNED_UINT32_READ(data + 52);
143  HASH->DIN = __UNALIGNED_UINT32_READ(data + 56);
144  HASH->DIN = __UNALIGNED_UINT32_READ(data + 60);
145 
146  //128-octet data block?
147  if(blockSize == 128)
148  {
149  HASH->DIN = __UNALIGNED_UINT32_READ(data + 64);
150  HASH->DIN = __UNALIGNED_UINT32_READ(data + 68);
151  HASH->DIN = __UNALIGNED_UINT32_READ(data + 72);
152  HASH->DIN = __UNALIGNED_UINT32_READ(data + 76);
153  HASH->DIN = __UNALIGNED_UINT32_READ(data + 80);
154  HASH->DIN = __UNALIGNED_UINT32_READ(data + 84);
155  HASH->DIN = __UNALIGNED_UINT32_READ(data + 88);
156  HASH->DIN = __UNALIGNED_UINT32_READ(data + 92);
157  HASH->DIN = __UNALIGNED_UINT32_READ(data + 96);
158  HASH->DIN = __UNALIGNED_UINT32_READ(data + 100);
159  HASH->DIN = __UNALIGNED_UINT32_READ(data + 104);
160  HASH->DIN = __UNALIGNED_UINT32_READ(data + 108);
161  HASH->DIN = __UNALIGNED_UINT32_READ(data + 112);
162  HASH->DIN = __UNALIGNED_UINT32_READ(data + 116);
163  HASH->DIN = __UNALIGNED_UINT32_READ(data + 120);
164  HASH->DIN = __UNALIGNED_UINT32_READ(data + 124);
165  }
166 
167  //Advance data pointer
168  data += blockSize;
169  length -= blockSize;
170  }
171 
172  //Partial digest computation are triggered each time the application
173  //writes the first word of the next block
174  HASH->DIN = 0;
175 
176  //Wait for the BUSY bit to be cleared
177  while((HASH->SR & HASH_SR_BUSY) != 0)
178  {
179  }
180 
181  //SHA-1, SHA-224 or SHA-256 algorithm?
182  if(blockSize == 64)
183  {
184  //Save intermediate hash value
185  for(i = 0; i < hLen; i++)
186  {
187  h[i] = HASH->CSR[6 + i];
188  }
189  }
190  else
191  {
192  //Save intermediate hash value
193  for(i = 0; i < hLen; i += 2)
194  {
195  h[i] = HASH->CSR[7 + i];
196  h[i + 1] = HASH->CSR[6 + i];
197  }
198  }
199 
200  //Release exclusive access to the HASH module
202 }
203 
204 
205 #if (SHA1_SUPPORT == ENABLED)
206 
207 /**
208  * @brief Update the SHA-1 context with a portion of the message being hashed
209  * @param[in] context Pointer to the SHA-1 context
210  * @param[in] data Pointer to the buffer being hashed
211  * @param[in] length Length of the buffer
212  **/
213 
214 void sha1Update(Sha1Context *context, const void *data, size_t length)
215 {
216  size_t n;
217 
218  //Process the incoming data
219  while(length > 0)
220  {
221  //Check whether some data is pending in the buffer
222  if(context->size == 0 && length >= 64)
223  {
224  //The length must be a multiple of 64 bytes
225  n = length - (length % 64);
226 
227  //Update hash value
229  SHA1_DIGEST_SIZE / 4);
230 
231  //Update the SHA-1 context
232  context->totalSize += n;
233  //Advance the data pointer
234  data = (uint8_t *) data + n;
235  //Remaining bytes to process
236  length -= n;
237  }
238  else
239  {
240  //The buffer can hold at most 64 bytes
241  n = MIN(length, 64 - context->size);
242 
243  //Copy the data to the buffer
244  osMemcpy(context->buffer + context->size, data, n);
245 
246  //Update the SHA-1 context
247  context->size += n;
248  context->totalSize += n;
249  //Advance the data pointer
250  data = (uint8_t *) data + n;
251  //Remaining bytes to process
252  length -= n;
253 
254  //Check whether the buffer is full
255  if(context->size == 64)
256  {
257  //Update hash value
258  hashProcessData(HASH_CR_ALGO_SHA1, context->buffer, context->size,
259  context->h, SHA1_DIGEST_SIZE / 4);
260 
261  //Empty the buffer
262  context->size = 0;
263  }
264  }
265  }
266 }
267 
268 
269 /**
270  * @brief Process message in 16-word blocks
271  * @param[in] context Pointer to the SHA-1 context
272  **/
273 
275 {
276  //Update hash value
277  hashProcessData(HASH_CR_ALGO_SHA1, context->buffer, 64, context->h,
278  SHA1_DIGEST_SIZE / 4);
279 }
280 
281 #endif
282 #if (SHA256_SUPPORT == ENABLED)
283 
284 /**
285  * @brief Update the SHA-256 context with a portion of the message being hashed
286  * @param[in] context Pointer to the SHA-256 context
287  * @param[in] data Pointer to the buffer being hashed
288  * @param[in] length Length of the buffer
289  **/
290 
291 void sha256Update(Sha256Context *context, const void *data, size_t length)
292 {
293  size_t n;
294 
295  //Process the incoming data
296  while(length > 0)
297  {
298  //Check whether some data is pending in the buffer
299  if(context->size == 0 && length >= 64)
300  {
301  //The length must be a multiple of 64 bytes
302  n = length - (length % 64);
303 
304  //Update hash value
306  SHA256_DIGEST_SIZE / 4);
307 
308  //Update the SHA-256 context
309  context->totalSize += n;
310  //Advance the data pointer
311  data = (uint8_t *) data + n;
312  //Remaining bytes to process
313  length -= n;
314  }
315  else
316  {
317  //The buffer can hold at most 64 bytes
318  n = MIN(length, 64 - context->size);
319 
320  //Copy the data to the buffer
321  osMemcpy(context->buffer + context->size, data, n);
322 
323  //Update the SHA-256 context
324  context->size += n;
325  context->totalSize += n;
326  //Advance the data pointer
327  data = (uint8_t *) data + n;
328  //Remaining bytes to process
329  length -= n;
330 
331  //Check whether the buffer is full
332  if(context->size == 64)
333  {
334  //Update hash value
335  hashProcessData(HASH_CR_ALGO_SHA256, context->buffer, context->size,
336  context->h, SHA256_DIGEST_SIZE / 4);
337 
338  //Empty the buffer
339  context->size = 0;
340  }
341  }
342  }
343 }
344 
345 
346 /**
347  * @brief Process message in 16-word blocks
348  * @param[in] context Pointer to the SHA-256 context
349  **/
350 
352 {
353  //Update hash value
354  hashProcessData(HASH_CR_ALGO_SHA256, context->buffer, 64, context->h,
355  SHA256_DIGEST_SIZE / 4);
356 }
357 
358 #endif
359 #if (SHA512_SUPPORT == ENABLED)
360 
361 /**
362  * @brief Update the SHA-512 context with a portion of the message being hashed
363  * @param[in] context Pointer to the SHA-512 context
364  * @param[in] data Pointer to the buffer being hashed
365  * @param[in] length Length of the buffer
366  **/
367 
368 void sha512Update(Sha512Context *context, const void *data, size_t length)
369 {
370  size_t n;
371 
372  //Process the incoming data
373  while(length > 0)
374  {
375  //Check whether some data is pending in the buffer
376  if(context->size == 0 && length >= 128)
377  {
378  //The length must be a multiple of 128 bytes
379  n = length - (length % 128);
380 
381  //Update hash value
382  hashProcessData(HASH_CR_ALGO_SHA512, data, n, (uint32_t *) context->h,
383  SHA512_DIGEST_SIZE / 4);
384 
385  //Update the SHA-512 context
386  context->totalSize += n;
387  //Advance the data pointer
388  data = (uint8_t *) data + n;
389  //Remaining bytes to process
390  length -= n;
391  }
392  else
393  {
394  //The buffer can hold at most 128 bytes
395  n = MIN(length, 128 - context->size);
396 
397  //Copy the data to the buffer
398  osMemcpy(context->buffer + context->size, data, n);
399 
400  //Update the SHA-512 context
401  context->size += n;
402  context->totalSize += n;
403  //Advance the data pointer
404  data = (uint8_t *) data + n;
405  //Remaining bytes to process
406  length -= n;
407 
408  //Check whether the buffer is full
409  if(context->size == 128)
410  {
411  //Update hash value
412  hashProcessData(HASH_CR_ALGO_SHA512, context->buffer, context->size,
413  (uint32_t *) context->h, SHA512_DIGEST_SIZE / 4);
414 
415  //Empty the buffer
416  context->size = 0;
417  }
418  }
419  }
420 }
421 
422 
423 /**
424  * @brief Process message in 16-word blocks
425  * @param[in] context Pointer to the SHA-512 context
426  **/
427 
429 {
430  //Update hash value
432  (uint32_t *) context->h, SHA512_DIGEST_SIZE / 4);
433 }
434 
435 #endif
436 #endif
unsigned int uint_t
Definition: compiler_port.h:50
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
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
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
#define SHA1_DIGEST_SIZE
Definition: sha1.h:45
#define SHA256_DIGEST_SIZE
Definition: sha256.h:45
#define SHA512_DIGEST_SIZE
Definition: sha512.h:45
#define HASH_CR_DATATYPE_8B
#define HASH_CR_ALGO_SHA1
#define HASH_CR_ALGO_SHA256
#define HASH_CR_ALGO_SHA224
OsMutex stm32h5xxCryptoMutex
STM32H5 hardware cryptographic accelerator.
void sha512ProcessBlock(Sha512Context *context)
Process message in 16-word blocks.
void hashProcessData(uint32_t algo, const uint8_t *data, size_t length, uint32_t *h, size_t hLen)
Update hash value.
void sha1ProcessBlock(Sha1Context *context)
Process message in 16-word blocks.
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 sha256ProcessBlock(Sha256Context *context)
Process message in 16-word blocks.
void sha512Update(Sha512Context *context, const void *data, size_t length)
Update the SHA-512 context with a portion of the message being hashed.
error_t hashInit(void)
HASH module initialization.
STM32H5 hash hardware accelerator.
#define HASH_CR_ALGO_SHA512
SHA-1 algorithm context.
Definition: sha1.h:62
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
SHA-256 algorithm context.
Definition: sha256.h:62
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
SHA-512 algorithm context.
Definition: sha512.h:62
uint64_t h[8]
Definition: sha512.h:65
uint64_t totalSize
Definition: sha512.h:74
size_t size
Definition: sha512.h:73
uint8_t buffer[128]
Definition: sha512.h:71
uint8_t length
Definition: tcp.h:368