Embedded SDK
Embedded SDK
Loading...
Searching...
No Matches
cx_blake2b.c
Go to the documentation of this file.
1
2
3/*******************************************************************************
4 * Ledger Nano S - Secure firmware
5 * (c) 2022 Ledger
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 ********************************************************************************/
19
20#ifdef HAVE_BLAKE2
21
22#include "cx_blake2.h"
23#include "cx_utils.h"
24#include "cx_ram.h"
25
26#include <string.h>
27
28#ifdef ARCH_LITTLE_ENDIAN
29#ifndef NATIVE_LITTLE_ENDIAN
30#define NATIVE_LITTLE_ENDIAN
31#endif
32#endif
33
34const cx_hash_info_t cx_blake2b_info
35 = {CX_BLAKE2B,
36 0,
37 BLAKE2B_BLOCKBYTES,
38 sizeof(cx_blake2b_t),
39 NULL,
40 (cx_err_t(*)(cx_hash_t * ctx, const uint8_t *data, size_t len)) cx_blake2b_update,
41 (cx_err_t(*)(cx_hash_t * ctx, uint8_t *digest)) cx_blake2b_final,
42 (cx_err_t(*)(cx_hash_t * ctx, size_t output_size)) cx_blake2b_init_no_throw,
43 (size_t(*)(const cx_hash_t *ctx)) cx_blake2b_get_output_size};
44
45cx_err_t cx_blake2b_init_no_throw(cx_blake2b_t *hash, size_t size)
46{
47 return cx_blake2b_init2_no_throw(hash, size, NULL, 0, NULL, 0);
48}
49
50cx_err_t cx_blake2b_init2_no_throw(cx_blake2b_t *hash,
51 size_t size,
52 uint8_t *salt,
53 size_t salt_len,
54 uint8_t *perso,
55 size_t perso_len)
56{
57 if (salt == NULL && salt_len != 0) {
58 goto err;
59 }
60 if (perso == NULL && perso_len != 0) {
61 goto err;
62 }
63 if (salt_len > 16 || perso_len > 16) {
64 goto err;
65 }
66 if (size % 8 != 0 || size < 8 || size > 512) {
67 goto err;
68 }
69 memset(hash, 0, sizeof(cx_blake2b_t));
70
71 size = size / 8;
72 hash->output_size = size;
73 hash->header.info = &cx_blake2b_info;
74
75 if (blake2b_init(&hash->ctx, size, salt, salt_len, perso, perso_len) < 0) {
76 goto err;
77 }
78 return CX_OK;
79
80err:
81 return CX_INVALID_PARAMETER;
82}
83
84cx_err_t cx_blake2b_update(cx_blake2b_t *ctx, const uint8_t *data, size_t len)
85{
86 if (ctx == NULL) {
87 return CX_INVALID_PARAMETER;
88 }
89 if (data == NULL && len != 0) {
90 return CX_INVALID_PARAMETER;
91 }
92 blake2b_update(&ctx->ctx, data, len);
93 return CX_OK;
94}
95
96cx_err_t cx_blake2b_final(cx_blake2b_t *ctx, uint8_t *digest)
97{
98 (void) blake2b_final(&ctx->ctx, digest, ctx->output_size);
99 return CX_OK;
100}
101
102size_t cx_blake2b_get_output_size(const cx_blake2b_t *ctx)
103{
104 return ctx->output_size;
105}
106
107cx_err_t cx_blake2b(cx_hash_t *hash,
108 uint32_t mode,
109 const uint8_t *in,
110 size_t len,
111 uint8_t *out,
112 size_t out_len)
113{
114 size_t sz = 0;
115 blake2b_update(&((cx_blake2b_t *) hash)->ctx, in, len);
116 if (mode & CX_LAST) {
117 sz = ((cx_blake2b_t *) hash)->output_size;
118 if (out && (out_len < sz)) {
119 return INVALID_PARAMETER;
120 }
121 if ((size_t) blake2b_final(&((cx_blake2b_t *) hash)->ctx, out, out_len) != sz) {
122 return INVALID_PARAMETER;
123 }
124 }
125 return CX_OK;
126}
127
128/*
129 BLAKE2 reference source code package - reference C implementations
130
131 Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the
132 terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at
133 your option. The terms of these licenses can be found at:
134
135 - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
136 - OpenSSL license : https://www.openssl.org/source/license.html
137 - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
138
139 More information about the BLAKE2 hash function can be found at
140 https://blake2.net.
141*/
142#include <stddef.h>
143#include <string.h>
144
145/* ***
146#include "cx_blake2-impl.h"
147//inline here:
148*/
149
150#if !defined(__cplusplus) && (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L)
151#if defined(_MSC_VER)
152#define BLAKE2_INLINE __inline
153#elif defined(__GNUC__)
154#define BLAKE2_INLINE __inline__
155#else
156#define BLAKE2_INLINE
157#endif
158#else
159#define BLAKE2_INLINE inline
160#endif
161
162#if defined(BLAKE2_UNUSED)
163static BLAKE2_INLINE uint16_t load16(const void *src)
164{
165#if defined(NATIVE_LITTLE_ENDIAN)
166 uint16_t w;
167 memcpy(&w, src, sizeof w);
168 return w;
169#else
170 const uint8_t *p = (const uint8_t *) src;
171 return ((uint16_t) (p[0]) << 0) | ((uint16_t) (p[1]) << 8);
172#endif
173}
174
175static BLAKE2_INLINE void store16(void *dst, uint16_t w)
176{
177#if defined(NATIVE_LITTLE_ENDIAN)
178 memcpy(dst, &w, sizeof w);
179#else
180 uint8_t *p = (uint8_t *) dst;
181 *p++ = (uint8_t) w;
182 w >>= 8;
183 *p++ = (uint8_t) w;
184#endif
185}
186static BLAKE2_INLINE uint32_t load32(const void *src)
187{
188#if defined(NATIVE_LITTLE_ENDIAN)
189 uint32_t w;
190 memcpy(&w, src, sizeof w);
191 return w;
192#else
193 const uint8_t *p = (const uint8_t *) src;
194 return ((uint32_t) (p[0]) << 0) | ((uint32_t) (p[1]) << 8) | ((uint32_t) (p[2]) << 16)
195 | ((uint32_t) (p[3]) << 24);
196#endif
197}
198
199static BLAKE2_INLINE uint64_t load48(const void *src)
200{
201 const uint8_t *p = (const uint8_t *) src;
202 return ((uint64_t) (p[0]) << 0) | ((uint64_t) (p[1]) << 8) | ((uint64_t) (p[2]) << 16)
203 | ((uint64_t) (p[3]) << 24) | ((uint64_t) (p[4]) << 32) | ((uint64_t) (p[5]) << 40);
204}
205
206static BLAKE2_INLINE void store48(void *dst, uint64_t w)
207{
208 uint8_t *p = (uint8_t *) dst;
209 p[0] = (uint8_t) (w >> 0);
210 p[1] = (uint8_t) (w >> 8);
211 p[2] = (uint8_t) (w >> 16);
212 p[3] = (uint8_t) (w >> 24);
213 p[4] = (uint8_t) (w >> 32);
214 p[5] = (uint8_t) (w >> 40);
215}
216
217#endif
218
219static BLAKE2_INLINE void store32(void *dst, uint32_t w)
220{
221#if defined(NATIVE_LITTLE_ENDIAN)
222 memcpy(dst, &w, sizeof w);
223#else
224 uint8_t *p = (uint8_t *) dst;
225 p[0] = (uint8_t) (w >> 0);
226 p[1] = (uint8_t) (w >> 8);
227 p[2] = (uint8_t) (w >> 16);
228 p[3] = (uint8_t) (w >> 24);
229#endif
230}
231static BLAKE2_INLINE uint64_t load64(const void *src)
232{
233#if defined(NATIVE_LITTLE_ENDIAN)
234 uint64_t w;
235 memcpy(&w, src, sizeof w);
236 return w;
237#else
238 const uint8_t *p = (const uint8_t *) src;
239 return ((uint64_t) (p[0]) << 0) | ((uint64_t) (p[1]) << 8) | ((uint64_t) (p[2]) << 16)
240 | ((uint64_t) (p[3]) << 24) | ((uint64_t) (p[4]) << 32) | ((uint64_t) (p[5]) << 40)
241 | ((uint64_t) (p[6]) << 48) | ((uint64_t) (p[7]) << 56);
242#endif
243}
244
245static BLAKE2_INLINE void store64(void *dst, uint64_t w)
246{
247#if defined(NATIVE_LITTLE_ENDIAN)
248 memcpy(dst, &w, sizeof w);
249#else
250 uint8_t *p = (uint8_t *) dst;
251 p[0] = (uint8_t) (w >> 0);
252 p[1] = (uint8_t) (w >> 8);
253 p[2] = (uint8_t) (w >> 16);
254 p[3] = (uint8_t) (w >> 24);
255 p[4] = (uint8_t) (w >> 32);
256 p[5] = (uint8_t) (w >> 40);
257 p[6] = (uint8_t) (w >> 48);
258 p[7] = (uint8_t) (w >> 56);
259#endif
260}
261
262#if defined(BLAKE2_UNUSED)
263static BLAKE2_INLINE uint32_t rotr32(const uint32_t w, const unsigned c)
264{
265 return (w >> c) | (w << (32 - c));
266}
267#endif
268
269static BLAKE2_INLINE uint64_t rotr64(const uint64_t w, const unsigned c)
270{
271 return (w >> c) | (w << (64 - c));
272}
273
274/* prevents compiler optimizing out memset() */
275static BLAKE2_INLINE void secure_zero_memory(void *v, size_t n)
276{
277 memset(v, 0, n);
278}
279
280/*
281endof inline
282*** */
283
284static const uint64_t blake2b_IV[8] = {0x6a09e667f3bcc908ULL,
285 0xbb67ae8584caa73bULL,
286 0x3c6ef372fe94f82bULL,
287 0xa54ff53a5f1d36f1ULL,
288 0x510e527fade682d1ULL,
289 0x9b05688c2b3e6c1fULL,
290 0x1f83d9abfb41bd6bULL,
291 0x5be0cd19137e2179ULL};
292
293static const uint8_t blake2b_sigma[12][16] = {
294 {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
295 {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
296 {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
297 {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
298 {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13},
299 {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
300 {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11},
301 {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10},
302 {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
303 {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 },
304 {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
305 {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }
306};
307
308static void blake2b_set_lastnode(blake2b_state *S)
309{
310 S->f[1] = (uint64_t) -1;
311}
312
313/* Some helper functions, not necessarily useful */
314static int blake2b_is_lastblock(const blake2b_state *S)
315{
316 return S->f[0] != 0;
317}
318
319static void blake2b_set_lastblock(blake2b_state *S)
320{
321 if (S->last_node) {
322 blake2b_set_lastnode(S);
323 }
324
325 S->f[0] = (uint64_t) -1;
326}
327
328static void blake2b_increment_counter(blake2b_state *S, const uint64_t inc)
329{
330 S->t[0] += inc;
331 S->t[1] += (S->t[0] < inc);
332}
333
334static void blake2b_init0(blake2b_state *S)
335{
336 size_t i;
337 memset(S, 0, sizeof(blake2b_state));
338
339 for (i = 0; i < 8; ++i) {
340 S->h[i] = blake2b_IV[i];
341 }
342}
343
344/* init xors IV with input parameter block */
345int blake2b_init_param(blake2b_state *S, const blake2b_param *P)
346{
347 const uint8_t *p = (const uint8_t *) (P);
348 size_t i;
349
350 blake2b_init0(S);
351
352 /* IV XOR ParamBlock */
353 for (i = 0; i < 8; ++i) {
354 S->h[i] ^= load64(p + sizeof(S->h[i]) * i);
355 }
356
357 S->outlen = P->digest_length;
358 return 0;
359}
360
361int blake2b_init(blake2b_state *S,
362 size_t outlen,
363 uint8_t *salt,
364 size_t salt_len,
365 uint8_t *personal,
366 size_t personal_len)
367{
368 blake2b_param P[1];
369
370 if ((!outlen) || (outlen > BLAKE2B_OUTBYTES)) {
371 return CX_INVALID_PARAMETER;
372 }
373
374 P->digest_length = (uint8_t) outlen;
375 P->key_length = 0;
376 P->fanout = 1;
377 P->depth = 1;
378 store32(&P->leaf_length, 0);
379 store32(&P->node_offset, 0);
380 store32(&P->xof_length, 0);
381 P->node_depth = 0;
382 P->inner_length = 0;
383 memset(P->reserved, 0, sizeof(P->reserved));
384 memset(P->salt, 0, sizeof(P->salt));
385 memset(P->personal, 0, sizeof(P->personal));
386 if (salt) {
387 memcpy(P->salt, salt, salt_len);
388 }
389 if (personal) {
390 memcpy(P->personal, personal, personal_len);
391 }
392 return blake2b_init_param(S, P);
393}
394
395int blake2b_init_key(blake2b_state *S, size_t outlen, const void *key, size_t keylen)
396{
397 blake2b_param P[1];
398
399 if ((!outlen) || (outlen > BLAKE2B_OUTBYTES)) {
400 return -1;
401 }
402
403 if (!key || !keylen || keylen > BLAKE2B_KEYBYTES) {
404 return -1;
405 }
406
407 P->digest_length = (uint8_t) outlen;
408 P->key_length = (uint8_t) keylen;
409 P->fanout = 1;
410 P->depth = 1;
411 store32(&P->leaf_length, 0);
412 store32(&P->node_offset, 0);
413 store32(&P->xof_length, 0);
414 P->node_depth = 0;
415 P->inner_length = 0;
416 memset(P->reserved, 0, sizeof(P->reserved));
417 memset(P->salt, 0, sizeof(P->salt));
418 memset(P->personal, 0, sizeof(P->personal));
419
420 if (blake2b_init_param(S, P) < 0) {
421 return -1;
422 }
423
424 {
425// uint8_t block[BLAKE2B_BLOCKBYTES];
426#define block G_cx.blake.block1
427 memset(block, 0, BLAKE2B_BLOCKBYTES);
428 memcpy(block, key, keylen);
429 blake2b_update(S, block, BLAKE2B_BLOCKBYTES);
430 secure_zero_memory(block, BLAKE2B_BLOCKBYTES); /* Burn the key from stack */
431#undef block
432 }
433 return 0;
434}
435
436#define G(r, i, a, b, c, d) \
437 do { \
438 a = a + b + m[blake2b_sigma[r][2 * (i) + 0]]; \
439 d = rotr64(d ^ a, 32); \
440 c = c + d; \
441 b = rotr64(b ^ c, 24); \
442 a = a + b + m[blake2b_sigma[r][2 * (i) + 1]]; \
443 d = rotr64(d ^ a, 16); \
444 c = c + d; \
445 b = rotr64(b ^ c, 63); \
446 } while (0)
447
448static void blake2b_compress(blake2b_state *S, const uint8_t block[BLAKE2B_BLOCKBYTES])
449{
450/*
451uint64_t m[16];
452uint64_t v[16];
453*/
454#define m G_cx.blake.m
455#define v G_cx.blake.v
456
457 size_t i;
458
459 for (i = 0; i < 16; ++i) {
460 m[i] = load64(block + i * sizeof(m[i]));
461 }
462
463 for (i = 0; i < 8; ++i) {
464 v[i] = S->h[i];
465 }
466
467 v[8] = blake2b_IV[0];
468 v[9] = blake2b_IV[1];
469 v[10] = blake2b_IV[2];
470 v[11] = blake2b_IV[3];
471 v[12] = blake2b_IV[4] ^ S->t[0];
472 v[13] = blake2b_IV[5] ^ S->t[1];
473 v[14] = blake2b_IV[6] ^ S->f[0];
474 v[15] = blake2b_IV[7] ^ S->f[1];
475
476 for (int r = 0; r < 12; r++) {
477 for (i = 0; i < 4; i++) {
478 G(r, i, v[i], v[4 + i], v[8 + i], v[12 + i]);
479 }
480
481 for (i = 0; i < 4; i++) {
482 G(r, 4 + i, v[i], v[4 + ((i + 1) & 3)], v[8 + ((i + 2) & 3)], v[12 + ((i + 3) & 3)]);
483 }
484 }
485
486 for (i = 0; i < 8; ++i) {
487 S->h[i] = S->h[i] ^ v[i] ^ v[i + 8];
488 }
489#undef m
490#undef v
491}
492
493#undef G
494#undef ROUND
495
496void blake2b_update(blake2b_state *S, const void *pin, size_t inlen)
497{
498 const uint8_t *in = (const uint8_t *) pin;
499 if (inlen > 0) {
500 size_t left = S->buflen;
501 size_t fill = BLAKE2B_BLOCKBYTES - left;
502 if (inlen > fill) {
503 S->buflen = 0;
504 memcpy(S->buf + left, in, fill); /* Fill buffer */
505 blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES);
506 blake2b_compress(S, S->buf); /* Compress */
507 in += fill;
508 inlen -= fill;
509 while (inlen > BLAKE2B_BLOCKBYTES) {
510 blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES);
511 blake2b_compress(S, in);
512 in += BLAKE2B_BLOCKBYTES;
513 inlen -= BLAKE2B_BLOCKBYTES;
514 }
515 }
516 memcpy(S->buf + S->buflen, in, inlen);
517 S->buflen += inlen;
518 }
519}
520
521int blake2b_final(blake2b_state *S, void *out, size_t outlen)
522{
523 size_t i;
524// uint8_t buffer[BLAKE2B_OUTBYTES] = {0};
525#define buffer G_cx.blake.buffer
526 memset(buffer, 0, BLAKE2B_OUTBYTES);
527
528 if ((out != NULL) && (outlen < S->outlen)) {
529 return -1;
530 }
531
532 if (blake2b_is_lastblock(S)) {
533 return -1;
534 }
535
536 blake2b_increment_counter(S, S->buflen);
537 blake2b_set_lastblock(S);
538 memset(S->buf + S->buflen, 0, BLAKE2B_BLOCKBYTES - S->buflen); /* Padding */
539 blake2b_compress(S, S->buf);
540
541 for (i = 0; i < 8; ++i) { /* Output full hash to temp buffer */
542 store64(buffer + sizeof(S->h[i]) * i, S->h[i]);
543 }
544 memcpy(S->buf, buffer, S->outlen); //.acc destination
545 if (out) {
546 memcpy(out, buffer, S->outlen);
547 }
548 secure_zero_memory(buffer, sizeof(buffer));
549 return S->outlen;
550#undef buffer
551}
552
553/* =============================== UNUSED =============================== */
554// Following code is not used
555#if defined(BLAKE2_UNUSED)
556/* inlen, at least, should be uint64_t. Others can be size_t. */
557int blake2b(void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen)
558{
559 blake2b_state S[1];
560
561 /* Verify parameters */
562 if (NULL == in && inlen > 0) {
563 return -1;
564 }
565
566 if (NULL == out) {
567 return -1;
568 }
569
570 if (NULL == key && keylen > 0) {
571 return -1;
572 }
573
574 if (!outlen || outlen > BLAKE2B_OUTBYTES) {
575 return -1;
576 }
577
578 if (keylen > BLAKE2B_KEYBYTES) {
579 return -1;
580 }
581
582 if (keylen > 0) {
583 if (blake2b_init_key(S, outlen, key, keylen) < 0) {
584 return -1;
585 }
586 }
587 else {
588 if (blake2b_init(S, outlen) < 0) {
589 return -1;
590 }
591 }
592
593 blake2b_update(S, (const uint8_t *) in, inlen);
594 return blake2b_final(S, out, outlen);
595}
596
597int blake2(void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen)
598{
599 return blake2b(out, outlen, in, inlen, key, keylen);
600}
601
602#if defined(BLAKE2B_SELFTEST)
603#include <string.h>
604#include "blake2-kat.h"
605int main(void)
606{
607 uint8_t key[BLAKE2B_KEYBYTES];
608 uint8_t buf[BLAKE2_KAT_LENGTH];
609 size_t i, step;
610
611 for (i = 0; i < BLAKE2B_KEYBYTES; ++i) {
612 key[i] = (uint8_t) i;
613 }
614
615 for (i = 0; i < BLAKE2_KAT_LENGTH; ++i) {
616 buf[i] = (uint8_t) i;
617 }
618
619 /* Test simple API */
620 for (i = 0; i < BLAKE2_KAT_LENGTH; ++i) {
621 uint8_t hash[BLAKE2B_OUTBYTES];
622 blake2b(hash, BLAKE2B_OUTBYTES, buf, i, key, BLAKE2B_KEYBYTES);
623
624 if (0 != memcmp(hash, blake2b_keyed_kat[i], BLAKE2B_OUTBYTES)) {
625 goto fail;
626 }
627 }
628
629 /* Test streaming API */
630 for (step = 1; step < BLAKE2B_BLOCKBYTES; ++step) {
631 for (i = 0; i < BLAKE2_KAT_LENGTH; ++i) {
632 uint8_t hash[BLAKE2B_OUTBYTES];
633 blake2b_state S;
634 uint8_t *p = buf;
635 size_t mlen = i;
636 int err = 0;
637
638 if ((err = blake2b_init_key(&S, BLAKE2B_OUTBYTES, key, BLAKE2B_KEYBYTES)) < 0) {
639 goto fail;
640 }
641
642 while (mlen >= step) {
643 blake2b_update(&S, p, step);
644 mlen -= step;
645 p += step;
646 }
647 blake2b_update(&S, p, mlen);
648 if ((err = blake2b_final(&S, hash, BLAKE2B_OUTBYTES)) < 0) {
649 goto fail;
650 }
651
652 if (0 != memcmp(hash, blake2b_keyed_kat[i], BLAKE2B_OUTBYTES)) {
653 goto fail;
654 }
655 }
656 }
657
658 puts("ok");
659 return 0;
660fail:
661 puts("error");
662 return -1;
663}
664#endif
665
666#endif // BLAKE2_UNUSED
667
668#endif // HAVE_BLAKE2
#define CX_LAST
Definition lcx_common.h:115