Files
rippled/websocketpp/sha1/sha1.hpp
2013-07-21 07:49:15 -05:00

407 lines
12 KiB
C++
Executable File

/*
* sha1.hpp
*
* Copyright (C) 1998, 2009
* Paul E. Jones <paulej@packetizer.com>
* All Rights Reserved.
*
* Modifications were done in 2012-13 by Peter Thorson (webmaster@zaphoyd.com)
* to allow header only usage of the library and use C++ features to better
* support C++ usage. These changes are distributed under the original freeware
* license included below
*
* Freeware Public License (FPL)
*
* This software is licensed as "freeware." Permission to distribute
* this software in source and binary forms, including incorporation
* into other products, is hereby granted without a fee. THIS SOFTWARE
* IS PROVIDED 'AS IS' AND WITHOUT ANY EXPRESSED OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHOR SHALL NOT BE HELD
* LIABLE FOR ANY DAMAGES RESULTING FROM THE USE OF THIS SOFTWARE, EITHER
* DIRECTLY OR INDIRECTLY, INCLUDING, BUT NOT LIMITED TO, LOSS OF DATA
* OR DATA BEING RENDERED INACCURATE.
*
*****************************************************************************
*
* Description:
* This class implements the Secure Hashing Standard as defined
* in FIPS PUB 180-1 published April 17, 1995.
*
* Many of the variable names in this class, especially the single
* character names, were used because those were the names used
* in the publication.
*
* 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.
*
*****************************************************************************
*/
#ifndef _SHA1_H_
#define _SHA1_H_
#include <websocketpp/common/stdint.hpp>
namespace websocketpp {
/// Provides SHA1 hashing functionality
class sha1 {
public:
sha1() {
reset();
}
virtual ~sha1() {}
/// Re-initialize the class
void 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;
}
/// Extract the message digest as a raw integer array
/**
* @param [out] message_digest_array Integer array to store the message in
* @return Whether or not the extraction was sucessful
*/
bool get_raw_digest(uint32_t * message_digest_array) {
if (corrupted) {
return false;
}
if (!computed) {
pad_message();
computed = true;
}
for (int i = 0; i < 5; i++) {
message_digest_array[i] = H[i];
}
return true;
}
/// Provide input to SHA1
/**
* @param [in] message_array The input bytes
* @param [in] length Length of the message array
*/
void input(unsigned char const * message_array, uint32_t length) {
if (!length) {
return;
}
if (computed || corrupted) {
corrupted = true;
return;
}
while (length-- && !corrupted) {
// Suppresses Visual Studio code analysis for write overrun. It doesn't know the
// index into Message_Block is protected by checking length.
//
// TODO: is there a more compatible way to write the original code to avoid
// this sort of warning?
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(suppress: 6386)
#endif
message_block[message_block_index++] = (*message_array & 0xFF);
#ifdef _MSC_VER
#pragma warning(pop)
#endif
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) {
process_message_block();
}
message_array++;
}
}
/// Provide input to SHA1
/**
* Overload with signed message array
*
* @param [in] message_array The input bytes
* @param [in] length Length of the message array
*/
void input(char const * message_array, uint32_t length) {
input(reinterpret_cast<const unsigned char *>(message_array), length);
}
/// Provide input to SHA1
/**
* Overload with a single unsigned char
*
* @param [in] message_element The character to input
*/
void input(unsigned char message_element) {
input(&message_element, 1);
}
/// Provide input to SHA1
/**
* Overload with a single signed char
*
* @param [in] message_element The character to input
*/
void input(char message_element) {
input(reinterpret_cast<unsigned char *>(&message_element), 1);
}
/// Provide input to SHA1
/**
* Overload via signed char array stream input
*
* @param [in] message_array The character array to input
*/
sha1& operator<<(char const * message_array) {
char const * p = message_array;
while(*p) {
input(*p);
p++;
}
return *this;
}
/// Provide input to SHA1
/**
* Overload via unsigned char array stream input
*
* @param [in] message_array The character array to input
*/
sha1& operator<<(unsigned char const * message_array) {
unsigned char const * p = message_array;
while(*p) {
input(*p);
p++;
}
return *this;
}
/// Provide input to SHA1
/**
* Overload via signed char stream input
*
* @param [in] message_element The character to input
*/
sha1& operator<<(char message_element) {
input((unsigned char *) &message_element, 1);
return *this;
}
/// Provide input to SHA1
/**
* Overload via unsigned char stream input
*
* @param [in] message_element The character to input
*/
sha1& operator<<(unsigned char message_element) {
input(&message_element, 1);
return *this;
}
private:
/// Process the next 512 bits of the message
/**
* 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 process_message_block() {
// Constants defined for SHA-1
uint32_t const K[] = { 0x5A827999,
0x6ED9EBA1,
0x8F1BBCDC,
0xCA62C1D6 };
uint32_t temp; // Temporary word value
uint32_t W[80]; // Word sequence
uint32_t A, B, C, D, E; // Word buffers
// Initialize the first 16 words in the array W
for (int t = 0; t < 16; t++) {
W[t] = ((uint32_t) message_block[t * 4]) << 24;
W[t] |= ((uint32_t) message_block[t * 4 + 1]) << 16;
W[t] |= ((uint32_t) message_block[t * 4 + 2]) << 8;
W[t] |= ((uint32_t) message_block[t * 4 + 3]);
}
for (int 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 (int 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 (int 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 (int 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 (int 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;
}
/// Pads the current message block to 512 bits
/**
* 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.
*/
void pad_message() {
// 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;
}
process_message_block();
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;
process_message_block();
}
/// Performs a circular left shift operation
/**
* @param [in] bits How many bits to shift
* @param [in] word The word to shift
* @return The shifted word
*/
inline uint32_t CircularShift(int bits, uint32_t word) {
return ((word << bits) & 0xFFFFFFFF) | ((word & 0xFFFFFFFF) >> (32-bits));
}
uint32_t H[5]; // Message digest buffers
uint32_t length_low; // Message length in bits
uint32_t length_high; // Message length in bits
unsigned char message_block[64]; // 512-bit message blocks
int message_block_index; // Index into message block array
bool computed; // Is the digest computed?
bool corrupted; // Is the message digest corruped?
};
} // namespace websocketpp
#endif // _SHA1_H_