]> git.sesse.net Git - casparcg/blob - dependencies/boost/boost/uuid/sha1.hpp
Manually merged pull request #222
[casparcg] / dependencies / boost / 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
12 // This is a byte oriented implementation
13 // Note: this implementation does not handle message longer than
14 //       2^32 bytes.
15
16 #ifndef BOOST_UUID_SHA1_H
17 #define BOOST_UUID_SHA1_H
18
19 #include <boost/static_assert.hpp>
20 #include <cstddef>
21
22 #ifdef BOOST_NO_STDC_NAMESPACE
23 namespace std {
24     using ::size_t;
25 } // namespace std
26 #endif
27
28 namespace boost {
29 namespace uuids {
30 namespace detail {
31
32 BOOST_STATIC_ASSERT(sizeof(unsigned char)*8 == 8);
33 BOOST_STATIC_ASSERT(sizeof(unsigned int)*8 == 32);
34
35 inline unsigned int left_rotate(unsigned int x, std::size_t n)
36 {
37     return (x<<n) ^ (x>> (32-n));
38 }
39
40 class sha1
41 {
42 public:
43     typedef unsigned int(&digest_type)[5];
44 public:
45     sha1();
46
47     void reset();
48
49     void process_byte(unsigned char byte);
50     void process_block(void const* bytes_begin, void const* bytes_end);
51     void process_bytes(void const* buffer, std::size_t byte_count);
52
53     void get_digest(digest_type digest);
54
55 private:
56     void process_block();
57
58 private:
59     unsigned int h_[5];
60
61     unsigned char block_[64];
62
63     std::size_t block_byte_index_;
64     std::size_t byte_count_;
65 };
66
67 inline sha1::sha1()
68 {
69     reset();
70 }
71
72 inline void sha1::reset()
73 {
74     h_[0] = 0x67452301;
75     h_[1] = 0xEFCDAB89;
76     h_[2] = 0x98BADCFE;
77     h_[3] = 0x10325476;
78     h_[4] = 0xC3D2E1F0;
79
80     block_byte_index_ = 0;
81     byte_count_ = 0;
82 }
83
84 inline void sha1::process_byte(unsigned char byte)
85 {
86     block_[block_byte_index_++] = byte;
87     ++byte_count_;
88     if (block_byte_index_ == 64) {
89         block_byte_index_ = 0;
90         process_block();
91     }
92 }
93
94 inline void sha1::process_block(void const* bytes_begin, void const* bytes_end)
95 {
96     unsigned char const* begin = static_cast<unsigned char const*>(bytes_begin);
97     unsigned char const* end = static_cast<unsigned char const*>(bytes_end);
98     for(; begin != end; ++begin) {
99         process_byte(*begin);
100     }
101 }
102
103 inline void sha1::process_bytes(void const* buffer, std::size_t byte_count)
104 {
105     unsigned char const* b = static_cast<unsigned char const*>(buffer);
106     process_block(b, b+byte_count);
107 }
108
109 inline void sha1::process_block()
110 {
111     unsigned int w[80];
112     for (std::size_t i=0; i<16; ++i) {
113         w[i]  = (block_[i*4 + 0] << 24);
114         w[i] |= (block_[i*4 + 1] << 16);
115         w[i] |= (block_[i*4 + 2] << 8);
116         w[i] |= (block_[i*4 + 3]);
117     }
118     for (std::size_t i=16; i<80; ++i) {
119         w[i] = left_rotate((w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]), 1);
120     }
121
122     unsigned int a = h_[0];
123     unsigned int b = h_[1];
124     unsigned int c = h_[2];
125     unsigned int d = h_[3];
126     unsigned int e = h_[4];
127
128     for (std::size_t i=0; i<80; ++i) {
129         unsigned int f;
130         unsigned int k;
131
132         if (i<20) {
133             f = (b & c) | (~b & d);
134             k = 0x5A827999;
135         } else if (i<40) {
136             f = b ^ c ^ d;
137             k = 0x6ED9EBA1;
138         } else if (i<60) {
139             f = (b & c) | (b & d) | (c & d);
140             k = 0x8F1BBCDC;
141         } else {
142             f = b ^ c ^ d;
143             k = 0xCA62C1D6;
144         }
145
146         unsigned temp = left_rotate(a, 5) + f + e + k + w[i];
147         e = d;
148         d = c;
149         c = left_rotate(b, 30);
150         b = a;
151         a = temp;
152     }
153
154     h_[0] += a;
155     h_[1] += b;
156     h_[2] += c;
157     h_[3] += d;
158     h_[4] += e;
159 }
160
161 inline void sha1::get_digest(digest_type digest)
162 {
163     std::size_t bit_count = byte_count_*8;
164
165     // append the bit '1' to the message
166     process_byte(0x80);
167
168     // append k bits '0', where k is the minimum number >= 0
169     // such that the resulting message length is congruent to 56 (mod 64)
170     // check if there is enough space for padding and bit_count
171     if (block_byte_index_ > 56) {
172         // finish this block
173         while (block_byte_index_ != 0) {
174             process_byte(0);
175         }
176
177         // one more block
178         while (block_byte_index_ < 56) {
179             process_byte(0);
180         }
181     } else {
182         while (block_byte_index_ < 56) {
183             process_byte(0);
184         }
185     }
186
187     // append length of message (before pre-processing) 
188     // as a 64-bit big-endian integer
189     process_byte(0);
190     process_byte(0);
191     process_byte(0);
192     process_byte(0);
193     process_byte( static_cast<unsigned char>((bit_count>>24) & 0xFF));
194     process_byte( static_cast<unsigned char>((bit_count>>16) & 0xFF));
195     process_byte( static_cast<unsigned char>((bit_count>>8 ) & 0xFF));
196     process_byte( static_cast<unsigned char>((bit_count)     & 0xFF));
197
198     // get final digest
199     digest[0] = h_[0];
200     digest[1] = h_[1];
201     digest[2] = h_[2];
202     digest[3] = h_[3];
203     digest[4] = h_[4];
204 }
205
206 }}} // namespace boost::uuids::detail
207
208 #endif