1 /*
2  * blake2b.c - definitions for the blake2b hash function
3  *
4  * This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 
8 #ifdef FREEBL_NO_DEPEND
9 #include "stubs.h"
10 #endif
11 
12 #include "secerr.h"
13 #include "blapi.h"
14 #include "blake2b.h"
15 #include "crypto_primitives.h"
16 
17 /**
18  * This contains the BLAKE2b initialization vectors.
19  */
20 static const uint64_t iv[8] = {
21     0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 0x3c6ef372fe94f82bULL,
22     0xa54ff53a5f1d36f1ULL, 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL,
23     0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL
24 };
25 
26 /**
27  * This contains the table of permutations for blake2b compression function.
28  */
29 static const uint8_t sigma[12][16] = {
30     { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
31     { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
32     { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
33     { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
34     { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
35     { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
36     { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
37     { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
38     { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
39     { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 },
40     { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
41     { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }
42 };
43 
44 /**
45  * This function increments the blake2b ctx counter.
46  */
47 void
blake2b_IncrementCounter(BLAKE2BContext * ctx,const uint64_t inc)48 blake2b_IncrementCounter(BLAKE2BContext* ctx, const uint64_t inc)
49 {
50     ctx->t[0] += inc;
51     ctx->t[1] += ctx->t[0] < inc;
52 }
53 
54 /**
55  * This macro implements the blake2b mixing function which mixes two 8-byte
56  * words from the message into the hash.
57  */
58 #define G(a, b, c, d, x, y) \
59     a += b + x;             \
60     d = ROTR64(d ^ a, 32);  \
61     c += d;                 \
62     b = ROTR64(b ^ c, 24);  \
63     a += b + y;             \
64     d = ROTR64(d ^ a, 16);  \
65     c += d;                 \
66     b = ROTR64(b ^ c, 63)
67 
68 #define ROUND(i)                                                   \
69     G(v[0], v[4], v[8], v[12], m[sigma[i][0]], m[sigma[i][1]]);    \
70     G(v[1], v[5], v[9], v[13], m[sigma[i][2]], m[sigma[i][3]]);    \
71     G(v[2], v[6], v[10], v[14], m[sigma[i][4]], m[sigma[i][5]]);   \
72     G(v[3], v[7], v[11], v[15], m[sigma[i][6]], m[sigma[i][7]]);   \
73     G(v[0], v[5], v[10], v[15], m[sigma[i][8]], m[sigma[i][9]]);   \
74     G(v[1], v[6], v[11], v[12], m[sigma[i][10]], m[sigma[i][11]]); \
75     G(v[2], v[7], v[8], v[13], m[sigma[i][12]], m[sigma[i][13]]);  \
76     G(v[3], v[4], v[9], v[14], m[sigma[i][14]], m[sigma[i][15]])
77 
78 /**
79  * The blake2b compression function which takes a full 128-byte chunk of the
80  * input message and mixes it into the ongoing ctx array, i.e., permute the
81  * ctx while xoring in the block of data.
82  */
83 void
blake2b_Compress(BLAKE2BContext * ctx,const uint8_t * block)84 blake2b_Compress(BLAKE2BContext* ctx, const uint8_t* block)
85 {
86     size_t i;
87     uint64_t v[16], m[16];
88 
89     PORT_Memcpy(m, block, BLAKE2B_BLOCK_LENGTH);
90 #if !defined(IS_LITTLE_ENDIAN)
91     for (i = 0; i < 16; ++i) {
92         m[i] = FREEBL_HTONLL(m[i]);
93     }
94 #endif
95 
96     PORT_Memcpy(v, ctx->h, 8 * 8);
97     PORT_Memcpy(v + 8, iv, 8 * 8);
98 
99     v[12] ^= ctx->t[0];
100     v[13] ^= ctx->t[1];
101     v[14] ^= ctx->f;
102 
103     ROUND(0);
104     ROUND(1);
105     ROUND(2);
106     ROUND(3);
107     ROUND(4);
108     ROUND(5);
109     ROUND(6);
110     ROUND(7);
111     ROUND(8);
112     ROUND(9);
113     ROUND(10);
114     ROUND(11);
115 
116     for (i = 0; i < 8; i++) {
117         ctx->h[i] ^= v[i] ^ v[i + 8];
118     }
119 }
120 
121 /**
122  * This function can be used for both keyed and unkeyed version.
123  */
124 BLAKE2BContext*
BLAKE2B_NewContext()125 BLAKE2B_NewContext()
126 {
127     return PORT_ZNew(BLAKE2BContext);
128 }
129 
130 /**
131  * Zero and free the context and can be used for both keyed and unkeyed version.
132  */
133 void
BLAKE2B_DestroyContext(BLAKE2BContext * ctx,PRBool freeit)134 BLAKE2B_DestroyContext(BLAKE2BContext* ctx, PRBool freeit)
135 {
136     PORT_Memset(ctx, 0, sizeof(*ctx));
137     if (freeit) {
138         PORT_Free(ctx);
139     }
140 }
141 
142 /**
143  * This function initializes blake2b ctx and can be used for both keyed and
144  * unkeyed version. It also checks ctx and sets error states.
145  */
146 static SECStatus
blake2b_Begin(BLAKE2BContext * ctx,uint8_t outlen,const uint8_t * key,size_t keylen)147 blake2b_Begin(BLAKE2BContext* ctx, uint8_t outlen, const uint8_t* key,
148               size_t keylen)
149 {
150     PORT_Assert(ctx != NULL);
151     if (!ctx) {
152         goto failure;
153     }
154     if (outlen == 0 || outlen > BLAKE2B512_LENGTH) {
155         goto failure;
156     }
157     if (key && keylen > BLAKE2B_KEY_SIZE) {
158         goto failure;
159     }
160     /* Note: key can be null if it's unkeyed. */
161     if ((key == NULL && keylen > 0) || keylen > BLAKE2B_KEY_SIZE ||
162         (key != NULL && keylen == 0)) {
163         goto failure;
164     }
165 
166     /* Mix key size(keylen) and desired hash length(outlen) into h0 */
167     uint64_t param = outlen ^ (keylen << 8) ^ (1 << 16) ^ (1 << 24);
168     PORT_Memcpy(ctx->h, iv, 8 * 8);
169     ctx->h[0] ^= param;
170     ctx->outlen = outlen;
171 
172     /* This updates the context for only the keyed version */
173     if (keylen > 0 && keylen <= BLAKE2B_KEY_SIZE && key) {
174         uint8_t block[BLAKE2B_BLOCK_LENGTH] = { 0 };
175         PORT_Memcpy(block, key, keylen);
176         BLAKE2B_Update(ctx, block, BLAKE2B_BLOCK_LENGTH);
177         PORT_Memset(block, 0, BLAKE2B_BLOCK_LENGTH);
178     }
179 
180     return SECSuccess;
181 
182 failure:
183     PORT_Memset(&ctx, 0, sizeof(ctx));
184     PORT_SetError(SEC_ERROR_INVALID_ARGS);
185     return SECFailure;
186 }
187 
188 SECStatus
BLAKE2B_Begin(BLAKE2BContext * ctx)189 BLAKE2B_Begin(BLAKE2BContext* ctx)
190 {
191     return blake2b_Begin(ctx, BLAKE2B512_LENGTH, NULL, 0);
192 }
193 
194 SECStatus
BLAKE2B_MAC_Begin(BLAKE2BContext * ctx,const PRUint8 * key,const size_t keylen)195 BLAKE2B_MAC_Begin(BLAKE2BContext* ctx, const PRUint8* key, const size_t keylen)
196 {
197     PORT_Assert(key != NULL);
198     if (!key) {
199         PORT_SetError(SEC_ERROR_INVALID_ARGS);
200         return SECFailure;
201     }
202     return blake2b_Begin(ctx, BLAKE2B512_LENGTH, (const uint8_t*)key, keylen);
203 }
204 
205 static void
blake2b_IncrementCompress(BLAKE2BContext * ctx,size_t blockLength,const unsigned char * input)206 blake2b_IncrementCompress(BLAKE2BContext* ctx, size_t blockLength,
207                           const unsigned char* input)
208 {
209     blake2b_IncrementCounter(ctx, blockLength);
210     blake2b_Compress(ctx, input);
211 }
212 
213 /**
214  * This function updates blake2b ctx and can be used for both keyed and unkeyed
215  * version.
216  */
217 SECStatus
BLAKE2B_Update(BLAKE2BContext * ctx,const unsigned char * in,unsigned int inlen)218 BLAKE2B_Update(BLAKE2BContext* ctx, const unsigned char* in,
219                unsigned int inlen)
220 {
221     size_t left = ctx->buflen;
222     size_t fill = BLAKE2B_BLOCK_LENGTH - left;
223 
224     /* Nothing to do if there's nothing. */
225     if (inlen == 0) {
226         return SECSuccess;
227     }
228 
229     PORT_Assert(ctx != NULL);
230     PORT_Assert(in != NULL);
231     PORT_Assert(left <= BLAKE2B_BLOCK_LENGTH);
232     if (!ctx || !in) {
233         PORT_SetError(SEC_ERROR_INVALID_ARGS);
234         return SECFailure;
235     }
236 
237     /* Is this a reused context? */
238     if (ctx->f) {
239         PORT_SetError(SEC_ERROR_INVALID_ARGS);
240         return SECFailure;
241     }
242 
243     if (inlen > fill) {
244         if (ctx->buflen) {
245             /* There's some remaining data in ctx->buf that we have to prepend
246              * to in. */
247             PORT_Memcpy(ctx->buf + left, in, fill);
248             ctx->buflen = 0;
249             blake2b_IncrementCompress(ctx, BLAKE2B_BLOCK_LENGTH, ctx->buf);
250             in += fill;
251             inlen -= fill;
252         }
253         while (inlen > BLAKE2B_BLOCK_LENGTH) {
254             blake2b_IncrementCompress(ctx, BLAKE2B_BLOCK_LENGTH, in);
255             in += BLAKE2B_BLOCK_LENGTH;
256             inlen -= BLAKE2B_BLOCK_LENGTH;
257         }
258     }
259 
260     /* Store the remaining data from in in ctx->buf to process later.
261      * Note that ctx->buflen can be BLAKE2B_BLOCK_LENGTH. We can't process that
262      * here because we have to update ctx->f before compressing the last block.
263      */
264     PORT_Assert(inlen <= BLAKE2B_BLOCK_LENGTH);
265     PORT_Memcpy(ctx->buf + ctx->buflen, in, inlen);
266     ctx->buflen += inlen;
267 
268     return SECSuccess;
269 }
270 
271 /**
272  * This function finalizes ctx, pads final block and stores hash.
273  * It can be used for both keyed and unkeyed version.
274  */
275 SECStatus
BLAKE2B_End(BLAKE2BContext * ctx,unsigned char * out,unsigned int * digestLen,size_t maxDigestLen)276 BLAKE2B_End(BLAKE2BContext* ctx, unsigned char* out,
277             unsigned int* digestLen, size_t maxDigestLen)
278 {
279     size_t i;
280     unsigned int outlen = PR_MIN(BLAKE2B512_LENGTH, maxDigestLen);
281 
282     /* Argument checks */
283     if (!ctx || !out) {
284         PORT_SetError(SEC_ERROR_INVALID_ARGS);
285         return SECFailure;
286     }
287 
288     /* Sanity check against outlen in context. */
289     if (ctx->outlen < outlen) {
290         PORT_SetError(SEC_ERROR_INVALID_ARGS);
291         return SECFailure;
292     }
293 
294     /* Is this a reused context? */
295     if (ctx->f != 0) {
296         PORT_SetError(SEC_ERROR_INVALID_ARGS);
297         return SECFailure;
298     }
299 
300     /* Process the remaining data from ctx->buf (padded with 0). */
301     blake2b_IncrementCounter(ctx, ctx->buflen);
302     /* BLAKE2B_BLOCK_LENGTH - ctx->buflen can be 0. */
303     PORT_Memset(ctx->buf + ctx->buflen, 0, BLAKE2B_BLOCK_LENGTH - ctx->buflen);
304     ctx->f = UINT64_MAX;
305     blake2b_Compress(ctx, ctx->buf);
306 
307     /* Write out the blake2b context(ctx). */
308     for (i = 0; i < outlen; ++i) {
309         out[i] = ctx->h[i / 8] >> ((i % 8) * 8);
310     }
311 
312     if (digestLen) {
313         *digestLen = outlen;
314     }
315 
316     return SECSuccess;
317 }
318 
319 SECStatus
blake2b_HashBuf(uint8_t * output,const uint8_t * input,uint8_t outlen,size_t inlen,const uint8_t * key,size_t keylen)320 blake2b_HashBuf(uint8_t* output, const uint8_t* input, uint8_t outlen,
321                 size_t inlen, const uint8_t* key, size_t keylen)
322 {
323     SECStatus rv = SECFailure;
324     BLAKE2BContext ctx = { { 0 } };
325 
326     if (inlen != 0) {
327         PORT_Assert(input != NULL);
328         if (input == NULL) {
329             PORT_SetError(SEC_ERROR_INVALID_ARGS);
330             goto done;
331         }
332     }
333 
334     PORT_Assert(output != NULL);
335     if (output == NULL) {
336         PORT_SetError(SEC_ERROR_INVALID_ARGS);
337         goto done;
338     }
339 
340     if (blake2b_Begin(&ctx, outlen, key, keylen) != SECSuccess) {
341         goto done;
342     }
343 
344     if (BLAKE2B_Update(&ctx, input, inlen) != SECSuccess) {
345         goto done;
346     }
347 
348     if (BLAKE2B_End(&ctx, output, NULL, outlen) != SECSuccess) {
349         goto done;
350     }
351     rv = SECSuccess;
352 
353 done:
354     PORT_Memset(&ctx, 0, sizeof ctx);
355     return rv;
356 }
357 
358 SECStatus
BLAKE2B_Hash(unsigned char * dest,const char * src)359 BLAKE2B_Hash(unsigned char* dest, const char* src)
360 {
361     return blake2b_HashBuf(dest, (const unsigned char*)src, BLAKE2B512_LENGTH,
362                            PORT_Strlen(src), NULL, 0);
363 }
364 
365 SECStatus
BLAKE2B_HashBuf(unsigned char * output,const unsigned char * input,PRUint32 inlen)366 BLAKE2B_HashBuf(unsigned char* output, const unsigned char* input, PRUint32 inlen)
367 {
368     return blake2b_HashBuf(output, input, BLAKE2B512_LENGTH, inlen, NULL, 0);
369 }
370 
371 SECStatus
BLAKE2B_MAC_HashBuf(unsigned char * output,const unsigned char * input,unsigned int inlen,const unsigned char * key,unsigned int keylen)372 BLAKE2B_MAC_HashBuf(unsigned char* output, const unsigned char* input,
373                     unsigned int inlen, const unsigned char* key,
374                     unsigned int keylen)
375 {
376     PORT_Assert(key != NULL);
377     if (!key && keylen <= BLAKE2B_KEY_SIZE) {
378         PORT_SetError(SEC_ERROR_INVALID_ARGS);
379         return SECFailure;
380     }
381     return blake2b_HashBuf(output, input, BLAKE2B512_LENGTH, inlen, key, keylen);
382 }
383 
384 unsigned int
BLAKE2B_FlattenSize(BLAKE2BContext * ctx)385 BLAKE2B_FlattenSize(BLAKE2BContext* ctx)
386 {
387     return sizeof(BLAKE2BContext);
388 }
389 
390 SECStatus
BLAKE2B_Flatten(BLAKE2BContext * ctx,unsigned char * space)391 BLAKE2B_Flatten(BLAKE2BContext* ctx, unsigned char* space)
392 {
393     PORT_Assert(space != NULL);
394     if (!space) {
395         PORT_SetError(SEC_ERROR_INVALID_ARGS);
396         return SECFailure;
397     }
398     PORT_Memcpy(space, ctx, sizeof(BLAKE2BContext));
399     return SECSuccess;
400 }
401 
402 BLAKE2BContext*
BLAKE2B_Resurrect(unsigned char * space,void * arg)403 BLAKE2B_Resurrect(unsigned char* space, void* arg)
404 {
405     PORT_Assert(space != NULL);
406     if (!space) {
407         PORT_SetError(SEC_ERROR_INVALID_ARGS);
408         return NULL;
409     }
410     BLAKE2BContext* ctx = BLAKE2B_NewContext();
411     if (ctx == NULL) {
412         PORT_SetError(SEC_ERROR_INVALID_ARGS);
413         return NULL;
414     }
415 
416     PORT_Memcpy(ctx, space, sizeof(BLAKE2BContext));
417     return ctx;
418 }
419 
420 void
BLAKE2B_Clone(BLAKE2BContext * dest,BLAKE2BContext * src)421 BLAKE2B_Clone(BLAKE2BContext* dest, BLAKE2BContext* src)
422 {
423     PORT_Assert(dest != NULL);
424     PORT_Assert(src != NULL);
425     if (!dest || !src) {
426         PORT_SetError(SEC_ERROR_INVALID_ARGS);
427         return;
428     }
429     PORT_Memcpy(dest, src, sizeof(BLAKE2BContext));
430 }
431