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