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-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 "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 (optional parameter)
246  **/
247 
248 void sha1Final(Sha1Context *context, uint8_t *digest)
249 {
250  size_t paddingSize;
251  uint64_t totalSize;
252 
253  //Length of the original message (before padding)
254  totalSize = context->totalSize * 8;
255 
256  //Pad the message so that its length is congruent to 56 modulo 64
257  if(context->size < 56)
258  {
259  paddingSize = 56 - context->size;
260  }
261  else
262  {
263  paddingSize = 64 + 56 - context->size;
264  }
265 
266  //Append padding
267  sha1Update(context, padding, paddingSize);
268 
269  //Append the length of the original message
270  context->w[14] = htobe32((uint32_t) (totalSize >> 32));
271  context->w[15] = htobe32((uint32_t) totalSize);
272 
273  //Calculate the message digest
274  hashProcessData(ICM_ALGO_SHA1, context->buffer, 64, context->h);
275 
276  //Copy the resulting digest
277  if(digest != NULL)
278  {
279  osMemcpy(digest, context->digest, SHA1_DIGEST_SIZE);
280  }
281 }
282 
283 
284 /**
285  * @brief Finish the SHA-1 message digest (no padding added)
286  * @param[in] context Pointer to the SHA-1 context
287  * @param[out] digest Calculated digest
288  **/
289 
290 void sha1FinalRaw(Sha1Context *context, uint8_t *digest)
291 {
292  //Copy the resulting digest
293  osMemcpy(digest, context->digest, SHA1_DIGEST_SIZE);
294 }
295 
296 #endif
297 #if (SHA224_SUPPORT == ENABLED)
298 
299 /**
300  * @brief Initialize SHA-224 message digest context
301  * @param[in] context Pointer to the SHA-224 context to initialize
302  **/
303 
304 void sha224Init(Sha224Context *context)
305 {
306  //Set initial hash value
307  context->h[0] = BETOH32(0xC1059ED8);
308  context->h[1] = BETOH32(0x367CD507);
309  context->h[2] = BETOH32(0x3070DD17);
310  context->h[3] = BETOH32(0xF70E5939);
311  context->h[4] = BETOH32(0xFFC00B31);
312  context->h[5] = BETOH32(0x68581511);
313  context->h[6] = BETOH32(0x64F98FA7);
314  context->h[7] = BETOH32(0xBEFA4FA4);
315 
316  //Number of bytes in the buffer
317  context->size = 0;
318  //Total length of the message
319  context->totalSize = 0;
320 }
321 
322 #endif
323 #if (SHA256_SUPPORT == ENABLED)
324 
325 /**
326  * @brief Initialize SHA-256 message digest context
327  * @param[in] context Pointer to the SHA-256 context to initialize
328  **/
329 
330 void sha256Init(Sha256Context *context)
331 {
332  //Set initial hash value
333  context->h[0] = BETOH32(0x6A09E667);
334  context->h[1] = BETOH32(0xBB67AE85);
335  context->h[2] = BETOH32(0x3C6EF372);
336  context->h[3] = BETOH32(0xA54FF53A);
337  context->h[4] = BETOH32(0x510E527F);
338  context->h[5] = BETOH32(0x9B05688C);
339  context->h[6] = BETOH32(0x1F83D9AB);
340  context->h[7] = BETOH32(0x5BE0CD19);
341 
342  //Number of bytes in the buffer
343  context->size = 0;
344  //Total length of the message
345  context->totalSize = 0;
346 }
347 
348 
349 /**
350  * @brief Update the SHA-256 context with a portion of the message being hashed
351  * @param[in] context Pointer to the SHA-256 context
352  * @param[in] data Pointer to the buffer being hashed
353  * @param[in] length Length of the buffer
354  **/
355 
356 void sha256Update(Sha256Context *context, const void *data, size_t length)
357 {
358  size_t n;
359 
360  //Process the incoming data
361  while(length > 0)
362  {
363  //Check whether some data is pending in the buffer
364  if(context->size == 0 && length >= 64)
365  {
366  //The length must be a multiple of 64 bytes
367  n = length - (length % 64);
368 
369  //Update hash value
370  hashProcessData(ICM_ALGO_SHA256, data, n, context->h);
371 
372  //Update the SHA-256 context
373  context->totalSize += n;
374  //Advance the data pointer
375  data = (uint8_t *) data + n;
376  //Remaining bytes to process
377  length -= n;
378  }
379  else
380  {
381  //The buffer can hold at most 64 bytes
382  n = MIN(length, 64 - context->size);
383 
384  //Copy the data to the buffer
385  osMemcpy(context->buffer + context->size, data, n);
386 
387  //Update the SHA-256 context
388  context->size += n;
389  context->totalSize += n;
390  //Advance the data pointer
391  data = (uint8_t *) data + n;
392  //Remaining bytes to process
393  length -= n;
394 
395  //Check whether the buffer is full
396  if(context->size == 64)
397  {
398  //Update hash value
399  hashProcessData(ICM_ALGO_SHA256, context->buffer, context->size,
400  context->h);
401 
402  //Empty the buffer
403  context->size = 0;
404  }
405  }
406  }
407 }
408 
409 
410 /**
411  * @brief Finish the SHA-256 message digest
412  * @param[in] context Pointer to the SHA-256 context
413  * @param[out] digest Calculated digest (optional parameter)
414  **/
415 
416 void sha256Final(Sha256Context *context, uint8_t *digest)
417 {
418  size_t paddingSize;
419  uint64_t totalSize;
420 
421  //Length of the original message (before padding)
422  totalSize = context->totalSize * 8;
423 
424  //Pad the message so that its length is congruent to 56 modulo 64
425  if(context->size < 56)
426  {
427  paddingSize = 56 - context->size;
428  }
429  else
430  {
431  paddingSize = 64 + 56 - context->size;
432  }
433 
434  //Append padding
435  sha256Update(context, padding, paddingSize);
436 
437  //Append the length of the original message
438  context->w[14] = htobe32((uint32_t) (totalSize >> 32));
439  context->w[15] = htobe32((uint32_t) totalSize);
440 
441  //Calculate the message digest
442  hashProcessData(ICM_ALGO_SHA256, context->buffer, 64, context->h);
443 
444  //Copy the resulting digest
445  if(digest != NULL)
446  {
447  osMemcpy(digest, context->digest, SHA256_DIGEST_SIZE);
448  }
449 }
450 
451 
452 /**
453  * @brief Finish the SHA-256 message digest (no padding added)
454  * @param[in] context Pointer to the SHA-256 context
455  * @param[out] digest Calculated digest
456  **/
457 
458 void sha256FinalRaw(Sha256Context *context, uint8_t *digest)
459 {
460  //Copy the resulting digest
461  osMemcpy(digest, context->digest, SHA256_DIGEST_SIZE);
462 }
463 
464 #endif
465 #endif
void sha256Final(Sha256Context *context, uint8_t *digest)
Finish the SHA-256 message digest.
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
size_t size
Definition: sha256.h:73
uint32_t rcfg
ICM region configuration.
uint32_t h[8]
Definition: sha256.h:65
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)
#define ICM_RCFG_ALGO
SAM4C hash hardware accelerator.
uint64_t totalSize
Definition: sha1.h:74
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:141
#define ICM_ALGO_SHA256
uint32_t w[16]
Definition: sha256.h:70
#define ICM_ALGO_SHA224
uint32_t h[5]
Definition: sha1.h:65
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:368
uint8_t buffer[64]
Definition: sha256.h:71
#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.
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 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:73
uint32_t w[16]
Definition: sha1.h:70
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:71
uint64_t totalSize
Definition: sha256.h:74
#define ICM_RCFG_EOM
OsMutex sam4cCryptoMutex
Definition: sam4c_crypto.c:43
#define SHA256_DIGEST_SIZE
Definition: sha256.h:45
uint8_t digest[20]
Definition: sha1.h:66
uint32_t raddr
ICM region start address.
__attribute__((naked))
AVR32 Ethernet MAC interrupt wrapper.
Debugging facilities.