1//
2// BLAKE2Engine.cpp
3//
4// Library: Foundation
5// Package: Crypt
6// Module: BLAKE2Engine
7//
8// Code of class BLAKE2Engine.
9//
10// This class implements the BLAKE2 hashing algorithm.
11// (RFC 7693, see https://tools.ietf.org/html/rfc7693)
12//
13// Based on the BLAKE2 reference implementation (CC0, OpenSSL or Apache 2.0)
14// http://creativecommons.org/publicdomain/zero/1.0
15// https://www.openssl.org/source/license.html
16// http://www.apache.org/licenses/LICENSE-2.0
17//
18// Copyright (c) 2017, Applied Informatics Software Engineering GmbH
19// and Contributors.
20//
21// SPDX-License-Identifier: BSL-1.0
22//
23
24#include "Poco/BLAKE2Engine.h"
25
26#include <stdint.h>
27#include <string.h>
28#include <stdio.h>
29
30#if defined(_MSC_VER)
31#define BLAKE2_PACKED(x) __pragma(pack(push, 1)) x __pragma(pack(pop))
32#else
33#define BLAKE2_PACKED(x) x __attribute__((packed))
34#endif
35#if !defined(__cplusplus) && (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L)
36#if defined(_MSC_VER)
37#define BLAKE2_INLINE __inline
38#elif defined(__GNUC__)
39#define BLAKE2_INLINE __inline__
40#else
41#define BLAKE2_INLINE
42#endif
43#else
44#define BLAKE2_INLINE inline
45#endif
46
47namespace Poco {
48static BLAKE2_INLINE uint32_t load32(const void *src)
49{
50#if defined(POCO_ARCH_LITTLE_ENDIAN)
51 uint32_t w;
52 memcpy(&w, src, sizeof w);
53 return w;
54#else
55 const uint8_t *p = (const uint8_t *)src;
56 return ((uint32_t)(p[0]) << 0) |
57 ((uint32_t)(p[1]) << 8) |
58 ((uint32_t)(p[2]) << 16) |
59 ((uint32_t)(p[3]) << 24);
60#endif
61}
62
63static BLAKE2_INLINE uint64_t load64(const void *src)
64{
65#if defined(POCO_ARCH_LITTLE_ENDIAN)
66 uint64_t w;
67 memcpy(&w, src, sizeof w);
68 return w;
69#else
70 const uint8_t *p = (const uint8_t *)src;
71 return ((uint64_t)(p[0]) << 0) |
72 ((uint64_t)(p[1]) << 8) |
73 ((uint64_t)(p[2]) << 16) |
74 ((uint64_t)(p[3]) << 24) |
75 ((uint64_t)(p[4]) << 32) |
76 ((uint64_t)(p[5]) << 40) |
77 ((uint64_t)(p[6]) << 48) |
78 ((uint64_t)(p[7]) << 56);
79#endif
80}
81
82static BLAKE2_INLINE uint16_t load16(const void *src)
83{
84#if defined(POCO_ARCH_LITTLE_ENDIAN)
85 uint16_t w;
86 memcpy(&w, src, sizeof w);
87 return w;
88#else
89 const uint8_t *p = (const uint8_t *)src;
90 return ((uint16_t)(p[0]) << 0) |
91 ((uint16_t)(p[1]) << 8);
92#endif
93}
94
95static BLAKE2_INLINE void store16(void *dst, uint16_t w)
96{
97#if defined(POCO_ARCH_LITTLE_ENDIAN)
98 memcpy(dst, &w, sizeof w);
99#else
100 uint8_t *p = (uint8_t *)dst;
101 *p++ = (uint8_t)w; w >>= 8;
102 *p++ = (uint8_t)w;
103#endif
104}
105
106static BLAKE2_INLINE void store32(void *dst, uint32_t w)
107{
108#if defined(POCO_ARCH_LITTLE_ENDIAN)
109 memcpy(dst, &w, sizeof w);
110#else
111 uint8_t *p = (uint8_t *)dst;
112 p[0] = (uint8_t)(w >> 0);
113 p[1] = (uint8_t)(w >> 8);
114 p[2] = (uint8_t)(w >> 16);
115 p[3] = (uint8_t)(w >> 24);
116#endif
117}
118
119static BLAKE2_INLINE void store64(void *dst, uint64_t w)
120{
121#if defined(POCO_ARCH_LITTLE_ENDIAN)
122 memcpy(dst, &w, sizeof w);
123#else
124 uint8_t *p = (uint8_t *)dst;
125 p[0] = (uint8_t)(w >> 0);
126 p[1] = (uint8_t)(w >> 8);
127 p[2] = (uint8_t)(w >> 16);
128 p[3] = (uint8_t)(w >> 24);
129 p[4] = (uint8_t)(w >> 32);
130 p[5] = (uint8_t)(w >> 40);
131 p[6] = (uint8_t)(w >> 48);
132 p[7] = (uint8_t)(w >> 56);
133#endif
134}
135
136static BLAKE2_INLINE uint64_t load48(const void *src)
137{
138 const uint8_t *p = (const uint8_t *)src;
139 return ((uint64_t)(p[0]) << 0) |
140 ((uint64_t)(p[1]) << 8) |
141 ((uint64_t)(p[2]) << 16) |
142 ((uint64_t)(p[3]) << 24) |
143 ((uint64_t)(p[4]) << 32) |
144 ((uint64_t)(p[5]) << 40);
145}
146
147static BLAKE2_INLINE void store48(void *dst, uint64_t w)
148{
149 uint8_t *p = (uint8_t *)dst;
150 p[0] = (uint8_t)(w >> 0);
151 p[1] = (uint8_t)(w >> 8);
152 p[2] = (uint8_t)(w >> 16);
153 p[3] = (uint8_t)(w >> 24);
154 p[4] = (uint8_t)(w >> 32);
155 p[5] = (uint8_t)(w >> 40);
156}
157
158static BLAKE2_INLINE uint32_t rotr32(const uint32_t w, const unsigned c)
159{
160 return (w >> c) | (w << (32 - c));
161}
162
163static BLAKE2_INLINE uint64_t rotr64(const uint64_t w, const unsigned c)
164{
165 return (w >> c) | (w << (64 - c));
166}
167
168#define BLAKE2B_BLOCKBYTES 128
169#define BLAKE2B_OUTBYTES 64
170#define BLAKE2B_KEYBYTES 64
171#define BLAKE2B_SALTBYTES 16
172#define BLAKE2B_PERSONALBYTES 16
173
174static const uint64_t blake2b_IV[8] =
175{
176 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL,
177 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL,
178 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL,
179 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL
180};
181
182static const uint8_t blake2b_sigma[12][16] =
183{
184 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
185 { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
186 { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
187 { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
188 { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
189 { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
190 { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
191 { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
192 { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
193 { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 },
194 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
195 { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }
196};
197
198typedef struct
199{
200 uint64_t h[8];
201 uint64_t t[2];
202 uint64_t f[2];
203 uint8_t buf[BLAKE2B_BLOCKBYTES];
204 size_t buflen;
205 size_t outlen;
206 uint8_t last_node;
207} blake2b_state;
208
209BLAKE2_PACKED(struct blake2b_param__
210{
211 uint8_t digest_length; /* 1 */
212 uint8_t key_length; /* 2 */
213 uint8_t fanout; /* 3 */
214 uint8_t depth; /* 4 */
215 uint32_t leaf_length; /* 8 */
216 uint32_t node_offset; /* 12 */
217 uint32_t xof_length; /* 16 */
218 uint8_t node_depth; /* 17 */
219 uint8_t inner_length; /* 18 */
220 uint8_t reserved[14]; /* 32 */
221 uint8_t salt[BLAKE2B_SALTBYTES]; /* 48 */
222 uint8_t personal[BLAKE2B_PERSONALBYTES]; /* 64 */
223});
224
225typedef struct blake2b_param__ blake2b_param;
226
227#define G(r,i,a,b,c,d) \
228 do { \
229 a = a + b + m[blake2b_sigma[r][2*i+0]]; \
230 d = rotr64(d ^ a, 32); \
231 c = c + d; \
232 b = rotr64(b ^ c, 24); \
233 a = a + b + m[blake2b_sigma[r][2*i+1]]; \
234 d = rotr64(d ^ a, 16); \
235 c = c + d; \
236 b = rotr64(b ^ c, 63); \
237 } while(0)
238
239#define ROUND(r) \
240 do { \
241 G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \
242 G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \
243 G(r,2,v[ 2],v[ 6],v[10],v[14]); \
244 G(r,3,v[ 3],v[ 7],v[11],v[15]); \
245 G(r,4,v[ 0],v[ 5],v[10],v[15]); \
246 G(r,5,v[ 1],v[ 6],v[11],v[12]); \
247 G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \
248 G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \
249 } while(0)
250
251static void blake2b_compress(blake2b_state *S, const uint8_t block[BLAKE2B_BLOCKBYTES])
252{
253 uint64_t m[16];
254 uint64_t v[16];
255 size_t i;
256
257 for (i = 0; i < 16; ++i) {
258 m[i] = load64(block + i * sizeof(m[i]));
259 }
260
261 for (i = 0; i < 8; ++i) {
262 v[i] = S->h[i];
263 }
264
265 v[8] = blake2b_IV[0];
266 v[9] = blake2b_IV[1];
267 v[10] = blake2b_IV[2];
268 v[11] = blake2b_IV[3];
269 v[12] = blake2b_IV[4] ^ S->t[0];
270 v[13] = blake2b_IV[5] ^ S->t[1];
271 v[14] = blake2b_IV[6] ^ S->f[0];
272 v[15] = blake2b_IV[7] ^ S->f[1];
273
274 ROUND(0);
275 ROUND(1);
276 ROUND(2);
277 ROUND(3);
278 ROUND(4);
279 ROUND(5);
280 ROUND(6);
281 ROUND(7);
282 ROUND(8);
283 ROUND(9);
284 ROUND(10);
285 ROUND(11);
286
287 for (i = 0; i < 8; ++i) {
288 S->h[i] = S->h[i] ^ v[i] ^ v[i + 8];
289 }
290}
291
292BLAKE2Engine::BLAKE2Engine(ALGORITHM algorithm): _context(NULL),
293 _algorithm(algorithm)
294{
295 _digest.reserve(digestLength());
296 reset();
297}
298
299BLAKE2Engine::~BLAKE2Engine()
300{
301 reset();
302 free(_context);
303}
304
305void BLAKE2Engine::updateImpl(const void* buffer_, std::size_t count)
306{
307 if (_context == NULL || buffer_ == NULL || count == 0) return;
308 const unsigned char * in = (const unsigned char *)buffer_;
309 blake2b_state* S = (blake2b_state*)_context;
310 size_t left = S->buflen;
311 size_t fill = BLAKE2B_BLOCKBYTES - left;
312 if (count > fill)
313 {
314 S->buflen = 0;
315 memcpy(S->buf + left, in, fill); /* Fill buffer */
316 S->t[0] += BLAKE2B_BLOCKBYTES;
317 S->t[1] += (S->t[0] < BLAKE2B_BLOCKBYTES);
318 blake2b_compress(S, S->buf); /* Compress */
319 in += fill; count -= fill;
320 while (count > BLAKE2B_BLOCKBYTES)
321 {
322 S->t[0] += BLAKE2B_BLOCKBYTES;
323 S->t[1] += (S->t[0] < BLAKE2B_BLOCKBYTES);
324 blake2b_compress(S, in);
325 in += BLAKE2B_BLOCKBYTES;
326 count -= BLAKE2B_BLOCKBYTES;
327 }
328 }
329 memcpy(S->buf + S->buflen, in, count);
330 S->buflen += count;
331}
332
333std::size_t BLAKE2Engine::digestLength() const
334{
335 return (size_t)((int)_algorithm / 8);
336}
337
338void BLAKE2Engine::reset()
339{
340 if (_context != NULL) free(_context);
341 _context = calloc(1, sizeof(blake2b_state));
342 blake2b_param P[1];
343 uint8_t outlen = (uint8_t)(_algorithm / 8);
344 if ((!outlen) || (outlen > BLAKE2B_OUTBYTES)) return;
345 P->digest_length = outlen;
346 P->key_length = 0;
347 P->fanout = 1;
348 P->depth = 1;
349 store32(&P->leaf_length, 0);
350 store32(&P->node_offset, 0);
351 store32(&P->xof_length, 0);
352 P->node_depth = 0;
353 P->inner_length = 0;
354 memset(P->reserved, 0, sizeof(P->reserved));
355 memset(P->salt, 0, sizeof(P->salt));
356 memset(P->personal, 0, sizeof(P->personal));
357 blake2b_state* S = (blake2b_state*)_context;
358 for (size_t i = 0; i < 8; ++i) S->h[i] = blake2b_IV[i];
359 const uint8_t *p = (const uint8_t *)(P);
360 for (size_t i = 0; i < 8; ++i) S->h[i] ^= load64(p + sizeof(S->h[i]) * i);
361 S->outlen = P->digest_length;
362 _digest.resize(S->outlen);
363}
364
365const DigestEngine::Digest& BLAKE2Engine::digest()
366{
367 _digest.clear();
368 if (_context == NULL) return _digest;
369 blake2b_state* S = (blake2b_state*)_context;
370 uint8_t buffer[BLAKE2B_OUTBYTES] = { 0 };
371 if (S->f[0] != 0) return _digest;
372 S->t[0] += S->buflen;
373 S->t[1] += (S->t[0] < S->buflen);
374 if (S->last_node) S->f[1] = (uint64_t)-1;
375 S->f[0] = (uint64_t)-1;
376 memset(S->buf + S->buflen, 0, BLAKE2B_BLOCKBYTES - S->buflen);
377 blake2b_compress(S, S->buf);
378 for (size_t i = 0; i < 8; ++i) store64(buffer + sizeof(S->h[i]) * i, S->h[i]);
379 _digest.insert(_digest.begin(), buffer, buffer + digestLength());
380 memset(buffer, 0, BLAKE2B_OUTBYTES);
381 reset();
382 return _digest;
383}
384
385} // namespace Poco
386