1  /* sha.c


2  *


3  * Copyright (C) 20062015 wolfSSL Inc.


4  *


5  * This file is part of wolfSSL. (formerly known as CyaSSL)


6  *


7  * wolfSSL is free software; you can redistribute it and/or modify


8  * it under the terms of the GNU General Public License as published by


9  * the Free Software Foundation; either version 2 of the License, or


10  * (at your option) any later version.


11  *


12  * wolfSSL is distributed in the hope that it will be useful,


13  * but WITHOUT ANY WARRANTY; without even the implied warranty of


14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the


15  * GNU General Public License for more details.


16  *


17  * You should have received a copy of the GNU General Public License


18  * along with this program; if not, write to the Free Software


19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 021101301, USA


20  */


21 


22 


23  #ifdef HAVE_CONFIG_H


24  #include <config.h>


25  #endif


26 


27  #include <wolfssl/wolfcrypt/settings.h>


28 


29  #if !defined(NO_SHA)


30 


31  #include <wolfssl/wolfcrypt/sha.h>


32  #include <wolfssl/wolfcrypt/logging.h>


33  #include <wolfssl/wolfcrypt/errorcrypt.h>


34 


35  #ifdef NO_INLINE


36  #include <wolfssl/wolfcrypt/misc.h>


37  #else


38  #include <wolfcrypt/src/misc.c>


39  #endif


40 


41  /* fips wrapper calls, user can call direct */


42  #ifdef HAVE_FIPS


43  int wc_InitSha(Sha* sha)


44  {


45  return InitSha_fips(sha);


46  }


47 


48 


49  int wc_ShaUpdate(Sha* sha, const byte* data, word32 len)


50  {


51  return ShaUpdate_fips(sha, data, len);


52  }


53 


54 


55  int wc_ShaFinal(Sha* sha, byte* out)


56  {


57  return ShaFinal_fips(sha,out);


58  }


59 


60  #else /* else build without fips */


61 


62  #if defined(WOLFSSL_TI_HASH)


63  /* #include <wolfcrypt/src/port/ti/tihash.c> included by wc_port.c */


64  #else


65 


66  #ifdef WOLFSSL_PIC32MZ_HASH


67  #define wc_InitSha wc_InitSha_sw


68  #define wc_ShaUpdate wc_ShaUpdate_sw


69  #define wc_ShaFinal wc_ShaFinal_sw


70  #endif


71 


72 


73  #ifdef FREESCALE_MMCAU


74  #include "cau_api.h"


75  #define XTRANSFORM(S,B) Transform((S), (B))


76  #else


77  #define XTRANSFORM(S,B) Transform((S))


78  #endif


79 


80  #ifdef STM32F2_HASH


81  /*


82  * STM32F2 hardware SHA1 support through the STM32F2 standard peripheral


83  * library. Documentation located in STM32F2xx Standard Peripheral Library


84  * document (See note in README).


85  */


86  #include "stm32f2xx.h"


87  #include "stm32f2xx_hash.h"


88 


89  int wc_InitSha(Sha* sha)


90  {


91  /* STM32F2 struct notes:


92  * sha>buffer = first 4 bytes used to hold partial block if needed


93  * sha>buffLen = num bytes currently stored in sha>buffer


94  * sha>loLen = num bytes that have been written to STM32 FIFO


95  */


96  XMEMSET(sha>buffer, 0, SHA_REG_SIZE);


97  sha>buffLen = 0;


98  sha>loLen = 0;


99 


100  /* initialize HASH peripheral */


101  HASH_DeInit();


102 


103  /* configure algo used, algo mode, datatype */


104  HASH>CR &= ~ (HASH_CR_ALGO  HASH_CR_DATATYPE  HASH_CR_MODE);


105  HASH>CR = (HASH_AlgoSelection_SHA1  HASH_AlgoMode_HASH


106   HASH_DataType_8b);


107 


108  /* reset HASH processor */


109  HASH>CR = HASH_CR_INIT;


110 


111  return 0;


112  }


113 


114  int wc_ShaUpdate(Sha* sha, const byte* data, word32 len)


