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