1 /*
2 BLAKE2 reference source code package - reference C implementations
3
4 Written in 2012 by Samuel Neves <sneves@dei.uc.pt>
5
6 To the extent possible under law, the author(s) have dedicated all copyright
7 and related and neighboring rights to this software to the public domain
8 worldwide. This software is distributed without any warranty.
9
10 You should have received a copy of the CC0 Public Domain Dedication along with
11 this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
12 */
13 /* blake2s.c
14 *
15 * Copyright (C) 2006-2021 wolfSSL Inc.
16 *
17 * This file is part of wolfSSL.
18 *
19 * wolfSSL is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
23 *
24 * wolfSSL is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
28 *
29 * You should have received a copy of the GNU General Public License
30 * along with this program; if not, write to the Free Software
31 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
32 */
33
34
35
36 #ifdef HAVE_CONFIG_H
37 #include <config.h>
38 #endif
39
40 #include <wolfssl/wolfcrypt/settings.h>
41
42 #ifdef HAVE_BLAKE2S
43
44 #include <wolfssl/wolfcrypt/blake2.h>
45 #include <wolfssl/wolfcrypt/blake2-impl.h>
46 #include <wolfssl/wolfcrypt/error-crypt.h>
47
48
49 static const word32 blake2s_IV[8] =
50 {
51 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
52 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
53 };
54
55 static const byte blake2s_sigma[10][16] =
56 {
57 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } ,
58 { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } ,
59 { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } ,
60 { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } ,
61 { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } ,
62 { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } ,
63 { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } ,
64 { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } ,
65 { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } ,
66 { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 }
67 };
68
69
blake2s_set_lastnode(blake2s_state * S)70 static WC_INLINE int blake2s_set_lastnode( blake2s_state *S )
71 {
72 S->f[1] = ~0;
73 return 0;
74 }
75
76 /* Some helper functions, not necessarily useful */
blake2s_set_lastblock(blake2s_state * S)77 static WC_INLINE int blake2s_set_lastblock( blake2s_state *S )
78 {
79 if( S->last_node ) blake2s_set_lastnode( S );
80
81 S->f[0] = ~0;
82 return 0;
83 }
84
blake2s_increment_counter(blake2s_state * S,const word32 inc)85 static WC_INLINE int blake2s_increment_counter( blake2s_state *S, const word32
86 inc )
87 {
88 S->t[0] += inc;
89 S->t[1] += ( S->t[0] < inc );
90 return 0;
91 }
92
blake2s_init0(blake2s_state * S)93 static WC_INLINE int blake2s_init0( blake2s_state *S )
94 {
95 int i;
96 XMEMSET( S, 0, sizeof( blake2s_state ) );
97
98 for( i = 0; i < 8; ++i ) S->h[i] = blake2s_IV[i];
99
100 return 0;
101 }
102
103 /* init xors IV with input parameter block */
blake2s_init_param(blake2s_state * S,const blake2s_param * P)104 int blake2s_init_param( blake2s_state *S, const blake2s_param *P )
105 {
106 word32 i;
107 byte *p ;
108 blake2s_init0( S );
109 p = ( byte * )( P );
110
111 /* IV XOR ParamBlock */
112 for( i = 0; i < 8; ++i )
113 S->h[i] ^= load32( p + sizeof( S->h[i] ) * i );
114
115 return 0;
116 }
117
118
119
blake2s_init(blake2s_state * S,const byte outlen)120 int blake2s_init( blake2s_state *S, const byte outlen )
121 {
122 blake2s_param P[1];
123
124 if ( ( !outlen ) || ( outlen > BLAKE2S_OUTBYTES ) ) return BAD_FUNC_ARG;
125
126 #ifdef WOLFSSL_BLAKE2S_INIT_EACH_FIELD
127 P->digest_length = outlen;
128 P->key_length = 0;
129 P->fanout = 1;
130 P->depth = 1;
131 store32( &P->leaf_length, 0 );
132 store32( &P->node_offset, 0 );
133 P->node_depth = 0;
134 P->inner_length = 0;
135 XMEMSET( P->reserved, 0, sizeof( P->reserved ) );
136 XMEMSET( P->salt, 0, sizeof( P->salt ) );
137 XMEMSET( P->personal, 0, sizeof( P->personal ) );
138 #else
139 XMEMSET( P, 0, sizeof( *P ) );
140 P->digest_length = outlen;
141 P->fanout = 1;
142 P->depth = 1;
143 #endif
144 return blake2s_init_param( S, P );
145 }
146
147
blake2s_init_key(blake2s_state * S,const byte outlen,const void * key,const byte keylen)148 int blake2s_init_key( blake2s_state *S, const byte outlen, const void *key,
149 const byte keylen )
150 {
151 int ret = 0;
152 blake2s_param P[1];
153
154 if ( ( !outlen ) || ( outlen > BLAKE2S_OUTBYTES ) ) return BAD_FUNC_ARG;
155
156 if ( !key || !keylen || keylen > BLAKE2S_KEYBYTES ) return BAD_FUNC_ARG;
157
158 #ifdef WOLFSSL_BLAKE2S_INIT_EACH_FIELD
159 P->digest_length = outlen;
160 P->key_length = keylen;
161 P->fanout = 1;
162 P->depth = 1;
163 store32( &P->leaf_length, 0 );
164 store64( &P->node_offset, 0 );
165 P->node_depth = 0;
166 P->inner_length = 0;
167 XMEMSET( P->reserved, 0, sizeof( P->reserved ) );
168 XMEMSET( P->salt, 0, sizeof( P->salt ) );
169 XMEMSET( P->personal, 0, sizeof( P->personal ) );
170 #else
171 XMEMSET( P, 0, sizeof( *P ) );
172 P->digest_length = outlen;
173 P->key_length = keylen;
174 P->fanout = 1;
175 P->depth = 1;
176 #endif
177
178 ret = blake2s_init_param( S, P );
179 if (ret < 0)
180 return ret;
181
182 {
183 #ifdef WOLFSSL_SMALL_STACK
184 byte* block;
185
186 block = (byte*)XMALLOC(BLAKE2S_BLOCKBYTES, NULL, DYNAMIC_TYPE_TMP_BUFFER);
187
188 if ( block == NULL ) return MEMORY_E;
189 #else
190 byte block[BLAKE2S_BLOCKBYTES];
191 #endif
192
193 XMEMSET( block, 0, BLAKE2S_BLOCKBYTES );
194 XMEMCPY( block, key, keylen );
195 ret = blake2s_update( S, block, BLAKE2S_BLOCKBYTES );
196 secure_zero_memory( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from */
197 /* memory */
198
199 #ifdef WOLFSSL_SMALL_STACK
200 XFREE(block, NULL, DYNAMIC_TYPE_TMP_BUFFER);
201 #endif
202 }
203 return ret;
204 }
205
blake2s_compress(blake2s_state * S,const byte block[BLAKE2S_BLOCKBYTES],word32 * m,word32 * v)206 static WC_INLINE int blake2s_compress(
207 blake2s_state *S,
208 const byte block[BLAKE2S_BLOCKBYTES],
209 word32* m,
210 word32* v)
211 {
212 int i;
213
214 for( i = 0; i < 16; ++i )
215 m[i] = load32( block + i * sizeof( m[i] ) );
216
217 for( i = 0; i < 8; ++i )
218 v[i] = S->h[i];
219
220 v[ 8] = blake2s_IV[0];
221 v[ 9] = blake2s_IV[1];
222 v[10] = blake2s_IV[2];
223 v[11] = blake2s_IV[3];
224 v[12] = S->t[0] ^ blake2s_IV[4];
225 v[13] = S->t[1] ^ blake2s_IV[5];
226 v[14] = S->f[0] ^ blake2s_IV[6];
227 v[15] = S->f[1] ^ blake2s_IV[7];
228 #define G(r,i,a,b,c,d) \
229 do { \
230 a = a + b + m[blake2s_sigma[r][2*i+0]]; \
231 d = rotr32(d ^ a, 16); \
232 c = c + d; \
233 b = rotr32(b ^ c, 12); \
234 a = a + b + m[blake2s_sigma[r][2*i+1]]; \
235 d = rotr32(d ^ a, 8); \
236 c = c + d; \
237 b = rotr32(b ^ c, 7); \
238 } while(0)
239 #define ROUND(r) \
240 do { \
241 G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \
242 G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \
243 G(r,2,v[ 2],v[ 6],v[10],v[14]); \
244 G(r,3,v[ 3],v[ 7],v[11],v[15]); \
245 G(r,4,v[ 0],v[ 5],v[10],v[15]); \
246 G(r,5,v[ 1],v[ 6],v[11],v[12]); \
247 G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \
248 G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \
249 } while(0)
250 ROUND( 0 );
251 ROUND( 1 );
252 ROUND( 2 );
253 ROUND( 3 );
254 ROUND( 4 );
255 ROUND( 5 );
256 ROUND( 6 );
257 ROUND( 7 );
258 ROUND( 8 );
259 ROUND( 9 );
260
261 for( i = 0; i < 8; ++i )
262 S->h[i] = S->h[i] ^ v[i] ^ v[i + 8];
263
264 #undef G
265 #undef ROUND
266
267 return 0;
268 }
269
270 /* inlen now in bytes */
blake2s_update(blake2s_state * S,const byte * in,word32 inlen)271 int blake2s_update( blake2s_state *S, const byte *in, word32 inlen )
272 {
273 int ret = 0;
274 #ifdef WOLFSSL_SMALL_STACK
275 word32* m;
276 word32* v;
277
278 m = (word32*)XMALLOC(sizeof(word32) * 32, NULL, DYNAMIC_TYPE_TMP_BUFFER);
279
280 if ( m == NULL ) return MEMORY_E;
281
282 v = &m[16];
283 #else
284 word32 m[16];
285 word32 v[16];
286 #endif
287
288 while( inlen > 0 )
289 {
290 word32 left = S->buflen;
291 word32 fill = 2 * BLAKE2S_BLOCKBYTES - left;
292
293 if( inlen > fill )
294 {
295 XMEMCPY( S->buf + left, in, (wolfssl_word)fill ); /* Fill buffer */
296 S->buflen += fill;
297 blake2s_increment_counter( S, BLAKE2S_BLOCKBYTES );
298
299 {
300 ret= blake2s_compress( S, S->buf, m, v );
301 if (ret < 0) break;
302 }
303
304 XMEMCPY( S->buf, S->buf + BLAKE2S_BLOCKBYTES, BLAKE2S_BLOCKBYTES );
305 /* Shift buffer left */
306 S->buflen -= BLAKE2S_BLOCKBYTES;
307 in += fill;
308 inlen -= fill;
309 }
310 else /* inlen <= fill */
311 {
312 XMEMCPY( S->buf + left, in, (wolfssl_word)inlen );
313 S->buflen += inlen; /* Be lazy, do not compress */
314 inlen = 0;
315 }
316 }
317
318 #ifdef WOLFSSL_SMALL_STACK
319 XFREE(m, NULL, DYNAMIC_TYPE_TMP_BUFFER);
320 #endif
321
322 return ret;
323 }
324
325 /* Is this correct? */
blake2s_final(blake2s_state * S,byte * out,byte outlen)326 int blake2s_final( blake2s_state *S, byte *out, byte outlen )
327 {
328 int ret = 0;
329 int i;
330 byte buffer[BLAKE2S_BLOCKBYTES];
331 #ifdef WOLFSSL_SMALL_STACK
332 word32* m;
333 word32* v;
334
335 m = (word32*)XMALLOC(sizeof(word32) * 32, NULL, DYNAMIC_TYPE_TMP_BUFFER);
336
337 if ( m == NULL ) return MEMORY_E;
338
339 v = &m[16];
340 #else
341 word32 m[16];
342 word32 v[16];
343 #endif
344
345 if( S->buflen > BLAKE2S_BLOCKBYTES )
346 {
347 blake2s_increment_counter( S, BLAKE2S_BLOCKBYTES );
348
349 {
350 ret = blake2s_compress( S, S->buf, m, v );
351 if (ret < 0) goto out;
352 }
353
354 S->buflen -= BLAKE2S_BLOCKBYTES;
355 XMEMCPY( S->buf, S->buf + BLAKE2S_BLOCKBYTES, (wolfssl_word)S->buflen );
356 }
357
358 blake2s_increment_counter( S, S->buflen );
359 blake2s_set_lastblock( S );
360 XMEMSET( S->buf + S->buflen, 0, (wolfssl_word)(2 * BLAKE2S_BLOCKBYTES - S->buflen) );
361 /* Padding */
362 {
363 ret = blake2s_compress( S, S->buf, m, v );
364 if (ret < 0) goto out;
365 }
366
367 for( i = 0; i < 8; ++i ) /* Output full hash to temp buffer */
368 store64( buffer + sizeof( S->h[i] ) * i, S->h[i] );
369
370 XMEMCPY( out, buffer, outlen );
371
372 out:
373
374 #ifdef WOLFSSL_SMALL_STACK
375 XFREE(m, NULL, DYNAMIC_TYPE_TMP_BUFFER);
376 #endif
377
378 return ret;
379 }
380
381 /* inlen, at least, should be word32. Others can be size_t. */
blake2s(byte * out,const void * in,const void * key,const byte outlen,const word32 inlen,byte keylen)382 int blake2s( byte *out, const void *in, const void *key, const byte outlen,
383 const word32 inlen, byte keylen )
384 {
385 blake2s_state S[1];
386
387 /* Verify parameters */
388 if ( NULL == in ) return BAD_FUNC_ARG;
389
390 if ( NULL == out ) return BAD_FUNC_ARG;
391
392 if( NULL == key ) keylen = 0;
393
394 if( keylen > 0 )
395 {
396 int ret = blake2s_init_key( S, outlen, key, keylen );
397 if (ret < 0) return ret;
398 }
399 else
400 {
401 int ret = blake2s_init( S, outlen );
402 if (ret < 0) return ret;
403 }
404
405 {
406 int ret = blake2s_update( S, ( byte * )in, inlen );
407 if (ret < 0) return ret;
408 }
409
410 return blake2s_final( S, out, outlen );
411 }
412
413 #if defined(BLAKE2S_SELFTEST)
414 #include <string.h>
415 #include "blake2-kat.h"
main(int argc,char ** argv)416 int main( int argc, char **argv )
417 {
418 byte key[BLAKE2S_KEYBYTES];
419 byte buf[KAT_LENGTH];
420
421 for( word32 i = 0; i < BLAKE2S_KEYBYTES; ++i )
422 key[i] = ( byte )i;
423
424 for( word32 i = 0; i < KAT_LENGTH; ++i )
425 buf[i] = ( byte )i;
426
427 for( word32 i = 0; i < KAT_LENGTH; ++i )
428 {
429 byte hash[BLAKE2S_OUTBYTES];
430 if ( blake2s( hash, buf, key, BLAKE2S_OUTBYTES, i, BLAKE2S_KEYBYTES ) < 0 )
431 {
432 puts( "error" );
433 return -1;
434 }
435
436 if( 0 != XMEMCMP( hash, blake2s_keyed_kat[i], BLAKE2S_OUTBYTES ) )
437 {
438 puts( "error" );
439 return -1;
440 }
441 }
442
443 puts( "ok" );
444 return 0;
445 }
446 #endif
447
448
449 /* wolfCrypt API */
450
451 /* Init Blake2s digest, track size in case final doesn't want to "remember" */
wc_InitBlake2s(Blake2s * b2s,word32 digestSz)452 int wc_InitBlake2s(Blake2s* b2s, word32 digestSz)
453 {
454 if (b2s == NULL){
455 return BAD_FUNC_ARG;
456 }
457 b2s->digestSz = digestSz;
458
459 return blake2s_init(b2s->S, (byte)digestSz);
460 }
461
462
463 /* Init Blake2s digest with key, track size in case final doesn't want to "remember" */
wc_InitBlake2s_WithKey(Blake2s * b2s,word32 digestSz,const byte * key,word32 keylen)464 int wc_InitBlake2s_WithKey(Blake2s* b2s, word32 digestSz, const byte *key, word32 keylen)
465 {
466 if (b2s == NULL){
467 return BAD_FUNC_ARG;
468 }
469 b2s->digestSz = digestSz;
470
471 if (keylen >= 256)
472 return BAD_FUNC_ARG;
473
474 if (key)
475 return blake2s_init_key(b2s->S, (byte)digestSz, key, (byte)keylen);
476 else
477 return blake2s_init(b2s->S, (byte)digestSz);
478 }
479
480
481 /* Blake2s Update */
wc_Blake2sUpdate(Blake2s * b2s,const byte * data,word32 sz)482 int wc_Blake2sUpdate(Blake2s* b2s, const byte* data, word32 sz)
483 {
484 return blake2s_update(b2s->S, data, sz);
485 }
486
487
488 /* Blake2s Final, if pass in zero size we use init digestSz */
wc_Blake2sFinal(Blake2s * b2s,byte * final,word32 requestSz)489 int wc_Blake2sFinal(Blake2s* b2s, byte* final, word32 requestSz)
490 {
491 word32 sz = requestSz ? requestSz : b2s->digestSz;
492
493 return blake2s_final(b2s->S, final, (byte)sz);
494 }
495
496
497 /* end CTaoCrypt API */
498
499 #endif /* HAVE_BLAKE2S */
500
501