1 /*
2 *****
3 sha1.hpp is a repackaging of the sha1.cpp and sha1.h files from the smallsha1
4 library (http://code.google.com/p/smallsha1/) into a single header suitable for
5 use as a header only library. This conversion was done by Peter Thorson
6 (webmaster@zaphoyd.com) in 2013. All modifications to the code are redistributed
7 under the same license as the original, which is listed below.
8 *****
9
10 Copyright (c) 2011, Micael Hildenborg
11 All rights reserved.
12
13 Redistribution and use in source and binary forms, with or without
14 modification, are permitted provided that the following conditions are met:
15 * Redistributions of source code must retain the above copyright
16 notice, this list of conditions and the following disclaimer.
17 * Redistributions in binary form must reproduce the above copyright
18 notice, this list of conditions and the following disclaimer in the
19 documentation and/or other materials provided with the distribution.
20 * Neither the name of Micael Hildenborg nor the
21 names of its contributors may be used to endorse or promote products
22 derived from this software without specific prior written permission.
23
24 THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY
25 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY
28 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36 #ifndef SHA1_DEFINED
37 #define SHA1_DEFINED
38
39 namespace websocketpp {
40 namespace sha1 {
41
42 namespace { // local
43
44 // Rotate an integer value to left.
rol(unsigned int value,unsigned int steps)45 inline unsigned int rol(unsigned int value, unsigned int steps) {
46 return ((value << steps) | (value >> (32 - steps)));
47 }
48
49 // Sets the first 16 integers in the buffert to zero.
50 // Used for clearing the W buffert.
clearWBuffert(unsigned int * buffert)51 inline void clearWBuffert(unsigned int * buffert)
52 {
53 for (int pos = 16; --pos >= 0;)
54 {
55 buffert[pos] = 0;
56 }
57 }
58
innerHash(unsigned int * result,unsigned int * w)59 inline void innerHash(unsigned int * result, unsigned int * w)
60 {
61 unsigned int a = result[0];
62 unsigned int b = result[1];
63 unsigned int c = result[2];
64 unsigned int d = result[3];
65 unsigned int e = result[4];
66
67 int round = 0;
68
69 #define sha1macro(func,val) \
70 { \
71 const unsigned int t = rol(a, 5) + (func) + e + val + w[round]; \
72 e = d; \
73 d = c; \
74 c = rol(b, 30); \
75 b = a; \
76 a = t; \
77 }
78
79 while (round < 16)
80 {
81 sha1macro((b & c) | (~b & d), 0x5a827999)
82 ++round;
83 }
84 while (round < 20)
85 {
86 w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
87 sha1macro((b & c) | (~b & d), 0x5a827999)
88 ++round;
89 }
90 while (round < 40)
91 {
92 w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
93 sha1macro(b ^ c ^ d, 0x6ed9eba1)
94 ++round;
95 }
96 while (round < 60)
97 {
98 w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
99 sha1macro((b & c) | (b & d) | (c & d), 0x8f1bbcdc)
100 ++round;
101 }
102 while (round < 80)
103 {
104 w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
105 sha1macro(b ^ c ^ d, 0xca62c1d6)
106 ++round;
107 }
108
109 #undef sha1macro
110
111 result[0] += a;
112 result[1] += b;
113 result[2] += c;
114 result[3] += d;
115 result[4] += e;
116 }
117
118 } // namespace
119
120 /// Calculate a SHA1 hash
121 /**
122 * @param src points to any kind of data to be hashed.
123 * @param bytelength the number of bytes to hash from the src pointer.
124 * @param hash should point to a buffer of at least 20 bytes of size for storing
125 * the sha1 result in.
126 */
calc(void const * src,size_t bytelength,unsigned char * hash)127 inline void calc(void const * src, size_t bytelength, unsigned char * hash) {
128 // Init the result array.
129 unsigned int result[5] = { 0x67452301, 0xefcdab89, 0x98badcfe,
130 0x10325476, 0xc3d2e1f0 };
131
132 // Cast the void src pointer to be the byte array we can work with.
133 unsigned char const * sarray = (unsigned char const *) src;
134
135 // The reusable round buffer
136 unsigned int w[80];
137
138 // Loop through all complete 64byte blocks.
139
140 size_t endCurrentBlock;
141 size_t currentBlock = 0;
142
143 if (bytelength >= 64) {
144 size_t const endOfFullBlocks = bytelength - 64;
145
146 while (currentBlock <= endOfFullBlocks) {
147 endCurrentBlock = currentBlock + 64;
148
149 // Init the round buffer with the 64 byte block data.
150 for (int roundPos = 0; currentBlock < endCurrentBlock; currentBlock += 4)
151 {
152 // This line will swap endian on big endian and keep endian on
153 // little endian.
154 w[roundPos++] = (unsigned int) sarray[currentBlock + 3]
155 | (((unsigned int) sarray[currentBlock + 2]) << 8)
156 | (((unsigned int) sarray[currentBlock + 1]) << 16)
157 | (((unsigned int) sarray[currentBlock]) << 24);
158 }
159 innerHash(result, w);
160 }
161 }
162
163 // Handle the last and not full 64 byte block if existing.
164 endCurrentBlock = bytelength - currentBlock;
165 clearWBuffert(w);
166 size_t lastBlockBytes = 0;
167 for (;lastBlockBytes < endCurrentBlock; ++lastBlockBytes) {
168 w[lastBlockBytes >> 2] |= (unsigned int) sarray[lastBlockBytes + currentBlock] << ((3 - (lastBlockBytes & 3)) << 3);
169 }
170
171 w[lastBlockBytes >> 2] |= 0x80 << ((3 - (lastBlockBytes & 3)) << 3);
172 if (endCurrentBlock >= 56) {
173 innerHash(result, w);
174 clearWBuffert(w);
175 }
176 w[15] = bytelength << 3;
177 innerHash(result, w);
178
179 // Store hash in result pointer, and make sure we get in in the correct
180 // order on both endian models.
181 for (int hashByte = 20; --hashByte >= 0;) {
182 hash[hashByte] = (result[hashByte >> 2] >> (((3 - hashByte) & 0x3) << 3)) & 0xff;
183 }
184 }
185
186 } // namespace sha1
187 } // namespace websocketpp
188
189 #endif // SHA1_DEFINED
190