sha1transform.cpp

Go to the documentation of this file.
00001 /**
00002  *  \file sha1transform.cpp
00003  *
00004  *      This file implements the Secure Hashing Algorithm 1 as
00005  *      defined in FIPS PUB 180-1 published April 17, 1995.
00006  *
00007  *      The SHA-1, produces a 160-bit message digest for a given
00008  *      data stream.  It should take about 2**n steps to find a
00009  *      message with the same digest as a given message and
00010  *      2**(n/2) to find any two messages with the same digest,
00011  *      when n is the digest size in bits.  Therefore, this
00012  *      algorithm can serve as a means of providing a
00013  *      "fingerprint" for a message.
00014  *
00015  *  Portability Issues:
00016  *      SHA-1 is defined in terms of 32-bit "words".  This code
00017  *      uses <stdint.h> (included via "sha1.h" to define 32 and 8
00018  *      bit unsigned integer types.  If your C compiler does not
00019  *      support 32 bit unsigned integers, this code is not
00020  *      appropriate.
00021  *
00022  *  Caveats:
00023  *      SHA-1 is designed to work with messages less than 2^64 bits
00024  *      long.  Although SHA-1 allows a message digest to be generated
00025  *      for messages of any number of bits less than 2^64, this
00026  *      implementation only works with messages with a length that is
00027  *      a multiple of the size of an 8-bit character.
00028  *
00029  */
00030 
00031 #include <hn/hnprec.h>
00032 #include <hn/sha1transform.h>
00033 
00034 /*
00035  *  Define the SHA1 circular left shift macro
00036  */
00037 #define SHA1CircularShift(bits,word) \
00038                 (((word) << (bits)) | ((word) >> (32-(bits))))
00039 
00040 /*
00041  *  SHA1ProcessMessageBlock
00042  *
00043  *  Description:
00044  *      This function will process the next 512 bits of the message
00045  *      stored in the Message_Block array.
00046  *
00047  *  Parameters:
00048  *      None.
00049  *
00050  *  Returns:
00051  *      Nothing.
00052  *
00053  *  Comments:
00054  *      Many of the variable names in this code, especially the
00055  *      single character names, were used because those were the
00056  *      names used in the publication.
00057  *
00058  *
00059  */
00060 void Sha1Transform::SHA1ProcessMessageBlock() {
00061         const uint32_t K[] = {          /* Constants defined in SHA-1   */
00062                 0x5A827999,
00063                 0x6ED9EBA1,
00064                 0x8F1BBCDC,
00065                 0xCA62C1D6
00066         };
00067         int           t;                 /* Loop counter                */
00068         uint32_t      temp;              /* Temporary word value        */
00069         uint32_t      W[80];             /* Word sequence               */
00070         uint32_t      A, B, C, D, E;     /* Word buffers                */
00071 
00072         /*
00073          *  Initialize the first 16 words in the array W
00074          */
00075         for(t = 0; t < 16; t++) {
00076                 W[t] = Message_Block[t * 4] << 24;
00077                 W[t] |= Message_Block[t * 4 + 1] << 16;
00078                 W[t] |= Message_Block[t * 4 + 2] << 8;
00079                 W[t] |= Message_Block[t * 4 + 3];
00080         }
00081 
00082         for(t = 16; t < 80; t++) {
00083                 W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14]^W[t-16]);
00084         }
00085 
00086         A = Intermediate_Hash[0];
00087         B = Intermediate_Hash[1];
00088         C = Intermediate_Hash[2];
00089         D = Intermediate_Hash[3];
00090         E = Intermediate_Hash[4];
00091 
00092         for(t = 0; t < 20; t++) {
00093                 temp =  SHA1CircularShift(5,A) +
00094                         ((B & C) | ((~B) & D)) + E + W[t] + K[0];
00095                 E = D;
00096                 D = C;
00097                 C = SHA1CircularShift(30,B);
00098                 B = A;
00099                 A = temp;
00100         }
00101 
00102         for(t = 20; t < 40; t++) {
00103                 temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
00104                 E = D;
00105                 D = C;
00106                 C = SHA1CircularShift(30,B);
00107                 B = A;
00108                 A = temp;
00109         }
00110 
00111         for(t = 40; t < 60; t++) {
00112                 temp = SHA1CircularShift(5,A) +
00113                 ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
00114                 E = D;
00115                 D = C;
00116                 C = SHA1CircularShift(30,B);
00117                 B = A;
00118                 A = temp;
00119         }
00120 
00121         for(t = 60; t < 80; t++) {
00122                 temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
00123                 E = D;
00124                 D = C;
00125                 C = SHA1CircularShift(30,B);
00126                 B = A;
00127                 A = temp;
00128         }
00129 
00130         Intermediate_Hash[0] += A;
00131         Intermediate_Hash[1] += B;
00132         Intermediate_Hash[2] += C;
00133         Intermediate_Hash[3] += D;
00134         Intermediate_Hash[4] += E;
00135 
00136         Message_Block_Index = 0;
00137 }
00138 
00139 
00140 /*
00141  *  SHA1PadMessage
00142  *
00143  *  Description:
00144  *      According to the standard, the message must be padded to an even
00145  *      512 bits.  The first padding bit must be a '1'.  The last 64
00146  *      bits represent the length of the original message.  All bits in
00147  *      between should be 0.  This function will pad the message
00148  *      according to those rules by filling the Message_Block array
00149  *      accordingly.  It will also call the ProcessMessageBlock function
00150  *      provided appropriately.  When it returns, it can be assumed that
00151  *      the message digest has been computed.
00152  *
00153  *  Parameters:
00154  *      context: [in/out]
00155  *          The context to pad
00156  *      ProcessMessageBlock: [in]
00157  *          The appropriate SHA*ProcessMessageBlock function
00158  *  Returns:
00159  *      Nothing.
00160  *
00161  */
00162 void Sha1Transform::SHA1PadMessage() {
00163         /*
00164          *  Check to see if the current message block is too small to hold
00165          *  the initial padding bits and length.  If so, we will pad the
00166          *  block, process it, and then continue padding into a second
00167          *  block.
00168          */
00169         if (Message_Block_Index > 55) {
00170                 Message_Block[Message_Block_Index++] = 0x80;
00171                 while(Message_Block_Index < 64) {
00172                         Message_Block[Message_Block_Index++] = 0;
00173                 }
00174 
00175                 SHA1ProcessMessageBlock();
00176 
00177                 while(Message_Block_Index < 56) {
00178                         Message_Block[Message_Block_Index++] = 0;
00179                 }
00180         } else {
00181                 Message_Block[Message_Block_Index++] = 0x80;
00182                 while (Message_Block_Index < 56) {
00183                         Message_Block[Message_Block_Index++] = 0;
00184                 }
00185         }
00186 
00187         /*
00188          *  Store the message length as the last 8 octets
00189          */
00190         Message_Block[56] = Length_High >> 24;
00191         Message_Block[57] = Length_High >> 16;
00192         Message_Block[58] = Length_High >> 8;
00193         Message_Block[59] = Length_High;
00194         Message_Block[60] = Length_Low >> 24;
00195         Message_Block[61] = Length_Low >> 16;
00196         Message_Block[62] = Length_Low >> 8;
00197         Message_Block[63] = Length_Low;
00198 
00199         SHA1ProcessMessageBlock();
00200 }
00201 
00202 
00203 Sha1Transform::Sha1Transform() {
00204         Length_Low             = 0;
00205         Length_High            = 0;
00206         Message_Block_Index    = 0;
00207 
00208         Intermediate_Hash[0]   = 0x67452301;
00209         Intermediate_Hash[1]   = 0xEFCDAB89;
00210         Intermediate_Hash[2]   = 0x98BADCFE;
00211         Intermediate_Hash[3]   = 0x10325476;
00212         Intermediate_Hash[4]   = 0xC3D2E1F0;
00213 
00214         Computed   = 0;
00215         Corrupted  = 0;
00216 }
00217 
00218 Sha1Transform::~Sha1Transform() {
00219 }
00220 
00221 int Sha1Transform::sumUp(const char *data, uint32_t length) {
00222         if (!length) {
00223                 return shaSuccess;
00224         }
00225 
00226         if (!data) {
00227                 return shaNull;
00228         }
00229 
00230         if (Computed) {
00231                 Corrupted = shaStateError;
00232                 return shaStateError;
00233         }
00234 
00235         if (Corrupted) {
00236                 return Corrupted;
00237         }
00238         while(length-- && !Corrupted) {
00239                 Message_Block[Message_Block_Index++] =
00240                         (*data & 0xFF);
00241                 Length_Low += 8;
00242                 if (Length_Low == 0) {
00243                         Length_High++;
00244                         if (Length_High == 0) {
00245                                 /* Message is too long */
00246                                 Corrupted = 1;
00247                         }
00248                 }
00249 
00250                 if (Message_Block_Index == 64) {
00251                         SHA1ProcessMessageBlock();
00252                 }
00253 
00254                 data++;
00255         }
00256 
00257         return shaSuccess;
00258 }
00259 
00260 int Sha1Transform::sumUp(const unsigned char *data, uint32_t length) {
00261         return sumUp(reinterpret_cast<const char *>(data), length);
00262 }
00263 
00264 Hash<SHA1Hash> Sha1Transform::getHash() {
00265         int i;
00266 
00267         if (Corrupted) {
00268                 throw std::runtime_error("Corrupted!");
00269         }
00270 
00271         if (!Computed) {
00272                 SHA1PadMessage();
00273                 for(i=0; i<64; ++i) {
00274                         /* message may be sensitive, clear it out */
00275                         Message_Block[i] = 0;
00276                 }
00277                 Length_Low = 0;    /* and clear length */
00278                 Length_High = 0;
00279                 Computed = 1;
00280         }
00281 
00282         unsigned char hash[SHA1HashSize];
00283 
00284         for(i = 0; i < SHA1HashSize; ++i) {
00285                 hash[i] = Intermediate_Hash[i>>2]
00286                                 >> 8 * ( 3 - ( i & 0x03 ) );
00287         }
00288 
00289         return hash;
00290 }