Chris@16: // boost/uuid/sha1.hpp header file ----------------------------------------------// Chris@16: Chris@16: // Copyright 2007 Andy Tompkins. Chris@16: // Distributed under the Boost Software License, Version 1.0. (See Chris@16: // accompanying file LICENSE_1_0.txt or copy at Chris@16: // http://www.boost.org/LICENSE_1_0.txt) Chris@16: Chris@16: // Revision History Chris@16: // 29 May 2007 - Initial Revision Chris@16: // 25 Feb 2008 - moved to namespace boost::uuids::detail Chris@16: // 10 Jan 2012 - can now handle the full size of messages (2^64 - 1 bits) Chris@16: Chris@16: // This is a byte oriented implementation Chris@16: Chris@16: #ifndef BOOST_UUID_SHA1_H Chris@16: #define BOOST_UUID_SHA1_H Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #ifdef BOOST_NO_STDC_NAMESPACE Chris@16: namespace std { Chris@16: using ::size_t; Chris@16: } // namespace std Chris@16: #endif Chris@16: Chris@16: namespace boost { Chris@16: namespace uuids { Chris@16: namespace detail { Chris@16: Chris@16: BOOST_STATIC_ASSERT(sizeof(unsigned char)*8 == 8); Chris@16: BOOST_STATIC_ASSERT(sizeof(unsigned int)*8 == 32); Chris@16: Chris@16: inline unsigned int left_rotate(unsigned int x, std::size_t n) Chris@16: { Chris@16: return (x<> (32-n)); Chris@16: } Chris@16: Chris@16: class sha1 Chris@16: { Chris@16: public: Chris@16: typedef unsigned int(&digest_type)[5]; Chris@16: public: Chris@16: sha1(); Chris@16: Chris@16: void reset(); Chris@16: Chris@16: void process_byte(unsigned char byte); Chris@16: void process_block(void const* bytes_begin, void const* bytes_end); Chris@16: void process_bytes(void const* buffer, std::size_t byte_count); Chris@16: Chris@16: void get_digest(digest_type digest); Chris@16: Chris@16: private: Chris@16: void process_block(); Chris@16: void process_byte_impl(unsigned char byte); Chris@16: Chris@16: private: Chris@16: unsigned int h_[5]; Chris@16: Chris@16: unsigned char block_[64]; Chris@16: Chris@16: std::size_t block_byte_index_; Chris@16: std::size_t bit_count_low; Chris@16: std::size_t bit_count_high; Chris@16: }; Chris@16: Chris@16: inline sha1::sha1() Chris@16: { Chris@16: reset(); Chris@16: } Chris@16: Chris@16: inline void sha1::reset() Chris@16: { Chris@16: h_[0] = 0x67452301; Chris@16: h_[1] = 0xEFCDAB89; Chris@16: h_[2] = 0x98BADCFE; Chris@16: h_[3] = 0x10325476; Chris@16: h_[4] = 0xC3D2E1F0; Chris@16: Chris@16: block_byte_index_ = 0; Chris@16: bit_count_low = 0; Chris@16: bit_count_high = 0; Chris@16: } Chris@16: Chris@16: inline void sha1::process_byte(unsigned char byte) Chris@16: { Chris@16: process_byte_impl(byte); Chris@16: Chris@16: // size_t max value = 0xFFFFFFFF Chris@16: //if (bit_count_low + 8 >= 0x100000000) { // would overflow Chris@16: //if (bit_count_low >= 0x100000000-8) { Chris@16: if (bit_count_low < 0xFFFFFFF8) { Chris@16: bit_count_low += 8; Chris@16: } else { Chris@16: bit_count_low = 0; Chris@16: Chris@16: if (bit_count_high <= 0xFFFFFFFE) { Chris@16: ++bit_count_high; Chris@16: } else { Chris@16: BOOST_THROW_EXCEPTION(std::runtime_error("sha1 too many bytes")); Chris@16: } Chris@16: } Chris@16: } Chris@16: Chris@16: inline void sha1::process_byte_impl(unsigned char byte) Chris@16: { Chris@16: block_[block_byte_index_++] = byte; Chris@16: Chris@16: if (block_byte_index_ == 64) { Chris@16: block_byte_index_ = 0; Chris@16: process_block(); Chris@16: } Chris@16: } Chris@16: Chris@16: inline void sha1::process_block(void const* bytes_begin, void const* bytes_end) Chris@16: { Chris@16: unsigned char const* begin = static_cast(bytes_begin); Chris@16: unsigned char const* end = static_cast(bytes_end); Chris@16: for(; begin != end; ++begin) { Chris@16: process_byte(*begin); Chris@16: } Chris@16: } Chris@16: Chris@16: inline void sha1::process_bytes(void const* buffer, std::size_t byte_count) Chris@16: { Chris@16: unsigned char const* b = static_cast(buffer); Chris@16: process_block(b, b+byte_count); Chris@16: } Chris@16: Chris@16: inline void sha1::process_block() Chris@16: { Chris@16: unsigned int w[80]; Chris@16: for (std::size_t i=0; i<16; ++i) { Chris@16: w[i] = (block_[i*4 + 0] << 24); Chris@16: w[i] |= (block_[i*4 + 1] << 16); Chris@16: w[i] |= (block_[i*4 + 2] << 8); Chris@16: w[i] |= (block_[i*4 + 3]); Chris@16: } Chris@16: for (std::size_t i=16; i<80; ++i) { Chris@16: w[i] = left_rotate((w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]), 1); Chris@16: } Chris@16: Chris@16: unsigned int a = h_[0]; Chris@16: unsigned int b = h_[1]; Chris@16: unsigned int c = h_[2]; Chris@16: unsigned int d = h_[3]; Chris@16: unsigned int e = h_[4]; Chris@16: Chris@16: for (std::size_t i=0; i<80; ++i) { Chris@16: unsigned int f; Chris@16: unsigned int k; Chris@16: Chris@16: if (i<20) { Chris@16: f = (b & c) | (~b & d); Chris@16: k = 0x5A827999; Chris@16: } else if (i<40) { Chris@16: f = b ^ c ^ d; Chris@16: k = 0x6ED9EBA1; Chris@16: } else if (i<60) { Chris@16: f = (b & c) | (b & d) | (c & d); Chris@16: k = 0x8F1BBCDC; Chris@16: } else { Chris@16: f = b ^ c ^ d; Chris@16: k = 0xCA62C1D6; Chris@16: } Chris@16: Chris@16: unsigned temp = left_rotate(a, 5) + f + e + k + w[i]; Chris@16: e = d; Chris@16: d = c; Chris@16: c = left_rotate(b, 30); Chris@16: b = a; Chris@16: a = temp; Chris@16: } Chris@16: Chris@16: h_[0] += a; Chris@16: h_[1] += b; Chris@16: h_[2] += c; Chris@16: h_[3] += d; Chris@16: h_[4] += e; Chris@16: } Chris@16: Chris@16: inline void sha1::get_digest(digest_type digest) Chris@16: { Chris@16: // append the bit '1' to the message Chris@16: process_byte_impl(0x80); Chris@16: Chris@16: // append k bits '0', where k is the minimum number >= 0 Chris@16: // such that the resulting message length is congruent to 56 (mod 64) Chris@16: // check if there is enough space for padding and bit_count Chris@16: if (block_byte_index_ > 56) { Chris@16: // finish this block Chris@16: while (block_byte_index_ != 0) { Chris@16: process_byte_impl(0); Chris@16: } Chris@16: Chris@16: // one more block Chris@16: while (block_byte_index_ < 56) { Chris@16: process_byte_impl(0); Chris@16: } Chris@16: } else { Chris@16: while (block_byte_index_ < 56) { Chris@16: process_byte_impl(0); Chris@16: } Chris@16: } Chris@16: Chris@16: // append length of message (before pre-processing) Chris@16: // as a 64-bit big-endian integer Chris@16: process_byte_impl( static_cast((bit_count_high>>24) & 0xFF) ); Chris@16: process_byte_impl( static_cast((bit_count_high>>16) & 0xFF) ); Chris@16: process_byte_impl( static_cast((bit_count_high>>8 ) & 0xFF) ); Chris@16: process_byte_impl( static_cast((bit_count_high) & 0xFF) ); Chris@16: process_byte_impl( static_cast((bit_count_low>>24) & 0xFF) ); Chris@16: process_byte_impl( static_cast((bit_count_low>>16) & 0xFF) ); Chris@16: process_byte_impl( static_cast((bit_count_low>>8 ) & 0xFF) ); Chris@16: process_byte_impl( static_cast((bit_count_low) & 0xFF) ); Chris@16: Chris@16: // get final digest Chris@16: digest[0] = h_[0]; Chris@16: digest[1] = h_[1]; Chris@16: digest[2] = h_[2]; Chris@16: digest[3] = h_[3]; Chris@16: digest[4] = h_[4]; Chris@16: } Chris@16: Chris@16: }}} // namespace boost::uuids::detail Chris@16: Chris@16: #endif