blake2s.c
Go to the documentation of this file.
1 /**
2  * @file blake2s.c
3  * @brief BLAKE2 cryptographic hash and MAC (BLAKE2s variant)
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  * @section Description
28  *
29  * BLAKE2s is cryptographic hash function optimized for 8- to 32-bit platforms
30  * that produces digests of any size between 1 and 32 bytes. Refer to RFC 7693
31  * for more details
32  *
33  * @author Oryx Embedded SARL (www.oryx-embedded.com)
34  * @version 2.5.0
35  **/
36 
37 //Switch to the appropriate trace level
38 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
39 
40 //Dependencies
41 #include "core/crypto.h"
42 #include "mac/blake2s.h"
43 
44 //Check crypto library configuration
45 #if (BLAKE2S_SUPPORT == ENABLED)
46 
47 //Mixing function G (borrowed from ChaCha quarter-round function)
48 #define G(a, b, c, d, x, y) \
49 { \
50  a += b + x; \
51  d ^= a; \
52  d = ROR32(d, 16); \
53  c += d; \
54  b ^= c; \
55  b = ROR32(b, 12); \
56  a += b + y; \
57  d ^= a; \
58  d = ROR32(d, 8); \
59  c += d; \
60  b ^= c; \
61  b = ROR32(b, 7); \
62 }
63 
64 //Message schedule SIGMA
65 static const uint8_t sigma[10][16] =
66 {
67  {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
68  {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3},
69  {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4},
70  {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8},
71  {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13},
72  {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9},
73  {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11},
74  {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10},
75  {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5},
76  {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0}
77 };
78 
79 //Initialization vector
80 static const uint32_t iv[8] =
81 {
82  0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
83  0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19
84 };
85 
86 
87 /**
88  * @brief Digest a message using BLAKE2s
89  * @param[in] key Pointer to the key
90  * @param[in] keyLen Length of the key
91  * @param[in] data Pointer to the message being hashed
92  * @param[in] dataLen Length of the message
93  * @param[out] digest Pointer to the calculated digest
94  * @param[in] digestLen Expected length of the digest
95  * @return Error code
96  **/
97 
98 error_t blake2sCompute(const void *key, size_t keyLen, const void *data,
99  size_t dataLen, uint8_t *digest, size_t digestLen)
100 {
101  error_t error;
102 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
103  Blake2sContext *context;
104 #else
105  Blake2sContext context[1];
106 #endif
107 
108  //Check parameters
109  if(data == NULL && dataLen != 0)
111 
112  if(digest == NULL)
114 
115 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
116  //Allocate a memory buffer to hold the BLAKE2s context
117  context = cryptoAllocMem(sizeof(Blake2sContext));
118  //Failed to allocate memory?
119  if(context == NULL)
120  return ERROR_OUT_OF_MEMORY;
121 #endif
122 
123  //Initialize the hashing context
124  error = blake2sInit(context, key, keyLen, digestLen);
125 
126  //Check status code
127  if(!error)
128  {
129  //Digest the message
130  blake2sUpdate(context, data, dataLen);
131  //Finalize the BLAKE2s message digest
132  blake2sFinal(context, digest);
133  }
134 
135 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
136  //Free previously allocated memory
137  cryptoFreeMem(context);
138 #endif
139 
140  //Return status code
141  return error;
142 }
143 
144 
145 /**
146  * @brief Initialize BLAKE2s message digest context
147  * @param[in] context Pointer to the BLAKE2s context to initialize
148  * @param[in] key Pointer to the key
149  * @param[in] keyLen Length of the key
150  * @param[in] digestLen Expected length of the digest
151  * @return Error code
152  **/
153 
154 error_t blake2sInit(Blake2sContext *context, const void *key,
155  size_t keyLen, size_t digestLen)
156 {
157  size_t i;
158 
159  //Check parameters
160  if(context == NULL)
162 
163  if(key == NULL && keyLen != 0)
165 
166  //Check the length of the key
167  if(keyLen > 32)
169 
170  //Check the length of the hash
171  if(digestLen < 1 || digestLen > 32)
173 
174  //Initialize state vector
175  for(i = 0; i < 8; i++)
176  {
177  context->h[i] = iv[i];
178  }
179 
180  //The first byte of the parameter block is the hash size in bytes
181  context->h[0] ^= digestLen;
182  //The second byte of the parameter block is the key size in bytes
183  context->h[0] ^= keyLen << 8;
184  //Bytes 2 and 3 are set as 01
185  context->h[0] ^= 0x01010000;
186 
187  //Number of bytes in the buffer
188  context->size = 0;
189 
190  //Total number of bytes
191  context->totalSize[0] = 0;
192  context->totalSize[1] = 0;
193 
194  //Size of the digest
195  context->digestSize = digestLen;
196 
197  //Clear input buffer
198  osMemset(context->buffer, 0, 64);
199 
200  //Any secret key?
201  if(keyLen > 0)
202  {
203  //Copy the secret key
204  osMemcpy(context->buffer, key, keyLen);
205  //The secret key is padded with zero bytes
206  context->size = 64;
207  }
208 
209  //Successful initialization
210  return NO_ERROR;
211 }
212 
213 
214 /**
215  * @brief Update the BLAKE2s context with a portion of the message being hashed
216  * @param[in] context Pointer to the BLAKE2s context
217  * @param[in] data Pointer to the buffer being hashed
218  * @param[in] length Length of the buffer
219  **/
220 
221 void blake2sUpdate(Blake2sContext *context, const void *data, size_t length)
222 {
223  size_t n;
224 
225  //Process the incoming data
226  while(length > 0)
227  {
228  //Each message block consists of 16 words
229  if(context->size == 64)
230  {
231  //Compress the 16-word block
232  blake2sProcessBlock(context, FALSE);
233  //Empty the buffer
234  context->size = 0;
235  }
236 
237  //The buffer can hold at most 64 bytes
238  n = MIN(length, 64 - context->size);
239 
240  //Copy the data to the buffer
241  osMemcpy(context->buffer + context->size, data, n);
242  //Update the length of the buffer
243  context->size += n;
244 
245  //Advance the data pointer
246  data = (uint8_t *) data + n;
247  //Remaining bytes to process
248  length -= n;
249  }
250 }
251 
252 
253 /**
254  * @brief Finish the BLAKE2s message digest
255  * @param[in] context Pointer to the BLAKE2s context
256  * @param[out] digest Calculated digest
257  **/
258 
259 void blake2sFinal(Blake2sContext *context, uint8_t *digest)
260 {
261  size_t i;
262  size_t n;
263  uint8_t buffer[4];
264 
265  //The last block is padded with zeros to full block size, if required
266  for(i = context->size; i < 64; i++)
267  {
268  context->buffer[i] = 0;
269  }
270 
271  //Compress the last block
272  blake2sProcessBlock(context, TRUE);
273 
274  //Copy the resulting digest
275  for(i = 0; (i * 4) < context->digestSize; i++)
276  {
277  n = MIN(context->digestSize - i * 4, 4);
278  STORE32LE(context->h[i], buffer);
279  memcpy(digest + i * 4, buffer, n);
280  }
281 }
282 
283 
284 /**
285  * @brief Compression function F
286  * @param[in] context Pointer to the BLAKE2s context
287  * @param[in] last Flag indicating the last block
288  **/
289 
291 {
292  uint_t i;
293  uint32_t *m;
294  uint32_t v[16];
295 
296  //Initialize the working vector
297  for(i = 0; i < 8; i++)
298  {
299  //First half from state
300  v[i] = context->h[i];
301  //Second half from IV
302  v[i + 8] = iv[i];
303  }
304 
305  //Increment offset counter
306  context->totalSize[0] += context->size;
307 
308  //Propagate the carry if necessary
309  if(context->totalSize[0] < context->size)
310  {
311  context->totalSize[1]++;
312  }
313 
314  //Low word of the offset
315  v[12] ^= context->totalSize[0];
316  //High word of the offset
317  v[13] ^= context->totalSize[1];
318 
319  //Last block flag?
320  if(last)
321  {
322  //Invert all bits
323  v[14] = ~v[14];
324  }
325 
326  //Point to the message block vector
327  m = context->m;
328 
329  //Convert from little-endian byte order to host byte order
330  for(i = 0; i < 16; i++)
331  {
332  m[i] = LOAD32LE(context->buffer + i * 4);
333  }
334 
335  //Cryptographic mixing
336  for(i = 0; i < 10; i++)
337  {
338  //The column rounds apply the quarter-round function to the four
339  //columns, from left to right
340  G(v[0], v[4], v[8], v[12], m[sigma[i][0]], m[sigma[i][1]]);
341  G(v[1], v[5], v[9], v[13], m[sigma[i][2]], m[sigma[i][3]]);
342  G(v[2], v[6], v[10], v[14], m[sigma[i][4]], m[sigma[i][5]]);
343  G(v[3], v[7], v[11], v[15], m[sigma[i][6]], m[sigma[i][7]]);
344 
345  //The diagonal rounds apply the quarter-round function to the top-left,
346  //bottom-right diagonal, followed by the pattern shifted one place to
347  //the right, for three more quarter-rounds
348  G(v[0], v[5], v[10], v[15], m[sigma[i][8]], m[sigma[i][9]]);
349  G(v[1], v[6], v[11], v[12], m[sigma[i][10]], m[sigma[i][11]]);
350  G(v[2], v[7], v[8], v[13], m[sigma[i][12]], m[sigma[i][13]]);
351  G(v[3], v[4], v[9], v[14], m[sigma[i][14]], m[sigma[i][15]]);
352  }
353 
354  //XOR the two halves
355  for(i = 0; i < 8; i++)
356  {
357  context->h[i] ^= v[i] ^ v[i + 8];
358  }
359 }
360 
361 #endif
int bool_t
Definition: compiler_port.h:61
uint8_t buffer[64]
Definition: blake2s.h:56
void blake2sFinal(Blake2sContext *context, uint8_t *digest)
Finish the BLAKE2s message digest.
Definition: blake2s.c:259
void blake2sProcessBlock(Blake2sContext *context, bool_t last)
Compression function F.
Definition: blake2s.c:290
uint32_t totalSize[2]
Definition: blake2s.h:59
#define TRUE
Definition: os_port.h:50
uint8_t data[]
Definition: ethernet.h:222
#define STORE32LE(a, p)
Definition: cpu_endian.h:279
BLAKE2 cryptographic hash and MAC (BLAKE2s variant)
uint16_t last
Definition: ipv4_frag.h:105
size_t digestSize
Definition: blake2s.h:60
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
#define G(a, b, c, d, x, y)
Definition: blake2s.c:48
uint32_t h[8]
Definition: blake2s.h:52
#define FALSE
Definition: os_port.h:46
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
#define osMemcpy(dest, src, length)
Definition: os_port.h:144
size_t size
Definition: blake2s.h:58
error_t
Error codes.
Definition: error.h:43
void blake2sUpdate(Blake2sContext *context, const void *data, size_t length)
Update the BLAKE2s context with a portion of the message being hashed.
Definition: blake2s.c:221
General definitions for cryptographic algorithms.
BLAKE2s algorithm context.
Definition: blake2s.h:51
uint8_t iv[]
Definition: ike.h:1626
uint8_t length
Definition: tcp.h:375
#define MIN(a, b)
Definition: os_port.h:63
uint32_t dataLen
Definition: sftp_common.h:229
error_t blake2sCompute(const void *key, size_t keyLen, const void *data, size_t dataLen, uint8_t *digest, size_t digestLen)
Digest a message using BLAKE2s.
Definition: blake2s.c:98
error_t blake2sInit(Blake2sContext *context, const void *key, size_t keyLen, size_t digestLen)
Initialize BLAKE2s message digest context.
Definition: blake2s.c:154
uint32_t m[16]
Definition: blake2s.h:55
uint8_t m
Definition: ndp.h:304
uint8_t n
#define cryptoFreeMem(p)
Definition: crypto.h:826
#define cryptoAllocMem(size)
Definition: crypto.h:821
#define LOAD32LE(p)
Definition: cpu_endian.h:203
unsigned int uint_t
Definition: compiler_port.h:57
#define osMemset(p, value, length)
Definition: os_port.h:138
@ NO_ERROR
Success.
Definition: error.h:44