1 /* 2 BLAKE2 reference source code package - optimized C implementations 3 4 Written in 2012 by Samuel Neves <sneves@dei.uc.pt> 5 6 To the extent possible under law, the author(s) have dedicated all copyright 7 and related and neighboring rights to this software to the public domain 8 worldwide. This software is distributed without any warranty. 9 10 You should have received a copy of the CC0 Public Domain Dedication along with 11 this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>. 12 */ 13 14 #include <stdio.h> 15 #include <stdlib.h> 16 #include <string.h> 17 #include <stdint.h> 18 19 #if defined(_OPENMP) 20 #include <omp.h> 21 #endif 22 23 #include "blake2.h" 24 #include "blake2-impl.h" 25 26 #define PARALLELISM_DEGREE 4 27 28 static int blake2bp_init_leaf( blake2b_state *S, uint8_t outlen, uint8_t keylen, uint64_t offset ) 29 { 30 blake2b_param P[1]; 31 P->digest_length = outlen; 32 P->key_length = keylen; 33 P->fanout = PARALLELISM_DEGREE; 34 P->depth = 2; 35 store32(&P->leaf_length, 0); 36 store64(&P->node_offset, offset); 37 P->node_depth = 0; 38 P->inner_length = BLAKE2B_OUTBYTES; 39 memset( P->reserved, 0, sizeof( P->reserved ) ); 40 memset( P->salt, 0, sizeof( P->salt ) ); 41 memset( P->personal, 0, sizeof( P->personal ) ); 42 blake2b_init_param( S, P ); 43 S->outlen = P->inner_length; 44 return 0; 45 } 46 47 static int blake2bp_init_root( blake2b_state *S, uint8_t outlen, uint8_t keylen ) 48 { 49 blake2b_param P[1]; 50 P->digest_length = outlen; 51 P->key_length = keylen; 52 P->fanout = PARALLELISM_DEGREE; 53 P->depth = 2; 54 store32(&P->leaf_length, 0); 55 store64(&P->node_offset, 0); 56 P->node_depth = 1; 57 P->inner_length = BLAKE2B_OUTBYTES; 58 memset( P->reserved, 0, sizeof( P->reserved ) ); 59 memset( P->salt, 0, sizeof( P->salt ) ); 60 memset( P->personal, 0, sizeof( P->personal ) ); 61 blake2b_init_param( S, P ); 62 S->outlen = P->digest_length; 63 return 0; 64 } 65 66 67 int blake2bp_init( blake2bp_state *S, size_t outlen ) 68 { 69 if( !outlen || outlen > BLAKE2B_OUTBYTES ) return -1; 70 71 memset( S->buf, 0, sizeof( S->buf ) ); 72 S->buflen = 0; 73 74 if( blake2bp_init_root( S->R, ( uint8_t ) outlen, 0 ) < 0 ) 75 return -1; 76 77 for( size_t i = 0; i < PARALLELISM_DEGREE; ++i ) 78 if( blake2bp_init_leaf( S->S[i], ( uint8_t ) outlen, 0, i ) < 0 ) return -1; 79 80 S->R->last_node = 1; 81 S->S[PARALLELISM_DEGREE - 1]->last_node = 1; 82 S->outlen = ( uint8_t ) outlen; 83 return 0; 84 } 85 86 int blake2bp_init_key( blake2bp_state *S, size_t outlen, const void *key, size_t keylen ) 87 { 88 if( !outlen || outlen > BLAKE2B_OUTBYTES ) return -1; 89 90 if( !key || !keylen || keylen > BLAKE2B_KEYBYTES ) return -1; 91 92 memset( S->buf, 0, sizeof( S->buf ) ); 93 S->buflen = 0; 94 95 if( blake2bp_init_root( S->R, ( uint8_t ) outlen, ( uint8_t ) keylen ) < 0 ) 96 return -1; 97 98 for( size_t i = 0; i < PARALLELISM_DEGREE; ++i ) 99 if( blake2bp_init_leaf( S->S[i], ( uint8_t ) outlen, ( uint8_t ) keylen, i ) < 0 ) 100 return -1; 101 102 S->R->last_node = 1; 103 S->S[PARALLELISM_DEGREE - 1]->last_node = 1; 104 S->outlen = ( uint8_t ) outlen; 105 { 106 uint8_t block[BLAKE2B_BLOCKBYTES]; 107 memset( block, 0, BLAKE2B_BLOCKBYTES ); 108 memcpy( block, key, keylen ); 109 110 for( size_t i = 0; i < PARALLELISM_DEGREE; ++i ) 111 blake2b_update( S->S[i], block, BLAKE2B_BLOCKBYTES ); 112 113 secure_zero_memory( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from stack */ 114 } 115 return 0; 116 } 117 118 119 int blake2bp_update( blake2bp_state *S, const uint8_t *in, size_t inlen ) 120 { 121 size_t left = S->buflen; 122 size_t fill = sizeof( S->buf ) - left; 123 124 if( left && inlen >= fill ) 125 { 126 memcpy( S->buf + left, in, fill ); 127 128 for( size_t i = 0; i < PARALLELISM_DEGREE; ++i ) 129 blake2b_update( S->S[i], S->buf + i * BLAKE2B_BLOCKBYTES, BLAKE2B_BLOCKBYTES ); 130 131 in += fill; 132 inlen -= fill; 133 left = 0; 134 } 135 136 #if defined(_OPENMP) 137 omp_set_num_threads(PARALLELISM_DEGREE); 138 #pragma omp parallel shared(S) 139 #else 140 for( size_t id__ = 0; id__ < PARALLELISM_DEGREE; ++id__ ) 141 #endif 142 { 143 #if defined(_OPENMP) 144 size_t id__ = ( size_t ) omp_get_thread_num(); 145 #endif 146 size_t inlen__ = inlen; 147 const uint8_t *in__ = ( const uint8_t * )in; 148 in__ += id__ * BLAKE2B_BLOCKBYTES; 149 150 while( inlen__ >= PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES ) 151 { 152 blake2b_update( S->S[id__], in__, BLAKE2B_BLOCKBYTES ); 153 in__ += PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES; 154 inlen__ -= PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES; 155 } 156 } 157 158 in += inlen - inlen % ( PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES ); 159 inlen %= PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES; 160 161 if( inlen > 0 ) 162 memcpy( S->buf + left, in, inlen ); 163 164 S->buflen = ( uint32_t ) left + ( uint32_t ) inlen; 165 return 0; 166 } 167 168 169 170 int blake2bp_final( blake2bp_state *S, uint8_t *out, size_t outlen ) 171 { 172 uint8_t hash[PARALLELISM_DEGREE][BLAKE2B_OUTBYTES]; 173 174 if(S->outlen != outlen) return -1; 175 176 for( size_t i = 0; i < PARALLELISM_DEGREE; ++i ) 177 { 178 if( S->buflen > i * BLAKE2B_BLOCKBYTES ) 179 { 180 size_t left = S->buflen - i * BLAKE2B_BLOCKBYTES; 181 182 if( left > BLAKE2B_BLOCKBYTES ) left = BLAKE2B_BLOCKBYTES; 183 184 blake2b_update( S->S[i], S->buf + i * BLAKE2B_BLOCKBYTES, left ); 185 } 186 187 blake2b_final( S->S[i], hash[i], BLAKE2B_OUTBYTES ); 188 } 189 190 for( size_t i = 0; i < PARALLELISM_DEGREE; ++i ) 191 blake2b_update( S->R, hash[i], BLAKE2B_OUTBYTES ); 192 193 return blake2b_final( S->R, out, outlen ); 194 } 195 196 int blake2bp( uint8_t *out, const void *in, const void *key, size_t outlen, size_t inlen, size_t keylen ) 197 { 198 uint8_t hash[PARALLELISM_DEGREE][BLAKE2B_OUTBYTES]; 199 blake2b_state S[PARALLELISM_DEGREE][1]; 200 blake2b_state FS[1]; 201 202 /* Verify parameters */ 203 if ( NULL == in && inlen > 0 ) return -1; 204 205 if ( NULL == out ) return -1; 206 207 if ( NULL == key && keylen > 0) return -1; 208 209 if( !outlen || outlen > BLAKE2B_OUTBYTES ) return -1; 210 211 if( keylen > BLAKE2B_KEYBYTES ) return -1; 212 213 for( size_t i = 0; i < PARALLELISM_DEGREE; ++i ) 214 if( blake2bp_init_leaf( S[i], ( uint8_t ) outlen, ( uint8_t ) keylen, i ) < 0 ) 215 return -1; 216 217 S[PARALLELISM_DEGREE - 1]->last_node = 1; // mark last node 218 219 if( keylen > 0 ) 220 { 221 uint8_t block[BLAKE2B_BLOCKBYTES]; 222 memset( block, 0, BLAKE2B_BLOCKBYTES ); 223 memcpy( block, key, keylen ); 224 225 for( size_t i = 0; i < PARALLELISM_DEGREE; ++i ) 226 blake2b_update( S[i], block, BLAKE2B_BLOCKBYTES ); 227 228 secure_zero_memory( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from stack */ 229 } 230 231 #if defined(_OPENMP) 232 omp_set_num_threads(PARALLELISM_DEGREE); 233 #pragma omp parallel shared(S,hash) 234 #else 235 for( size_t id__ = 0; id__ < PARALLELISM_DEGREE; ++id__ ) 236 #endif 237 { 238 #if defined(_OPENMP) 239 size_t id__ = ( size_t ) omp_get_thread_num(); 240 #endif 241 size_t inlen__ = inlen; 242 const uint8_t *in__ = ( const uint8_t * )in; 243 in__ += id__ * BLAKE2B_BLOCKBYTES; 244 245 while( inlen__ >= PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES ) 246 { 247 blake2b_update( S[id__], in__, BLAKE2B_BLOCKBYTES ); 248 in__ += PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES; 249 inlen__ -= PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES; 250 } 251 252 if( inlen__ > id__ * BLAKE2B_BLOCKBYTES ) 253 { 254 const size_t left = inlen__ - id__ * BLAKE2B_BLOCKBYTES; 255 const size_t len = left <= BLAKE2B_BLOCKBYTES ? left : BLAKE2B_BLOCKBYTES; 256 blake2b_update( S[id__], in__, len ); 257 } 258 259 blake2b_final( S[id__], hash[id__], BLAKE2B_OUTBYTES ); 260 } 261 262 if( blake2bp_init_root( FS, ( uint8_t ) outlen, ( uint8_t ) keylen ) < 0 ) 263 return -1; 264 265 FS->last_node = 1; // Mark as last node 266 267 for( size_t i = 0; i < PARALLELISM_DEGREE; ++i ) 268 blake2b_update( FS, hash[i], BLAKE2B_OUTBYTES ); 269 270 return blake2b_final( FS, out, outlen ); 271 } 272 273 274 275