/* * fhicl-sha1.cpp * * Copyright (C) 1998, 2009 * Paul E. Jones * All Rights Reserved. * ***************************************************************************** * $Id: fhicl-sha1.cpp 12 2009-06-22 19:34:25Z paulej $ ***************************************************************************** * * Description: * This class implements the Secure Hashing Standard as defined * in FIPS PUB 180-1 published April 17, 1995. * * The Secure Hashing Standard, which uses the Secure Hashing * Algorithm (SHA), produces a 160-bit message digest for a * given data stream. In theory, it is highly improbable that * two messages will produce the same message digest. Therefore, * this algorithm can serve as a means of providing a "fingerprint" * for a message. * * Portability Issues: * SHA-1 is defined in terms of 32-bit "words". This code was * written with the expectation that the processor has at least * a 32-bit machine word size. If the machine word size is larger, * the code should still function properly. One caveat to that * is that the input functions taking characters and character arrays * assume that only 8 bits of information are stored in each character. * * Caveats: * SHA-1 is designed to work with messages less than 2^64 bits long. * Although SHA-1 allows a message digest to be generated for * messages of any number of bits less than 2^64, this implementation * only works with messages with a length that is a multiple of 8 * bits. * */ #include "fhicl-sha1.h" namespace fhicl { /* * SHA1 * * Description: * This is the constructor for the sha1 class. * * Parameters: * None. * * Returns: * Nothing. * * Comments: * */ SHA1::SHA1() { Reset(); } /* * ~SHA1 * * Description: * This is the destructor for the sha1 class * * Parameters: * None. * * Returns: * Nothing. * * Comments: * */ SHA1::~SHA1() { // The destructor does nothing } /* * Reset * * Description: * This function will initialize the sha1 class member variables * in preparation for computing a new message digest. * * Parameters: * None. * * Returns: * Nothing. * * Comments: * */ void SHA1::Reset() { Length_Low = 0; Length_High = 0; Message_Block_Index = 0; H[0] = 0x67452301; H[1] = 0xEFCDAB89; H[2] = 0x98BADCFE; H[3] = 0x10325476; H[4] = 0xC3D2E1F0; Computed = false; Corrupted = false; } /* * Result * * Description: * This function will return the 160-bit message digest into the * array provided. * * Parameters: * message_digest_array: [out] * This is an array of five unsigned integers which will be filled * with the message digest that has been computed. * * Returns: * True if successful, false if it failed. * * Comments: * */ bool SHA1::Result(unsigned *message_digest_array) { int i; // Counter if (Corrupted) { return false; } if (!Computed) { PadMessage(); Computed = true; } for(i = 0; i < 5; i++) { message_digest_array[i] = H[i]; } return true; } /* * Input * * Description: * This function accepts an array of octets as the next portion of * the message. * * Parameters: * message_array: [in] * An array of characters representing the next portion of the * message. * * Returns: * Nothing. * * Comments: * */ void SHA1::Input( const unsigned char *message_array, unsigned length) { if (!length) { return; } if (Computed || Corrupted) { Corrupted = true; return; } while(length-- && !Corrupted) { Message_Block[Message_Block_Index++] = (*message_array & 0xFF); Length_Low += 8; Length_Low &= 0xFFFFFFFF; // Force it to 32 bits if (Length_Low == 0) { Length_High++; Length_High &= 0xFFFFFFFF; // Force it to 32 bits if (Length_High == 0) { Corrupted = true; // Message is too long } } if (Message_Block_Index == 64) { ProcessMessageBlock(); } message_array++; } } /* * Input * * Description: * This function accepts an array of octets as the next portion of * the message. * * Parameters: * message_array: [in] * An array of characters representing the next portion of the * message. * length: [in] * The length of the message_array * * Returns: * Nothing. * * Comments: * */ void SHA1::Input( const char *message_array, unsigned length) { Input((unsigned char *) message_array, length); } /* * Input * * Description: * This function accepts a single octets as the next message element. * * Parameters: * message_element: [in] * The next octet in the message. * * Returns: * Nothing. * * Comments: * */ void SHA1::Input(unsigned char message_element) { Input(&message_element, 1); } /* * Input * * Description: * This function accepts a single octet as the next message element. * * Parameters: * message_element: [in] * The next octet in the message. * * Returns: * Nothing. * * Comments: * */ void SHA1::Input(char message_element) { Input((unsigned char *) &message_element, 1); } /* * operator<< * * Description: * This operator makes it convenient to provide character strings to * the SHA1 object for processing. * * Parameters: * message_array: [in] * The character array to take as input. * * Returns: * A reference to the SHA1 object. * * Comments: * Each character is assumed to hold 8 bits of information. * */ SHA1& SHA1::operator<<(const char *message_array) { const char *p = message_array; while(*p) { Input(*p); p++; } return *this; } /* * operator<< * * Description: * This operator makes it convenient to provide character strings to * the SHA1 object for processing. * * Parameters: * message_array: [in] * The character array to take as input. * * Returns: * A reference to the SHA1 object. * * Comments: * Each character is assumed to hold 8 bits of information. * */ SHA1& SHA1::operator<<(const unsigned char *message_array) { const unsigned char *p = message_array; while(*p) { Input(*p); p++; } return *this; } /* * operator<< * * Description: * This function provides the next octet in the message. * * Parameters: * message_element: [in] * The next octet in the message * * Returns: * A reference to the SHA1 object. * * Comments: * The character is assumed to hold 8 bits of information. * */ SHA1& SHA1::operator<<(const char message_element) { Input((unsigned char *) &message_element, 1); return *this; } /* * operator<< * * Description: * This function provides the next octet in the message. * * Parameters: * message_element: [in] * The next octet in the message * * Returns: * A reference to the SHA1 object. * * Comments: * The character is assumed to hold 8 bits of information. * */ SHA1& SHA1::operator<<(const unsigned char message_element) { Input(&message_element, 1); return *this; } /* * ProcessMessageBlock * * Description: * This function will process the next 512 bits of the message * stored in the Message_Block array. * * Parameters: * None. * * Returns: * Nothing. * * Comments: * Many of the variable names in this function, especially the single * character names, were used because those were the names used * in the publication. * */ void SHA1::ProcessMessageBlock() { const unsigned K[] = { // Constants defined for SHA-1 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 }; int t; // Loop counter unsigned temp; // Temporary word value unsigned W[80]; // Word sequence unsigned A, B, C, D, E; // Word buffers /* * Initialize the first 16 words in the array W */ for(t = 0; t < 16; t++) { W[t] = ((unsigned) Message_Block[t * 4]) << 24; W[t] |= ((unsigned) Message_Block[t * 4 + 1]) << 16; W[t] |= ((unsigned) Message_Block[t * 4 + 2]) << 8; W[t] |= ((unsigned) Message_Block[t * 4 + 3]); } for(t = 16; t < 80; t++) { W[t] = CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]); } A = H[0]; B = H[1]; C = H[2]; D = H[3]; E = H[4]; for(t = 0; t < 20; t++) { temp = CircularShift(5,A) + ((B & C) | ((~B) & D)) + E + W[t] + K[0]; temp &= 0xFFFFFFFF; E = D; D = C; C = CircularShift(30,B); B = A; A = temp; } for(t = 20; t < 40; t++) { temp = CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1]; temp &= 0xFFFFFFFF; E = D; D = C; C = CircularShift(30,B); B = A; A = temp; } for(t = 40; t < 60; t++) { temp = CircularShift(5,A) + ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2]; temp &= 0xFFFFFFFF; E = D; D = C; C = CircularShift(30,B); B = A; A = temp; } for(t = 60; t < 80; t++) { temp = CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3]; temp &= 0xFFFFFFFF; E = D; D = C; C = CircularShift(30,B); B = A; A = temp; } H[0] = (H[0] + A) & 0xFFFFFFFF; H[1] = (H[1] + B) & 0xFFFFFFFF; H[2] = (H[2] + C) & 0xFFFFFFFF; H[3] = (H[3] + D) & 0xFFFFFFFF; H[4] = (H[4] + E) & 0xFFFFFFFF; Message_Block_Index = 0; } /* * PadMessage * * Description: * According to the standard, the message must be padded to an even * 512 bits. The first padding bit must be a '1'. The last 64 bits * represent the length of the original message. All bits in between * should be 0. This function will pad the message according to those * rules by filling the message_block array accordingly. It will also * call ProcessMessageBlock() appropriately. When it returns, it * can be assumed that the message digest has been computed. * * Parameters: * None. * * Returns: * Nothing. * * Comments: * */ void SHA1::PadMessage() { /* * Check to see if the current message block is too small to hold * the initial padding bits and length. If so, we will pad the * block, process it, and then continue padding into a second block. */ if (Message_Block_Index > 55) { Message_Block[Message_Block_Index++] = 0x80; while(Message_Block_Index < 64) { Message_Block[Message_Block_Index++] = 0; } ProcessMessageBlock(); while(Message_Block_Index < 56) { Message_Block[Message_Block_Index++] = 0; } } else { Message_Block[Message_Block_Index++] = 0x80; while(Message_Block_Index < 56) { Message_Block[Message_Block_Index++] = 0; } } /* * Store the message length as the last 8 octets */ Message_Block[56] = (Length_High >> 24) & 0xFF; Message_Block[57] = (Length_High >> 16) & 0xFF; Message_Block[58] = (Length_High >> 8) & 0xFF; Message_Block[59] = (Length_High) & 0xFF; Message_Block[60] = (Length_Low >> 24) & 0xFF; Message_Block[61] = (Length_Low >> 16) & 0xFF; Message_Block[62] = (Length_Low >> 8) & 0xFF; Message_Block[63] = (Length_Low) & 0xFF; ProcessMessageBlock(); } /* * CircularShift * * Description: * This member function will perform a circular shifting operation. * * Parameters: * bits: [in] * The number of bits to shift (1-31) * word: [in] * The value to shift (assumes a 32-bit integer) * * Returns: * The shifted value. * * Comments: * */ unsigned SHA1::CircularShift(int bits, unsigned word) { return ((word << bits) & 0xFFFFFFFF) | ((word & 0xFFFFFFFF) >> (32-bits)); } } //end of namespace mf