summaryrefslogtreecommitdiff
path: root/ThirdParty/hash-library/sha1.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ThirdParty/hash-library/sha1.cpp')
-rw-r--r--ThirdParty/hash-library/sha1.cpp326
1 files changed, 326 insertions, 0 deletions
diff --git a/ThirdParty/hash-library/sha1.cpp b/ThirdParty/hash-library/sha1.cpp
new file mode 100644
index 0000000..8331e92
--- /dev/null
+++ b/ThirdParty/hash-library/sha1.cpp
@@ -0,0 +1,326 @@
+// //////////////////////////////////////////////////////////
+// sha1.cpp
+// Copyright (c) 2014,2015 Stephan Brumme. All rights reserved.
+// see http://create.stephan-brumme.com/disclaimer.html
+//
+
+#include "sha1.h"
+
+// big endian architectures need #define __BYTE_ORDER __BIG_ENDIAN
+#ifndef _MSC_VER
+#include <endian.h>
+#endif
+
+
+/// same as reset()
+SHA1::SHA1()
+{
+ reset();
+}
+
+
+/// restart
+void SHA1::reset()
+{
+ m_numBytes = 0;
+ m_bufferSize = 0;
+
+ // according to RFC 1321
+ m_hash[0] = 0x67452301;
+ m_hash[1] = 0xefcdab89;
+ m_hash[2] = 0x98badcfe;
+ m_hash[3] = 0x10325476;
+ m_hash[4] = 0xc3d2e1f0;
+}
+
+
+namespace
+{
+ // mix functions for processBlock()
+ inline uint32_t f1(uint32_t b, uint32_t c, uint32_t d)
+ {
+ return d ^ (b & (c ^ d)); // original: f = (b & c) | ((~b) & d);
+ }
+
+ inline uint32_t f2(uint32_t b, uint32_t c, uint32_t d)
+ {
+ return b ^ c ^ d;
+ }
+
+ inline uint32_t f3(uint32_t b, uint32_t c, uint32_t d)
+ {
+ return (b & c) | (b & d) | (c & d);
+ }
+
+ inline uint32_t rotate(uint32_t a, uint32_t c)
+ {
+ return (a << c) | (a >> (32 - c));
+ }
+
+ inline uint32_t swap(uint32_t x)
+ {
+#if defined(__GNUC__) || defined(__clang__)
+ return __builtin_bswap32(x);
+#endif
+#ifdef MSC_VER
+ return _byteswap_ulong(x);
+#endif
+
+ return (x >> 24) |
+ ((x >> 8) & 0x0000FF00) |
+ ((x << 8) & 0x00FF0000) |
+ (x << 24);
+ }
+}
+
+
+/// process 64 bytes
+void SHA1::processBlock(const void* data)
+{
+ // get last hash
+ uint32_t a = m_hash[0];
+ uint32_t b = m_hash[1];
+ uint32_t c = m_hash[2];
+ uint32_t d = m_hash[3];
+ uint32_t e = m_hash[4];
+
+ // data represented as 16x 32-bit words
+ const uint32_t* input = (uint32_t*) data;
+ // convert to big endian
+ uint32_t words[80];
+ for (int i = 0; i < 16; i++)
+#if defined(__BYTE_ORDER) && (__BYTE_ORDER != 0) && (__BYTE_ORDER == __BIG_ENDIAN)
+ words[i] = input[i];
+#else
+ words[i] = swap(input[i]);
+#endif
+
+ // extend to 80 words
+ for (int i = 16; i < 80; i++)
+ words[i] = rotate(words[i-3] ^ words[i-8] ^ words[i-14] ^ words[i-16], 1);
+
+ // first round
+ for (int i = 0; i < 4; i++)
+ {
+ int offset = 5*i;
+ e += rotate(a,5) + f1(b,c,d) + words[offset ] + 0x5a827999; b = rotate(b,30);
+ d += rotate(e,5) + f1(a,b,c) + words[offset+1] + 0x5a827999; a = rotate(a,30);
+ c += rotate(d,5) + f1(e,a,b) + words[offset+2] + 0x5a827999; e = rotate(e,30);
+ b += rotate(c,5) + f1(d,e,a) + words[offset+3] + 0x5a827999; d = rotate(d,30);
+ a += rotate(b,5) + f1(c,d,e) + words[offset+4] + 0x5a827999; c = rotate(c,30);
+ }
+
+ // second round
+ for (int i = 4; i < 8; i++)
+ {
+ int offset = 5*i;
+ e += rotate(a,5) + f2(b,c,d) + words[offset ] + 0x6ed9eba1; b = rotate(b,30);
+ d += rotate(e,5) + f2(a,b,c) + words[offset+1] + 0x6ed9eba1; a = rotate(a,30);
+ c += rotate(d,5) + f2(e,a,b) + words[offset+2] + 0x6ed9eba1; e = rotate(e,30);
+ b += rotate(c,5) + f2(d,e,a) + words[offset+3] + 0x6ed9eba1; d = rotate(d,30);
+ a += rotate(b,5) + f2(c,d,e) + words[offset+4] + 0x6ed9eba1; c = rotate(c,30);
+ }
+
+ // third round
+ for (int i = 8; i < 12; i++)
+ {
+ int offset = 5*i;
+ e += rotate(a,5) + f3(b,c,d) + words[offset ] + 0x8f1bbcdc; b = rotate(b,30);
+ d += rotate(e,5) + f3(a,b,c) + words[offset+1] + 0x8f1bbcdc; a = rotate(a,30);
+ c += rotate(d,5) + f3(e,a,b) + words[offset+2] + 0x8f1bbcdc; e = rotate(e,30);
+ b += rotate(c,5) + f3(d,e,a) + words[offset+3] + 0x8f1bbcdc; d = rotate(d,30);
+ a += rotate(b,5) + f3(c,d,e) + words[offset+4] + 0x8f1bbcdc; c = rotate(c,30);
+ }
+
+ // fourth round
+ for (int i = 12; i < 16; i++)
+ {
+ int offset = 5*i;
+ e += rotate(a,5) + f2(b,c,d) + words[offset ] + 0xca62c1d6; b = rotate(b,30);
+ d += rotate(e,5) + f2(a,b,c) + words[offset+1] + 0xca62c1d6; a = rotate(a,30);
+ c += rotate(d,5) + f2(e,a,b) + words[offset+2] + 0xca62c1d6; e = rotate(e,30);
+ b += rotate(c,5) + f2(d,e,a) + words[offset+3] + 0xca62c1d6; d = rotate(d,30);
+ a += rotate(b,5) + f2(c,d,e) + words[offset+4] + 0xca62c1d6; c = rotate(c,30);
+ }
+
+ // update hash
+ m_hash[0] += a;
+ m_hash[1] += b;
+ m_hash[2] += c;
+ m_hash[3] += d;
+ m_hash[4] += e;
+}
+
+
+/// add arbitrary number of bytes
+void SHA1::add(const void* data, size_t numBytes)
+{
+ const uint8_t* current = (const uint8_t*) data;
+
+ if (m_bufferSize > 0)
+ {
+ while (numBytes > 0 && m_bufferSize < BlockSize)
+ {
+ m_buffer[m_bufferSize++] = *current++;
+ numBytes--;
+ }
+ }
+
+ // full buffer
+ if (m_bufferSize == BlockSize)
+ {
+ processBlock((void*)m_buffer);
+ m_numBytes += BlockSize;
+ m_bufferSize = 0;
+ }
+
+ // no more data ?
+ if (numBytes == 0)
+ return;
+
+ // process full blocks
+ while (numBytes >= BlockSize)
+ {
+ processBlock(current);
+ current += BlockSize;
+ m_numBytes += BlockSize;
+ numBytes -= BlockSize;
+ }
+
+ // keep remaining bytes in buffer
+ while (numBytes > 0)
+ {
+ m_buffer[m_bufferSize++] = *current++;
+ numBytes--;
+ }
+}
+
+
+/// process final block, less than 64 bytes
+void SHA1::processBuffer()
+{
+ // the input bytes are considered as bits strings, where the first bit is the most significant bit of the byte
+
+ // - append "1" bit to message
+ // - append "0" bits until message length in bit mod 512 is 448
+ // - append length as 64 bit integer
+
+ // number of bits
+ size_t paddedLength = m_bufferSize * 8;
+
+ // plus one bit set to 1 (always appended)
+ paddedLength++;
+
+ // number of bits must be (numBits % 512) = 448
+ size_t lower11Bits = paddedLength & 511;
+ if (lower11Bits <= 448)
+ paddedLength += 448 - lower11Bits;
+ else
+ paddedLength += 512 + 448 - lower11Bits;
+ // convert from bits to bytes
+ paddedLength /= 8;
+
+ // only needed if additional data flows over into a second block
+ unsigned char extra[BlockSize];
+
+ // append a "1" bit, 128 => binary 10000000
+ if (m_bufferSize < BlockSize)
+ m_buffer[m_bufferSize] = 128;
+ else
+ extra[0] = 128;
+
+ size_t i;
+ for (i = m_bufferSize + 1; i < BlockSize; i++)
+ m_buffer[i] = 0;
+ for (; i < paddedLength; i++)
+ extra[i - BlockSize] = 0;
+
+ // add message length in bits as 64 bit number
+ uint64_t msgBits = 8 * (m_numBytes + m_bufferSize);
+ // find right position
+ unsigned char* addLength;
+ if (paddedLength < BlockSize)
+ addLength = m_buffer + paddedLength;
+ else
+ addLength = extra + paddedLength - BlockSize;
+
+ // must be big endian
+ *addLength++ = (unsigned char)((msgBits >> 56) & 0xFF);
+ *addLength++ = (unsigned char)((msgBits >> 48) & 0xFF);
+ *addLength++ = (unsigned char)((msgBits >> 40) & 0xFF);
+ *addLength++ = (unsigned char)((msgBits >> 32) & 0xFF);
+ *addLength++ = (unsigned char)((msgBits >> 24) & 0xFF);
+ *addLength++ = (unsigned char)((msgBits >> 16) & 0xFF);
+ *addLength++ = (unsigned char)((msgBits >> 8) & 0xFF);
+ *addLength = (unsigned char)( msgBits & 0xFF);
+
+ // process blocks
+ processBlock(m_buffer);
+ // flowed over into a second block ?
+ if (paddedLength > BlockSize)
+ processBlock(extra);
+}
+
+
+/// return latest hash as 40 hex characters
+std::string SHA1::getHash()
+{
+ // compute hash (as raw bytes)
+ unsigned char rawHash[HashBytes];
+ getHash(rawHash);
+
+ // convert to hex string
+ std::string result;
+ result.reserve(2 * HashBytes);
+ for (int i = 0; i < HashBytes; i++)
+ {
+ static const char dec2hex[16+1] = "0123456789abcdef";
+ result += dec2hex[(rawHash[i] >> 4) & 15];
+ result += dec2hex[ rawHash[i] & 15];
+ }
+
+ return result;
+}
+
+
+/// return latest hash as bytes
+void SHA1::getHash(unsigned char buffer[SHA1::HashBytes])
+{
+ // save old hash if buffer is partially filled
+ uint32_t oldHash[HashValues];
+ for (int i = 0; i < HashValues; i++)
+ oldHash[i] = m_hash[i];
+
+ // process remaining bytes
+ processBuffer();
+
+ unsigned char* current = buffer;
+ for (int i = 0; i < HashValues; i++)
+ {
+ *current++ = (m_hash[i] >> 24) & 0xFF;
+ *current++ = (m_hash[i] >> 16) & 0xFF;
+ *current++ = (m_hash[i] >> 8) & 0xFF;
+ *current++ = m_hash[i] & 0xFF;
+
+ // restore old hash
+ m_hash[i] = oldHash[i];
+ }
+}
+
+
+/// compute SHA1 of a memory block
+std::string SHA1::operator()(const void* data, size_t numBytes)
+{
+ reset();
+ add(data, numBytes);
+ return getHash();
+}
+
+
+/// compute SHA1 of a string, excluding final zero
+std::string SHA1::operator()(const std::string& text)
+{
+ reset();
+ add(text.c_str(), text.size());
+ return getHash();
+}