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