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