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