Wiselib
wiselib.testing/algorithms/crypto/sha1.h
Go to the documentation of this file.
00001 /***************************************************************************
00002  ** This file is part of the generic algorithm library Wiselib.           **
00003  ** Copyright (C) 2008,2009 by the Wisebed (www.wisebed.eu) project.      **
00004  **                                                                       **
00005  ** The Wiselib is free software: you can redistribute it and/or modify   **
00006  ** it under the terms of the GNU Lesser General Public License as        **
00007  ** published by the Free Software Foundation, either version 3 of the    **
00008  ** License, or (at your option) any later version.                       **
00009  **                                                                       **
00010  ** The Wiselib is distributed in the hope that it will be useful,        **
00011  ** but WITHOUT ANY WARRANTY; without even the implied warranty of        **
00012  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         **
00013  ** GNU Lesser General Public License for more details.                   **
00014  **                                                                       **
00015  ** You should have received a copy of the GNU Lesser General Public      **
00016  ** License along with the Wiselib.                                       **
00017  ** If not, see <http://www.gnu.org/licenses/>.                           **
00018  ***************************************************************************/
00019 
00020 #ifndef __ALGORITHMS_CRYPTO_SHA1_H_
00021 #define __ALGORITHMS_CRYPTO_SHA1_H_
00022 
00023 #include "algorithms/crypto/pmp.h"
00024 #include <string.h>
00025 
00026 #ifndef _SHA_enum_
00027 #define _SHA_enum_
00028 enum
00029 {
00030     shaSuccess = 0,
00031     shaNull,            /* Null pointer parameter */
00032     shaInputTooLong,    /* input data too long */
00033     shaStateError       /* called Input after Result */
00034 };
00035 #endif
00036 #define SHA1HashSize 20
00037 #define METHOD2
00038 
00039 /*Define the circular shift macro*/
00040 #define SHA1CircularShift(bits,word) \
00041                 ((((word) << (bits)) & 0xFFFFFFFF) | \
00042                 ((word) >> (32-(bits))))
00043 
00044 
00045 namespace wiselib
00046 {
00047    typedef struct SHA1Context
00048    {
00049       uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest  */
00050 
00051       uint32_t Length_Low;            /* Message length in bits      */
00052       uint32_t Length_High;           /* Message length in bits      */
00053 
00054                         /* Index into message block array   */
00055       uint16_t Message_Block_Index;
00056       uint8_t Message_Block[64];      /* 512-bit message blocks      */
00057 
00058       int8_t Computed;               /* Is the digest computed?         */
00059       int8_t Corrupted;             /* Is the message digest corrupted? */
00060    } SHA1Context;
00061 
00071 class SHA1
00072    {
00073    public:
00074 
00075       //sha1reset
00076       static void SHA1Reset(SHA1Context *context)
00077       {
00078          context->Length_Low             = 0;
00079          context->Length_High            = 0;
00080          context->Message_Block_Index    = 0;
00081 
00082          context->Intermediate_Hash[0]      = 0x67452301;
00083          context->Intermediate_Hash[1]      = 0xEFCDAB89;
00084          context->Intermediate_Hash[2]      = 0x98BADCFE;
00085          context->Intermediate_Hash[3]      = 0x10325476;
00086          context->Intermediate_Hash[4]      = 0xC3D2E1F0;
00087 
00088          context->Computed   = 0;
00089          context->Corrupted  = 0;
00090       }
00091 
00092       //sha1processmessageblock
00093       static void SHA1ProcessMessageBlock(SHA1Context *context)
00094       {
00095          const uint32_t K[] =    {       /* Constants defined in SHA-1   */
00096                0x5A827999,
00097                0x6ED9EBA1,
00098                0x8F1BBCDC,
00099                0xCA62C1D6
00100          };
00101          uint8_t       t;                 /* Loop counter                */
00102          uint32_t      temp;              /* Temporary word value        */
00103 #ifdef METHOD2
00104          uint8_t       s;
00105          uint32_t      W[16];
00106 #else
00107          uint32_t      W[80];             /* Word sequence               */
00108 #endif
00109          uint32_t      wA, wB, wC, wD, wE;     /* Word buffers                */
00110 
00111          /*
00112           *  Initialize the first 16 words in the array W
00113           */
00114          for(t = 0; t < 16; t++){
00115             W[t] = ((uint32_t)context->Message_Block[t * 4]) << 24;
00116             W[t] |= ((uint32_t)context->Message_Block[t * 4 + 1]) << 16;
00117             W[t] |= ((uint32_t)context->Message_Block[t * 4 + 2]) << 8;
00118             W[t] |= ((uint32_t)context->Message_Block[t * 4 + 3]);
00119          }
00120 
00121 #ifndef METHOD2
00122          for(t = 16; t < 80; t++){
00123             W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
00124          }
00125 #endif
00126 
00127          wA = context->Intermediate_Hash[0];
00128          wB = context->Intermediate_Hash[1];
00129          wC = context->Intermediate_Hash[2];
00130          wD = context->Intermediate_Hash[3];
00131          wE = context->Intermediate_Hash[4];
00132 
00133          for(t = 0; t < 20; t++){
00134 #ifdef METHOD2
00135             s = t & 0x0f;
00136             if (t >= 16){
00137                W[s] = SHA1CircularShift(1,
00138                      W[(s + 13) & 0x0f] ^ \
00139                      W[(s + 8) & 0x0f] ^ \
00140                      W[(s + 2) & 0x0f] ^ \
00141                      W[s]);
00142             }
00143             temp =  SHA1CircularShift(5,wA) +
00144                   ((wB & wC) | ((~wB) & wD)) + wE + W[s] + K[0];
00145 #else
00146             temp =  SHA1CircularShift(5,A) +
00147                   ((wB & wC) | ((~wB) & wD)) + wE + W[t] + K[0];
00148 #endif
00149             wE = wD;
00150             wD = wC;
00151             wC = SHA1CircularShift(30,wB);
00152 
00153             wB = wA;
00154             wA = temp;
00155          }
00156 
00157          for(t = 20; t < 40; t++){
00158 #ifdef METHOD2
00159             s = t & 0x0f;
00160             W[s] = SHA1CircularShift(1,
00161                   W[(s + 13) & 0x0f] ^  \
00162                   W[(s + 8) & 0x0f] ^   \
00163                   W[(s + 2) & 0x0f] ^   \
00164                   W[s]);
00165             temp = SHA1CircularShift(5,wA) + (wB ^ wC ^ wD) + wE + W[s] + K[1];
00166 #else
00167             temp = SHA1CircularShift(5,wA) + (wB ^ wC ^ wD) + wE + W[t] + K[1];
00168 #endif
00169             wE = wD;
00170             wD = wC;
00171             wC = SHA1CircularShift(30,wB);
00172             wB = wA;
00173             wA = temp;
00174          }
00175 
00176          for(t = 40; t < 60; t++){
00177 #ifdef METHOD2
00178             s = t & 0x0f;
00179             W[s] = SHA1CircularShift(1,
00180                   W[(s + 13) & 0x0f] ^  \
00181                   W[(s + 8) & 0x0f] ^   \
00182                   W[(s + 2) & 0x0f] ^   \
00183                   W[s]);
00184             temp = SHA1CircularShift(5,wA) +
00185                   ((wB & wC) | (wB & wD) | (wC & wD)) + wE + W[s] + K[2];
00186 #else
00187             temp = SHA1CircularShift(5,A) +
00188                   ((wB & wC) | (wB & wD) | (wC & wD)) + wE + W[t] + K[2];
00189 #endif
00190             wE = wD;
00191             wD = wC;
00192             wC = SHA1CircularShift(30,wB);
00193             wB = wA;
00194             wA = temp;
00195          }
00196 
00197          for(t = 60; t < 80; t++){
00198 #ifdef METHOD2
00199             s = t & 0x0f;
00200             W[s] = SHA1CircularShift(1,
00201                   W[(s + 13) & 0x0f] ^  \
00202                   W[(s + 8) & 0x0f] ^   \
00203                   W[(s + 2) & 0x0f] ^   \
00204                   W[s]);
00205             temp = SHA1CircularShift(5,wA) + (wB ^ wC ^ wD) + wE + W[s] + K[3];
00206 #else
00207             temp = SHA1CircularShift(5,wA) + (wB ^ wC ^ wD) + wE + W[t] + K[3];
00208 #endif
00209             wE = wD;
00210             wD = wC;
00211             wC = SHA1CircularShift(30,wB);
00212             wB = wA;
00213             wA = temp;
00214          }
00215 
00216          context->Intermediate_Hash[0] += wA;
00217          context->Intermediate_Hash[1] += wB;
00218          context->Intermediate_Hash[2] += wC;
00219          context->Intermediate_Hash[3] += wD;
00220          context->Intermediate_Hash[4] += wE;
00221 
00222          context->Message_Block_Index = 0;
00223       }
00224 
00225       //sha1pad
00226       static void SHA1PadMessage(SHA1Context *context)
00227       {
00228          /*
00229           *  Check to see if the current message block is too small to hold
00230           *  the initial padding bits and length.  If so, we will pad the
00231           *  block, process it, and then continue padding into a second
00232           *  block.
00233           */
00234          if (context->Message_Block_Index > 55){
00235             context->Message_Block[context->Message_Block_Index++] = 0x80;
00236             while(context->Message_Block_Index < 64){
00237                context->Message_Block[context->Message_Block_Index++] = 0;
00238             }
00239 
00240             SHA1ProcessMessageBlock(context);
00241 
00242             while(context->Message_Block_Index < 56){
00243                context->Message_Block[context->Message_Block_Index++] = 0;
00244             }
00245          }else{
00246             context->Message_Block[context->Message_Block_Index++] = 0x80;
00247             while(context->Message_Block_Index < 56){
00248                context->Message_Block[context->Message_Block_Index++] = 0;
00249             }
00250          }
00251 
00252          /*
00253           *  Store the message length as the last 8 octets
00254           */
00255          context->Message_Block[56] = context->Length_High >> 24;
00256          context->Message_Block[57] = context->Length_High >> 16;
00257          context->Message_Block[58] = context->Length_High >> 8;
00258          context->Message_Block[59] = context->Length_High;
00259          context->Message_Block[60] = context->Length_Low >> 24;
00260          context->Message_Block[61] = context->Length_Low >> 16;
00261          context->Message_Block[62] = context->Length_Low >> 8;
00262          context->Message_Block[63] = context->Length_Low;
00263 
00264          SHA1ProcessMessageBlock(context);
00265       }
00266 
00267       //sha1digest
00268       static int8_t SHA1Digest( SHA1Context *context, uint8_t Message_Digest[SHA1HashSize])
00269       {
00270          uint8_t i;
00271 
00272          if (!context || !Message_Digest){
00273             return shaNull;
00274          }
00275 
00276          if (context->Corrupted){
00277             return context->Corrupted;
00278          }
00279 
00280          if (!context->Computed){
00281             SHA1PadMessage(context);
00282             for(i=0; i<64; ++i){
00283                /* message may be sensitive, clear it out */
00284                context->Message_Block[i] = 0;
00285             }
00286             context->Length_Low = 0;    /* and clear length */
00287             context->Length_High = 0;
00288             context->Computed = 1;
00289 
00290          }
00291 
00292          for(i = 0; i < SHA1HashSize; ++i){
00293             Message_Digest[i] = context->Intermediate_Hash[i>>2]
00294                                                            >> 8 * ( 3 - ( i & 0x03 ) );
00295          }
00296 
00297          return 1;
00298       }
00299 
00300       //sha1update
00301       static int8_t SHA1Update(SHA1Context *context, const uint8_t *message_array, uint32_t length)
00302       {
00303          if (!length){
00304             return shaSuccess;
00305          }
00306 
00307          if (!context || !message_array){
00308             return shaNull;
00309          }
00310 
00311          if (context->Computed){
00312             context->Corrupted = shaStateError;
00313 
00314             return shaStateError;
00315          }
00316 
00317          if (context->Corrupted){
00318             return context->Corrupted;
00319          }
00320          while(length-- && !context->Corrupted){
00321             context->Message_Block[context->Message_Block_Index++] =
00322                   (*message_array & 0xFF);
00323 
00324             context->Length_Low += 8;
00325             if (context->Length_Low == 0){
00326                context->Length_High++;
00327                if (context->Length_High == 0){
00328                   /* Message is too long */
00329                   context->Corrupted = 1;
00330                }
00331             }
00332 
00333             if (context->Message_Block_Index == 64){
00334                SHA1ProcessMessageBlock(context);
00335             }
00336 
00337             message_array++;
00338          }
00339 
00340          return shaSuccess;
00341       }
00342 
00343       //key derivation function
00344       static void KDF(uint8_t *Kp, int32_t K_len, uint8_t *Zp)
00345       {
00346          int32_t len, i;
00347          uint8_t z[KEYDIGITS*NN_DIGIT_LEN+4];
00348          SHA1Context ctx;
00349          uint8_t sha1sum[20];
00350 
00351          memcpy(z, Zp, KEYDIGITS*NN_DIGIT_LEN);
00352          memset(z + KEYDIGITS*NN_DIGIT_LEN, 0, 3);
00353          //KDF
00354          len = K_len;
00355          i = 1;
00356          while(len > 0){
00357             z[KEYDIGITS*NN_DIGIT_LEN + 3] = i;
00358             SHA1Reset(&ctx);
00359             SHA1Update(&ctx, z, KEYDIGITS*NN_DIGIT_LEN+4);
00360             SHA1Digest(&ctx, sha1sum);
00361             if(len >= 20){
00362                memcpy(Kp+(i-1)*20, sha1sum, 20);
00363             }else{
00364                memcpy(Kp+(i-1)*20, sha1sum, len);
00365             }
00366             i++;
00367             len = len - 20;
00368          }
00369       }
00370 
00371 
00372       //function for mac generation on the data and the key
00373       static void hmac_sha1(uint8_t *text, int32_t text_len, uint8_t *key, int32_t key_len, uint8_t *digest)
00374       {
00375          SHA1Context context;
00376          uint8_t k_ipad[65];        /* inner padding -
00377           * key XORd with ipad
00378           */
00379          uint8_t k_opad[65];     /* outer padding -
00380           * key XORd with opad
00381           */
00382          int8_t i;
00383 
00384          /*
00385           * the HMAC_SHA1 transform looks like:
00386           *
00387           * SHA1(K XOR opad, SHA1(K XOR ipad, text))
00388           *
00389           * where K is an n byte key
00390           * ipad is the byte 0x36 repeated 64 times
00391 
00392           * opad is the byte 0x5c repeated 64 times
00393           * and text is the data being protected
00394           */
00395 
00396          /* start out by storing key in pads */
00397          memcpy(k_ipad, key, key_len);
00398          memset(k_ipad + key_len, 0, 65 - key_len);
00399          memcpy(k_opad, key, key_len);
00400          memset(k_opad + key_len, 0, 65 - key_len);
00401 
00402          /* XOR key with ipad and opad values */
00403          for (i=0; i<64; i++) {
00404             k_ipad[i] ^= 0x36;
00405             k_opad[i] ^= 0x5c;
00406          }
00407          /*
00408           * perform inner SHA1
00409           */
00410          SHA1Reset(&context);                   /* init context for 1st pass */
00411          SHA1Update(&context, k_ipad, 64);      /* start with inner pad */
00412          SHA1Update(&context, text, text_len); /* then text of datagram */
00413          SHA1Digest(&context, digest);          /* finish up 1st pass */
00414          /*
00415           * perform outer SHA1
00416           */
00417          SHA1Reset(&context);                   /* init context for 2nd pass */
00418          SHA1Update(&context, k_opad, 64);     /* start with outer pad */
00419          SHA1Update(&context, digest, 20);
00420          SHA1Digest(&context, digest);         /* then results of 1st hash */
00421 
00422       }
00423 };
00424 
00425 } //end of namespace wiselib
00426 
00427 #endif //SHA1_H
00428 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines