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