115  {


116  word32 i = 0;


117  word32 fill = 0;


118  word32 diff = 0;


119 


120  /* if saved partial block is available */


121  if (sha>buffLen) {


122  fill = 4  sha>buffLen;


123 


124  /* if enough data to fill, fill and push to FIFO */


125  if (fill <= len) {


126  XMEMCPY((byte*)sha>buffer + sha>buffLen, data, fill);


127  HASH_DataIn(*(uint32_t*)sha>buffer);


128 


129  data += fill;


130  len = fill;


131  sha>loLen += 4;


132  sha>buffLen = 0;


133  } else {


134  /* append partial to existing stored block */


135  XMEMCPY((byte*)sha>buffer + sha>buffLen, data, len);


136  sha>buffLen += len;


137  return;


138  }


139  }


140 


141  /* write input block in the IN FIFO */


142  for(i = 0; i < len; i += 4)


143  {


144  diff = len  i;


145  if ( diff < 4) {


146  /* store incomplete last block, not yet in FIFO */


147  XMEMSET(sha>buffer, 0, SHA_REG_SIZE);


148  XMEMCPY((byte*)sha>buffer, data, diff);


149  sha>buffLen = diff;


150  } else {


151  HASH_DataIn(*(uint32_t*)data);


152  data+=4;


153  }


154  }


155 


156  /* keep track of total data length thus far */


157  sha>loLen += (len  sha>buffLen);


158 


159  return 0;


160  }


161 


162  int wc_ShaFinal(Sha* sha, byte* hash)


163  {


164  __IO uint16_t nbvalidbitsdata = 0;


165 


166  /* finish reading any trailing bytes into FIFO */


167  if (sha>buffLen) {


168  HASH_DataIn(*(uint32_t*)sha>buffer);


169  sha>loLen += sha>buffLen;


170  }


171 


172  /* calculate number of valid bits in last word of input data */


173  nbvalidbitsdata = 8 * (sha>loLen % SHA_REG_SIZE);


174 


175  /* configure number of valid bits in last word of the data */


176  HASH_SetLastWordValidBitsNbr(nbvalidbitsdata);


177 


178  /* start HASH processor */


179  HASH_StartDigest();


180 


181  /* wait until Busy flag == RESET */


182  while (HASH_GetFlagStatus(HASH_FLAG_BUSY) != RESET) {}


183 


184  /* read message digest */


185  sha>digest[0] = HASH>HR[0];


186  sha>digest[1] = HASH>HR[1];


187  sha>digest[2] = HASH>HR[2];


188  sha>digest[3] = HASH>HR[3];


189  sha>digest[4] = HASH>HR[4];


190 


191  ByteReverseWords(sha>digest, sha>digest, SHA_DIGEST_SIZE);


192 


193  XMEMCPY(hash, sha>digest, SHA_DIGEST_SIZE);


194 


195  return wc_InitSha(sha); /* reset state */


196  }


197 


198  #else /* wc_ software implementation */


199 


200  #ifdef min


201  #define WOLFSSL_HAVE_MIN


202  #endif


203  #ifndef WOLFSSL_HAVE_MIN


204  #define WOLFSSL_HAVE_MIN


205 


206  static INLINE word32 min(word32 a, word32 b)


207  {


208  return a > b ? b : a;


209  }


210 


211  #endif /* WOLFSSL_HAVE_MIN */


212 


213 


214  int wc_InitSha(Sha* sha)


215  {


216  int ret = 0;


217  #ifdef FREESCALE_MMCAU


218  ret = wolfSSL_CryptHwMutexLock();


219  if(ret != 0) {


220  return ret;


221  }


222  cau_sha1_initialize_output(sha>digest);


223  wolfSSL_CryptHwMutexUnLock();


224  #else


225  sha>digest[0] = 0x67452301L;


226  sha>digest[1] = 0xEFCDAB89L;


227  sha>digest[2] = 0x98BADCFEL;


228  sha>digest[3] = 0x10325476L;


229  sha>digest[4] = 0xC3D2E1F0L;


230  #endif


231 


232  sha>buffLen = 0;


233  sha>loLen = 0;


234  sha>hiLen = 0;


235 


236  return ret;


237  }


238 


