CMSDK 2.0.1
Cross-platform C++ base library and SDK for the Psyclone AIOS platform
Loading...
Searching...
No Matches
sha1.cpp
Go to the documentation of this file.
1
6// //////////////////////////////////////////////////////////
7// sha1.cpp
8// Copyright (c) 2014,2015 Stephan Brumme. All rights reserved.
9// see http://create.stephan-brumme.com/disclaimer.html
10//
11
12#include "hash/sha1.h"
14
15// big endian architectures need #define __BYTE_ORDER __BIG_ENDIAN
16#ifndef _MSC_VER
17#ifndef __APPLE__
18#include <endian.h>
19#endif
20#endif
21
22// Added namespace to avoid clash with OpenSSL
23namespace hash {
24
27{
28 reset();
29}
30
31
33void SHA1::reset()
34{
35 m_numBytes = 0;
36 m_bufferSize = 0;
37
38 // according to RFC 1321
39 m_hash[0] = 0x67452301;
40 m_hash[1] = 0xefcdab89;
41 m_hash[2] = 0x98badcfe;
42 m_hash[3] = 0x10325476;
43 m_hash[4] = 0xc3d2e1f0;
44}
45
46
47namespace
48{
49 // mix functions for processBlock()
50 inline uint32_t f1(uint32_t b, uint32_t c, uint32_t d)
51 {
52 return d ^ (b & (c ^ d)); // original: f = (b & c) | ((~b) & d);
53 }
54
55 inline uint32_t f2(uint32_t b, uint32_t c, uint32_t d)
56 {
57 return b ^ c ^ d;
58 }
59
60 inline uint32_t f3(uint32_t b, uint32_t c, uint32_t d)
61 {
62 return (b & c) | (b & d) | (c & d);
63 }
64
65 inline uint32_t rotate(uint32_t a, uint32_t c)
66 {
67 return (a << c) | (a >> (32 - c));
68 }
69
70 inline uint32_t swap(uint32_t x)
71 {
72#if defined(__GNUC__) || defined(__clang__)
73 return __builtin_bswap32(x);
74#endif
75#ifdef MSC_VER
76 return _byteswap_ulong(x);
77#endif
78
79 return (x >> 24) |
80 ((x >> 8) & 0x0000FF00) |
81 ((x << 8) & 0x00FF0000) |
82 (x << 24);
83 }
84}
85
86
88void SHA1::processBlock(const void* data)
89{
90 // get last hash
91 uint32_t a = m_hash[0];
92 uint32_t b = m_hash[1];
93 uint32_t c = m_hash[2];
94 uint32_t d = m_hash[3];
95 uint32_t e = m_hash[4];
96
97 // data represented as 16x 32-bit words
98 const uint32_t* input = (uint32_t*) data;
99 // convert to big endian
100 uint32_t words[80];
101 for (int i = 0; i < 16; i++)
102#if defined(__BYTE_ORDER) && (__BYTE_ORDER != 0) && (__BYTE_ORDER == __BIG_ENDIAN)
103 words[i] = input[i];
104#else
105 words[i] = swap(input[i]);
106#endif
107
108 // extend to 80 words
109 for (int i = 16; i < 80; i++)
110 words[i] = rotate(words[i-3] ^ words[i-8] ^ words[i-14] ^ words[i-16], 1);
111
112 // first round
113 for (int i = 0; i < 4; i++)
114 {
115 int offset = 5*i;
116 e += rotate(a,5) + f1(b,c,d) + words[offset ] + 0x5a827999; b = rotate(b,30);
117 d += rotate(e,5) + f1(a,b,c) + words[offset+1] + 0x5a827999; a = rotate(a,30);
118 c += rotate(d,5) + f1(e,a,b) + words[offset+2] + 0x5a827999; e = rotate(e,30);
119 b += rotate(c,5) + f1(d,e,a) + words[offset+3] + 0x5a827999; d = rotate(d,30);
120 a += rotate(b,5) + f1(c,d,e) + words[offset+4] + 0x5a827999; c = rotate(c,30);
121 }
122
123 // second round
124 for (int i = 4; i < 8; i++)
125 {
126 int offset = 5*i;
127 e += rotate(a,5) + f2(b,c,d) + words[offset ] + 0x6ed9eba1; b = rotate(b,30);
128 d += rotate(e,5) + f2(a,b,c) + words[offset+1] + 0x6ed9eba1; a = rotate(a,30);
129 c += rotate(d,5) + f2(e,a,b) + words[offset+2] + 0x6ed9eba1; e = rotate(e,30);
130 b += rotate(c,5) + f2(d,e,a) + words[offset+3] + 0x6ed9eba1; d = rotate(d,30);
131 a += rotate(b,5) + f2(c,d,e) + words[offset+4] + 0x6ed9eba1; c = rotate(c,30);
132 }
133
134 // third round
135 for (int i = 8; i < 12; i++)
136 {
137 int offset = 5*i;
138 e += rotate(a,5) + f3(b,c,d) + words[offset ] + 0x8f1bbcdc; b = rotate(b,30);
139 d += rotate(e,5) + f3(a,b,c) + words[offset+1] + 0x8f1bbcdc; a = rotate(a,30);
140 c += rotate(d,5) + f3(e,a,b) + words[offset+2] + 0x8f1bbcdc; e = rotate(e,30);
141 b += rotate(c,5) + f3(d,e,a) + words[offset+3] + 0x8f1bbcdc; d = rotate(d,30);
142 a += rotate(b,5) + f3(c,d,e) + words[offset+4] + 0x8f1bbcdc; c = rotate(c,30);
143 }
144
145 // fourth round
146 for (int i = 12; i < 16; i++)
147 {
148 int offset = 5*i;
149 e += rotate(a,5) + f2(b,c,d) + words[offset ] + 0xca62c1d6; b = rotate(b,30);
150 d += rotate(e,5) + f2(a,b,c) + words[offset+1] + 0xca62c1d6; a = rotate(a,30);
151 c += rotate(d,5) + f2(e,a,b) + words[offset+2] + 0xca62c1d6; e = rotate(e,30);
152 b += rotate(c,5) + f2(d,e,a) + words[offset+3] + 0xca62c1d6; d = rotate(d,30);
153 a += rotate(b,5) + f2(c,d,e) + words[offset+4] + 0xca62c1d6; c = rotate(c,30);
154 }
155
156 // update hash
157 m_hash[0] += a;
158 m_hash[1] += b;
159 m_hash[2] += c;
160 m_hash[3] += d;
161 m_hash[4] += e;
162}
163
164
166void SHA1::add(const void* data, size_t numBytes)
167{
168 const uint8_t* current = (const uint8_t*) data;
169
170 if (m_bufferSize > 0)
171 {
172 while (numBytes > 0 && m_bufferSize < BlockSize)
173 {
174 m_buffer[m_bufferSize++] = *current++;
175 numBytes--;
176 }
177 }
178
179 // full buffer
180 if (m_bufferSize == BlockSize)
181 {
182 processBlock((void*)m_buffer);
183 m_numBytes += BlockSize;
184 m_bufferSize = 0;
185 }
186
187 // no more data ?
188 if (numBytes == 0)
189 return;
190
191 // process full blocks
192 while (numBytes >= BlockSize)
193 {
194 processBlock(current);
195 current += BlockSize;
196 m_numBytes += BlockSize;
197 numBytes -= BlockSize;
198 }
199
200 // keep remaining bytes in buffer
201 while (numBytes > 0)
202 {
203 m_buffer[m_bufferSize++] = *current++;
204 numBytes--;
205 }
206}
207
208
210void SHA1::processBuffer()
211{
212 // the input bytes are considered as bits strings, where the first bit is the most significant bit of the byte
213
214 // - append "1" bit to message
215 // - append "0" bits until message length in bit mod 512 is 448
216 // - append length as 64 bit integer
217
218 // number of bits
219 size_t paddedLength = m_bufferSize * 8;
220
221 // plus one bit set to 1 (always appended)
222 paddedLength++;
223
224 // number of bits must be (numBits % 512) = 448
225 size_t lower11Bits = paddedLength & 511;
226 if (lower11Bits <= 448)
227 paddedLength += 448 - lower11Bits;
228 else
229 paddedLength += 512 + 448 - lower11Bits;
230 // convert from bits to bytes
231 paddedLength /= 8;
232
233 // only needed if additional data flows over into a second block
234 unsigned char extra[BlockSize];
235
236 // append a "1" bit, 128 => binary 10000000
237 if (m_bufferSize < BlockSize)
238 m_buffer[m_bufferSize] = 128;
239 else
240 extra[0] = 128;
241
242 size_t i;
243 for (i = m_bufferSize + 1; i < BlockSize; i++)
244 m_buffer[i] = 0;
245 for (; i < paddedLength; i++)
246 extra[i - BlockSize] = 0;
247
248 // add message length in bits as 64 bit number
249 uint64_t msgBits = 8 * (m_numBytes + m_bufferSize);
250 // find right position
251 unsigned char* addLength;
252 if (paddedLength < BlockSize)
253 addLength = m_buffer + paddedLength;
254 else
255 addLength = extra + paddedLength - BlockSize;
256
257 // must be big endian
258 *addLength++ = (unsigned char)((msgBits >> 56) & 0xFF);
259 *addLength++ = (unsigned char)((msgBits >> 48) & 0xFF);
260 *addLength++ = (unsigned char)((msgBits >> 40) & 0xFF);
261 *addLength++ = (unsigned char)((msgBits >> 32) & 0xFF);
262 *addLength++ = (unsigned char)((msgBits >> 24) & 0xFF);
263 *addLength++ = (unsigned char)((msgBits >> 16) & 0xFF);
264 *addLength++ = (unsigned char)((msgBits >> 8) & 0xFF);
265 *addLength = (unsigned char)( msgBits & 0xFF);
266
267 // process blocks
268 processBlock(m_buffer);
269 // flowed over into a second block ?
270 if (paddedLength > BlockSize)
271 processBlock(extra);
272}
273
274
276std::string SHA1::getHash()
277{
278 // compute hash (as raw bytes)
279 unsigned char rawHash[HashBytes];
280 getHash(rawHash);
281
282 // convert to hex string
283 std::string result;
284 result.reserve(2 * HashBytes);
285 for (int i = 0; i < HashBytes; i++)
286 {
287 static const char dec2hex[16+1] = "0123456789abcdef";
288 result += dec2hex[(rawHash[i] >> 4) & 15];
289 result += dec2hex[ rawHash[i] & 15];
290 }
291
292 return result;
293}
294
296std::string SHA1::getHashRaw()
297{
298 // compute hash (as raw bytes)
299 unsigned char rawHash[HashBytes];
300 getHash(rawHash);
301
302 // convert to hex string
303 std::string result;
304 result.reserve(2 * HashBytes);
305 for (int i = 0; i < HashBytes; i++)
306 {
307 result += rawHash[i];
308 }
309
310 return result;
311}
312
313
315void SHA1::getHash(unsigned char buffer[SHA1::HashBytes])
316{
317 // save old hash if buffer is partially filled
318 uint32_t oldHash[HashValues];
319 for (int i = 0; i < HashValues; i++)
320 oldHash[i] = m_hash[i];
321
322 // process remaining bytes
323 processBuffer();
324
325 unsigned char* current = buffer;
326 for (int i = 0; i < HashValues; i++)
327 {
328 *current++ = (m_hash[i] >> 24) & 0xFF;
329 *current++ = (m_hash[i] >> 16) & 0xFF;
330 *current++ = (m_hash[i] >> 8) & 0xFF;
331 *current++ = m_hash[i] & 0xFF;
332
333 // restore old hash
334 m_hash[i] = oldHash[i];
335 }
336}
337
338
340std::string SHA1::operator()(const void* data, size_t numBytes)
341{
342 reset();
343 add(data, numBytes);
344 return getHash();
345}
346
347
349std::string SHA1::operator()(const std::string& text)
350{
351 reset();
352 add(text.c_str(), text.size());
353 return getHash();
354}
355
356} // namespace hash
std::string getHashRaw()
return latest hash as raw characters
SHA1()
same as reset()
void reset()
restart
void add(const void *data, size_t numBytes)
add arbitrary number of bytes
std::string operator()(const void *data, size_t numBytes)
compute SHA1 of a memory block
@ HashBytes
Definition sha1.h:48
@ BlockSize
Definition sha1.h:48
std::string getHash()
return latest hash as 40 hex characters
Usage: std::string msg = "The quick brown fox jumps over the lazy dog"; std::string key = "key"; std:...
Definition crc32.h:28
Third-party (vendored): SHA-1 hash from Stephan Brumme's portable hashing library (create....