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