/* =================================================================== * * Copyright (c) 2014, Legrandin * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * =================================================================== */ #include #include "common.h" #include "endianess.h" #define WORDS_IN_BLOCK 16 #define WORDS_IN_STATE 8 #define BLOCK_SIZE (WORDS_IN_BLOCK*BLAKE2_WORD_SIZE/8) typedef struct { blake2_word h[WORDS_IN_STATE]; blake2_word off_counter_low; blake2_word off_counter_high; unsigned buf_occ; uint8_t buf[BLOCK_SIZE]; } hash_state; typedef enum { NON_FINAL_BLOCK, FINAL_BLOCK } block_type; EXPORT_SYM int blake2_init (hash_state **state, const uint8_t *key, size_t key_size, size_t digest_size) { hash_state *hs; unsigned i; if (NULL == state) return ERR_NULL; if (NULL == key || key_size > MAX_KEY_BYTES) return ERR_KEY_SIZE; if (0 == digest_size || digest_size > MAX_DIGEST_BYTES) return ERR_DIGEST_SIZE; *state = hs = (hash_state*) calloc(1, sizeof(hash_state)); if (NULL == hs) return ERR_MEMORY; for (i=0; ih[i] = iv[i]; } hs->h[0] = (blake2_word)(hs->h[0] ^ 0x01010000 ^ (key_size << 8) ^ digest_size); /** If the key is present, the first block is the key padded with zeroes **/ if (key_size>0) { memcpy(hs->buf, key, key_size); hs->buf_occ = BLOCK_SIZE; } return 0; } EXPORT_SYM int blake2_destroy(hash_state *hs) { free(hs); return 0; } EXPORT_SYM int blake2_copy(const hash_state *src, hash_state *dst) { if (NULL == src || NULL == dst) { return ERR_NULL; } *dst = *src; return 0; } #define ROTR(x,n) (((x) >> (n)) ^ ((x) << (BLAKE2_WORD_SIZE - (n)))) #define G(v,a,b,c,d,x,y) \ { \ v[a] = v[a] + v[b] + x; \ v[d] = ROTR(v[d] ^ v[a], G_R1); \ v[c] = v[c] + v[d]; \ v[b] = ROTR(v[b] ^ v[c], G_R2); \ v[a] = v[a] + v[b] + y; \ v[d] = ROTR(v[d] ^ v[a], G_R3); \ v[c] = v[c] + v[d]; \ v[b] = ROTR(v[b] ^ v[c], G_R4); \ } static void blake2b_compress(blake2_word state[8], const blake2_word m[WORDS_IN_BLOCK], blake2_word off_counter_low, blake2_word off_counter_high, block_type bt ) { static const uint8_t sigma[12][16] = { { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }, { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 }, { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 }, { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 }, { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 }, { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 }, { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 }, { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 }, { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 }, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } }; blake2_word work[WORDS_IN_BLOCK]; unsigned i; for (i=0; ibuf; for (i=0; ioff_counter_low = (blake2_word)(hs->off_counter_low + new_data_added); if (hs->off_counter_low < new_data_added) { if (0 == ++hs->off_counter_high) return ERR_MAX_DATA; } blake2b_compress(hs->h, bufw, hs->off_counter_low, hs->off_counter_high, bt); hs->buf_occ = 0; return 0; } EXPORT_SYM int blake2_update(hash_state *hs, const uint8_t *in, size_t len) { if (NULL == hs) return ERR_NULL; if (len > 0 && NULL == in) return ERR_NULL; while (len > 0) { unsigned tc, left; /** Consume input **/ left = (unsigned)(BLOCK_SIZE - hs->buf_occ); tc = (unsigned)MIN(len, left); memcpy(&hs->buf[hs->buf_occ], in, tc); len -= tc; in += tc; hs->buf_occ += tc; /* Flush buffer if full. However, we must leave at least * one byte in the buffer at the end, because we don't * know if we are processing the last block. */ if (hs->buf_occ == BLOCK_SIZE && len>0) { int result; result = blake2b_process_buffer(hs, BLOCK_SIZE, NON_FINAL_BLOCK); if (result) return result; } } return 0; } EXPORT_SYM int blake2_digest(const hash_state *hs, uint8_t digest[MAX_DIGEST_BYTES]) { hash_state temp_hs; unsigned i; int result; if (NULL==hs || NULL==digest) return ERR_NULL; temp_hs = *hs; /** Pad buffer with zeroes, if needed. In the special case * of no key and no data, we must process an all zero block. */ for (i=temp_hs.buf_occ; i