Sirikata
libcore/src/util/boost_sha1.hpp
Go to the documentation of this file.
00001 // boost/uuid/sha1.hpp header file  ----------------------------------------------//
00002 
00003 // Copyright 2007 Andy Tompkins.
00004 // Distributed under the Boost Software License, Version 1.0. (See
00005 // accompanying file LICENSE_1_0.txt or copy at
00006 // http://www.boost.org/LICENSE_1_0.txt)
00007 
00008 // Revision History
00009 //  29 May 2007 - Initial Revision
00010 
00011 // This is a byte oriented implementation
00012 // Note: this implementation does not handle message longer than
00013 //       2^32 bytes.
00014 
00015 #ifndef BOOST_UUID_SHA1_H
00016 #define BOOST_UUID_SHA1_H
00017 
00018 #include <boost/static_assert.hpp>
00019 
00020 namespace boost_ {
00021 namespace detail {
00022 
00023 BOOST_STATIC_ASSERT(sizeof(unsigned char)*8 == 8);
00024 BOOST_STATIC_ASSERT(sizeof(unsigned int)*8 == 32);
00025 
00026 inline unsigned int left_rotate(unsigned int x, size_t n)
00027 {
00028     return (x<<n) ^ (x>> (32-n));
00029 }
00030 
00031 class sha1
00032 {
00033 public:
00034     typedef unsigned int(&digest_type)[5];
00035 public:
00036     sha1();
00037 
00038     void reset();
00039 
00040     void process_byte(unsigned char byte);
00041     void process_block(void const* bytes_begin, void const* bytes_end);
00042     void process_bytes(void const* buffer, std::size_t byte_count);
00043 
00044     void get_digest(digest_type digest);
00045 
00046 private:
00047     void process_block();
00048 
00049 private:
00050     unsigned int h_[5];
00051 
00052     unsigned char block_[64];
00053 
00054     size_t block_byte_index_;
00055     size_t byte_count_;
00056 };
00057 
00058 inline sha1::sha1()
00059 {
00060     reset();
00061 }
00062 
00063 inline void sha1::reset()
00064 {
00065     h_[0] = 0x67452301;
00066     h_[1] = 0xEFCDAB89;
00067     h_[2] = 0x98BADCFE;
00068     h_[3] = 0x10325476;
00069     h_[4] = 0xC3D2E1F0;
00070 
00071     block_byte_index_ = 0;
00072     byte_count_ = 0;
00073 }
00074 
00075 inline void sha1::process_byte(unsigned char byte)
00076 {
00077     block_[block_byte_index_++] = byte;
00078     ++byte_count_;
00079     if (block_byte_index_ == 64) {
00080         block_byte_index_ = 0;
00081         process_block();
00082     }
00083 }
00084 
00085 inline void sha1::process_block(void const* bytes_begin, void const* bytes_end)
00086 {
00087     unsigned char const* begin = static_cast<unsigned char const*>(bytes_begin);
00088     unsigned char const* end = static_cast<unsigned char const*>(bytes_end);
00089     for(; begin != end; ++begin) {
00090         process_byte(*begin);
00091     }
00092 }
00093 
00094 inline void sha1::process_bytes(void const* buffer, std::size_t byte_count)
00095 {
00096     unsigned char const* b = static_cast<unsigned char const*>(buffer);
00097     process_block(b, b+byte_count);
00098 }
00099 
00100 inline void sha1::process_block()
00101 {
00102     unsigned int w[80];
00103     for (size_t i=0; i<16; ++i) {
00104         w[i]  = (block_[i*4 + 0] << 24);
00105         w[i] |= (block_[i*4 + 1] << 16);
00106         w[i] |= (block_[i*4 + 2] << 8);
00107         w[i] |= (block_[i*4 + 3]);
00108     }
00109     for (size_t i=16; i<80; ++i) {
00110         w[i] = left_rotate((w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]), 1);
00111     }
00112 
00113     unsigned int a = h_[0];
00114     unsigned int b = h_[1];
00115     unsigned int c = h_[2];
00116     unsigned int d = h_[3];
00117     unsigned int e = h_[4];
00118 
00119     for (size_t i=0; i<80; ++i) {
00120         unsigned int f;
00121         unsigned int k;
00122 
00123         if (i<20) {
00124             f = (b & c) | (~b & d);
00125             k = 0x5A827999;
00126         } else if (i<40) {
00127             f = b ^ c ^ d;
00128             k = 0x6ED9EBA1;
00129         } else if (i<60) {
00130             f = (b & c) | (b & d) | (c & d);
00131             k = 0x8F1BBCDC;
00132         } else {
00133             f = b ^ c ^ d;
00134             k = 0xCA62C1D6;
00135         }
00136 
00137         unsigned temp = left_rotate(a, 5) + f + e + k + w[i];
00138         e = d;
00139         d = c;
00140         c = left_rotate(b, 30);
00141         b = a;
00142         a = temp;
00143     }
00144 
00145     h_[0] += a;
00146     h_[1] += b;
00147     h_[2] += c;
00148     h_[3] += d;
00149     h_[4] += e;
00150 }
00151 
00152 inline void sha1::get_digest(digest_type digest)
00153 {
00154     size_t bit_count = byte_count_*8;
00155 
00156     // append the bit '1' to the message
00157     process_byte(0x80);
00158 
00159     // append k bits '0', where k is the minimum number >= 0
00160     // such that the resulting message length is congruent to 56 (mod 64)
00161     // check if there is enough space for padding and bit_count
00162     if (block_byte_index_ > 56) {
00163         // finish this block
00164         while (block_byte_index_ != 0) {
00165             process_byte(0);
00166         }
00167 
00168         // one more block
00169         while (block_byte_index_ < 56) {
00170             process_byte(0);
00171         }
00172     } else {
00173         while (block_byte_index_ < 56) {
00174             process_byte(0);
00175         }
00176     }
00177 
00178     // append length of message (before pre-processing) 
00179     // as a 64-bit big-endian integer
00180     process_byte(0);
00181     process_byte(0);
00182     process_byte(0);
00183     process_byte(0);
00184     process_byte( static_cast<unsigned char>((bit_count>>24) & 0xFF));
00185     process_byte( static_cast<unsigned char>((bit_count>>16) & 0xFF));
00186     process_byte( static_cast<unsigned char>((bit_count>>8 ) & 0xFF));
00187     process_byte( static_cast<unsigned char>((bit_count)     & 0xFF));
00188 
00189     // get final digest
00190     digest[0] = h_[0];
00191     digest[1] = h_[1];
00192     digest[2] = h_[2];
00193     digest[3] = h_[3];
00194     digest[4] = h_[4];
00195 }
00196 
00197 
00198 } // namespace detail
00199 } // namespace boost
00200 
00201 #endif