Imported Upstream version 1.49.0
[platform/upstream/boost.git] / boost / uuid / sha1.hpp
1 // boost/uuid/sha1.hpp header file  ----------------------------------------------//
2
3 // Copyright 2007 Andy Tompkins.
4 // Distributed under the Boost Software License, Version 1.0. (See
5 // accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt)
7
8 // Revision History
9 //  29 May 2007 - Initial Revision
10 //  25 Feb 2008 - moved to namespace boost::uuids::detail
11 //  10 Jan 2012 - can now handle the full size of messages (2^64 - 1 bits)
12
13 // This is a byte oriented implementation
14
15 #ifndef BOOST_UUID_SHA1_H
16 #define BOOST_UUID_SHA1_H
17
18 #include <boost/static_assert.hpp>
19 #include <stdexcept>
20 #include <boost/throw_exception.hpp>
21 #include <cstddef>
22
23 #ifdef BOOST_NO_STDC_NAMESPACE
24 namespace std {
25     using ::size_t;
26 } // namespace std
27 #endif
28
29 namespace boost {
30 namespace uuids {
31 namespace detail {
32
33 BOOST_STATIC_ASSERT(sizeof(unsigned char)*8 == 8);
34 BOOST_STATIC_ASSERT(sizeof(unsigned int)*8 == 32);
35
36 inline unsigned int left_rotate(unsigned int x, std::size_t n)
37 {
38     return (x<<n) ^ (x>> (32-n));
39 }
40
41 class sha1
42 {
43 public:
44     typedef unsigned int(&digest_type)[5];
45 public:
46     sha1();
47
48     void reset();
49
50     void process_byte(unsigned char byte);
51     void process_block(void const* bytes_begin, void const* bytes_end);
52     void process_bytes(void const* buffer, std::size_t byte_count);
53
54     void get_digest(digest_type digest);
55
56 private:
57     void process_block();
58     void process_byte_impl(unsigned char byte);
59
60 private:
61     unsigned int h_[5];
62
63     unsigned char block_[64];
64
65     std::size_t block_byte_index_;
66     std::size_t bit_count_low;
67     std::size_t bit_count_high;
68 };
69
70 inline sha1::sha1()
71 {
72     reset();
73 }
74
75 inline void sha1::reset()
76 {
77     h_[0] = 0x67452301;
78     h_[1] = 0xEFCDAB89;
79     h_[2] = 0x98BADCFE;
80     h_[3] = 0x10325476;
81     h_[4] = 0xC3D2E1F0;
82
83     block_byte_index_ = 0;
84     bit_count_low = 0;
85     bit_count_high = 0;
86 }
87
88 inline void sha1::process_byte(unsigned char byte)
89 {
90     process_byte_impl(byte);
91
92     bit_count_low += 8;
93     if (bit_count_low == 0) {
94         ++bit_count_high;
95         if (bit_count_high == 0) {
96             BOOST_THROW_EXCEPTION(std::runtime_error("sha1 too many bytes"));
97         }
98     }
99 }
100
101 inline void sha1::process_byte_impl(unsigned char byte)
102 {
103     block_[block_byte_index_++] = byte;
104
105     if (block_byte_index_ == 64) {
106         block_byte_index_ = 0;
107         process_block();
108     }
109 }
110
111 inline void sha1::process_block(void const* bytes_begin, void const* bytes_end)
112 {
113     unsigned char const* begin = static_cast<unsigned char const*>(bytes_begin);
114     unsigned char const* end = static_cast<unsigned char const*>(bytes_end);
115     for(; begin != end; ++begin) {
116         process_byte(*begin);
117     }
118 }
119
120 inline void sha1::process_bytes(void const* buffer, std::size_t byte_count)
121 {
122     unsigned char const* b = static_cast<unsigned char const*>(buffer);
123     process_block(b, b+byte_count);
124 }
125
126 inline void sha1::process_block()
127 {
128     unsigned int w[80];
129     for (std::size_t i=0; i<16; ++i) {
130         w[i]  = (block_[i*4 + 0] << 24);
131         w[i] |= (block_[i*4 + 1] << 16);
132         w[i] |= (block_[i*4 + 2] << 8);
133         w[i] |= (block_[i*4 + 3]);
134     }
135     for (std::size_t i=16; i<80; ++i) {
136         w[i] = left_rotate((w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]), 1);
137     }
138
139     unsigned int a = h_[0];
140     unsigned int b = h_[1];
141     unsigned int c = h_[2];
142     unsigned int d = h_[3];
143     unsigned int e = h_[4];
144
145     for (std::size_t i=0; i<80; ++i) {
146         unsigned int f;
147         unsigned int k;
148
149         if (i<20) {
150             f = (b & c) | (~b & d);
151             k = 0x5A827999;
152         } else if (i<40) {
153             f = b ^ c ^ d;
154             k = 0x6ED9EBA1;
155         } else if (i<60) {
156             f = (b & c) | (b & d) | (c & d);
157             k = 0x8F1BBCDC;
158         } else {
159             f = b ^ c ^ d;
160             k = 0xCA62C1D6;
161         }
162
163         unsigned temp = left_rotate(a, 5) + f + e + k + w[i];
164         e = d;
165         d = c;
166         c = left_rotate(b, 30);
167         b = a;
168         a = temp;
169     }
170
171     h_[0] += a;
172     h_[1] += b;
173     h_[2] += c;
174     h_[3] += d;
175     h_[4] += e;
176 }
177
178 inline void sha1::get_digest(digest_type digest)
179 {
180     // append the bit '1' to the message
181     process_byte_impl(0x80);
182
183     // append k bits '0', where k is the minimum number >= 0
184     // such that the resulting message length is congruent to 56 (mod 64)
185     // check if there is enough space for padding and bit_count
186     if (block_byte_index_ > 56) {
187         // finish this block
188         while (block_byte_index_ != 0) {
189             process_byte_impl(0);
190         }
191
192         // one more block
193         while (block_byte_index_ < 56) {
194             process_byte_impl(0);
195         }
196     } else {
197         while (block_byte_index_ < 56) {
198             process_byte_impl(0);
199         }
200     }
201
202     // append length of message (before pre-processing) 
203     // as a 64-bit big-endian integer
204     process_byte_impl( static_cast<unsigned char>((bit_count_high>>24) & 0xFF) );
205     process_byte_impl( static_cast<unsigned char>((bit_count_high>>16) & 0xFF) );
206     process_byte_impl( static_cast<unsigned char>((bit_count_high>>8 ) & 0xFF) );
207     process_byte_impl( static_cast<unsigned char>((bit_count_high)     & 0xFF) );
208     process_byte_impl( static_cast<unsigned char>((bit_count_low>>24) & 0xFF) );
209     process_byte_impl( static_cast<unsigned char>((bit_count_low>>16) & 0xFF) );
210     process_byte_impl( static_cast<unsigned char>((bit_count_low>>8 ) & 0xFF) );
211     process_byte_impl( static_cast<unsigned char>((bit_count_low)     & 0xFF) );
212
213     // get final digest
214     digest[0] = h_[0];
215     digest[1] = h_[1];
216     digest[2] = h_[2];
217     digest[3] = h_[3];
218     digest[4] = h_[4];
219 }
220
221 }}} // namespace boost::uuids::detail
222
223 #endif