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 | |
36 | namespace 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 | |