sam4c_crypto_hash.c
Go to the documentation of this file.
1 /**
2  * @file sam4c_crypto_hash.c
3  * @brief SAM4C 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 "core/crypto.h"
38 #include "hash/hash_algorithms.h"
39 #include "debug.h"
40 
41 //Check crypto library configuration
42 #if (SAM4C_CRYPTO_HASH_SUPPORT == ENABLED)
43 
44 //IAR EWARM compiler?
45 #if defined(__ICCARM__)
46 
47 //ICM region descriptor
48 #pragma data_alignment = 64
49 static Sam4cIcmDesc icmDesc;
50 //ICM hash area
51 #pragma data_alignment = 128
52 static uint32_t icmHash[8];
53 
54 //Keil MDK-ARM or GCC compiler?
55 #else
56 
57 //ICM region descriptor
58 static Sam4cIcmDesc icmDesc __attribute__((aligned(64)));
59 //ICM hash area
60 static uint32_t icmHash[8] __attribute__((aligned(128)));
61 
62 #endif
63 
64 //Padding string
65 static const uint8_t padding[64] =
66 {
67  0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
68  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
69  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
70  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
71 };
72 
73 
74 /**
75  * @brief Update hash value
76  * @param[in] algo Hash algorithm
77  * @param[in] data Pointer to the input buffer
78  * @param[in] length Length of the input buffer
79  * @param[in,out] h Hash value
80  **/
81 
82 void hashProcessData(uint32_t algo, const uint8_t *data, size_t length,
83  uint32_t *h)
84 {
85  //Acquire exclusive access to the ICM module
87 
88  //Perform software reset
89  ICM->ICM_CTRL = ICM_CTRL_SWRST;
90 
91  //Set ICM region descriptor
92  icmDesc.raddr = (uint32_t) data;
93  icmDesc.rcfg = ((algo << 12) & ICM_RCFG_ALGO) | ICM_RCFG_EOM;
94  icmDesc.rctrl = (length / 64) - 1;
95  icmDesc.rnext = 0;
96 
97  //Data memory barrier
98  __DMB();
99 
100  //Set configuration register
101  ICM->ICM_CFG = ((algo << 13) & ICM_CFG_UALGO_Msk) | ICM_CFG_UIHASH | ICM_CFG_SLBDIS;
102  //The start address is a multiple of 64 bytes
103  ICM->ICM_DSCR = (uint32_t) &icmDesc;
104  //The hash memory location must be a multiple of 128 bytes
105  ICM->ICM_HASH = (uint32_t) &icmHash;
106 
107  //Set initial hash value
108  ICM->ICM_UIHVAL[0] = h[0];
109  ICM->ICM_UIHVAL[1] = h[1];
110  ICM->ICM_UIHVAL[2] = h[2];
111  ICM->ICM_UIHVAL[3] = h[3];
112  ICM->ICM_UIHVAL[4] = h[4];
113 
114  //SHA-224 or SHA-256 algorithm?
115  if(algo == ICM_ALGO_SHA224 || algo == ICM_ALGO_SHA256)
116  {
117  ICM->ICM_UIHVAL[5] = h[5];
118  ICM->ICM_UIHVAL[6] = h[6];
119  ICM->ICM_UIHVAL[7] = h[7];
120  }
121 
122  //Enable RHC interrupt (Region Hash Completed)
123  ICM->ICM_IER = ICM_IER_RHC(1);
124  //Enable ICM module
125  ICM->ICM_CTRL = ICM_CTRL_ENABLE;
126 
127  //The RHC status flag is set when the ICM has completed the region
128  while((ICM->ICM_ISR & ICM_ISR_RHC_Msk) == 0)
129  {
130  }
131 
132  //Disable ICM module
133  ICM->ICM_CTRL = ICM_CTRL_DISABLE;
134 
135  //Data memory barrier
136  __DMB();
137 
138  //Read resulting hash value
139  h[0] = icmHash[0];
140  h[1] = icmHash[1];
141  h[2] = icmHash[2];
142  h[3] = icmHash[3];
143  h[4] = icmHash[4];
144 
145  //SHA-224 or SHA-256 algorithm?
146  if(algo == ICM_ALGO_SHA224 || algo == ICM_ALGO_SHA256)
147  {
148  h[5] = icmHash[5];
149  h[6] = icmHash[6];
150  h[7] = icmHash[7];
151  }
152 
153  //Release exclusive access to the ICM module
155 }
156 
157 
158 #if (SHA1_SUPPORT == ENABLED)
159 
160 /**
161  * @brief Initialize SHA-1 message digest context
162  * @param[in] context Pointer to the SHA-1 context to initialize
163  **/
164 
165 void sha1Init(Sha1Context *context)
166 {
167  //Set initial hash value
168  context->h[0] = BETOH32(0x67452301);
169  context->h[1] = BETOH32(0xEFCDAB89);
170  context->h[2] = BETOH32(0x98BADCFE);
171  context->h[3] = BETOH32(0x10325476);
172  context->h[4] = BETOH32(0xC3D2E1F0);
173 
174  //Number of bytes in the buffer
175  context->size = 0;
176  //Total length of the message
177  context->totalSize = 0;
178 }
179 
180 
181 /**
182  * @brief Update the SHA-1 context with a portion of the message being hashed
183  * @param[in] context Pointer to the SHA-1 context
184  * @param[in] data Pointer to the buffer being hashed
185  * @param[in] length Length of the buffer
186  **/
187 
188 void sha1Update(Sha1Context *context, const void *data, size_t length)
189 {
190  size_t n;
191 
192  //Process the incoming data
193  while(length > 0)
194  {
195  //Check whether some data is pending in the buffer
196  if(context->size == 0 && length >= 64)
197  {
198  //The length must be a multiple of 64 bytes
199  n = length - (length % 64);
200 
201  //Update hash value
202  hashProcessData(ICM_ALGO_SHA1, data, n, context->h);
203 
204  //Update the SHA-1 context
205  context->totalSize += n;
206  //Advance the data pointer
207  data = (uint8_t *) data + n;
208  //Remaining bytes to process
209  length -= n;
210  }
211  else
212  {
213  //The buffer can hold at most 64 bytes
214  n = MIN(length, 64 - context->size);
215 
216  //Copy the data to the buffer
217  osMemcpy(context->buffer + context->size, data, n);
218 
219  //Update the SHA-1 context
220  context->size += n;
221  context->totalSize += n;
222  //Advance the data pointer
223  data = (uint8_t *) data + n;
224  //Remaining bytes to process
225  length -= n;
226 
227  //Check whether the buffer is full
228  if(context->size == 64)
229  {
230  //Update hash value
231  hashProcessData(ICM_ALGO_SHA1, context->buffer, context->size,
232  context->h);
233 
234  //Empty the buffer
235  context->size = 0;
236  }
237  }
238  }
239 }
240 
241 
242 /**
243  * @brief Finish the SHA-1 message digest
244  * @param[in] context Pointer to the SHA-1 context
245  * @param[out] digest Calculated digest
246  **/
247 
248 void sha1Final(Sha1Context *context, uint8_t *digest)
249 {
250  uint_t i;
251  size_t paddingSize;
252  uint64_t totalSize;
253 
254  //Length of the original message (before padding)
255  totalSize = context->totalSize * 8;
256 
257  //Pad the message so that its length is congruent to 56 modulo 64
258  if(context->size < 56)
259  {
260  paddingSize = 56 - context->size;
261  }
262  else
263  {
264  paddingSize = 64 + 56 - context->size;
265  }
266 
267  //Append padding
268  sha1Update(context, padding, paddingSize);
269 
270  //Append the length of the original message
271  for(i = 0; i < 8; i++)
272  {
273  context->buffer[63 - i] = totalSize & 0xFF;
274  totalSize >>= 8;
275  }
276 
277  //Calculate the message digest
278  hashProcessData(ICM_ALGO_SHA1, context->buffer, 64, context->h);
279 
280  //Copy the resulting digest
281  for(i = 0; i < (SHA1_DIGEST_SIZE / 4); i++)
282  {
283  STORE32LE(context->h[i], digest + i * 4);
284  }
285 }
286 
287 
288 /**
289  * @brief Finish the SHA-1 message digest (no padding added)
290  * @param[in] context Pointer to the SHA-1 context
291  * @param[out] digest Calculated digest
292  **/
293 
294 void sha1FinalRaw(Sha1Context *context, uint8_t *digest)
295 {
296  uint_t i;
297 
298  //Copy the resulting digest
299  for(i = 0; i < (SHA1_DIGEST_SIZE / 4); i++)
300  {
301  STORE32LE(context->h[i], digest + i * 4);
302  }
303 }
304 
305 #endif
306 #if (SHA224_SUPPORT == ENABLED)
307 
308 /**
309  * @brief Initialize SHA-224 message digest context
310  * @param[in] context Pointer to the SHA-224 context to initialize
311  **/
312 
313 void sha224Init(Sha224Context *context)
314 {
315  //Set initial hash value
316  context->h[0] = BETOH32(0xC1059ED8);
317  context->h[1] = BETOH32(0x367CD507);
318  context->h[2] = BETOH32(0x3070DD17);
319  context->h[3] = BETOH32(0xF70E5939);
320  context->h[4] = BETOH32(0xFFC00B31);
321  context->h[5] = BETOH32(0x68581511);
322  context->h[6] = BETOH32(0x64F98FA7);
323  context->h[7] = BETOH32(0xBEFA4FA4);
324 
325  //Number of bytes in the buffer
326  context->size = 0;
327  //Total length of the message
328  context->totalSize = 0;
329 }
330 
331 #endif
332 #if (SHA256_SUPPORT == ENABLED)
333 
334 /**
335  * @brief Initialize SHA-256 message digest context
336  * @param[in] context Pointer to the SHA-256 context to initialize
337  **/
338 
339 void sha256Init(Sha256Context *context)
340 {
341  //Set initial hash value
342  context->h[0] = BETOH32(0x6A09E667);
343  context->h[1] = BETOH32(0xBB67AE85);
344  context->h[2] = BETOH32(0x3C6EF372);
345  context->h[3] = BETOH32(0xA54FF53A);
346  context->h[4] = BETOH32(0x510E527F);
347  context->h[5] = BETOH32(0x9B05688C);
348  context->h[6] = BETOH32(0x1F83D9AB);
349  context->h[7] = BETOH32(0x5BE0CD19);
350 
351  //Number of bytes in the buffer
352  context->size = 0;
353  //Total length of the message
354  context->totalSize = 0;
355 }
356 
357 
358 /**
359  * @brief Update the SHA-256 context with a portion of the message being hashed
360  * @param[in] context Pointer to the SHA-256 context
361  * @param[in] data Pointer to the buffer being hashed
362  * @param[in] length Length of the buffer
363  **/
364 
365 void sha256Update(Sha256Context *context, const void *data, size_t length)
366 {
367  size_t n;
368 
369  //Process the incoming data
370  while(length > 0)
371  {
372  //Check whether some data is pending in the buffer
373  if(context->size == 0 && length >= 64)
374  {
375  //The length must be a multiple of 64 bytes
376  n = length - (length % 64);
377 
378  //Update hash value
379  hashProcessData(ICM_ALGO_SHA256, data, n, context->h);
380 
381  //Update the SHA-256 context
382  context->totalSize += n;
383  //Advance the data pointer
384  data = (uint8_t *) data + n;
385  //Remaining bytes to process
386  length -= n;
387  }
388  else
389  {
390  //The buffer can hold at most 64 bytes
391  n = MIN(length, 64 - context->size);
392 
393  //Copy the data to the buffer
394  osMemcpy(context->buffer + context->size, data, n);
395 
396  //Update the SHA-256 context
397  context->size += n;
398  context->totalSize += n;
399  //Advance the data pointer
400  data = (uint8_t *) data + n;
401  //Remaining bytes to process
402  length -= n;
403 
404  //Check whether the buffer is full
405  if(context->size == 64)
406  {
407  //Update hash value
408  hashProcessData(ICM_ALGO_SHA256, context->buffer, context->size,
409  context->h);
410 
411  //Empty the buffer
412  context->size = 0;
413  }
414  }
415  }
416 }
417 
418 
419 /**
420  * @brief Finish the SHA-256 message digest
421  * @param[in] context Pointer to the SHA-256 context
422  * @param[out] digest Calculated digest
423  **/
424 
425 void sha256Final(Sha256Context *context, uint8_t *digest)
426 {
427  uint_t i;
428  size_t paddingSize;
429  uint64_t totalSize;
430 
431  //Length of the original message (before padding)
432  totalSize = context->totalSize * 8;
433 
434  //Pad the message so that its length is congruent to 56 modulo 64
435  if(context->size < 56)
436  {
437  paddingSize = 56 - context->size;
438  }
439  else
440  {
441  paddingSize = 64 + 56 - context->size;
442  }
443 
444  //Append padding
445  sha256Update(context, padding, paddingSize);
446 
447  //Append the length of the original message
448  for(i = 0; i < 8; i++)
449  {
450  context->buffer[63 - i] = totalSize & 0xFF;
451  totalSize >>= 8;
452  }
453 
454  //Calculate the message digest
455  hashProcessData(ICM_ALGO_SHA256, context->buffer, 64, context->h);
456 
457  //Copy the resulting digest
458  for(i = 0; i < (SHA256_DIGEST_SIZE / 4); i++)
459  {
460  STORE32LE(context->h[i], digest + i * 4);
461  }
462 }
463 
464 
465 /**
466  * @brief Finish the SHA-256 message digest (no padding added)
467  * @param[in] context Pointer to the SHA-256 context
468  * @param[out] digest Calculated digest
469  **/
470 
471 void sha256FinalRaw(Sha256Context *context, uint8_t *digest)
472 {
473  uint_t i;
474 
475  //Copy the resulting digest
476  for(i = 0; i < (SHA256_DIGEST_SIZE / 4); i++)
477  {
478  STORE32LE(context->h[i], digest + i * 4);
479  }
480 }
481 
482 #endif
483 #endif
void sha256Final(Sha256Context *context, uint8_t *digest)
Finish the SHA-256 message digest.
#define ICM_ALGO_SHA224
SHA-256 algorithm context.
Definition: sha256.h:62
void sha224Init(Sha224Context *context)
Initialize SHA-224 message digest context.
void sha1FinalRaw(Sha1Context *context, uint8_t *digest)
Finish the SHA-1 message digest (no padding added)
void sha256Init(Sha256Context *context)
Initialize SHA-256 message digest context.
uint8_t data[]
Definition: ethernet.h:222
#define STORE32LE(a, p)
Definition: cpu_endian.h:279
size_t size
Definition: sha256.h:69
uint32_t rcfg
ICM region configuration.
uint32_t h[8]
Definition: sha256.h:63
ICM region descriptor.
uint32_t rctrl
ICM region control.
#define BETOH32(value)
Definition: cpu_endian.h:451
void sha256FinalRaw(Sha256Context *context, uint8_t *digest)
Finish the SHA-256 message digest (no padding added)
SAM4C hash hardware accelerator.
uint64_t totalSize
Definition: sha1.h:70
#define ICM_ALGO_SHA1
#define ICM_RCFG_EOM
void hashProcessData(uint32_t algo, const uint8_t *data, size_t length, uint32_t *h)
Update hash value.
uint8_t h
Definition: ndp.h:302
#define osMemcpy(dest, src, length)
Definition: os_port.h:144
uint32_t h[5]
Definition: sha1.h:63
General definitions for cryptographic algorithms.
void sha256Update(Sha256Context *context, const void *data, size_t length)
Update the SHA-256 context with a portion of the message being hashed.
uint8_t length
Definition: tcp.h:375
uint8_t buffer[64]
Definition: sha256.h:67
#define ICM_RCFG_ALGO
#define MIN(a, b)
Definition: os_port.h:63
void sha1Update(Sha1Context *context, const void *data, size_t length)
Update the SHA-1 context with a portion of the message being hashed.
SAM4C hardware cryptographic accelerator.
uint32_t rnext
ICM region next address.
#define ICM_ALGO_SHA256
Collection of hash algorithms.
#define SHA1_DIGEST_SIZE
Definition: sha1.h:45
uint8_t n
void sha1Final(Sha1Context *context, uint8_t *digest)
Finish the SHA-1 message digest.
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
size_t size
Definition: sha1.h:69
void sha1Init(Sha1Context *context)
Initialize SHA-1 message digest context.
SHA-1 algorithm context.
Definition: sha1.h:62
uint8_t buffer[64]
Definition: sha1.h:67
uint64_t totalSize
Definition: sha256.h:70
unsigned int uint_t
Definition: compiler_port.h:57
OsMutex sam4cCryptoMutex
Definition: sam4c_crypto.c:44
#define SHA256_DIGEST_SIZE
Definition: sha256.h:45
uint32_t raddr
ICM region start address.
__attribute__((naked))
AVR32 Ethernet MAC interrupt wrapper.
Debugging facilities.