ref: 73bd0dc6529657b972cdd00b16bfe7d788d73f8c
dir: /ref/blake2xs-ref.c/
#include <stdint.h> #include <string.h> #include <stdio.h> #include "blake2.h" #include "blake2-impl.h" typedef struct blake2xs_state__ { blake2s_state S[1]; blake2s_param P[1]; } blake2xs_state; int blake2xs_init( blake2xs_state *S, const size_t outlen, const void *key, size_t keylen ) { if ( outlen == 0 || outlen > 0xFFFFUL ) { return -1; } if (key == NULL || keylen > BLAKE2S_KEYBYTES) { return -1; } /* Initialize parameter block */ S->P->digest_length = BLAKE2S_OUTBYTES; S->P->key_length = keylen; S->P->fanout = 1; S->P->depth = 1; store32( &S->P->leaf_length, 0 ); store32( &S->P->node_offset, 0 ); store16( &S->P->xof_length, outlen ); S->P->node_depth = 0; S->P->inner_length = 0; memset( S->P->salt, 0, sizeof( S->P->salt ) ); memset( S->P->personal, 0, sizeof( S->P->personal ) ); if( blake2s_init_param( S->S, S->P ) < 0 ) { return -1; } if (keylen > 0) { uint8_t block[BLAKE2S_BLOCKBYTES]; memset(block, 0, BLAKE2S_BLOCKBYTES); memcpy(block, key, keylen); blake2s_update(S->S, block, BLAKE2S_BLOCKBYTES); secure_zero_memory(block, BLAKE2S_BLOCKBYTES); } return 0; } int blake2xs_update( blake2xs_state *S, const void *in, size_t inlen ) { return blake2s_update( S->S, in, inlen ); } int blake2xs_final(blake2xs_state *S, void *out, size_t outlen) { blake2s_state C[1]; blake2s_param P[1]; uint16_t xof_length = load16(&S->P->xof_length); uint8_t root[BLAKE2S_BLOCKBYTES]; size_t i; if (out == NULL) { return -1; } /* outlen must match the output size defined in xof_length, */ /* unless it was -1, in which case anything goes except 0. */ if(xof_length == 0xFFFFUL) { if(outlen == 0) { return -1; } } else { if(outlen != xof_length) { return -1; } } /* Finalize the root hash */ if (blake2s_final(S->S, root, BLAKE2S_OUTBYTES) < 0) { return -1; } /* Set common block structure values */ /* Copy values from parent instance, and only change the ones below */ memcpy(P, S->P, sizeof(blake2s_param)); P->fanout = 0; P->depth = 0; store32(&P->leaf_length, BLAKE2S_OUTBYTES); P->inner_length = BLAKE2S_OUTBYTES; P->node_depth = 0; for (i = 0; outlen > 0; ++i) { const size_t block_size = (outlen < BLAKE2S_OUTBYTES) ? outlen : BLAKE2S_OUTBYTES; /* Initialize state */ P->digest_length = block_size; store32(&P->node_offset, i); blake2s_init_param(C, P); /* Process key if needed */ blake2s_update(C, root, BLAKE2S_OUTBYTES); blake2s_final(C, (uint8_t *)out + i * BLAKE2S_OUTBYTES, block_size); outlen -= block_size; } secure_zero_memory(root, sizeof(root)); secure_zero_memory(P, sizeof(P)); secure_zero_memory(C, sizeof(C)); /* Put blake2xs in an invalid state? cf. blake2s_is_lastblock */ return 0; } int blake2xs(void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen) { blake2xs_state S[1]; /* Verify parameters */ if (NULL == in && inlen > 0) return -1; if (NULL == out) return -1; if (NULL == key && keylen > 0) return -1; if (keylen > BLAKE2S_KEYBYTES) return -1; if (outlen == 0) return -1; /* Initialize the root block structure */ if (blake2xs_init(S, outlen, key, keylen) < 0) { return -1; } /* Absorb the input message */ if (blake2xs_update(S, in, inlen) < 0) { return -1; } /* Compute the root node of the tree and the final hash using the counter construction */ return blake2xs_final(S, out, outlen); } #if defined(BLAKE2XS_SELFTEST) #include <string.h> #include "blake2-kat.h" int main( void ) { uint8_t key[BLAKE2S_KEYBYTES]; uint8_t buf[BLAKE2_KAT_LENGTH]; for( size_t i = 0; i < BLAKE2S_KEYBYTES; ++i ) { key[i] = ( uint8_t )i; } for( size_t i = 0; i < BLAKE2_KAT_LENGTH; ++i ) { buf[i] = ( uint8_t )i; } for( size_t i = 1; i < BLAKE2_KAT_LENGTH; ++i ) { uint8_t hash[BLAKE2_KAT_LENGTH] = {0}; blake2xs( hash, i, buf, BLAKE2_KAT_LENGTH, key, BLAKE2S_KEYBYTES ); for( size_t j = 0; j < i; ++j ) { printf("%02x", hash[j]); } printf("\n"); } //puts( "ok" ); return 0; } #endif