sams70_crypto_hash.c
Go to the documentation of this file.
1 /**
2  * @file sams70_crypto_hash.c
3  * @brief SAMS70 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.4
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 (SAMS70_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 = SAMS70_ICM_RAM_SECTION
51 static Sams70IcmDesc icmDesc;
52 //ICM data buffer
53 #pragma data_alignment = 4
54 #pragma location = SAMS70_ICM_RAM_SECTION
55 static uint8_t icmBuffer[SAMS70_ICM_BUFFER_SIZE];
56 //ICM hash area
57 #pragma data_alignment = 128
58 #pragma location = SAMS70_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 Sams70IcmDesc icmDesc
66  __attribute__((aligned(64), __section__(SAMS70_ICM_RAM_SECTION)));
67 //ICM data buffer
68 static uint8_t icmBuffer[SAMS70_ICM_BUFFER_SIZE]
69  __attribute__((aligned(4), __section__(SAMS70_ICM_RAM_SECTION)));
70 //ICM hash area
71 static uint32_t icmHash[8]
72  __attribute__((aligned(128), __section__(SAMS70_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 (optional parameter)
274  **/
275 
276 void sha1Final(Sha1Context *context, uint8_t *digest)
277 {
278  size_t paddingSize;
279  uint64_t totalSize;
280 
281  //Length of the original message (before padding)
282  totalSize = context->totalSize * 8;
283 
284  //Pad the message so that its length is congruent to 56 modulo 64
285  if(context->size < 56)
286  {
287  paddingSize = 56 - context->size;
288  }
289  else
290  {
291  paddingSize = 64 + 56 - context->size;
292  }
293 
294  //Append padding
295  sha1Update(context, padding, paddingSize);
296 
297  //Append the length of the original message
298  context->w[14] = htobe32((uint32_t) (totalSize >> 32));
299  context->w[15] = htobe32((uint32_t) totalSize);
300 
301  //Calculate the message digest
302  hashProcessData(ICM_ALGO_SHA1, context->buffer, 64, context->h);
303 
304  //Copy the resulting digest
305  if(digest != NULL)
306  {
307  osMemcpy(digest, context->digest, SHA1_DIGEST_SIZE);
308  }
309 }
310 
311 
312 /**
313  * @brief Finish the SHA-1 message digest (no padding added)
314  * @param[in] context Pointer to the SHA-1 context
315  * @param[out] digest Calculated digest
316  **/
317 
318 void sha1FinalRaw(Sha1Context *context, uint8_t *digest)
319 {
320  //Copy the resulting digest
321  osMemcpy(digest, context->digest, SHA1_DIGEST_SIZE);
322 }
323 
324 #endif
325 #if (SHA224_SUPPORT == ENABLED)
326 
327 /**
328  * @brief Initialize SHA-224 message digest context
329  * @param[in] context Pointer to the SHA-224 context to initialize
330  **/
331 
332 void sha224Init(Sha224Context *context)
333 {
334  //Set initial hash value
335  context->h[0] = BETOH32(0xC1059ED8);
336  context->h[1] = BETOH32(0x367CD507);
337  context->h[2] = BETOH32(0x3070DD17);
338  context->h[3] = BETOH32(0xF70E5939);
339  context->h[4] = BETOH32(0xFFC00B31);
340  context->h[5] = BETOH32(0x68581511);
341  context->h[6] = BETOH32(0x64F98FA7);
342  context->h[7] = BETOH32(0xBEFA4FA4);
343 
344  //Number of bytes in the buffer
345  context->size = 0;
346  //Total length of the message
347  context->totalSize = 0;
348 }
349 
350 #endif
351 #if (SHA256_SUPPORT == ENABLED)
352 
353 /**
354  * @brief Initialize SHA-256 message digest context
355  * @param[in] context Pointer to the SHA-256 context to initialize
356  **/
357 
358 void sha256Init(Sha256Context *context)
359 {
360  //Set initial hash value
361  context->h[0] = BETOH32(0x6A09E667);
362  context->h[1] = BETOH32(0xBB67AE85);
363  context->h[2] = BETOH32(0x3C6EF372);
364  context->h[3] = BETOH32(0xA54FF53A);
365  context->h[4] = BETOH32(0x510E527F);
366  context->h[5] = BETOH32(0x9B05688C);
367  context->h[6] = BETOH32(0x1F83D9AB);
368  context->h[7] = BETOH32(0x5BE0CD19);
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 Update the SHA-256 context with a portion of the message being hashed
379  * @param[in] context Pointer to the SHA-256 context
380  * @param[in] data Pointer to the buffer being hashed
381  * @param[in] length Length of the buffer
382  **/
383 
384 void sha256Update(Sha256Context *context, const void *data, size_t length)
385 {
386  size_t n;
387 
388  //Process the incoming data
389  while(length > 0)
390  {
391  //Check whether some data is pending in the buffer
392  if(context->size == 0 && length >= 64)
393  {
394  //The length must be a multiple of 64 bytes
395  n = length - (length % 64);
396 
397  //Update hash value
398  hashProcessData(ICM_ALGO_SHA256, data, n, context->h);
399 
400  //Update the SHA-256 context
401  context->totalSize += n;
402  //Advance the data pointer
403  data = (uint8_t *) data + n;
404  //Remaining bytes to process
405  length -= n;
406  }
407  else
408  {
409  //The buffer can hold at most 64 bytes
410  n = MIN(length, 64 - context->size);
411 
412  //Copy the data to the buffer
413  osMemcpy(context->buffer + context->size, data, n);
414 
415  //Update the SHA-256 context
416  context->size += n;
417  context->totalSize += n;
418  //Advance the data pointer
419  data = (uint8_t *) data + n;
420  //Remaining bytes to process
421  length -= n;
422 
423  //Check whether the buffer is full
424  if(context->size == 64)
425  {
426  //Update hash value
427  hashProcessData(ICM_ALGO_SHA256, context->buffer, context->size,
428  context->h);
429 
430  //Empty the buffer
431  context->size = 0;
432  }
433  }
434  }
435 }
436 
437 
438 /**
439  * @brief Finish the SHA-256 message digest
440  * @param[in] context Pointer to the SHA-256 context
441  * @param[out] digest Calculated digest (optional parameter)
442  **/
443 
444 void sha256Final(Sha256Context *context, uint8_t *digest)
445 {
446  size_t paddingSize;
447  uint64_t totalSize;
448 
449  //Length of the original message (before padding)
450  totalSize = context->totalSize * 8;
451 
452  //Pad the message so that its length is congruent to 56 modulo 64
453  if(context->size < 56)
454  {
455  paddingSize = 56 - context->size;
456  }
457  else
458  {
459  paddingSize = 64 + 56 - context->size;
460  }
461 
462  //Append padding
463  sha256Update(context, padding, paddingSize);
464 
465  //Append the length of the original message
466  context->w[14] = htobe32((uint32_t) (totalSize >> 32));
467  context->w[15] = htobe32((uint32_t) totalSize);
468 
469  //Calculate the message digest
470  hashProcessData(ICM_ALGO_SHA256, context->buffer, 64, context->h);
471 
472  //Copy the resulting digest
473  if(digest != NULL)
474  {
475  osMemcpy(digest, context->digest, SHA256_DIGEST_SIZE);
476  }
477 }
478 
479 
480 /**
481  * @brief Finish the SHA-256 message digest (no padding added)
482  * @param[in] context Pointer to the SHA-256 context
483  * @param[out] digest Calculated digest
484  **/
485 
486 void sha256FinalRaw(Sha256Context *context, uint8_t *digest)
487 {
488  //Copy the resulting digest
489  osMemcpy(digest, context->digest, SHA256_DIGEST_SIZE);
490 }
491 
492 #endif
493 #endif
void sha224Init(Sha224Context *context)
Initialize SHA-224 message digest context.
uint32_t rcfg
ICM region configuration.
SHA-256 algorithm context.
Definition: sha256.h:62
void sha1Init(Sha1Context *context)
Initialize SHA-1 message digest context.
SAMS70 hash hardware accelerator.
uint8_t data[]
Definition: ethernet.h:222
size_t size
Definition: sha256.h:73
ICM region descriptor.
void sha256Final(Sha256Context *context, uint8_t *digest)
Finish the SHA-256 message digest.
uint32_t h[8]
Definition: sha256.h:65
#define BETOH32(value)
Definition: cpu_endian.h:451
#define SAMS70_ICM_BUFFER_SIZE
#define ICM_RCFG_ALGO
uint32_t rctrl
ICM region control.
uint64_t totalSize
Definition: sha1.h:74
uint8_t h
Definition: ndp.h:302
#define osMemcpy(dest, src, length)
Definition: os_port.h:141
#define ICM_ALGO_SHA256
uint32_t w[16]
Definition: sha256.h:70
#define ICM_ALGO_SHA224
void sha1FinalRaw(Sha1Context *context, uint8_t *digest)
Finish the SHA-1 message digest (no padding added)
uint32_t h[5]
Definition: sha1.h:65
General definitions for cryptographic algorithms.
uint32_t rnext
ICM region next address.
#define SAMS70_ICM_RAM_SECTION
void sha256Init(Sha256Context *context)
Initialize SHA-256 message digest context.
uint8_t length
Definition: tcp.h:368
uint8_t buffer[64]
Definition: sha256.h:71
#define MIN(a, b)
Definition: os_port.h:63
uint32_t raddr
ICM region start address.
Collection of hash algorithms.
#define ICM_ALGO_SHA1
#define htobe32(value)
Definition: cpu_endian.h:446
uint8_t digest[32]
Definition: sha256.h:66
#define SHA1_DIGEST_SIZE
Definition: sha1.h:45
uint8_t n
void sha256FinalRaw(Sha256Context *context, uint8_t *digest)
Finish the SHA-256 message digest (no padding added)
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
void sha1Update(Sha1Context *context, const void *data, size_t length)
Update the SHA-1 context with a portion of the message being hashed.
void sha1Final(Sha1Context *context, uint8_t *digest)
Finish the SHA-1 message digest.
size_t size
Definition: sha1.h:73
uint32_t w[16]
Definition: sha1.h:70
SHA-1 algorithm context.
Definition: sha1.h:62
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 buffer[64]
Definition: sha1.h:71
uint64_t totalSize
Definition: sha256.h:74
#define ICM_RCFG_EOM
#define SHA256_DIGEST_SIZE
Definition: sha256.h:45
void hashProcessData(uint32_t algo, const uint8_t *data, size_t length, uint32_t *h)
Update hash value.
uint8_t digest[20]
Definition: sha1.h:66
__attribute__((naked))
AVR32 Ethernet MAC interrupt wrapper.
Debugging facilities.
SAMS70 hardware cryptographic accelerator.
OsMutex sams70CryptoMutex
Definition: sams70_crypto.c:44