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 <stdlib.h> 15 #include <string.h> 16 #include <stdio.h> 17 18 #if defined(_OPENMP) 19 #include <omp.h> 20 #endif 21 22 #include "blake2.h" 23 #include "blake2-impl.h" 24 25 #define PARALLELISM_DEGREE 8 26 27 static int blake2sp_init_leaf( blake2s_state *S, uint8_t outlen, uint8_t keylen, uint64_t offset ) 28 { 29 blake2s_param P[1]; 30 P->digest_length = outlen; 31 P->key_length = keylen; 32 P->fanout = PARALLELISM_DEGREE; 33 P->depth = 2; 34 P->leaf_length = 0; 35 store48( P->node_offset, offset ); 36 P->node_depth = 0; 37 P->inner_length = BLAKE2S_OUTBYTES; 38 memset( P->salt, 0, sizeof( P->salt ) ); 39 memset( P->personal, 0, sizeof( P->personal ) ); 40 blake2s_init_param( S, P ); 41 S->outlen = P->inner_length; 42 return 0; 43 } 44 45 static int blake2sp_init_root( blake2s_state *S, uint8_t outlen, uint8_t keylen ) 46 { 47 blake2s_param P[1]; 48 P->digest_length = outlen; 49 P->key_length = keylen; 50 P->fanout = PARALLELISM_DEGREE; 51 P->depth = 2; 52 P->leaf_length = 0; 53 store48( P->node_offset, 0ULL ); 54 P->node_depth = 1; 55 P->inner_length = BLAKE2S_OUTBYTES; 56 memset( P->salt, 0, sizeof( P->salt ) ); 57 memset( P->personal, 0, sizeof( P->personal ) ); 58 blake2s_init_param( S, P ); 59 S->outlen = P->digest_length; 60 return 0; 61 } 62 63 64 int blake2sp_init( blake2sp_state *S, size_t outlen ) 65 { 66 if( !outlen || outlen > BLAKE2S_OUTBYTES ) return -1; 67 68 memset( S->buf, 0, sizeof( S->buf ) ); 69 S->buflen = 0; 70 71 if( blake2sp_init_root( S->R, ( uint8_t ) outlen, 0 ) < 0 ) 72 return -1; 73 74 for( size_t i = 0; i < PARALLELISM_DEGREE; ++i ) 75 if( blake2sp_init_leaf( S->S[i], ( uint8_t ) outlen, 0, i ) < 0 ) return -1; 76 77 S->R->last_node = 1; 78 S->S[PARALLELISM_DEGREE - 1]->last_node = 1; 79 S->outlen = ( uint8_t ) outlen; 80 return 0; 81 } 82 83 int blake2sp_init_key( blake2sp_state *S, size_t outlen, const void *key, size_t keylen ) 84 { 85 if( !outlen || outlen > BLAKE2S_OUTBYTES ) return -1; 86 87 if( !key || !keylen || keylen > BLAKE2S_KEYBYTES ) return -1; 88 89 memset( S->buf, 0, sizeof( S->buf ) ); 90 S->buflen = 0; 91 92 if( blake2sp_init_root( S->R, ( uint8_t ) outlen, ( uint8_t ) keylen ) < 0 ) 93 return -1; 94 95 for( size_t i = 0; i < PARALLELISM_DEGREE; ++i ) 96 if( blake2sp_init_leaf( S->S[i], ( uint8_t ) outlen, ( uint8_t ) keylen, i ) < 0 ) 97 return -1; 98 99 S->R->last_node = 1; 100 S->S[PARALLELISM_DEGREE - 1]->last_node = 1; 101 S->outlen = ( uint8_t ) outlen; 102 { 103 uint8_t block[BLAKE2S_BLOCKBYTES]; 104 memset( block, 0, BLAKE2S_BLOCKBYTES ); 105 memcpy( block, key, keylen ); 106 107 for( size_t i = 0; i < PARALLELISM_DEGREE; ++i ) 108 blake2s_update( S->S[i], block, BLAKE2S_BLOCKBYTES ); 109 110 secure_zero_memory( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from stack */ 111 } 112 return 0; 113 } 114 115 116 int blake2sp_update( blake2sp_state *S, const uint8_t *in, size_t inlen ) 117 { 118 size_t left = S->buflen; 119 size_t fill = sizeof( S->buf ) - left; 120 121 if( left && inlen >= fill ) 122 { 123 memcpy( S->buf + left, in, fill ); 124 125 for( size_t i = 0; i < PARALLELISM_DEGREE; ++i ) 126 blake2s_update( S->S[i], S->buf + i * BLAKE2S_BLOCKBYTES, BLAKE2S_BLOCKBYTES ); 127 128 in += fill; 129 inlen -= fill; 130 left = 0; 131 } 132 133 #if defined(_OPENMP) 134 omp_set_num_threads(PARALLELISM_DEGREE); 135 #pragma omp parallel shared(S) 136 #else 137 for( size_t id__ = 0; id__ < PARALLELISM_DEGREE; ++id__ ) 138 #endif 139 { 140 #if defined(_OPENMP) 141 size_t id__ = ( size_t ) omp_get_thread_num(); 142 #endif 143 size_t inlen__ = inlen; 144 const uint8_t *in__ = ( const uint8_t * )in; 145 in__ += id__ * BLAKE2S_BLOCKBYTES; 146 147 while( inlen__ >= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES ) 148 { 149 blake2s_update( S->S[id__], in__, BLAKE2S_BLOCKBYTES ); 150 in__ += PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES; 151 inlen__ -= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES; 152 } 153 } 154 155 in += inlen - inlen % ( PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES ); 156 inlen %= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES; 157 158 if( inlen > 0 ) 159 memcpy( S->buf + left, in, inlen ); 160 161 S->buflen = ( uint32_t ) left + ( uint32_t ) inlen; 162 return 0; 163 } 164 165 166 int blake2sp_final( blake2sp_state *S, uint8_t *out, size_t outlen ) 167 { 168 uint8_t hash[PARALLELISM_DEGREE][BLAKE2S_OUTBYTES]; 169 170 if(S->outlen != outlen) return -1; 171 172 for( size_t i = 0; i < PARALLELISM_DEGREE; ++i ) 173 { 174 if( S->buflen > i * BLAKE2S_BLOCKBYTES ) 175 { 176 size_t left = S->buflen - i * BLAKE2S_BLOCKBYTES; 177 178 if( left > BLAKE2S_BLOCKBYTES ) left = BLAKE2S_BLOCKBYTES; 179 180 blake2s_update( S->S[i], S->buf + i * BLAKE2S_BLOCKBYTES, left ); 181 } 182 183 blake2s_final( S->S[i], hash[i], BLAKE2S_OUTBYTES ); 184 } 185 186 for( size_t i = 0; i < PARALLELISM_DEGREE; ++i ) 187 blake2s_update( S->R, hash[i], BLAKE2S_OUTBYTES ); 188 189 blake2s_final( S->R, out, outlen ); 190 return 0; 191 } 192 193 194 int blake2sp( uint8_t *out, const void *in, const void *key, size_t outlen, size_t inlen, size_t keylen ) 195 { 196 uint8_t hash[PARALLELISM_DEGREE][BLAKE2S_OUTBYTES]; 197 blake2s_state S[PARALLELISM_DEGREE][1]; 198 blake2s_state FS[1]; 199 200 /* Verify parameters */ 201 if ( NULL == in && inlen > 0 ) return -1; 202 203 if ( NULL == out ) return -1; 204 205 if ( NULL == key && keylen > 0 ) return -1; 206 207 if( !outlen || outlen > BLAKE2S_OUTBYTES ) return -1; 208 209 if( keylen > BLAKE2S_KEYBYTES ) return -1; 210 211 for( size_t i = 0; i < PARALLELISM_DEGREE; ++i ) 212 if( blake2sp_init_leaf( S[i], ( uint8_t ) outlen, ( uint8_t ) keylen, i ) < 0 ) 213 return -1; 214 215 S[PARALLELISM_DEGREE - 1]->last_node = 1; // mark last node 216 217 if( keylen > 0 ) 218 { 219 uint8_t block[BLAKE2S_BLOCKBYTES]; 220 memset( block, 0, BLAKE2S_BLOCKBYTES ); 221 memcpy( block, key, keylen ); 222 223 for( size_t i = 0; i < PARALLELISM_DEGREE; ++i ) 224 blake2s_update( S[i], block, BLAKE2S_BLOCKBYTES ); 225 226 secure_zero_memory( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from stack */ 227 } 228 229 #if defined(_OPENMP) 230 omp_set_num_threads(PARALLELISM_DEGREE); 231 #pragma omp parallel shared(S,hash) 232 #else 233 234 for( size_t id__ = 0; id__ < PARALLELISM_DEGREE; ++id__ ) 235 #endif 236 { 237 #if defined(_OPENMP) 238 size_t id__ = ( size_t ) omp_get_thread_num(); 239 #endif 240 size_t inlen__ = inlen; 241 const uint8_t *in__ = ( const uint8_t * )in; 242 in__ += id__ * BLAKE2S_BLOCKBYTES; 243 244 while( inlen__ >= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES ) 245 { 246 blake2s_update( S[id__], in__, BLAKE2S_BLOCKBYTES ); 247 in__ += PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES; 248 inlen__ -= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES; 249 } 250 251 if( inlen__ > id__ * BLAKE2S_BLOCKBYTES ) 252 { 253 const size_t left = inlen__ - id__ * BLAKE2S_BLOCKBYTES; 254 const size_t len = left <= BLAKE2S_BLOCKBYTES ? left : BLAKE2S_BLOCKBYTES; 255 blake2s_update( S[id__], in__, len ); 256 } 257 258 blake2s_final( S[id__], hash[id__], BLAKE2S_OUTBYTES ); 259 } 260 261 if( blake2sp_init_root( FS, ( uint8_t ) outlen, ( uint8_t ) keylen ) < 0 ) 262 return -1; 263 264 FS->last_node = 1; 265 266 for( size_t i = 0; i < PARALLELISM_DEGREE; ++i ) 267 blake2s_update( FS, hash[i], BLAKE2S_OUTBYTES ); 268 269 return blake2s_final( FS, out, outlen ); 270 } 271 272 273 274 275