CyaSSL is an SSL library for devices like mbed.

Dependents:   cyassl-client Sync

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers sha256.c Source File

sha256.c

00001 /* sha256.c
00002  *
00003  * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
00020  */
00021 
00022 /* code submitted by raphael.huck@efixo.com */
00023 
00024 
00025 
00026 #ifndef NO_SHA256
00027 
00028 #include "sha256.h"
00029 #ifdef NO_INLINE
00030     #include "misc.h"
00031 #else
00032     #include "misc.c"
00033 #endif
00034 
00035 
00036 #ifndef min
00037 
00038     static INLINE word32 min(word32 a, word32 b)
00039     {
00040         return a > b ? b : a;
00041     }
00042 
00043 #endif /* min */
00044 
00045 
00046 void InitSha256(Sha256* sha256)
00047 {
00048     sha256->digest[0] = 0x6A09E667L;
00049     sha256->digest[1] = 0xBB67AE85L;
00050     sha256->digest[2] = 0x3C6EF372L;
00051     sha256->digest[3] = 0xA54FF53AL;
00052     sha256->digest[4] = 0x510E527FL;
00053     sha256->digest[5] = 0x9B05688CL;
00054     sha256->digest[6] = 0x1F83D9ABL;
00055     sha256->digest[7] = 0x5BE0CD19L;
00056 
00057     sha256->buffLen = 0;
00058     sha256->loLen   = 0;
00059     sha256->hiLen   = 0;
00060 }
00061 
00062 static const word32 K[64] = {
00063     0x428A2F98L, 0x71374491L, 0xB5C0FBCFL, 0xE9B5DBA5L, 0x3956C25BL,
00064     0x59F111F1L, 0x923F82A4L, 0xAB1C5ED5L, 0xD807AA98L, 0x12835B01L,
00065     0x243185BEL, 0x550C7DC3L, 0x72BE5D74L, 0x80DEB1FEL, 0x9BDC06A7L,
00066     0xC19BF174L, 0xE49B69C1L, 0xEFBE4786L, 0x0FC19DC6L, 0x240CA1CCL,
00067     0x2DE92C6FL, 0x4A7484AAL, 0x5CB0A9DCL, 0x76F988DAL, 0x983E5152L,
00068     0xA831C66DL, 0xB00327C8L, 0xBF597FC7L, 0xC6E00BF3L, 0xD5A79147L,
00069     0x06CA6351L, 0x14292967L, 0x27B70A85L, 0x2E1B2138L, 0x4D2C6DFCL,
00070     0x53380D13L, 0x650A7354L, 0x766A0ABBL, 0x81C2C92EL, 0x92722C85L,
00071     0xA2BFE8A1L, 0xA81A664BL, 0xC24B8B70L, 0xC76C51A3L, 0xD192E819L,
00072     0xD6990624L, 0xF40E3585L, 0x106AA070L, 0x19A4C116L, 0x1E376C08L,
00073     0x2748774CL, 0x34B0BCB5L, 0x391C0CB3L, 0x4ED8AA4AL, 0x5B9CCA4FL,
00074     0x682E6FF3L, 0x748F82EEL, 0x78A5636FL, 0x84C87814L, 0x8CC70208L,
00075     0x90BEFFFAL, 0xA4506CEBL, 0xBEF9A3F7L, 0xC67178F2L
00076 };
00077 
00078 #define Ch(x,y,z)       (z ^ (x & (y ^ z)))
00079 #define Maj(x,y,z)      (((x | y) & z) | (x & y))
00080 #define S(x, n)         rotrFixed(x, n)
00081 #define R(x, n)         (((x)&0xFFFFFFFFL)>>(n))
00082 #define Sigma0(x)       (S(x, 2) ^ S(x, 13) ^ S(x, 22))
00083 #define Sigma1(x)       (S(x, 6) ^ S(x, 11) ^ S(x, 25))
00084 #define Gamma0(x)       (S(x, 7) ^ S(x, 18) ^ R(x, 3))
00085 #define Gamma1(x)       (S(x, 17) ^ S(x, 19) ^ R(x, 10))
00086 
00087 #define RND(a,b,c,d,e,f,g,h,i) \
00088      t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \
00089      t1 = Sigma0(a) + Maj(a, b, c); \
00090      d += t0; \
00091      h  = t0 + t1;
00092 
00093 
00094 static void Transform(Sha256* sha256)
00095 {
00096     word32 S[8], W[64], t0, t1;
00097     int i;
00098 
00099     /* Copy context->state[] to working vars */
00100     for (i = 0; i < 8; i++)
00101         S[i] = sha256->digest[i];
00102 
00103     for (i = 0; i < 16; i++)
00104         W[i] = sha256->buffer[i];
00105 
00106     for (i = 16; i < 64; i++)
00107         W[i] = Gamma1(W[i-2]) + W[i-7] + Gamma0(W[i-15]) + W[i-16];
00108 
00109     for (i = 0; i < 64; i += 8) {
00110         RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i+0);
00111         RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],i+1);
00112         RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],i+2);
00113         RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],i+3);
00114         RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],i+4);
00115         RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],i+5);
00116         RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],i+6);
00117         RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],i+7);
00118     }
00119 
00120     /* Add the working vars back into digest state[] */
00121     for (i = 0; i < 8; i++) {
00122         sha256->digest[i] += S[i];
00123     }
00124 }
00125 
00126 
00127 static INLINE void AddLength(Sha256* sha256, word32 len)
00128 {
00129     word32 tmp = sha256->loLen;
00130     if ( (sha256->loLen += len) < tmp)
00131         sha256->hiLen++;                       /* carry low to high */
00132 }
00133 
00134 
00135 void Sha256Update(Sha256* sha256, const byte* data, word32 len)
00136 {
00137     /* do block size increments */
00138     byte* local = (byte*)sha256->buffer;
00139 
00140     while (len) {
00141         word32 add = min(len, SHA256_BLOCK_SIZE - sha256->buffLen);
00142         XMEMCPY(&local[sha256->buffLen], data, add);
00143 
00144         sha256->buffLen += add;
00145         data            += add;
00146         len             -= add;
00147 
00148         if (sha256->buffLen == SHA256_BLOCK_SIZE) {
00149             #ifdef LITTLE_ENDIAN_ORDER
00150                 ByteReverseBytes(local, local, SHA256_BLOCK_SIZE);
00151             #endif
00152             Transform(sha256);
00153             AddLength(sha256, SHA256_BLOCK_SIZE);
00154             sha256->buffLen = 0;
00155         }
00156     }
00157 }
00158 
00159 
00160 void Sha256Final(Sha256* sha256, byte* hash)
00161 {
00162     byte* local = (byte*)sha256->buffer;
00163 
00164     AddLength(sha256, sha256->buffLen);  /* before adding pads */
00165 
00166     local[sha256->buffLen++] = 0x80;  /* add 1 */
00167 
00168     /* pad with zeros */
00169     if (sha256->buffLen > SHA256_PAD_SIZE) {
00170         XMEMSET(&local[sha256->buffLen], 0, SHA256_BLOCK_SIZE - sha256->buffLen);
00171         sha256->buffLen += SHA256_BLOCK_SIZE - sha256->buffLen;
00172 
00173         #ifdef LITTLE_ENDIAN_ORDER
00174             ByteReverseBytes(local, local, SHA256_BLOCK_SIZE);
00175         #endif
00176         Transform(sha256);
00177         sha256->buffLen = 0;
00178     }
00179     XMEMSET(&local[sha256->buffLen], 0, SHA256_PAD_SIZE - sha256->buffLen);
00180 
00181     /* put lengths in bits */
00182     sha256->loLen = sha256->loLen << 3;
00183     sha256->hiLen = (sha256->loLen >> (8*sizeof(sha256->loLen) - 3)) +
00184                  (sha256->hiLen << 3);
00185 
00186     /* store lengths */
00187     #ifdef LITTLE_ENDIAN_ORDER
00188         ByteReverseBytes(local, local, SHA256_BLOCK_SIZE);
00189     #endif
00190     /* ! length ordering dependent on digest endian type ! */
00191     XMEMCPY(&local[SHA256_PAD_SIZE], &sha256->hiLen, sizeof(word32));
00192     XMEMCPY(&local[SHA256_PAD_SIZE + sizeof(word32)], &sha256->loLen,
00193             sizeof(word32));
00194 
00195     Transform(sha256);
00196     #ifdef LITTLE_ENDIAN_ORDER
00197         ByteReverseWords(sha256->digest, sha256->digest, SHA256_DIGEST_SIZE);
00198     #endif
00199     XMEMCPY(hash, sha256->digest, SHA256_DIGEST_SIZE);
00200 
00201     InitSha256(sha256);  /* reset state */
00202 }
00203 
00204 
00205 #endif /* NO_SHA256 */
00206