From 97e5e5fc7bf70d44206af48d986cb548e3a55324 Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Thu, 10 Oct 2013 08:19:43 -0500 Subject: [PATCH] replaces sha1 library with a more clearly licensed project references #294 --- test/utility/sha1.cpp | 53 ++- websocketpp/processors/hybi13.hpp | 24 +- websocketpp/sha1/license.txt | 14 - websocketpp/sha1/sha1.cpp | 185 ++++++++++ websocketpp/sha1/sha1.h | 49 +++ websocketpp/sha1/sha1.hpp | 590 ++++++++++-------------------- 6 files changed, 447 insertions(+), 468 deletions(-) delete mode 100755 websocketpp/sha1/license.txt create mode 100755 websocketpp/sha1/sha1.cpp create mode 100755 websocketpp/sha1/sha1.h diff --git a/test/utility/sha1.cpp b/test/utility/sha1.cpp index 500e29788a..ab25f970d2 100644 --- a/test/utility/sha1.cpp +++ b/test/utility/sha1.cpp @@ -37,48 +37,45 @@ BOOST_AUTO_TEST_SUITE ( sha1 ) BOOST_AUTO_TEST_CASE( sha1_test_a ) { - websocketpp::sha1 sha; - uint32_t digest[5]; + unsigned char hash[20]; + unsigned char reference[20] = {0xa9, 0x99, 0x3e, 0x36, 0x47, + 0x06, 0x81, 0x6a, 0xba, 0x3e, + 0x25, 0x71, 0x78, 0x50, 0xc2, + 0x6c, 0x9c, 0xd0, 0xd8, 0x9d}; - sha << "abc"; - BOOST_CHECK(sha.get_raw_digest(digest)); + websocketpp::sha1::calc("abc",3,hash); - BOOST_CHECK_EQUAL( digest[0], 0xa9993e36 ); - BOOST_CHECK_EQUAL( digest[1], 0x4706816a ); - BOOST_CHECK_EQUAL( digest[2], 0xba3e2571 ); - BOOST_CHECK_EQUAL( digest[3], 0x7850c26c ); - BOOST_CHECK_EQUAL( digest[4], 0x9cd0d89d ); + BOOST_CHECK_EQUAL_COLLECTIONS(hash, hash+20, reference, reference+20); } BOOST_AUTO_TEST_CASE( sha1_test_b ) { - websocketpp::sha1 sha; - uint32_t digest[5]; + unsigned char hash[20]; + unsigned char reference[20] = {0x84, 0x98, 0x3e, 0x44, 0x1c, + 0x3b, 0xd2, 0x6e, 0xba, 0xae, + 0x4a, 0xa1, 0xf9, 0x51, 0x29, + 0xe5, 0xe5, 0x46, 0x70, 0xf1}; - sha << "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; - BOOST_CHECK(sha.get_raw_digest(digest)); + websocketpp::sha1::calc( + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",56,hash); - BOOST_CHECK_EQUAL( digest[0], 0x84983e44 ); - BOOST_CHECK_EQUAL( digest[1], 0x1c3bd26e ); - BOOST_CHECK_EQUAL( digest[2], 0xbaae4aa1 ); - BOOST_CHECK_EQUAL( digest[3], 0xf95129e5 ); - BOOST_CHECK_EQUAL( digest[4], 0xe54670f1 ); + BOOST_CHECK_EQUAL_COLLECTIONS(hash, hash+20, reference, reference+20); } BOOST_AUTO_TEST_CASE( sha1_test_c ) { - websocketpp::sha1 sha; - uint32_t digest[5]; + std::string input; + unsigned char hash[20]; + unsigned char reference[20] = {0x34, 0xaa, 0x97, 0x3c, 0xd4, + 0xc4, 0xda, 0xa4, 0xf6, 0x1e, + 0xeb, 0x2b, 0xdb, 0xad, 0x27, + 0x31, 0x65, 0x34, 0x01, 0x6f}; - for (int i = 1; i <= 1000000; i++) { - sha.input('a'); + for (int i = 0; i < 1000000; i++) { + input += 'a'; } - BOOST_CHECK(sha.get_raw_digest(digest)); + websocketpp::sha1::calc(input.c_str(),input.size(),hash); - BOOST_CHECK_EQUAL( digest[0], 0x34aa973c ); - BOOST_CHECK_EQUAL( digest[1], 0xd4c4daa4 ); - BOOST_CHECK_EQUAL( digest[2], 0xf61eeb2b ); - BOOST_CHECK_EQUAL( digest[3], 0xdbad2731 ); - BOOST_CHECK_EQUAL( digest[4], 0x6534016f ); + BOOST_CHECK_EQUAL_COLLECTIONS(hash, hash+20, reference, reference+20); } BOOST_AUTO_TEST_SUITE_END() diff --git a/websocketpp/processors/hybi13.hpp b/websocketpp/processors/hybi13.hpp index 3c11e5b6c5..b6b984fece 100644 --- a/websocketpp/processors/hybi13.hpp +++ b/websocketpp/processors/hybi13.hpp @@ -614,27 +614,11 @@ protected: lib::error_code process_handshake_key(std::string & key) const { key.append(constants::handshake_guid); - sha1 sha; - uint32_t message_digest[5]; + unsigned char message_digest[20]; + sha1::calc(key.c_str(),key.length(),message_digest); + key = base64_encode(message_digest,20); - sha << key.c_str(); - - if (sha.get_raw_digest(message_digest)){ - // convert sha1 hash bytes to network byte order because this sha1 - // library works on ints rather than bytes - for (int i = 0; i < 5; i++) { - message_digest[i] = htonl(message_digest[i]); - } - - key = base64_encode( - reinterpret_cast(message_digest), - 20 - ); - - return lib::error_code(); - } else { - return error::make_error_code(error::sha1_library); - } + return lib::error_code(); } /// Reads bytes from buf into m_basic_header diff --git a/websocketpp/sha1/license.txt b/websocketpp/sha1/license.txt deleted file mode 100755 index 8401f0ed31..0000000000 --- a/websocketpp/sha1/license.txt +++ /dev/null @@ -1,14 +0,0 @@ -Copyright (C) 1998, 2009 -Paul E. Jones - -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. diff --git a/websocketpp/sha1/sha1.cpp b/websocketpp/sha1/sha1.cpp new file mode 100755 index 0000000000..49c504538a --- /dev/null +++ b/websocketpp/sha1/sha1.cpp @@ -0,0 +1,185 @@ +/* + Copyright (c) 2011, Micael Hildenborg + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of Micael Hildenborg nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + Contributors: + Gustav + Several members in the gamedev.se forum. + Gregory Petrosyan + */ + +#include "sha1.h" + +namespace sha1 +{ + namespace // local + { + // Rotate an integer value to left. + inline const unsigned int rol(const unsigned int value, + const unsigned int steps) + { + return ((value << steps) | (value >> (32 - steps))); + } + + // Sets the first 16 integers in the buffert to zero. + // Used for clearing the W buffert. + inline void clearWBuffert(unsigned int* buffert) + { + for (int pos = 16; --pos >= 0;) + { + buffert[pos] = 0; + } + } + + void innerHash(unsigned int* result, unsigned int* w) + { + unsigned int a = result[0]; + unsigned int b = result[1]; + unsigned int c = result[2]; + unsigned int d = result[3]; + unsigned int e = result[4]; + + int round = 0; + + #define sha1macro(func,val) \ + { \ + const unsigned int t = rol(a, 5) + (func) + e + val + w[round]; \ + e = d; \ + d = c; \ + c = rol(b, 30); \ + b = a; \ + a = t; \ + } + + while (round < 16) + { + sha1macro((b & c) | (~b & d), 0x5a827999) + ++round; + } + while (round < 20) + { + w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); + sha1macro((b & c) | (~b & d), 0x5a827999) + ++round; + } + while (round < 40) + { + w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); + sha1macro(b ^ c ^ d, 0x6ed9eba1) + ++round; + } + while (round < 60) + { + w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); + sha1macro((b & c) | (b & d) | (c & d), 0x8f1bbcdc) + ++round; + } + while (round < 80) + { + w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); + sha1macro(b ^ c ^ d, 0xca62c1d6) + ++round; + } + + #undef sha1macro + + result[0] += a; + result[1] += b; + result[2] += c; + result[3] += d; + result[4] += e; + } + } // namespace + + void calc(const void* src, const int bytelength, unsigned char* hash) + { + // Init the result array. + unsigned int result[5] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 }; + + // Cast the void src pointer to be the byte array we can work with. + const unsigned char* sarray = (const unsigned char*) src; + + // The reusable round buffer + unsigned int w[80]; + + // Loop through all complete 64byte blocks. + const int endOfFullBlocks = bytelength - 64; + int endCurrentBlock; + int currentBlock = 0; + + while (currentBlock <= endOfFullBlocks) + { + endCurrentBlock = currentBlock + 64; + + // Init the round buffer with the 64 byte block data. + for (int roundPos = 0; currentBlock < endCurrentBlock; currentBlock += 4) + { + // This line will swap endian on big endian and keep endian on little endian. + w[roundPos++] = (unsigned int) sarray[currentBlock + 3] + | (((unsigned int) sarray[currentBlock + 2]) << 8) + | (((unsigned int) sarray[currentBlock + 1]) << 16) + | (((unsigned int) sarray[currentBlock]) << 24); + } + innerHash(result, w); + } + + // Handle the last and not full 64 byte block if existing. + endCurrentBlock = bytelength - currentBlock; + clearWBuffert(w); + int lastBlockBytes = 0; + for (;lastBlockBytes < endCurrentBlock; ++lastBlockBytes) + { + w[lastBlockBytes >> 2] |= (unsigned int) sarray[lastBlockBytes + currentBlock] << ((3 - (lastBlockBytes & 3)) << 3); + } + w[lastBlockBytes >> 2] |= 0x80 << ((3 - (lastBlockBytes & 3)) << 3); + if (endCurrentBlock >= 56) + { + innerHash(result, w); + clearWBuffert(w); + } + w[15] = bytelength << 3; + innerHash(result, w); + + // Store hash in result pointer, and make sure we get in in the correct order on both endian models. + for (int hashByte = 20; --hashByte >= 0;) + { + hash[hashByte] = (result[hashByte >> 2] >> (((3 - hashByte) & 0x3) << 3)) & 0xff; + } + } + + void toHexString(const unsigned char* hash, char* hexstring) + { + const char hexDigits[] = { "0123456789abcdef" }; + + for (int hashByte = 20; --hashByte >= 0;) + { + hexstring[hashByte << 1] = hexDigits[(hash[hashByte] >> 4) & 0xf]; + hexstring[(hashByte << 1) + 1] = hexDigits[hash[hashByte] & 0xf]; + } + hexstring[40] = 0; + } +} // namespace sha1 diff --git a/websocketpp/sha1/sha1.h b/websocketpp/sha1/sha1.h new file mode 100755 index 0000000000..540c156d14 --- /dev/null +++ b/websocketpp/sha1/sha1.h @@ -0,0 +1,49 @@ +/* + Copyright (c) 2011, Micael Hildenborg + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of Micael Hildenborg nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SHA1_DEFINED +#define SHA1_DEFINED + +namespace sha1 +{ + + /** + @param src points to any kind of data to be hashed. + @param bytelength the number of bytes to hash from the src pointer. + @param hash should point to a buffer of at least 20 bytes of size for storing the sha1 result in. + */ + void calc(const void* src, const int bytelength, unsigned char* hash); + + /** + @param hash is 20 bytes of sha1 hash. This is the same data that is the result from the calc function. + @param hexstring should point to a buffer of at least 41 bytes of size for storing the hexadecimal representation of the hash. A zero will be written at position 40, so the buffer will be a valid zero ended string. + */ + void toHexString(const unsigned char* hash, char* hexstring); + +} // namespace sha1 + +#endif // SHA1_DEFINED diff --git a/websocketpp/sha1/sha1.hpp b/websocketpp/sha1/sha1.hpp index 154196aced..76a9eaf756 100755 --- a/websocketpp/sha1/sha1.hpp +++ b/websocketpp/sha1/sha1.hpp @@ -1,406 +1,184 @@ -/* - * sha1.hpp - * - * Copyright (C) 1998, 2009 - * Paul E. Jones - * 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 - -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(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(&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_ +/* +***** +sha1.hpp is a repackaging of the sha1.cpp and sha1.h files from the shallsha1 +library (http://code.google.com/p/smallsha1/) into a single header suitable for +use as a header only library. This conversion was done by Peter Thorson +(webmaster@zaphoyd.com) in 2013. All modifications to the code are redistributed +under the same license as the original, which is listed below. +***** + + Copyright (c) 2011, Micael Hildenborg + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of Micael Hildenborg nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SHA1_DEFINED +#define SHA1_DEFINED + +namespace websocketpp { +namespace sha1 { + + namespace // local + { + // Rotate an integer value to left. + inline const unsigned int rol(const unsigned int value, + const unsigned int steps) + { + return ((value << steps) | (value >> (32 - steps))); + } + + // Sets the first 16 integers in the buffert to zero. + // Used for clearing the W buffert. + inline void clearWBuffert(unsigned int* buffert) + { + for (int pos = 16; --pos >= 0;) + { + buffert[pos] = 0; + } + } + + inline void innerHash(unsigned int* result, unsigned int* w) + { + unsigned int a = result[0]; + unsigned int b = result[1]; + unsigned int c = result[2]; + unsigned int d = result[3]; + unsigned int e = result[4]; + + int round = 0; + + #define sha1macro(func,val) \ + { \ + const unsigned int t = rol(a, 5) + (func) + e + val + w[round]; \ + e = d; \ + d = c; \ + c = rol(b, 30); \ + b = a; \ + a = t; \ + } + + while (round < 16) + { + sha1macro((b & c) | (~b & d), 0x5a827999) + ++round; + } + while (round < 20) + { + w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); + sha1macro((b & c) | (~b & d), 0x5a827999) + ++round; + } + while (round < 40) + { + w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); + sha1macro(b ^ c ^ d, 0x6ed9eba1) + ++round; + } + while (round < 60) + { + w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); + sha1macro((b & c) | (b & d) | (c & d), 0x8f1bbcdc) + ++round; + } + while (round < 80) + { + w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); + sha1macro(b ^ c ^ d, 0xca62c1d6) + ++round; + } + + #undef sha1macro + + result[0] += a; + result[1] += b; + result[2] += c; + result[3] += d; + result[4] += e; + } + } // namespace + + /** + @param src points to any kind of data to be hashed. + @param bytelength the number of bytes to hash from the src pointer. + @param hash should point to a buffer of at least 20 bytes of size for storing the sha1 result in. + */ + inline void calc(const void* src, const int bytelength, unsigned char* hash) { + // Init the result array. + unsigned int result[5] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 }; + + // Cast the void src pointer to be the byte array we can work with. + const unsigned char* sarray = (const unsigned char*) src; + + // The reusable round buffer + unsigned int w[80]; + + // Loop through all complete 64byte blocks. + const int endOfFullBlocks = bytelength - 64; + int endCurrentBlock; + int currentBlock = 0; + + while (currentBlock <= endOfFullBlocks) + { + endCurrentBlock = currentBlock + 64; + + // Init the round buffer with the 64 byte block data. + for (int roundPos = 0; currentBlock < endCurrentBlock; currentBlock += 4) + { + // This line will swap endian on big endian and keep endian on little endian. + w[roundPos++] = (unsigned int) sarray[currentBlock + 3] + | (((unsigned int) sarray[currentBlock + 2]) << 8) + | (((unsigned int) sarray[currentBlock + 1]) << 16) + | (((unsigned int) sarray[currentBlock]) << 24); + } + innerHash(result, w); + } + + // Handle the last and not full 64 byte block if existing. + endCurrentBlock = bytelength - currentBlock; + clearWBuffert(w); + int lastBlockBytes = 0; + for (;lastBlockBytes < endCurrentBlock; ++lastBlockBytes) + { + w[lastBlockBytes >> 2] |= (unsigned int) sarray[lastBlockBytes + currentBlock] << ((3 - (lastBlockBytes & 3)) << 3); + } + w[lastBlockBytes >> 2] |= 0x80 << ((3 - (lastBlockBytes & 3)) << 3); + if (endCurrentBlock >= 56) + { + innerHash(result, w); + clearWBuffert(w); + } + w[15] = bytelength << 3; + innerHash(result, w); + + // Store hash in result pointer, and make sure we get in in the correct order on both endian models. + for (int hashByte = 20; --hashByte >= 0;) + { + hash[hashByte] = (result[hashByte >> 2] >> (((3 - hashByte) & 0x3) << 3)) & 0xff; + } + } + +} // namespace sha1 +} // namespace websocketpp + +#endif // SHA1_DEFINED