1 /*
2 BLAKE2 reference source code package - optimized 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
14 #include <stdlib.h>
15 #include <string.h>
16 #include <stdio.h>
17
18 #if defined(_OPENMP)
19 #include <omp.h>
20 #endif
21
22 #include "blake2.h"
23 #include "blake2-impl.h"
24
25 #define PARALLELISM_DEGREE 8
26
blake2sp_init_leaf(blake2s_state * S,uint8_t outlen,uint8_t keylen,uint64_t offset)27 static int blake2sp_init_leaf( blake2s_state *S, uint8_t outlen, uint8_t keylen, uint64_t offset )
28 {
29 blake2s_param P[1];
30 P->digest_length = outlen;
31 P->key_length = keylen;
32 P->fanout = PARALLELISM_DEGREE;
33 P->depth = 2;
34 P->leaf_length = 0;
35 store48( P->node_offset, offset );
36 P->node_depth = 0;
37 P->inner_length = BLAKE2S_OUTBYTES;
38 memset( P->salt, 0, sizeof( P->salt ) );
39 memset( P->personal, 0, sizeof( P->personal ) );
40 blake2s_init_param( S, P );
41 S->outlen = P->inner_length;
42 return 0;
43 }
44
blake2sp_init_root(blake2s_state * S,uint8_t outlen,uint8_t keylen)45 static int blake2sp_init_root( blake2s_state *S, uint8_t outlen, uint8_t keylen )
46 {
47 blake2s_param P[1];
48 P->digest_length = outlen;
49 P->key_length = keylen;
50 P->fanout = PARALLELISM_DEGREE;
51 P->depth = 2;
52 P->leaf_length = 0;
53 store48( P->node_offset, 0ULL );
54 P->node_depth = 1;
55 P->inner_length = BLAKE2S_OUTBYTES;
56 memset( P->salt, 0, sizeof( P->salt ) );
57 memset( P->personal, 0, sizeof( P->personal ) );
58 blake2s_init_param( S, P );
59 S->outlen = P->digest_length;
60 return 0;
61 }
62
63
blake2sp_init(blake2sp_state * S,size_t outlen)64 int blake2sp_init( blake2sp_state *S, size_t outlen )
65 {
66 if( !outlen || outlen > BLAKE2S_OUTBYTES ) return -1;
67
68 memset( S->buf, 0, sizeof( S->buf ) );
69 S->buflen = 0;
70
71 if( blake2sp_init_root( S->R, ( uint8_t ) outlen, 0 ) < 0 )
72 return -1;
73
74 for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
75 if( blake2sp_init_leaf( S->S[i], ( uint8_t ) outlen, 0, i ) < 0 ) return -1;
76
77 S->R->last_node = 1;
78 S->S[PARALLELISM_DEGREE - 1]->last_node = 1;
79 S->outlen = ( uint8_t ) outlen;
80 return 0;
81 }
82
blake2sp_init_key(blake2sp_state * S,size_t outlen,const void * key,size_t keylen)83 int blake2sp_init_key( blake2sp_state *S, size_t outlen, const void *key, size_t keylen )
84 {
85 if( !outlen || outlen > BLAKE2S_OUTBYTES ) return -1;
86
87 if( !key || !keylen || keylen > BLAKE2S_KEYBYTES ) return -1;
88
89 memset( S->buf, 0, sizeof( S->buf ) );
90 S->buflen = 0;
91
92 if( blake2sp_init_root( S->R, ( uint8_t ) outlen, ( uint8_t ) keylen ) < 0 )
93 return -1;
94
95 for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
96 if( blake2sp_init_leaf( S->S[i], ( uint8_t ) outlen, ( uint8_t ) keylen, i ) < 0 )
97 return -1;
98
99 S->R->last_node = 1;
100 S->S[PARALLELISM_DEGREE - 1]->last_node = 1;
101 S->outlen = ( uint8_t ) outlen;
102 {
103 uint8_t block[BLAKE2S_BLOCKBYTES];
104 memset( block, 0, BLAKE2S_BLOCKBYTES );
105 memcpy( block, key, keylen );
106
107 for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
108 blake2s_update( S->S[i], block, BLAKE2S_BLOCKBYTES );
109
110 secure_zero_memory( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from stack */
111 }
112 return 0;
113 }
114
115
blake2sp_update(blake2sp_state * S,const uint8_t * in,size_t inlen)116 int blake2sp_update( blake2sp_state *S, const uint8_t *in, size_t inlen )
117 {
118 size_t left = S->buflen;
119 size_t fill = sizeof( S->buf ) - left;
120
121 if( left && inlen >= fill )
122 {
123 memcpy( S->buf + left, in, fill );
124
125 for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
126 blake2s_update( S->S[i], S->buf + i * BLAKE2S_BLOCKBYTES, BLAKE2S_BLOCKBYTES );
127
128 in += fill;
129 inlen -= fill;
130 left = 0;
131 }
132
133 #if defined(_OPENMP)
134 omp_set_num_threads(PARALLELISM_DEGREE);
135 #pragma omp parallel shared(S)
136 #else
137 for( size_t id__ = 0; id__ < PARALLELISM_DEGREE; ++id__ )
138 #endif
139 {
140 #if defined(_OPENMP)
141 size_t id__ = ( size_t ) omp_get_thread_num();
142 #endif
143 size_t inlen__ = inlen;
144 const uint8_t *in__ = ( const uint8_t * )in;
145 in__ += id__ * BLAKE2S_BLOCKBYTES;
146
147 while( inlen__ >= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES )
148 {
149 blake2s_update( S->S[id__], in__, BLAKE2S_BLOCKBYTES );
150 in__ += PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
151 inlen__ -= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
152 }
153 }
154
155 in += inlen - inlen % ( PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES );
156 inlen %= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
157
158 if( inlen > 0 )
159 memcpy( S->buf + left, in, inlen );
160
161 S->buflen = ( uint32_t ) left + ( uint32_t ) inlen;
162 return 0;
163 }
164
165
blake2sp_final(blake2sp_state * S,uint8_t * out,size_t outlen)166 int blake2sp_final( blake2sp_state *S, uint8_t *out, size_t outlen )
167 {
168 uint8_t hash[PARALLELISM_DEGREE][BLAKE2S_OUTBYTES];
169
170 if(S->outlen != outlen) return -1;
171
172 for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
173 {
174 if( S->buflen > i * BLAKE2S_BLOCKBYTES )
175 {
176 size_t left = S->buflen - i * BLAKE2S_BLOCKBYTES;
177
178 if( left > BLAKE2S_BLOCKBYTES ) left = BLAKE2S_BLOCKBYTES;
179
180 blake2s_update( S->S[i], S->buf + i * BLAKE2S_BLOCKBYTES, left );
181 }
182
183 blake2s_final( S->S[i], hash[i], BLAKE2S_OUTBYTES );
184 }
185
186 for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
187 blake2s_update( S->R, hash[i], BLAKE2S_OUTBYTES );
188
189 blake2s_final( S->R, out, outlen );
190 return 0;
191 }
192
193
blake2sp(uint8_t * out,const void * in,const void * key,size_t outlen,size_t inlen,size_t keylen)194 int blake2sp( uint8_t *out, const void *in, const void *key, size_t outlen, size_t inlen, size_t keylen )
195 {
196 uint8_t hash[PARALLELISM_DEGREE][BLAKE2S_OUTBYTES];
197 blake2s_state S[PARALLELISM_DEGREE][1];
198 blake2s_state FS[1];
199
200 /* Verify parameters */
201 if ( NULL == in && inlen > 0 ) return -1;
202
203 if ( NULL == out ) return -1;
204
205 if ( NULL == key && keylen > 0 ) return -1;
206
207 if( !outlen || outlen > BLAKE2S_OUTBYTES ) return -1;
208
209 if( keylen > BLAKE2S_KEYBYTES ) return -1;
210
211 for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
212 if( blake2sp_init_leaf( S[i], ( uint8_t ) outlen, ( uint8_t ) keylen, i ) < 0 )
213 return -1;
214
215 S[PARALLELISM_DEGREE - 1]->last_node = 1; // mark last node
216
217 if( keylen > 0 )
218 {
219 uint8_t block[BLAKE2S_BLOCKBYTES];
220 memset( block, 0, BLAKE2S_BLOCKBYTES );
221 memcpy( block, key, keylen );
222
223 for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
224 blake2s_update( S[i], block, BLAKE2S_BLOCKBYTES );
225
226 secure_zero_memory( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from stack */
227 }
228
229 #if defined(_OPENMP)
230 omp_set_num_threads(PARALLELISM_DEGREE);
231 #pragma omp parallel shared(S,hash)
232 #else
233
234 for( size_t id__ = 0; id__ < PARALLELISM_DEGREE; ++id__ )
235 #endif
236 {
237 #if defined(_OPENMP)
238 size_t id__ = ( size_t ) omp_get_thread_num();
239 #endif
240 size_t inlen__ = inlen;
241 const uint8_t *in__ = ( const uint8_t * )in;
242 in__ += id__ * BLAKE2S_BLOCKBYTES;
243
244 while( inlen__ >= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES )
245 {
246 blake2s_update( S[id__], in__, BLAKE2S_BLOCKBYTES );
247 in__ += PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
248 inlen__ -= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
249 }
250
251 if( inlen__ > id__ * BLAKE2S_BLOCKBYTES )
252 {
253 const size_t left = inlen__ - id__ * BLAKE2S_BLOCKBYTES;
254 const size_t len = left <= BLAKE2S_BLOCKBYTES ? left : BLAKE2S_BLOCKBYTES;
255 blake2s_update( S[id__], in__, len );
256 }
257
258 blake2s_final( S[id__], hash[id__], BLAKE2S_OUTBYTES );
259 }
260
261 if( blake2sp_init_root( FS, ( uint8_t ) outlen, ( uint8_t ) keylen ) < 0 )
262 return -1;
263
264 FS->last_node = 1;
265
266 for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
267 blake2s_update( FS, hash[i], BLAKE2S_OUTBYTES );
268
269 return blake2s_final( FS, out, outlen );
270 }
271
272
273
274
275