Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-30 10:02:08

0001 // Copyright 2007 Andy Tompkins.
0002 // Distributed under the Boost Software License, Version 1.0. (See
0003 // accompanying file LICENSE_1_0.txt or copy at
0004 // https://www.boost.org/LICENSE_1_0.txt)
0005 
0006 // Revision History
0007 //  29 May 2007 - Initial Revision
0008 //  25 Feb 2008 - moved to namespace boost::uuids::detail
0009 //  10 Jan 2012 - can now handle the full size of messages (2^64 - 1 bits)
0010 
0011 // This is a byte oriented implementation
0012 
0013 #ifndef BOOST_UUID_SHA1_H
0014 #define BOOST_UUID_SHA1_H
0015 
0016 #include <boost/static_assert.hpp>
0017 #include <boost/throw_exception.hpp>
0018 #include <boost/uuid/uuid.hpp> // for version
0019 #include <cstddef>
0020 #include <stdexcept>
0021 #include <string>
0022 
0023 #ifdef BOOST_NO_STDC_NAMESPACE
0024 namespace std {
0025     using ::size_t;
0026 } // namespace std
0027 #endif
0028 
0029 namespace boost {
0030 namespace uuids {
0031 namespace detail {
0032 
0033 BOOST_STATIC_ASSERT(sizeof(unsigned char)*8 == 8);
0034 BOOST_STATIC_ASSERT(sizeof(unsigned int)*8 == 32);
0035 
0036 inline unsigned int left_rotate(unsigned int x, std::size_t n)
0037 {
0038     return (x<<n) ^ (x>> (32-n));
0039 }
0040 
0041 class sha1
0042 {
0043 public:
0044     typedef unsigned int(digest_type)[5];
0045 public:
0046     sha1();
0047 
0048     void reset();
0049 
0050     void process_byte(unsigned char byte);
0051     void process_block(void const* bytes_begin, void const* bytes_end);
0052     void process_bytes(void const* buffer, std::size_t byte_count);
0053 
0054     void get_digest(digest_type& digest);
0055     unsigned char get_version() const;
0056 
0057 private:
0058     void process_block();
0059     void process_byte_impl(unsigned char byte);
0060 
0061 private:
0062     unsigned int h_[5];
0063 
0064     unsigned char block_[64];
0065 
0066     std::size_t block_byte_index_;
0067     std::size_t bit_count_low;
0068     std::size_t bit_count_high;
0069 };
0070 
0071 inline sha1::sha1()
0072 {
0073     reset();
0074 }
0075 
0076 inline void sha1::reset()
0077 {
0078     h_[0] = 0x67452301;
0079     h_[1] = 0xEFCDAB89;
0080     h_[2] = 0x98BADCFE;
0081     h_[3] = 0x10325476;
0082     h_[4] = 0xC3D2E1F0;
0083 
0084     block_byte_index_ = 0;
0085     bit_count_low = 0;
0086     bit_count_high = 0;
0087 }
0088 
0089 inline void sha1::process_byte(unsigned char byte)
0090 {
0091     process_byte_impl(byte);
0092 
0093     // size_t max value = 0xFFFFFFFF
0094     //if (bit_count_low + 8 >= 0x100000000) { // would overflow
0095     //if (bit_count_low >= 0x100000000-8) {
0096     if (bit_count_low < 0xFFFFFFF8) {
0097         bit_count_low += 8;
0098     } else {
0099         bit_count_low = 0;
0100 
0101         if (bit_count_high <= 0xFFFFFFFE) {
0102             ++bit_count_high;
0103         } else {
0104             BOOST_THROW_EXCEPTION(std::runtime_error("sha1 too many bytes"));
0105         }
0106     }
0107 }
0108 
0109 inline void sha1::process_byte_impl(unsigned char byte)
0110 {
0111     block_[block_byte_index_++] = byte;
0112 
0113     if (block_byte_index_ == 64) {
0114         block_byte_index_ = 0;
0115         process_block();
0116     }
0117 }
0118 
0119 inline void sha1::process_block(void const* bytes_begin, void const* bytes_end)
0120 {
0121     unsigned char const* begin = static_cast<unsigned char const*>(bytes_begin);
0122     unsigned char const* end = static_cast<unsigned char const*>(bytes_end);
0123     for(; begin != end; ++begin) {
0124         process_byte(*begin);
0125     }
0126 }
0127 
0128 inline void sha1::process_bytes(void const* buffer, std::size_t byte_count)
0129 {
0130     unsigned char const* b = static_cast<unsigned char const*>(buffer);
0131     process_block(b, b+byte_count);
0132 }
0133 
0134 inline void sha1::process_block()
0135 {
0136     unsigned int w[80];
0137     for (std::size_t i=0; i<16; ++i) {
0138         w[i]  = (block_[i*4 + 0] << 24);
0139         w[i] |= (block_[i*4 + 1] << 16);
0140         w[i] |= (block_[i*4 + 2] << 8);
0141         w[i] |= (block_[i*4 + 3]);
0142     }
0143     for (std::size_t i=16; i<80; ++i) {
0144         w[i] = left_rotate((w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]), 1);
0145     }
0146 
0147     unsigned int a = h_[0];
0148     unsigned int b = h_[1];
0149     unsigned int c = h_[2];
0150     unsigned int d = h_[3];
0151     unsigned int e = h_[4];
0152 
0153     for (std::size_t i=0; i<80; ++i) {
0154         unsigned int f;
0155         unsigned int k;
0156 
0157         if (i<20) {
0158             f = (b & c) | (~b & d);
0159             k = 0x5A827999;
0160         } else if (i<40) {
0161             f = b ^ c ^ d;
0162             k = 0x6ED9EBA1;
0163         } else if (i<60) {
0164             f = (b & c) | (b & d) | (c & d);
0165             k = 0x8F1BBCDC;
0166         } else {
0167             f = b ^ c ^ d;
0168             k = 0xCA62C1D6;
0169         }
0170 
0171         unsigned temp = left_rotate(a, 5) + f + e + k + w[i];
0172         e = d;
0173         d = c;
0174         c = left_rotate(b, 30);
0175         b = a;
0176         a = temp;
0177     }
0178 
0179     h_[0] += a;
0180     h_[1] += b;
0181     h_[2] += c;
0182     h_[3] += d;
0183     h_[4] += e;
0184 }
0185 
0186 inline unsigned char sha1::get_version() const
0187 {
0188     // RFC 4122 Section 4.1.3
0189     return uuid::version_name_based_sha1;
0190 }
0191 
0192 inline void sha1::get_digest(digest_type& digest)
0193 {
0194     // append the bit '1' to the message
0195     process_byte_impl(0x80);
0196 
0197     // append k bits '0', where k is the minimum number >= 0
0198     // such that the resulting message length is congruent to 56 (mod 64)
0199     // check if there is enough space for padding and bit_count
0200     if (block_byte_index_ > 56) {
0201         // finish this block
0202         while (block_byte_index_ != 0) {
0203             process_byte_impl(0);
0204         }
0205 
0206         // one more block
0207         while (block_byte_index_ < 56) {
0208             process_byte_impl(0);
0209         }
0210     } else {
0211         while (block_byte_index_ < 56) {
0212             process_byte_impl(0);
0213         }
0214     }
0215 
0216     // append length of message (before pre-processing)
0217     // as a 64-bit big-endian integer
0218     process_byte_impl( static_cast<unsigned char>((bit_count_high>>24) & 0xFF) );
0219     process_byte_impl( static_cast<unsigned char>((bit_count_high>>16) & 0xFF) );
0220     process_byte_impl( static_cast<unsigned char>((bit_count_high>>8 ) & 0xFF) );
0221     process_byte_impl( static_cast<unsigned char>((bit_count_high)     & 0xFF) );
0222     process_byte_impl( static_cast<unsigned char>((bit_count_low>>24) & 0xFF) );
0223     process_byte_impl( static_cast<unsigned char>((bit_count_low>>16) & 0xFF) );
0224     process_byte_impl( static_cast<unsigned char>((bit_count_low>>8 ) & 0xFF) );
0225     process_byte_impl( static_cast<unsigned char>((bit_count_low)     & 0xFF) );
0226 
0227     // get final digest
0228     digest[0] = h_[0];
0229     digest[1] = h_[1];
0230     digest[2] = h_[2];
0231     digest[3] = h_[3];
0232     digest[4] = h_[4];
0233 }
0234 
0235 }}} // namespace boost::uuids::detail
0236 
0237 #endif