Dependents:   HTTPClient-SSL HTTPClient-SSL HTTPClient-SSL HTTPClient-SSL

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers blake2b.c Source File

blake2b.c

00001 /*
00002    BLAKE2 reference source code package - reference C implementations
00003 
00004    Written in 2012 by Samuel Neves <sneves@dei.uc.pt>
00005 
00006    To the extent possible under law, the author(s) have dedicated all copyright
00007    and related and neighboring rights to this software to the public domain
00008    worldwide. This software is distributed without any warranty.
00009 
00010    You should have received a copy of the CC0 Public Domain Dedication along with
00011    this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
00012 */
00013 /* blake2b.c
00014  *
00015  * Copyright (C) 2006-2014 wolfSSL Inc.
00016  *
00017  * This file is part of CyaSSL.
00018  *
00019  * CyaSSL is free software; you can redistribute it and/or modify
00020  * it under the terms of the GNU General Public License as published by
00021  * the Free Software Foundation; either version 2 of the License, or
00022  * (at your option) any later version.
00023  *
00024  * CyaSSL is distributed in the hope that it will be useful,
00025  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00026  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00027  * GNU General Public License for more details.
00028  *
00029  * You should have received a copy of the GNU General Public License
00030  * along with this program; if not, write to the Free Software
00031  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
00032  */
00033 
00034 
00035 #ifdef HAVE_CONFIG_H
00036     #include <config.h>
00037 #endif
00038 
00039 #include <cyassl/ctaocrypt/settings.h>
00040 
00041 #ifdef HAVE_BLAKE2
00042 
00043 #include <cyassl/ctaocrypt/blake2.h>
00044 #include <cyassl/ctaocrypt/blake2-impl.h>
00045 
00046 
00047 static const word64 blake2b_IV[8] =
00048 {
00049   0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL,
00050   0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL,
00051   0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL,
00052   0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL
00053 };
00054 
00055 static const byte blake2b_sigma[12][16] =
00056 {
00057   {  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15 } ,
00058   { 14, 10,  4,  8,  9, 15, 13,  6,  1, 12,  0,  2, 11,  7,  5,  3 } ,
00059   { 11,  8, 12,  0,  5,  2, 15, 13, 10, 14,  3,  6,  7,  1,  9,  4 } ,
00060   {  7,  9,  3,  1, 13, 12, 11, 14,  2,  6,  5, 10,  4,  0, 15,  8 } ,
00061   {  9,  0,  5,  7,  2,  4, 10, 15, 14,  1, 11, 12,  6,  8,  3, 13 } ,
00062   {  2, 12,  6, 10,  0, 11,  8,  3,  4, 13,  7,  5, 15, 14,  1,  9 } ,
00063   { 12,  5,  1, 15, 14, 13,  4, 10,  0,  7,  6,  3,  9,  2,  8, 11 } ,
00064   { 13, 11,  7, 14, 12,  1,  3,  9,  5,  0, 15,  4,  8,  6,  2, 10 } ,
00065   {  6, 15, 14,  9, 11,  3,  0,  8, 12,  2, 13,  7,  1,  4, 10,  5 } ,
00066   { 10,  2,  8,  4,  7,  6,  1,  5, 15, 11,  9, 14,  3, 12, 13 , 0 } ,
00067   {  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15 } ,
00068   { 14, 10,  4,  8,  9, 15, 13,  6,  1, 12,  0,  2, 11,  7,  5,  3 }
00069 };
00070 
00071 
00072 static INLINE int blake2b_set_lastnode( blake2b_state *S )
00073 {
00074   S->f[1] = ~0ULL;
00075   return 0;
00076 }
00077 
00078 /* Some helper functions, not necessarily useful */
00079 static INLINE int blake2b_set_lastblock( blake2b_state *S )
00080 {
00081   if( S->last_node ) blake2b_set_lastnode( S );
00082 
00083   S->f[0] = ~0ULL;
00084   return 0;
00085 }
00086 
00087 static INLINE int blake2b_increment_counter( blake2b_state *S, const word64
00088                                              inc )
00089 {
00090   S->t[0] += inc;
00091   S->t[1] += ( S->t[0] < inc );
00092   return 0;
00093 }
00094 
00095 static INLINE int blake2b_init0( blake2b_state *S )
00096 {
00097   int i;
00098   XMEMSET( S, 0, sizeof( blake2b_state ) );
00099 
00100   for( i = 0; i < 8; ++i ) S->h[i] = blake2b_IV[i];
00101 
00102   return 0;
00103 }
00104 
00105 /* init xors IV with input parameter block */
00106 int blake2b_init_param( blake2b_state *S, const blake2b_param *P )
00107 {
00108   word32 i;
00109   blake2b_init0( S );
00110   byte *p = ( byte * )( P );
00111 
00112   /* IV XOR ParamBlock */
00113   for( i = 0; i < 8; ++i )
00114     S->h[i] ^= load64( p + sizeof( S->h[i] ) * i );
00115 
00116   return 0;
00117 }
00118 
00119 
00120 
00121 int blake2b_init( blake2b_state *S, const byte outlen )
00122 {
00123   blake2b_param P[1];
00124 
00125   if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1;
00126 
00127   P->digest_length = outlen;
00128   P->key_length    = 0;
00129   P->fanout        = 1;
00130   P->depth         = 1;
00131   store32( &P->leaf_length, 0 );
00132   store64( &P->node_offset, 0 );
00133   P->node_depth    = 0;
00134   P->inner_length  = 0;
00135   XMEMSET( P->reserved, 0, sizeof( P->reserved ) );
00136   XMEMSET( P->salt,     0, sizeof( P->salt ) );
00137   XMEMSET( P->personal, 0, sizeof( P->personal ) );
00138   return blake2b_init_param( S, P );
00139 }
00140 
00141 
00142 int blake2b_init_key( blake2b_state *S, const byte outlen, const void *key,
00143                       const byte keylen )
00144 {
00145   blake2b_param P[1];
00146 
00147   if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1;
00148 
00149   if ( !key || !keylen || keylen > BLAKE2B_KEYBYTES ) return -1;
00150 
00151   P->digest_length = outlen;
00152   P->key_length    = keylen;
00153   P->fanout        = 1;
00154   P->depth         = 1;
00155   store32( &P->leaf_length, 0 );
00156   store64( &P->node_offset, 0 );
00157   P->node_depth    = 0;
00158   P->inner_length  = 0;
00159   XMEMSET( P->reserved, 0, sizeof( P->reserved ) );
00160   XMEMSET( P->salt,     0, sizeof( P->salt ) );
00161   XMEMSET( P->personal, 0, sizeof( P->personal ) );
00162 
00163   if( blake2b_init_param( S, P ) < 0 ) return -1;
00164 
00165   {
00166 #ifdef CYASSL_SMALL_STACK
00167     byte* block;
00168 
00169     block = (byte*)XMALLOC(BLAKE2B_BLOCKBYTES, NULL, DYNAMIC_TYPE_TMP_BUFFER);
00170 
00171     if ( block == NULL ) return -1;
00172 #else
00173     byte block[BLAKE2B_BLOCKBYTES];
00174 #endif
00175 
00176     XMEMSET( block, 0, BLAKE2B_BLOCKBYTES );
00177     XMEMCPY( block, key, keylen );
00178     blake2b_update( S, block, BLAKE2B_BLOCKBYTES );
00179     secure_zero_memory( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from */
00180                                                      /* memory */
00181 
00182 #ifdef CYASSL_SMALL_STACK
00183     XFREE(block, NULL, DYNAMIC_TYPE_TMP_BUFFER);
00184 #endif
00185   }
00186   return 0;
00187 }
00188 
00189 static int blake2b_compress( blake2b_state *S,
00190                              const byte block[BLAKE2B_BLOCKBYTES] )
00191 {
00192   int i;
00193 
00194 #ifdef CYASSL_SMALL_STACK
00195   word64* m;
00196   word64* v;
00197 
00198   m = (word64*)XMALLOC(sizeof(word64) * 16, NULL, DYNAMIC_TYPE_TMP_BUFFER);
00199 
00200   if ( m == NULL ) return -1;
00201 
00202   v = (word64*)XMALLOC(sizeof(word64) * 16, NULL, DYNAMIC_TYPE_TMP_BUFFER);
00203 
00204   if ( v == NULL )
00205   {
00206     XFREE(m, NULL, DYNAMIC_TYPE_TMP_BUFFER);
00207     return -1;
00208   }
00209 #else
00210   word64 m[16];
00211   word64 v[16];
00212 #endif
00213 
00214   for( i = 0; i < 16; ++i )
00215     m[i] = load64( block + i * sizeof( m[i] ) );
00216 
00217   for( i = 0; i < 8; ++i )
00218     v[i] = S->h[i];
00219 
00220   v[ 8] = blake2b_IV[0];
00221   v[ 9] = blake2b_IV[1];
00222   v[10] = blake2b_IV[2];
00223   v[11] = blake2b_IV[3];
00224   v[12] = S->t[0] ^ blake2b_IV[4];
00225   v[13] = S->t[1] ^ blake2b_IV[5];
00226   v[14] = S->f[0] ^ blake2b_IV[6];
00227   v[15] = S->f[1] ^ blake2b_IV[7];
00228 #define G(r,i,a,b,c,d) \
00229   do { \
00230     a = a + b + m[blake2b_sigma[r][2*i+0]]; \
00231     d = rotr64(d ^ a, 32); \
00232     c = c + d; \
00233     b = rotr64(b ^ c, 24); \
00234     a = a + b + m[blake2b_sigma[r][2*i+1]]; \
00235     d = rotr64(d ^ a, 16); \
00236     c = c + d; \
00237     b = rotr64(b ^ c, 63); \
00238   } while(0)
00239 #define ROUND(r)  \
00240   do { \
00241     G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \
00242     G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \
00243     G(r,2,v[ 2],v[ 6],v[10],v[14]); \
00244     G(r,3,v[ 3],v[ 7],v[11],v[15]); \
00245     G(r,4,v[ 0],v[ 5],v[10],v[15]); \
00246     G(r,5,v[ 1],v[ 6],v[11],v[12]); \
00247     G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \
00248     G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \
00249   } while(0)
00250   ROUND( 0 );
00251   ROUND( 1 );
00252   ROUND( 2 );
00253   ROUND( 3 );
00254   ROUND( 4 );
00255   ROUND( 5 );
00256   ROUND( 6 );
00257   ROUND( 7 );
00258   ROUND( 8 );
00259   ROUND( 9 );
00260   ROUND( 10 );
00261   ROUND( 11 );
00262 
00263   for( i = 0; i < 8; ++i )
00264     S->h[i] = S->h[i] ^ v[i] ^ v[i + 8];
00265 
00266 #undef G
00267 #undef ROUND
00268 
00269 #ifdef CYASSL_SMALL_STACK
00270   XFREE(m, NULL, DYNAMIC_TYPE_TMP_BUFFER);
00271   XFREE(v, NULL, DYNAMIC_TYPE_TMP_BUFFER);
00272 #endif
00273 
00274   return 0;
00275 }
00276 
00277 /* inlen now in bytes */
00278 int blake2b_update( blake2b_state *S, const byte *in, word64 inlen )
00279 {
00280   while( inlen > 0 )
00281   {
00282     word64 left = S->buflen;
00283     word64 fill = 2 * BLAKE2B_BLOCKBYTES - left;
00284 
00285     if( inlen > fill )
00286     {
00287       XMEMCPY( S->buf + left, in, (cyassl_word)fill ); /* Fill buffer */
00288       S->buflen += fill;
00289       blake2b_increment_counter( S, BLAKE2B_BLOCKBYTES );
00290 
00291       if ( blake2b_compress( S, S->buf ) < 0 ) return -1; /* Compress */
00292 
00293       XMEMCPY( S->buf, S->buf + BLAKE2B_BLOCKBYTES, BLAKE2B_BLOCKBYTES );
00294               /* Shift buffer left */
00295       S->buflen -= BLAKE2B_BLOCKBYTES;
00296       in += fill;
00297       inlen -= fill;
00298     }
00299     else /* inlen <= fill */
00300     {
00301       XMEMCPY( S->buf + left, in, (cyassl_word)inlen );
00302       S->buflen += inlen; /* Be lazy, do not compress */
00303       in += inlen;
00304       inlen -= inlen;
00305     }
00306   }
00307 
00308   return 0;
00309 }
00310 
00311 /* Is this correct? */
00312 int blake2b_final( blake2b_state *S, byte *out, byte outlen )
00313 {
00314   byte buffer[BLAKE2B_OUTBYTES];
00315   int     i;
00316 
00317   if( S->buflen > BLAKE2B_BLOCKBYTES )
00318   {
00319     blake2b_increment_counter( S, BLAKE2B_BLOCKBYTES );
00320 
00321     if ( blake2b_compress( S, S->buf ) < 0 ) return -1;
00322 
00323     S->buflen -= BLAKE2B_BLOCKBYTES;
00324     XMEMCPY( S->buf, S->buf + BLAKE2B_BLOCKBYTES, (cyassl_word)S->buflen );
00325   }
00326 
00327   blake2b_increment_counter( S, S->buflen );
00328   blake2b_set_lastblock( S );
00329   XMEMSET( S->buf + S->buflen, 0, (cyassl_word)(2 * BLAKE2B_BLOCKBYTES - S->buflen) );
00330          /* Padding */
00331   if ( blake2b_compress( S, S->buf ) < 0 ) return -1;
00332 
00333   for( i = 0; i < 8; ++i ) /* Output full hash to temp buffer */
00334     store64( buffer + sizeof( S->h[i] ) * i, S->h[i] );
00335 
00336   XMEMCPY( out, buffer, outlen );
00337   return 0;
00338 }
00339 
00340 /* inlen, at least, should be word64. Others can be size_t. */
00341 int blake2b( byte *out, const void *in, const void *key, const byte outlen,
00342              const word64 inlen, byte keylen )
00343 {
00344   blake2b_state S[1];
00345 
00346   /* Verify parameters */
00347   if ( NULL == in ) return -1;
00348 
00349   if ( NULL == out ) return -1;
00350 
00351   if( NULL == key ) keylen = 0;
00352 
00353   if( keylen > 0 )
00354   {
00355     if( blake2b_init_key( S, outlen, key, keylen ) < 0 ) return -1;
00356   }
00357   else
00358   {
00359     if( blake2b_init( S, outlen ) < 0 ) return -1;
00360   }
00361 
00362   if ( blake2b_update( S, ( byte * )in, inlen ) < 0) return -1;
00363 
00364   return blake2b_final( S, out, outlen );
00365 }
00366 
00367 #if defined(BLAKE2B_SELFTEST)
00368 #include <string.h>
00369 #include "blake2-kat.h"
00370 int main( int argc, char **argv )
00371 {
00372   byte key[BLAKE2B_KEYBYTES];
00373   byte buf[KAT_LENGTH];
00374 
00375   for( word32 i = 0; i < BLAKE2B_KEYBYTES; ++i )
00376     key[i] = ( byte )i;
00377 
00378   for( word32 i = 0; i < KAT_LENGTH; ++i )
00379     buf[i] = ( byte )i;
00380 
00381   for( word32 i = 0; i < KAT_LENGTH; ++i )
00382   {
00383     byte hash[BLAKE2B_OUTBYTES];
00384     if ( blake2b( hash, buf, key, BLAKE2B_OUTBYTES, i, BLAKE2B_KEYBYTES ) < 0 )
00385     {
00386       puts( "error" );
00387       return -1;
00388     }
00389 
00390     if( 0 != memcmp( hash, blake2b_keyed_kat[i], BLAKE2B_OUTBYTES ) )
00391     {
00392       puts( "error" );
00393       return -1;
00394     }
00395   }
00396 
00397   puts( "ok" );
00398   return 0;
00399 }
00400 #endif
00401 
00402 
00403 /* CTaoCrypt API */
00404 
00405 /* Init Blake2b digest, track size incase final doesn't want to "remember" */
00406 int InitBlake2b(Blake2b* b2b, word32 digestSz)
00407 {
00408     b2b->digestSz = digestSz;
00409 
00410     return blake2b_init(b2b->S, (byte)digestSz);
00411 }
00412 
00413 
00414 /* Blake2b Update */
00415 int Blake2bUpdate(Blake2b* b2b, const byte* data, word32 sz)
00416 {
00417     return blake2b_update(b2b->S, data, sz);
00418 }
00419 
00420 
00421 /* Blake2b Final, if pass in zero size we use init digestSz */
00422 int Blake2bFinal(Blake2b* b2b, byte* final, word32 requestSz)
00423 {
00424     word32 sz = requestSz ? requestSz : b2b->digestSz;
00425 
00426     return blake2b_final(b2b->S, final, (byte)sz);
00427 }
00428 
00429 
00430 /* end CTaoCrypt API */
00431 
00432 #endif  /* HAVE_BLAKE2 */
00433