239  #ifdef FREESCALE_MMCAU


240  static int Transform(Sha* sha, byte* data)


241  {


242  int ret = wolfSSL_CryptHwMutexLock();


243  if(ret == 0) {


244  cau_sha1_hash_n(data, 1, sha>digest);


245  wolfSSL_CryptHwMutexUnLock();


246  }


247  return ret;


248  }


249  #endif /* FREESCALE_MMCAU */


250 


251  #ifndef FREESCALE_MMCAU


252 


253  #define blk0(i) (W[i] = sha>buffer[i])


254  #define blk1(i) (W[(i)&15] = \


255  rotlFixed(W[((i)+13)&15]^W[((i)+8)&15]^W[((i)+2)&15]^W[(i)&15],1))


256 


257  #define f1(x,y,z) ((z)^((x) &((y)^(z))))


258  #define f2(x,y,z) ((x)^(y)^(z))


259  #define f3(x,y,z) (((x)&(y))((z)&((x)(y))))


260  #define f4(x,y,z) ((x)^(y)^(z))


261 


262  /* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */


263  #define R0(v,w,x,y,z,i) (z)+= f1((w),(x),(y)) + blk0((i)) + 0x5A827999+ \


264  rotlFixed((v),5); (w) = rotlFixed((w),30);


265  #define R1(v,w,x,y,z,i) (z)+= f1((w),(x),(y)) + blk1((i)) + 0x5A827999+ \


266  rotlFixed((v),5); (w) = rotlFixed((w),30);


267  #define R2(v,w,x,y,z,i) (z)+= f2((w),(x),(y)) + blk1((i)) + 0x6ED9EBA1+ \


268  rotlFixed((v),5); (w) = rotlFixed((w),30);


269  #define R3(v,w,x,y,z,i) (z)+= f3((w),(x),(y)) + blk1((i)) + 0x8F1BBCDC+ \


270  rotlFixed((v),5); (w) = rotlFixed((w),30);


271  #define R4(v,w,x,y,z,i) (z)+= f4((w),(x),(y)) + blk1((i)) + 0xCA62C1D6+ \


272  rotlFixed((v),5); (w) = rotlFixed((w),30);


273 


274  static void Transform(Sha* sha)


275  {


276  word32 W[SHA_BLOCK_SIZE / sizeof(word32)];


277 


278  /* Copy context>state[] to working vars */


279  word32 a = sha>digest[0];


280  word32 b = sha>digest[1];


281  word32 c = sha>digest[2];


282  word32 d = sha>digest[3];


283  word32 e = sha>digest[4];


284 


285  #ifdef USE_SLOW_SHA


286  word32 t, i;


287 


288  for (i = 0; i < 16; i++) {


289  R0(a, b, c, d, e, i);


290  t = e; e = d; d = c; c = b; b = a; a = t;


291  }


292 


293  for (; i < 20; i++) {


294  R1(a, b, c, d, e, i);


295  t = e; e = d; d = c; c = b; b = a; a = t;


296  }


297 


298  for (; i < 40; i++) {


299  R2(a, b, c, d, e, i);


300  t = e; e = d; d = c; c = b; b = a; a = t;


301  }


302 


303  for (; i < 60; i++) {


304  R3(a, b, c, d, e, i);


305  t = e; e = d; d = c; c = b; b = a; a = t;


306  }


307 


308  for (; i < 80; i++) {


309  R4(a, b, c, d, e, i);


310  t = e; e = d; d = c; c = b; b = a; a = t;


311  }


312  #else


313  /* nearly 1 K bigger in code size but 25% faster */


314  /* 4 rounds of 20 operations each. Loop unrolled. */


315  R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);


316  R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);


317  R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);


318  R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);


319 


320  R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);


321 


322  R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);


323  R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);


324  R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);


325  R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);


326  R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);


327 


328  R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);


329  R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);


330  R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);


331  R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);


332  R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);


333 


334  R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);


335  R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);


336  R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);


337  R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);


338  R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);


339  #endif


340 


341  /* Add the working vars back into digest state[] */


342  sha>digest[0] += a;


343  sha>digest[1] += b;


344  sha>digest[2] += c;


