| 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 |  | 
|---|
| 47 | namespace Poco { | 
|---|
| 48 | static 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 |  | 
|---|
| 63 | static 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 |  | 
|---|
| 82 | static 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 |  | 
|---|
| 95 | static 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 |  | 
|---|
| 106 | static 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 |  | 
|---|
| 119 | static 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 |  | 
|---|
| 136 | static 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 |  | 
|---|
| 147 | static 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 |  | 
|---|
| 158 | static BLAKE2_INLINE uint32_t rotr32(const uint32_t w, const unsigned c) | 
|---|
| 159 | { | 
|---|
| 160 | return (w >> c) | (w << (32 - c)); | 
|---|
| 161 | } | 
|---|
| 162 |  | 
|---|
| 163 | static 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 |  | 
|---|
| 174 | static const uint64_t blake2b_IV[8] = | 
|---|
| 175 | { | 
|---|
| 176 | 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, | 
|---|
| 177 | 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL, | 
|---|
| 178 | 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, | 
|---|
| 179 | 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL | 
|---|
| 180 | }; | 
|---|
| 181 |  | 
|---|
| 182 | static 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 |  | 
|---|
| 198 | typedef 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 |  | 
|---|
| 209 | BLAKE2_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 |  | 
|---|
| 225 | typedef 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 |  | 
|---|
| 251 | static 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 |  | 
|---|
| 292 | BLAKE2Engine::BLAKE2Engine(ALGORITHM algorithm): _context(NULL), | 
|---|
| 293 | _algorithm(algorithm) | 
|---|
| 294 | { | 
|---|
| 295 | _digest.reserve(digestLength()); | 
|---|
| 296 | reset(); | 
|---|
| 297 | } | 
|---|
| 298 |  | 
|---|
| 299 | BLAKE2Engine::~BLAKE2Engine() | 
|---|
| 300 | { | 
|---|
| 301 | reset(); | 
|---|
| 302 | free(_context); | 
|---|
| 303 | } | 
|---|
| 304 |  | 
|---|
| 305 | void 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 |  | 
|---|
| 333 | std::size_t BLAKE2Engine::digestLength() const | 
|---|
| 334 | { | 
|---|
| 335 | return (size_t)((int)_algorithm / 8); | 
|---|
| 336 | } | 
|---|
| 337 |  | 
|---|
| 338 | void 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 |  | 
|---|
| 365 | const 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 |  | 
|---|