1339640Smm/*
2339640Smm   BLAKE2 reference source code package - reference C implementations
3339640Smm
4339640Smm   Copyright 2012, Samuel Neves <sneves@dei.uc.pt>.  You may use this under the
5339640Smm   terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at
6339640Smm   your option.  The terms of these licenses can be found at:
7339640Smm
8339640Smm   - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
9339640Smm   - OpenSSL license   : https://www.openssl.org/source/license.html
10339640Smm   - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
11339640Smm
12339640Smm   More information about the BLAKE2 hash function can be found at
13339640Smm   https://blake2.net.
14339640Smm*/
15339640Smm
16339640Smm#include <stdlib.h>
17339640Smm#include <string.h>
18339640Smm#include <stdio.h>
19339640Smm
20339640Smm#if defined(_OPENMP)
21339640Smm#include <omp.h>
22339640Smm#endif
23339640Smm
24339640Smm#include "archive_blake2.h"
25339640Smm#include "archive_blake2_impl.h"
26339640Smm
27339640Smm#define PARALLELISM_DEGREE 8
28339640Smm
29339640Smm/*
30339640Smm  blake2sp_init_param defaults to setting the expecting output length
31339640Smm  from the digest_length parameter block field.
32339640Smm
33339640Smm  In some cases, however, we do not want this, as the output length
34339640Smm  of these instances is given by inner_length instead.
35339640Smm*/
36339640Smmstatic int blake2sp_init_leaf_param( blake2s_state *S, const blake2s_param *P )
37339640Smm{
38339640Smm  int err = blake2s_init_param(S, P);
39339640Smm  S->outlen = P->inner_length;
40339640Smm  return err;
41339640Smm}
42339640Smm
43339640Smmstatic int blake2sp_init_leaf( blake2s_state *S, size_t outlen, size_t keylen, uint32_t offset )
44339640Smm{
45339640Smm  blake2s_param P[1];
46339640Smm  P->digest_length = (uint8_t)outlen;
47339640Smm  P->key_length = (uint8_t)keylen;
48339640Smm  P->fanout = PARALLELISM_DEGREE;
49339640Smm  P->depth = 2;
50339640Smm  store32( &P->leaf_length, 0 );
51339640Smm  store32( &P->node_offset, offset );
52339640Smm  store16( &P->xof_length, 0 );
53339640Smm  P->node_depth = 0;
54339640Smm  P->inner_length = BLAKE2S_OUTBYTES;
55339640Smm  memset( P->salt, 0, sizeof( P->salt ) );
56339640Smm  memset( P->personal, 0, sizeof( P->personal ) );
57339640Smm  return blake2sp_init_leaf_param( S, P );
58339640Smm}
59339640Smm
60339640Smmstatic int blake2sp_init_root( blake2s_state *S, size_t outlen, size_t keylen )
61339640Smm{
62339640Smm  blake2s_param P[1];
63339640Smm  P->digest_length = (uint8_t)outlen;
64339640Smm  P->key_length = (uint8_t)keylen;
65339640Smm  P->fanout = PARALLELISM_DEGREE;
66339640Smm  P->depth = 2;
67339640Smm  store32( &P->leaf_length, 0 );
68339640Smm  store32( &P->node_offset, 0 );
69339640Smm  store16( &P->xof_length, 0 );
70339640Smm  P->node_depth = 1;
71339640Smm  P->inner_length = BLAKE2S_OUTBYTES;
72339640Smm  memset( P->salt, 0, sizeof( P->salt ) );
73339640Smm  memset( P->personal, 0, sizeof( P->personal ) );
74339640Smm  return blake2s_init_param( S, P );
75339640Smm}
76339640Smm
77339640Smm
78339640Smmint blake2sp_init( blake2sp_state *S, size_t outlen )
79339640Smm{
80339640Smm  size_t i;
81339640Smm
82339640Smm  if( !outlen || outlen > BLAKE2S_OUTBYTES ) return -1;
83339640Smm
84339640Smm  memset( S->buf, 0, sizeof( S->buf ) );
85339640Smm  S->buflen = 0;
86339640Smm  S->outlen = outlen;
87339640Smm
88339640Smm  if( blake2sp_init_root( S->R, outlen, 0 ) < 0 )
89339640Smm    return -1;
90339640Smm
91339640Smm  for( i = 0; i < PARALLELISM_DEGREE; ++i )
92346105Smm    if( blake2sp_init_leaf( S->S[i], outlen, 0, (uint32_t)i ) < 0 ) return -1;
93339640Smm
94339640Smm  S->R->last_node = 1;
95339640Smm  S->S[PARALLELISM_DEGREE - 1]->last_node = 1;
96339640Smm  return 0;
97339640Smm}
98339640Smm
99339640Smmint blake2sp_init_key( blake2sp_state *S, size_t outlen, const void *key, size_t keylen )
100339640Smm{
101339640Smm  size_t i;
102339640Smm
103339640Smm  if( !outlen || outlen > BLAKE2S_OUTBYTES ) return -1;
104339640Smm
105339640Smm  if( !key || !keylen || keylen > BLAKE2S_KEYBYTES ) return -1;
106339640Smm
107339640Smm  memset( S->buf, 0, sizeof( S->buf ) );
108339640Smm  S->buflen = 0;
109339640Smm  S->outlen = outlen;
110339640Smm
111339640Smm  if( blake2sp_init_root( S->R, outlen, keylen ) < 0 )
112339640Smm    return -1;
113339640Smm
114339640Smm  for( i = 0; i < PARALLELISM_DEGREE; ++i )
115346105Smm    if( blake2sp_init_leaf( S->S[i], outlen, keylen, (uint32_t)i ) < 0 ) return -1;
116339640Smm
117339640Smm  S->R->last_node = 1;
118339640Smm  S->S[PARALLELISM_DEGREE - 1]->last_node = 1;
119339640Smm  {
120339640Smm    uint8_t block[BLAKE2S_BLOCKBYTES];
121339640Smm    memset( block, 0, BLAKE2S_BLOCKBYTES );
122339640Smm    memcpy( block, key, keylen );
123339640Smm
124339640Smm    for( i = 0; i < PARALLELISM_DEGREE; ++i )
125339640Smm      blake2s_update( S->S[i], block, BLAKE2S_BLOCKBYTES );
126339640Smm
127339640Smm    secure_zero_memory( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from stack */
128339640Smm  }
129339640Smm  return 0;
130339640Smm}
131339640Smm
132339640Smm
133339640Smmint blake2sp_update( blake2sp_state *S, const void *pin, size_t inlen )
134339640Smm{
135339640Smm  const unsigned char * in = (const unsigned char *)pin;
136339640Smm  size_t left = S->buflen;
137339640Smm  size_t fill = sizeof( S->buf ) - left;
138339640Smm  size_t i;
139339640Smm
140339640Smm  if( left && inlen >= fill )
141339640Smm  {
142339640Smm    memcpy( S->buf + left, in, fill );
143339640Smm
144339640Smm    for( i = 0; i < PARALLELISM_DEGREE; ++i )
145339640Smm      blake2s_update( S->S[i], S->buf + i * BLAKE2S_BLOCKBYTES, BLAKE2S_BLOCKBYTES );
146339640Smm
147339640Smm    in += fill;
148339640Smm    inlen -= fill;
149339640Smm    left = 0;
150339640Smm  }
151339640Smm
152339640Smm#if defined(_OPENMP)
153339640Smm  #pragma omp parallel shared(S), num_threads(PARALLELISM_DEGREE)
154339640Smm#else
155339640Smm  for( i = 0; i < PARALLELISM_DEGREE; ++i )
156339640Smm#endif
157339640Smm  {
158339640Smm#if defined(_OPENMP)
159339640Smm    size_t      i = omp_get_thread_num();
160339640Smm#endif
161339640Smm    size_t inlen__ = inlen;
162339640Smm    const unsigned char *in__ = ( const unsigned char * )in;
163339640Smm    in__ += i * BLAKE2S_BLOCKBYTES;
164339640Smm
165339640Smm    while( inlen__ >= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES )
166339640Smm    {
167339640Smm      blake2s_update( S->S[i], in__, BLAKE2S_BLOCKBYTES );
168339640Smm      in__ += PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
169339640Smm      inlen__ -= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
170339640Smm    }
171339640Smm  }
172339640Smm
173339640Smm  in += inlen - inlen % ( PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES );
174339640Smm  inlen %= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
175339640Smm
176339640Smm  if( inlen > 0 )
177339640Smm    memcpy( S->buf + left, in, inlen );
178339640Smm
179339640Smm  S->buflen = left + inlen;
180339640Smm  return 0;
181339640Smm}
182339640Smm
183339640Smm
184339640Smmint blake2sp_final( blake2sp_state *S, void *out, size_t outlen )
185339640Smm{
186339640Smm  uint8_t hash[PARALLELISM_DEGREE][BLAKE2S_OUTBYTES];
187339640Smm  size_t i;
188339640Smm
189339640Smm  if(out == NULL || outlen < S->outlen) {
190339640Smm    return -1;
191339640Smm  }
192339640Smm
193339640Smm  for( i = 0; i < PARALLELISM_DEGREE; ++i )
194339640Smm  {
195339640Smm    if( S->buflen > i * BLAKE2S_BLOCKBYTES )
196339640Smm    {
197339640Smm      size_t left = S->buflen - i * BLAKE2S_BLOCKBYTES;
198339640Smm
199339640Smm      if( left > BLAKE2S_BLOCKBYTES ) left = BLAKE2S_BLOCKBYTES;
200339640Smm
201339640Smm      blake2s_update( S->S[i], S->buf + i * BLAKE2S_BLOCKBYTES, left );
202339640Smm    }
203339640Smm
204339640Smm    blake2s_final( S->S[i], hash[i], BLAKE2S_OUTBYTES );
205339640Smm  }
206339640Smm
207339640Smm  for( i = 0; i < PARALLELISM_DEGREE; ++i )
208339640Smm    blake2s_update( S->R, hash[i], BLAKE2S_OUTBYTES );
209339640Smm
210339640Smm  return blake2s_final( S->R, out, S->outlen );
211339640Smm}
212339640Smm
213339640Smm
214339640Smmint blake2sp( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen )
215339640Smm{
216339640Smm  uint8_t hash[PARALLELISM_DEGREE][BLAKE2S_OUTBYTES];
217339640Smm  blake2s_state S[PARALLELISM_DEGREE][1];
218339640Smm  blake2s_state FS[1];
219339640Smm  size_t i;
220339640Smm
221339640Smm  /* Verify parameters */
222339640Smm  if ( NULL == in && inlen > 0 ) return -1;
223339640Smm
224339640Smm  if ( NULL == out ) return -1;
225339640Smm
226339640Smm  if ( NULL == key && keylen > 0) return -1;
227339640Smm
228339640Smm  if( !outlen || outlen > BLAKE2S_OUTBYTES ) return -1;
229339640Smm
230339640Smm  if( keylen > BLAKE2S_KEYBYTES ) return -1;
231339640Smm
232339640Smm  for( i = 0; i < PARALLELISM_DEGREE; ++i )
233346105Smm    if( blake2sp_init_leaf( S[i], outlen, keylen, (uint32_t)i ) < 0 ) return -1;
234339640Smm
235339640Smm  S[PARALLELISM_DEGREE - 1]->last_node = 1; /* mark last node */
236339640Smm
237339640Smm  if( keylen > 0 )
238339640Smm  {
239339640Smm    uint8_t block[BLAKE2S_BLOCKBYTES];
240339640Smm    memset( block, 0, BLAKE2S_BLOCKBYTES );
241339640Smm    memcpy( block, key, keylen );
242339640Smm
243339640Smm    for( i = 0; i < PARALLELISM_DEGREE; ++i )
244339640Smm      blake2s_update( S[i], block, BLAKE2S_BLOCKBYTES );
245339640Smm
246339640Smm    secure_zero_memory( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from stack */
247339640Smm  }
248339640Smm
249339640Smm#if defined(_OPENMP)
250339640Smm  #pragma omp parallel shared(S,hash), num_threads(PARALLELISM_DEGREE)
251339640Smm#else
252339640Smm
253339640Smm  for( i = 0; i < PARALLELISM_DEGREE; ++i )
254339640Smm#endif
255339640Smm  {
256339640Smm#if defined(_OPENMP)
257339640Smm    size_t      i = omp_get_thread_num();
258339640Smm#endif
259339640Smm    size_t inlen__ = inlen;
260339640Smm    const unsigned char *in__ = ( const unsigned char * )in;
261339640Smm    in__ += i * BLAKE2S_BLOCKBYTES;
262339640Smm
263339640Smm    while( inlen__ >= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES )
264339640Smm    {
265339640Smm      blake2s_update( S[i], in__, BLAKE2S_BLOCKBYTES );
266339640Smm      in__ += PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
267339640Smm      inlen__ -= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
268339640Smm    }
269339640Smm
270339640Smm    if( inlen__ > i * BLAKE2S_BLOCKBYTES )
271339640Smm    {
272339640Smm      const size_t left = inlen__ - i * BLAKE2S_BLOCKBYTES;
273339640Smm      const size_t len = left <= BLAKE2S_BLOCKBYTES ? left : BLAKE2S_BLOCKBYTES;
274339640Smm      blake2s_update( S[i], in__, len );
275339640Smm    }
276339640Smm
277339640Smm    blake2s_final( S[i], hash[i], BLAKE2S_OUTBYTES );
278339640Smm  }
279339640Smm
280339640Smm  if( blake2sp_init_root( FS, outlen, keylen ) < 0 )
281339640Smm    return -1;
282339640Smm
283339640Smm  FS->last_node = 1;
284339640Smm
285339640Smm  for( i = 0; i < PARALLELISM_DEGREE; ++i )
286339640Smm    blake2s_update( FS, hash[i], BLAKE2S_OUTBYTES );
287339640Smm
288339640Smm  return blake2s_final( FS, out, outlen );
289339640Smm}
290339640Smm
291339640Smm
292339640Smm
293339640Smm#if defined(BLAKE2SP_SELFTEST)
294339640Smm#include <string.h>
295339640Smm#include "blake2-kat.h"
296339640Smmint main( void )
297339640Smm{
298339640Smm  uint8_t key[BLAKE2S_KEYBYTES];
299339640Smm  uint8_t buf[BLAKE2_KAT_LENGTH];
300339640Smm  size_t i, step;
301339640Smm
302339640Smm  for( i = 0; i < BLAKE2S_KEYBYTES; ++i )
303339640Smm    key[i] = ( uint8_t )i;
304339640Smm
305339640Smm  for( i = 0; i < BLAKE2_KAT_LENGTH; ++i )
306339640Smm    buf[i] = ( uint8_t )i;
307339640Smm
308339640Smm  /* Test simple API */
309339640Smm  for( i = 0; i < BLAKE2_KAT_LENGTH; ++i )
310339640Smm  {
311339640Smm    uint8_t hash[BLAKE2S_OUTBYTES];
312339640Smm    blake2sp( hash, BLAKE2S_OUTBYTES, buf, i, key, BLAKE2S_KEYBYTES );
313339640Smm
314339640Smm    if( 0 != memcmp( hash, blake2sp_keyed_kat[i], BLAKE2S_OUTBYTES ) )
315339640Smm    {
316339640Smm      goto fail;
317339640Smm    }
318339640Smm  }
319339640Smm
320339640Smm  /* Test streaming API */
321339640Smm  for(step = 1; step < BLAKE2S_BLOCKBYTES; ++step) {
322339640Smm    for (i = 0; i < BLAKE2_KAT_LENGTH; ++i) {
323339640Smm      uint8_t hash[BLAKE2S_OUTBYTES];
324339640Smm      blake2sp_state S;
325339640Smm      uint8_t * p = buf;
326339640Smm      size_t mlen = i;
327339640Smm      int err = 0;
328339640Smm
329339640Smm      if( (err = blake2sp_init_key(&S, BLAKE2S_OUTBYTES, key, BLAKE2S_KEYBYTES)) < 0 ) {
330339640Smm        goto fail;
331339640Smm      }
332339640Smm
333339640Smm      while (mlen >= step) {
334339640Smm        if ( (err = blake2sp_update(&S, p, step)) < 0 ) {
335339640Smm          goto fail;
336339640Smm        }
337339640Smm        mlen -= step;
338339640Smm        p += step;
339339640Smm      }
340339640Smm      if ( (err = blake2sp_update(&S, p, mlen)) < 0) {
341339640Smm        goto fail;
342339640Smm      }
343339640Smm      if ( (err = blake2sp_final(&S, hash, BLAKE2S_OUTBYTES)) < 0) {
344339640Smm        goto fail;
345339640Smm      }
346339640Smm
347339640Smm      if (0 != memcmp(hash, blake2sp_keyed_kat[i], BLAKE2S_OUTBYTES)) {
348339640Smm        goto fail;
349339640Smm      }
350339640Smm    }
351339640Smm  }
352339640Smm
353339640Smm  puts( "ok" );
354339640Smm  return 0;
355339640Smmfail:
356339640Smm  puts("error");
357339640Smm  return -1;
358339640Smm}
359339640Smm#endif
360