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

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers sha512.c Source File

sha512.c

00001 /* sha512.c
00002  *
00003  * Copyright (C) 2006-2014 wolfSSL Inc.
00004  *
00005  * This file is part of CyaSSL.
00006  *
00007  * CyaSSL is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation; either version 2 of the License, or
00010  * (at your option) any later version.
00011  *
00012  * CyaSSL is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
00020  */
00021 
00022 #ifdef HAVE_CONFIG_H
00023     #include <config.h>
00024 #endif
00025 
00026 #include <cyassl/ctaocrypt/settings.h>
00027 
00028 #ifdef CYASSL_SHA512
00029 
00030 #ifdef HAVE_FIPS
00031     /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */
00032     #define FIPS_NO_WRAPPERS
00033 #endif
00034 
00035 #include <cyassl/ctaocrypt/sha512.h>
00036 #include <cyassl/ctaocrypt/logging.h>
00037 #include <cyassl/ctaocrypt/error-crypt.h>
00038 
00039 #ifdef NO_INLINE
00040     #include <cyassl/ctaocrypt/misc.h>
00041 #else
00042     #include <ctaocrypt/src/misc.c>
00043 #endif
00044 
00045 
00046 #ifndef min
00047 
00048     static INLINE word32 min(word32 a, word32 b)
00049     {
00050         return a > b ? b : a;
00051     }
00052 
00053 #endif /* min */
00054 
00055 
00056 int InitSha512(Sha512* sha512)
00057 {
00058     sha512->digest[0] = W64LIT(0x6a09e667f3bcc908);
00059     sha512->digest[1] = W64LIT(0xbb67ae8584caa73b);
00060     sha512->digest[2] = W64LIT(0x3c6ef372fe94f82b);
00061     sha512->digest[3] = W64LIT(0xa54ff53a5f1d36f1);
00062     sha512->digest[4] = W64LIT(0x510e527fade682d1);
00063     sha512->digest[5] = W64LIT(0x9b05688c2b3e6c1f);
00064     sha512->digest[6] = W64LIT(0x1f83d9abfb41bd6b);
00065     sha512->digest[7] = W64LIT(0x5be0cd19137e2179);
00066 
00067     sha512->buffLen = 0;
00068     sha512->loLen   = 0;
00069     sha512->hiLen   = 0;
00070 
00071     return 0;
00072 }
00073 
00074 
00075 static const word64 K512[80] = {
00076     W64LIT(0x428a2f98d728ae22), W64LIT(0x7137449123ef65cd),
00077     W64LIT(0xb5c0fbcfec4d3b2f), W64LIT(0xe9b5dba58189dbbc),
00078     W64LIT(0x3956c25bf348b538), W64LIT(0x59f111f1b605d019),
00079     W64LIT(0x923f82a4af194f9b), W64LIT(0xab1c5ed5da6d8118),
00080     W64LIT(0xd807aa98a3030242), W64LIT(0x12835b0145706fbe),
00081     W64LIT(0x243185be4ee4b28c), W64LIT(0x550c7dc3d5ffb4e2),
00082     W64LIT(0x72be5d74f27b896f), W64LIT(0x80deb1fe3b1696b1),
00083     W64LIT(0x9bdc06a725c71235), W64LIT(0xc19bf174cf692694),
00084     W64LIT(0xe49b69c19ef14ad2), W64LIT(0xefbe4786384f25e3),
00085     W64LIT(0x0fc19dc68b8cd5b5), W64LIT(0x240ca1cc77ac9c65),
00086     W64LIT(0x2de92c6f592b0275), W64LIT(0x4a7484aa6ea6e483),
00087     W64LIT(0x5cb0a9dcbd41fbd4), W64LIT(0x76f988da831153b5),
00088     W64LIT(0x983e5152ee66dfab), W64LIT(0xa831c66d2db43210),
00089     W64LIT(0xb00327c898fb213f), W64LIT(0xbf597fc7beef0ee4),
00090     W64LIT(0xc6e00bf33da88fc2), W64LIT(0xd5a79147930aa725),
00091     W64LIT(0x06ca6351e003826f), W64LIT(0x142929670a0e6e70),
00092     W64LIT(0x27b70a8546d22ffc), W64LIT(0x2e1b21385c26c926),
00093     W64LIT(0x4d2c6dfc5ac42aed), W64LIT(0x53380d139d95b3df),
00094     W64LIT(0x650a73548baf63de), W64LIT(0x766a0abb3c77b2a8),
00095     W64LIT(0x81c2c92e47edaee6), W64LIT(0x92722c851482353b),
00096     W64LIT(0xa2bfe8a14cf10364), W64LIT(0xa81a664bbc423001),
00097     W64LIT(0xc24b8b70d0f89791), W64LIT(0xc76c51a30654be30),
00098     W64LIT(0xd192e819d6ef5218), W64LIT(0xd69906245565a910),
00099     W64LIT(0xf40e35855771202a), W64LIT(0x106aa07032bbd1b8),
00100     W64LIT(0x19a4c116b8d2d0c8), W64LIT(0x1e376c085141ab53),
00101     W64LIT(0x2748774cdf8eeb99), W64LIT(0x34b0bcb5e19b48a8),
00102     W64LIT(0x391c0cb3c5c95a63), W64LIT(0x4ed8aa4ae3418acb),
00103     W64LIT(0x5b9cca4f7763e373), W64LIT(0x682e6ff3d6b2b8a3),
00104     W64LIT(0x748f82ee5defb2fc), W64LIT(0x78a5636f43172f60),
00105     W64LIT(0x84c87814a1f0ab72), W64LIT(0x8cc702081a6439ec),
00106     W64LIT(0x90befffa23631e28), W64LIT(0xa4506cebde82bde9),
00107     W64LIT(0xbef9a3f7b2c67915), W64LIT(0xc67178f2e372532b),
00108     W64LIT(0xca273eceea26619c), W64LIT(0xd186b8c721c0c207),
00109     W64LIT(0xeada7dd6cde0eb1e), W64LIT(0xf57d4f7fee6ed178),
00110     W64LIT(0x06f067aa72176fba), W64LIT(0x0a637dc5a2c898a6),
00111     W64LIT(0x113f9804bef90dae), W64LIT(0x1b710b35131c471b),
00112     W64LIT(0x28db77f523047d84), W64LIT(0x32caab7b40c72493),
00113     W64LIT(0x3c9ebe0a15c9bebc), W64LIT(0x431d67c49c100d4c),
00114     W64LIT(0x4cc5d4becb3e42b6), W64LIT(0x597f299cfc657e2a),
00115     W64LIT(0x5fcb6fab3ad6faec), W64LIT(0x6c44198c4a475817)
00116 };
00117 
00118 
00119 #define blk0(i) (W[i] = sha512->buffer[i])
00120 #define blk2(i) (W[i&15] += s1(W[(i-2)&15])+W[(i-7)&15]+s0(W[(i-15)&15])+0)
00121 
00122 #define Ch(x,y,z) (z^(x&(y^z)))
00123 #define Maj(x,y,z) ((x&y)|(z&(x|y)))
00124 
00125 #define a(i) T[(0-i)&7]
00126 #define b(i) T[(1-i)&7]
00127 #define c(i) T[(2-i)&7]
00128 #define d(i) T[(3-i)&7]
00129 #define e(i) T[(4-i)&7]
00130 #define f(i) T[(5-i)&7]
00131 #define g(i) T[(6-i)&7]
00132 #define h(i) T[(7-i)&7]
00133 
00134 #define S0(x) (rotrFixed64(x,28)^rotrFixed64(x,34)^rotrFixed64(x,39))
00135 #define S1(x) (rotrFixed64(x,14)^rotrFixed64(x,18)^rotrFixed64(x,41))
00136 #define s0(x) (rotrFixed64(x,1)^rotrFixed64(x,8)^(x>>7))
00137 #define s1(x) (rotrFixed64(x,19)^rotrFixed64(x,61)^(x>>6))
00138 
00139 #define R(i) (j?blk2(i):blk0(i));\
00140     h(i)+=S1(e(i))+Ch(e(i),f(i),g(i))+K[i+j]+W[i&15];\
00141     d(i)+=h(i);h(i)+=S0(a(i))+Maj(a(i),b(i),c(i))
00142 
00143 #define blk384(i) (W[i] = sha384->buffer[i])
00144 
00145 #define R2(i) (j?blk2(i):blk384(i));\
00146     h(i)+=S1(e(i))+Ch(e(i),f(i),g(i))+K[i+j]+W[i&15];\
00147     d(i)+=h(i);\
00148     h(i)+=S0(a(i))+Maj(a(i),b(i),c(i))
00149 
00150 
00151 static int Transform(Sha512* sha512)
00152 {
00153     const word64* K = K512;
00154 
00155     word32 j;
00156     word64 T[8];
00157 
00158 #ifdef CYASSL_SMALL_STACK
00159     word64* W;
00160 
00161     W = (word64*) XMALLOC(sizeof(word64) * 16, NULL, DYNAMIC_TYPE_TMP_BUFFER);
00162     if (W == NULL)
00163         return MEMORY_E;
00164 #else
00165     word64 W[16];
00166 #endif
00167 
00168     /* Copy digest to working vars */
00169     XMEMCPY(T, sha512->digest, sizeof(T));
00170 
00171 #ifdef USE_SLOW_SHA2
00172     /* over twice as small, but 50% slower */
00173     /* 80 operations, not unrolled */
00174     for (j = 0; j < 80; j += 16) {
00175         int m; 
00176         for (m = 0; m < 16; m++) { /* braces needed here for macros {} */
00177             R(m);
00178         }
00179     }
00180 #else
00181     /* 80 operations, partially loop unrolled */
00182     for (j = 0; j < 80; j += 16) {
00183         R( 0); R( 1); R( 2); R( 3);
00184         R( 4); R( 5); R( 6); R( 7);
00185         R( 8); R( 9); R(10); R(11);
00186         R(12); R(13); R(14); R(15);
00187     }
00188 #endif /* USE_SLOW_SHA2 */
00189 
00190     /* Add the working vars back into digest */
00191 
00192     sha512->digest[0] += a(0);
00193     sha512->digest[1] += b(0);
00194     sha512->digest[2] += c(0);
00195     sha512->digest[3] += d(0);
00196     sha512->digest[4] += e(0);
00197     sha512->digest[5] += f(0);
00198     sha512->digest[6] += g(0);
00199     sha512->digest[7] += h(0);
00200 
00201     /* Wipe variables */
00202     XMEMSET(W, 0, sizeof(word64) * 16);
00203     XMEMSET(T, 0, sizeof(T));
00204 
00205 #ifdef CYASSL_SMALL_STACK
00206     XFREE(W, NULL, DYNAMIC_TYPE_TMP_BUFFER);
00207 #endif
00208 
00209     return 0;
00210 }
00211 
00212 
00213 static INLINE void AddLength(Sha512* sha512, word32 len)
00214 {
00215     word32 tmp = sha512->loLen;
00216     if ( (sha512->loLen += len) < tmp)
00217         sha512->hiLen++;                       /* carry low to high */
00218 }
00219 
00220 
00221 int Sha512Update(Sha512* sha512, const byte* data, word32 len)
00222 {
00223     /* do block size increments */
00224     byte* local = (byte*)sha512->buffer;
00225 
00226     while (len) {
00227         word32 add = min(len, SHA512_BLOCK_SIZE - sha512->buffLen);
00228         XMEMCPY(&local[sha512->buffLen], data, add);
00229 
00230         sha512->buffLen += add;
00231         data         += add;
00232         len          -= add;
00233 
00234         if (sha512->buffLen == SHA512_BLOCK_SIZE) {
00235             int ret;
00236 
00237             #ifdef LITTLE_ENDIAN_ORDER
00238                 ByteReverseWords64(sha512->buffer, sha512->buffer,
00239                                    SHA512_BLOCK_SIZE);
00240             #endif
00241             ret = Transform(sha512);
00242             if (ret != 0)
00243                 return ret;
00244 
00245             AddLength(sha512, SHA512_BLOCK_SIZE);
00246             sha512->buffLen = 0;
00247         }
00248     }
00249     return 0;
00250 }
00251 
00252 
00253 int Sha512Final(Sha512* sha512, byte* hash)
00254 {
00255     byte* local = (byte*)sha512->buffer;
00256     int ret;
00257 
00258     AddLength(sha512, sha512->buffLen);               /* before adding pads */
00259 
00260     local[sha512->buffLen++] = 0x80;  /* add 1 */
00261 
00262     /* pad with zeros */
00263     if (sha512->buffLen > SHA512_PAD_SIZE) {
00264         XMEMSET(&local[sha512->buffLen], 0, SHA512_BLOCK_SIZE -sha512->buffLen);
00265         sha512->buffLen += SHA512_BLOCK_SIZE - sha512->buffLen;
00266 
00267         #ifdef LITTLE_ENDIAN_ORDER
00268             ByteReverseWords64(sha512->buffer,sha512->buffer,SHA512_BLOCK_SIZE);
00269         #endif
00270         ret = Transform(sha512);
00271         if (ret != 0)
00272             return ret;
00273 
00274         sha512->buffLen = 0;
00275     }
00276     XMEMSET(&local[sha512->buffLen], 0, SHA512_PAD_SIZE - sha512->buffLen);
00277    
00278     /* put lengths in bits */
00279     sha512->hiLen = (sha512->loLen >> (8*sizeof(sha512->loLen) - 3)) + 
00280                  (sha512->hiLen << 3);
00281     sha512->loLen = sha512->loLen << 3;
00282 
00283     /* store lengths */
00284     #ifdef LITTLE_ENDIAN_ORDER
00285         ByteReverseWords64(sha512->buffer, sha512->buffer, SHA512_PAD_SIZE);
00286     #endif
00287     /* ! length ordering dependent on digest endian type ! */
00288     sha512->buffer[SHA512_BLOCK_SIZE / sizeof(word64) - 2] = sha512->hiLen;
00289     sha512->buffer[SHA512_BLOCK_SIZE / sizeof(word64) - 1] = sha512->loLen;
00290 
00291     ret = Transform(sha512);
00292     if (ret != 0)
00293         return ret;
00294 
00295     #ifdef LITTLE_ENDIAN_ORDER
00296         ByteReverseWords64(sha512->digest, sha512->digest, SHA512_DIGEST_SIZE);
00297     #endif
00298     XMEMCPY(hash, sha512->digest, SHA512_DIGEST_SIZE);
00299 
00300     return InitSha512(sha512);  /* reset state */
00301 }
00302 
00303 
00304 int Sha512Hash(const byte* data, word32 len, byte* hash)
00305 {
00306     int ret = 0;
00307 #ifdef CYASSL_SMALL_STACK
00308     Sha512* sha512;
00309 #else
00310     Sha512 sha512[1];
00311 #endif
00312 
00313 #ifdef CYASSL_SMALL_STACK
00314     sha512 = (Sha512*)XMALLOC(sizeof(Sha512), NULL, DYNAMIC_TYPE_TMP_BUFFER);
00315     if (sha512 == NULL)
00316         return MEMORY_E;
00317 #endif
00318     
00319     if ((ret = InitSha512(sha512)) != 0) {
00320         CYASSL_MSG("InitSha512 failed");
00321     }
00322     else if ((ret = Sha512Update(sha512, data, len)) != 0) {
00323         CYASSL_MSG("Sha512Update failed");
00324     }
00325     else if ((ret = Sha512Final(sha512, hash)) != 0) {
00326         CYASSL_MSG("Sha512Final failed");
00327     }
00328     
00329 #ifdef CYASSL_SMALL_STACK
00330     XFREE(sha512, NULL, DYNAMIC_TYPE_TMP_BUFFER);
00331 #endif
00332     
00333     return ret;
00334 }
00335 
00336 
00337 #ifdef CYASSL_SHA384
00338 
00339 int InitSha384(Sha384* sha384)
00340 {
00341     sha384->digest[0] = W64LIT(0xcbbb9d5dc1059ed8);
00342     sha384->digest[1] = W64LIT(0x629a292a367cd507);
00343     sha384->digest[2] = W64LIT(0x9159015a3070dd17);
00344     sha384->digest[3] = W64LIT(0x152fecd8f70e5939);
00345     sha384->digest[4] = W64LIT(0x67332667ffc00b31);
00346     sha384->digest[5] = W64LIT(0x8eb44a8768581511);
00347     sha384->digest[6] = W64LIT(0xdb0c2e0d64f98fa7);
00348     sha384->digest[7] = W64LIT(0x47b5481dbefa4fa4);
00349 
00350     sha384->buffLen = 0;
00351     sha384->loLen   = 0;
00352     sha384->hiLen   = 0;
00353 
00354     return 0;
00355 }
00356 
00357 
00358 static int Transform384(Sha384* sha384)
00359 {
00360     const word64* K = K512;
00361 
00362     word32 j;
00363     word64 T[8];
00364 
00365 #ifdef CYASSL_SMALL_STACK
00366     word64* W;
00367 
00368     W = (word64*) XMALLOC(sizeof(word64) * 16, NULL, DYNAMIC_TYPE_TMP_BUFFER);
00369     if (W == NULL)
00370         return MEMORY_E;
00371 #else
00372     word64 W[16];
00373 #endif
00374 
00375     /* Copy digest to working vars */
00376     XMEMCPY(T, sha384->digest, sizeof(T));
00377 
00378 #ifdef USE_SLOW_SHA2
00379     /* over twice as small, but 50% slower */
00380     /* 80 operations, not unrolled */
00381     for (j = 0; j < 80; j += 16) {
00382         int m;
00383         for (m = 0; m < 16; m++) {  /* braces needed for macros {} */
00384             R2(m);
00385         }
00386     }
00387 #else
00388     /* 80 operations, partially loop unrolled */
00389     for (j = 0; j < 80; j += 16) {
00390         R2( 0); R2( 1); R2( 2); R2( 3);
00391         R2( 4); R2( 5); R2( 6); R2( 7);
00392         R2( 8); R2( 9); R2(10); R2(11);
00393         R2(12); R2(13); R2(14); R2(15);
00394     }
00395 #endif /* USE_SLOW_SHA2 */
00396 
00397     /* Add the working vars back into digest */
00398 
00399     sha384->digest[0] += a(0);
00400     sha384->digest[1] += b(0);
00401     sha384->digest[2] += c(0);
00402     sha384->digest[3] += d(0);
00403     sha384->digest[4] += e(0);
00404     sha384->digest[5] += f(0);
00405     sha384->digest[6] += g(0);
00406     sha384->digest[7] += h(0);
00407 
00408     /* Wipe variables */
00409     XMEMSET(W, 0, sizeof(word64) * 16);
00410     XMEMSET(T, 0, sizeof(T));
00411 
00412 #ifdef CYASSL_SMALL_STACK
00413     XFREE(W, NULL, DYNAMIC_TYPE_TMP_BUFFER);
00414 #endif
00415 
00416     return 0;
00417 }
00418 
00419 
00420 static INLINE void AddLength384(Sha384* sha384, word32 len)
00421 {
00422     word32 tmp = sha384->loLen;
00423     if ( (sha384->loLen += len) < tmp)
00424         sha384->hiLen++;                       /* carry low to high */
00425 }
00426 
00427 
00428 int Sha384Update(Sha384* sha384, const byte* data, word32 len)
00429 {
00430     /* do block size increments */
00431     byte* local = (byte*)sha384->buffer;
00432 
00433     while (len) {
00434         word32 add = min(len, SHA384_BLOCK_SIZE - sha384->buffLen);
00435         XMEMCPY(&local[sha384->buffLen], data, add);
00436 
00437         sha384->buffLen += add;
00438         data         += add;
00439         len          -= add;
00440 
00441         if (sha384->buffLen == SHA384_BLOCK_SIZE) {
00442             int ret;
00443 
00444             #ifdef LITTLE_ENDIAN_ORDER
00445                 ByteReverseWords64(sha384->buffer, sha384->buffer,
00446                                    SHA384_BLOCK_SIZE);
00447             #endif
00448             ret = Transform384(sha384);
00449             if (ret != 0)
00450                 return ret;
00451 
00452             AddLength384(sha384, SHA384_BLOCK_SIZE);
00453             sha384->buffLen = 0;
00454         }
00455     }
00456     return 0;
00457 }
00458 
00459 
00460 int Sha384Final(Sha384* sha384, byte* hash)
00461 {
00462     byte* local = (byte*)sha384->buffer;
00463     int ret;
00464 
00465     AddLength384(sha384, sha384->buffLen);              /* before adding pads */
00466 
00467     local[sha384->buffLen++] = 0x80;  /* add 1 */
00468 
00469     /* pad with zeros */
00470     if (sha384->buffLen > SHA384_PAD_SIZE) {
00471         XMEMSET(&local[sha384->buffLen], 0, SHA384_BLOCK_SIZE -sha384->buffLen);
00472         sha384->buffLen += SHA384_BLOCK_SIZE - sha384->buffLen;
00473 
00474         #ifdef LITTLE_ENDIAN_ORDER
00475             ByteReverseWords64(sha384->buffer,sha384->buffer,SHA384_BLOCK_SIZE);
00476         #endif
00477         ret = Transform384(sha384);
00478         if (ret !=  0)
00479             return ret;
00480 
00481         sha384->buffLen = 0;
00482     }
00483     XMEMSET(&local[sha384->buffLen], 0, SHA384_PAD_SIZE - sha384->buffLen);
00484    
00485     /* put lengths in bits */
00486     sha384->hiLen = (sha384->loLen >> (8*sizeof(sha384->loLen) - 3)) + 
00487                  (sha384->hiLen << 3);
00488     sha384->loLen = sha384->loLen << 3;
00489 
00490     /* store lengths */
00491     #ifdef LITTLE_ENDIAN_ORDER
00492         ByteReverseWords64(sha384->buffer, sha384->buffer, SHA384_PAD_SIZE);
00493     #endif
00494     /* ! length ordering dependent on digest endian type ! */
00495     sha384->buffer[SHA384_BLOCK_SIZE / sizeof(word64) - 2] = sha384->hiLen;
00496     sha384->buffer[SHA384_BLOCK_SIZE / sizeof(word64) - 1] = sha384->loLen;
00497 
00498     ret = Transform384(sha384);
00499     if (ret != 0)
00500         return ret;
00501 
00502     #ifdef LITTLE_ENDIAN_ORDER
00503         ByteReverseWords64(sha384->digest, sha384->digest, SHA384_DIGEST_SIZE);
00504     #endif
00505     XMEMCPY(hash, sha384->digest, SHA384_DIGEST_SIZE);
00506 
00507     return InitSha384(sha384);  /* reset state */
00508 }
00509 
00510 
00511 int Sha384Hash(const byte* data, word32 len, byte* hash)
00512 {
00513     int ret = 0;
00514 #ifdef CYASSL_SMALL_STACK
00515     Sha384* sha384;
00516 #else
00517     Sha384 sha384[1];
00518 #endif
00519 
00520 #ifdef CYASSL_SMALL_STACK
00521     sha384 = (Sha384*)XMALLOC(sizeof(Sha384), NULL, DYNAMIC_TYPE_TMP_BUFFER);
00522     if (sha384 == NULL)
00523         return MEMORY_E;
00524 #endif
00525 
00526     if ((ret = InitSha384(sha384)) != 0) {
00527         CYASSL_MSG("InitSha384 failed");
00528     }
00529     else if ((ret = Sha384Update(sha384, data, len)) != 0) {
00530         CYASSL_MSG("Sha384Update failed");
00531     }
00532     else if ((ret = Sha384Final(sha384, hash)) != 0) {
00533         CYASSL_MSG("Sha384Final failed");
00534     }
00535 
00536 #ifdef CYASSL_SMALL_STACK
00537     XFREE(sha384, NULL, DYNAMIC_TYPE_TMP_BUFFER);
00538 #endif
00539 
00540     return ret;
00541 }
00542 
00543 #endif /* CYASSL_SHA384 */
00544 
00545 #endif /* CYASSL_SHA512 */