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 if (!ctx) {
151 goto failure_noclean;
152 }
153 if (outlen == 0 || outlen > BLAKE2B512_LENGTH) {
154 goto failure;
155 }
156 if (key && keylen > BLAKE2B_KEY_SIZE) {
157 goto failure;
158 }
159 /* Note: key can be null if it's unkeyed. */
160 if ((key == NULL && keylen > 0) || keylen > BLAKE2B_KEY_SIZE ||
161 (key != NULL && keylen == 0)) {
162 goto failure;
163 }
164
165 /* Mix key size(keylen) and desired hash length(outlen) into h0 */
166 uint64_t param = outlen ^ (keylen << 8) ^ (1 << 16) ^ (1 << 24);
167 PORT_Memcpy(ctx->h, iv, 8 * 8);
168 ctx->h[0] ^= param;
169 ctx->outlen = outlen;
170
171 /* This updates the context for only the keyed version */
172 if (keylen > 0 && keylen <= BLAKE2B_KEY_SIZE && key) {
173 uint8_t block[BLAKE2B_BLOCK_LENGTH] = { 0 };
174 PORT_Memcpy(block, key, keylen);
175 BLAKE2B_Update(ctx, block, BLAKE2B_BLOCK_LENGTH);
176 PORT_Memset(block, 0, BLAKE2B_BLOCK_LENGTH);
177 }
178
179 return SECSuccess;
180
181 failure:
182 PORT_Memset(ctx, 0, sizeof(*ctx));
183 failure_noclean:
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 /* Nothing to do if there's nothing. */
222 if (inlen == 0) {
223 return SECSuccess;
224 }
225
226 if (!ctx || !in) {
227 PORT_SetError(SEC_ERROR_INVALID_ARGS);
228 return SECFailure;
229 }
230
231 /* Is this a reused context? */
232 if (ctx->f) {
233 PORT_SetError(SEC_ERROR_INVALID_ARGS);
234 return SECFailure;
235 }
236
237 size_t left = ctx->buflen;
238 PORT_Assert(left <= BLAKE2B_BLOCK_LENGTH);
239 size_t fill = BLAKE2B_BLOCK_LENGTH - left;
240
241 if (inlen > fill) {
242 if (ctx->buflen) {
243 /* There's some remaining data in ctx->buf that we have to prepend
244 * to in. */
245 PORT_Memcpy(ctx->buf + left, in, fill);
246 ctx->buflen = 0;
247 blake2b_IncrementCompress(ctx, BLAKE2B_BLOCK_LENGTH, ctx->buf);
248 in += fill;
249 inlen -= fill;
250 }
251 while (inlen > BLAKE2B_BLOCK_LENGTH) {
252 blake2b_IncrementCompress(ctx, BLAKE2B_BLOCK_LENGTH, in);
253 in += BLAKE2B_BLOCK_LENGTH;
254 inlen -= BLAKE2B_BLOCK_LENGTH;
255 }
256 }
257
258 /* Store the remaining data from in in ctx->buf to process later.
259 * Note that ctx->buflen can be BLAKE2B_BLOCK_LENGTH. We can't process that
260 * here because we have to update ctx->f before compressing the last block.
261 */
262 PORT_Assert(inlen <= BLAKE2B_BLOCK_LENGTH);
263 PORT_Memcpy(ctx->buf + ctx->buflen, in, inlen);
264 ctx->buflen += inlen;
265
266 return SECSuccess;
267 }
268
269 /**
270 * This function finalizes ctx, pads final block and stores hash.
271 * It can be used for both keyed and unkeyed version.
272 */
273 SECStatus
BLAKE2B_End(BLAKE2BContext * ctx,unsigned char * out,unsigned int * digestLen,size_t maxDigestLen)274 BLAKE2B_End(BLAKE2BContext* ctx, unsigned char* out,
275 unsigned int* digestLen, size_t maxDigestLen)
276 {
277 size_t i;
278 unsigned int outlen = PR_MIN(BLAKE2B512_LENGTH, maxDigestLen);
279
280 /* Argument checks */
281 if (!ctx || !out) {
282 PORT_SetError(SEC_ERROR_INVALID_ARGS);
283 return SECFailure;
284 }
285
286 /* Sanity check against outlen in context. */
287 if (ctx->outlen < outlen) {
288 PORT_SetError(SEC_ERROR_INVALID_ARGS);
289 return SECFailure;
290 }
291
292 /* Is this a reused context? */
293 if (ctx->f != 0) {
294 PORT_SetError(SEC_ERROR_INVALID_ARGS);
295 return SECFailure;
296 }
297
298 /* Process the remaining data from ctx->buf (padded with 0). */
299 blake2b_IncrementCounter(ctx, ctx->buflen);
300 /* BLAKE2B_BLOCK_LENGTH - ctx->buflen can be 0. */
301 PORT_Memset(ctx->buf + ctx->buflen, 0, BLAKE2B_BLOCK_LENGTH - ctx->buflen);
302 ctx->f = UINT64_MAX;
303 blake2b_Compress(ctx, ctx->buf);
304
305 /* Write out the blake2b context(ctx). */
306 for (i = 0; i < outlen; ++i) {
307 out[i] = ctx->h[i / 8] >> ((i % 8) * 8);
308 }
309
310 if (digestLen) {
311 *digestLen = outlen;
312 }
313
314 return SECSuccess;
315 }
316
317 SECStatus
blake2b_HashBuf(uint8_t * output,const uint8_t * input,uint8_t outlen,size_t inlen,const uint8_t * key,size_t keylen)318 blake2b_HashBuf(uint8_t* output, const uint8_t* input, uint8_t outlen,
319 size_t inlen, const uint8_t* key, size_t keylen)
320 {
321 SECStatus rv = SECFailure;
322 BLAKE2BContext ctx = { { 0 } };
323
324 if (inlen != 0) {
325 PORT_Assert(input != NULL);
326 if (input == NULL) {
327 PORT_SetError(SEC_ERROR_INVALID_ARGS);
328 goto done;
329 }
330 }
331
332 PORT_Assert(output != NULL);
333 if (output == NULL) {
334 PORT_SetError(SEC_ERROR_INVALID_ARGS);
335 goto done;
336 }
337
338 if (blake2b_Begin(&ctx, outlen, key, keylen) != SECSuccess) {
339 goto done;
340 }
341
342 if (BLAKE2B_Update(&ctx, input, inlen) != SECSuccess) {
343 goto done;
344 }
345
346 if (BLAKE2B_End(&ctx, output, NULL, outlen) != SECSuccess) {
347 goto done;
348 }
349 rv = SECSuccess;
350
351 done:
352 PORT_Memset(&ctx, 0, sizeof ctx);
353 return rv;
354 }
355
356 SECStatus
BLAKE2B_Hash(unsigned char * dest,const char * src)357 BLAKE2B_Hash(unsigned char* dest, const char* src)
358 {
359 return blake2b_HashBuf(dest, (const unsigned char*)src, BLAKE2B512_LENGTH,
360 PORT_Strlen(src), NULL, 0);
361 }
362
363 SECStatus
BLAKE2B_HashBuf(unsigned char * output,const unsigned char * input,PRUint32 inlen)364 BLAKE2B_HashBuf(unsigned char* output, const unsigned char* input, PRUint32 inlen)
365 {
366 return blake2b_HashBuf(output, input, BLAKE2B512_LENGTH, inlen, NULL, 0);
367 }
368
369 SECStatus
BLAKE2B_MAC_HashBuf(unsigned char * output,const unsigned char * input,unsigned int inlen,const unsigned char * key,unsigned int keylen)370 BLAKE2B_MAC_HashBuf(unsigned char* output, const unsigned char* input,
371 unsigned int inlen, const unsigned char* key,
372 unsigned int keylen)
373 {
374 PORT_Assert(key != NULL);
375 if (!key && keylen <= BLAKE2B_KEY_SIZE) {
376 PORT_SetError(SEC_ERROR_INVALID_ARGS);
377 return SECFailure;
378 }
379 return blake2b_HashBuf(output, input, BLAKE2B512_LENGTH, inlen, key, keylen);
380 }
381
382 unsigned int
BLAKE2B_FlattenSize(BLAKE2BContext * ctx)383 BLAKE2B_FlattenSize(BLAKE2BContext* ctx)
384 {
385 return sizeof(BLAKE2BContext);
386 }
387
388 SECStatus
BLAKE2B_Flatten(BLAKE2BContext * ctx,unsigned char * space)389 BLAKE2B_Flatten(BLAKE2BContext* ctx, unsigned char* space)
390 {
391 PORT_Assert(space != NULL);
392 if (!space) {
393 PORT_SetError(SEC_ERROR_INVALID_ARGS);
394 return SECFailure;
395 }
396 PORT_Memcpy(space, ctx, sizeof(BLAKE2BContext));
397 return SECSuccess;
398 }
399
400 BLAKE2BContext*
BLAKE2B_Resurrect(unsigned char * space,void * arg)401 BLAKE2B_Resurrect(unsigned char* space, void* arg)
402 {
403 PORT_Assert(space != NULL);
404 if (!space) {
405 PORT_SetError(SEC_ERROR_INVALID_ARGS);
406 return NULL;
407 }
408 BLAKE2BContext* ctx = BLAKE2B_NewContext();
409 if (ctx == NULL) {
410 PORT_SetError(SEC_ERROR_INVALID_ARGS);
411 return NULL;
412 }
413
414 PORT_Memcpy(ctx, space, sizeof(BLAKE2BContext));
415 return ctx;
416 }
417
418 void
BLAKE2B_Clone(BLAKE2BContext * dest,BLAKE2BContext * src)419 BLAKE2B_Clone(BLAKE2BContext* dest, BLAKE2BContext* src)
420 {
421 PORT_Assert(dest != NULL);
422 PORT_Assert(src != NULL);
423 if (!dest || !src) {
424 PORT_SetError(SEC_ERROR_INVALID_ARGS);
425 return;
426 }
427 PORT_Memcpy(dest, src, sizeof(BLAKE2BContext));
428 }
429