345  sha>digest[3] += d;


346  sha>digest[4] += e;


347  }


348 


349  #endif /* FREESCALE_MMCAU */


350 


351 


352  static INLINE void AddLength(Sha* sha, word32 len)


353  {


354  word32 tmp = sha>loLen;


355  if ( (sha>loLen += len) < tmp)


356  sha>hiLen++; /* carry low to high */


357  }


358 


359 


360  int wc_ShaUpdate(Sha* sha, const byte* data, word32 len)


361  {


362  /* do block size increments */


363  byte* local = (byte*)sha>buffer;


364 


365  while (len) {


366  word32 add = min(len, SHA_BLOCK_SIZE  sha>buffLen);


367  XMEMCPY(&local[sha>buffLen], data, add);


368 


369  sha>buffLen += add;


370  data += add;


371  len = add;


372 


373  if (sha>buffLen == SHA_BLOCK_SIZE) {


374  #if defined(LITTLE_ENDIAN_ORDER) && !defined(FREESCALE_MMCAU)


375  ByteReverseWords(sha>buffer, sha>buffer, SHA_BLOCK_SIZE);


376  #endif


377  XTRANSFORM(sha, local);


378  AddLength(sha, SHA_BLOCK_SIZE);


379  sha>buffLen = 0;


380  }


381  }


382 


383  return 0;


384  }


385 


386 


387  int wc_ShaFinal(Sha* sha, byte* hash)


388  {


389  byte* local = (byte*)sha>buffer;


390 


391  AddLength(sha, sha>buffLen); /* before adding pads */


392 


393  local[sha>buffLen++] = 0x80; /* add 1 */


394 


395  /* pad with zeros */


396  if (sha>buffLen > SHA_PAD_SIZE) {


397  XMEMSET(&local[sha>buffLen], 0, SHA_BLOCK_SIZE  sha>buffLen);


398  sha>buffLen += SHA_BLOCK_SIZE  sha>buffLen;


399 


400  #if defined(LITTLE_ENDIAN_ORDER) && !defined(FREESCALE_MMCAU)


401  ByteReverseWords(sha>buffer, sha>buffer, SHA_BLOCK_SIZE);


402  #endif


403  XTRANSFORM(sha, local);


404  sha>buffLen = 0;


405  }


406  XMEMSET(&local[sha>buffLen], 0, SHA_PAD_SIZE  sha>buffLen);


407 


408  /* put lengths in bits */


409  sha>hiLen = (sha>loLen >> (8*sizeof(sha>loLen)  3)) +


410  (sha>hiLen << 3);


411  sha>loLen = sha>loLen << 3;


412 


413  /* store lengths */


414  #if defined(LITTLE_ENDIAN_ORDER) && !defined(FREESCALE_MMCAU)


415  ByteReverseWords(sha>buffer, sha>buffer, SHA_BLOCK_SIZE);


416  #endif


417  /* ! length ordering dependent on digest endian type ! */


418  XMEMCPY(&local[SHA_PAD_SIZE], &sha>hiLen, sizeof(word32));


419  XMEMCPY(&local[SHA_PAD_SIZE + sizeof(word32)], &sha>loLen, sizeof(word32));


420 


421  #ifdef FREESCALE_MMCAU


422  /* Kinetis requires only these bytes reversed */


423  ByteReverseWords(&sha>buffer[SHA_PAD_SIZE/sizeof(word32)],


424  &sha>buffer[SHA_PAD_SIZE/sizeof(word32)],


425  2 * sizeof(word32));


426  #endif


427 


428  XTRANSFORM(sha, local);


429  #ifdef LITTLE_ENDIAN_ORDER


430  ByteReverseWords(sha>digest, sha>digest, SHA_DIGEST_SIZE);


431  #endif


432  XMEMCPY(hash, sha>digest, SHA_DIGEST_SIZE);


433 


434  return wc_InitSha(sha); /* reset state */


435  }


436 


437  #endif /* STM32F2_HASH */


438 


439 


440 


441  #endif /* HAVE_FIPS */


442  #endif /* WOLFSSL_TI_HASH */


443  #endif /* NO_SHA */


444 

