diff options
Diffstat (limited to 'src/lib/util/hashing.cpp')
-rw-r--r-- | src/lib/util/hashing.cpp | 183 |
1 files changed, 164 insertions, 19 deletions
diff --git a/src/lib/util/hashing.cpp b/src/lib/util/hashing.cpp index a5946f1ace8..ebfc84fd33f 100644 --- a/src/lib/util/hashing.cpp +++ b/src/lib/util/hashing.cpp @@ -1,5 +1,5 @@ // license:BSD-3-Clause -// copyright-holders:Aaron Giles +// copyright-holders:Aaron Giles, Vas Crabb /*************************************************************************** hashing.c @@ -9,43 +9,114 @@ ***************************************************************************/ #include "hashing.h" + #include <zlib.h> + +#include <algorithm> #include <iomanip> #include <sstream> namespace util { -//************************************************************************** -// CONSTANTS -//************************************************************************** - -const crc16_t crc16_t::null = { 0 }; -const crc32_t crc32_t::null = { 0 }; -const md5_t md5_t::null = { { 0 } }; -const sha1_t sha1_t::null = { { 0 } }; - - //************************************************************************** // INLINE FUNCTIONS //************************************************************************** +namespace { + //------------------------------------------------- // char_to_hex - return the hex value of a // character //------------------------------------------------- -inline int char_to_hex(char c) +constexpr int char_to_hex(char c) +{ + return + (c >= '0' && c <= '9') ? (c - '0') : + (c >= 'a' && c <= 'f') ? (10 + c - 'a') : + (c >= 'A' && c <= 'F') ? (10 + c - 'A') : + -1; +} + + +constexpr uint32_t sha1_rol(uint32_t x, unsigned n) +{ + return (x << n) | (x >> (32 - n)); +} + +uint32_t sha1_b(uint32_t *data, unsigned i) +{ + uint32_t r = data[(i + 13) & 15U]; + r ^= data[(i + 8) & 15U]; + r ^= data[(i + 2) & 15U]; + r ^= data[i & 15U]; + r = sha1_rol(r, 1); + data[i & 15U] = r; + return r; +} + +inline void sha1_r0(const uint32_t *data, std::array<uint32_t, 5> &d, unsigned i) +{ + d[i % 5] = d[i % 5] + ((d[(i + 3) % 5] & (d[(i + 2) % 5] ^ d[(i + 1) % 5])) ^ d[(i + 1) % 5]) + data[i] + 0x5a827999U + sha1_rol(d[(i + 4) % 5], 5); + d[(i + 3) % 5] = sha1_rol(d[(i + 3) % 5], 30); +} + +inline void sha1_r1(uint32_t *data, std::array<uint32_t, 5> &d, unsigned i) +{ + d[i % 5] = d[i % 5] + ((d[(i + 3) % 5] & (d[(i + 2) % 5] ^ d[(i + 1) % 5])) ^ d[(i + 1) % 5])+ sha1_b(data, i) + 0x5a827999U + sha1_rol(d[(i + 4) % 5], 5); + d[(i + 3) % 5] = sha1_rol(d[(i + 3) % 5], 30); +} + +inline void sha1_r2(uint32_t *data, std::array<uint32_t, 5> &d, unsigned i) +{ + d[i % 5] = d[i % 5] + (d[(i + 3) % 5] ^ d[(i + 2) % 5] ^ d[(i + 1) % 5]) + sha1_b(data, i) + 0x6ed9eba1U + sha1_rol(d[(i + 4) % 5], 5); + d[(i + 3) % 5] = sha1_rol(d[(i + 3) % 5], 30); +} + +inline void sha1_r3(uint32_t *data, std::array<uint32_t, 5> &d, unsigned i) +{ + d[i % 5] = d[i % 5] + (((d[(i + 3) % 5] | d[(i + 2) % 5]) & d[(i + 1) % 5]) | (d[(i + 3) % 5] & d[(i + 2) % 5])) + sha1_b(data, i) + 0x8f1bbcdcU + sha1_rol(d[(i + 4) % 5], 5); + d[(i + 3) % 5] = sha1_rol(d[(i + 3) % 5], 30); +} + +inline void sha1_r4(uint32_t *data, std::array<uint32_t, 5> &d, unsigned i) +{ + d[i % 5] = d[i % 5] + (d[(i + 3) % 5] ^ d[(i + 2) % 5] ^ d[(i + 1) % 5]) + sha1_b(data, i) + 0xca62c1d6U + sha1_rol(d[(i + 4) % 5], 5); + d[(i + 3) % 5] = sha1_rol(d[(i + 3) % 5], 30); +} + +inline void sha1_process(std::array<uint32_t, 5> &st, uint32_t *data) { - if (c >= '0' && c <= '9') - return c - '0'; - if (c >= 'a' && c <= 'f') - return 10 + c - 'a'; - if (c >= 'A' && c <= 'F') - return 10 + c - 'A'; - return -1; + std::array<uint32_t, 5> d = st; + unsigned i = 0U; + while (i < 16U) + sha1_r0(data, d, i++); + while (i < 20U) + sha1_r1(data, d, i++); + while (i < 40U) + sha1_r2(data, d, i++); + while (i < 60U) + sha1_r3(data, d, i++); + while (i < 80U) + sha1_r4(data, d, i++); + for (i = 0U; i < 5U; i++) + st[i] += d[i]; } +} // anonymous namespace + + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +const crc16_t crc16_t::null = { 0 }; +const crc32_t crc32_t::null = { 0 }; +const md5_t md5_t::null = { { 0 } }; +const sha1_t sha1_t::null = { { 0 } }; + //************************************************************************** @@ -93,6 +164,80 @@ std::string sha1_t::as_string() const } +//------------------------------------------------- +// reset - prepare to digest a block of data +//------------------------------------------------- + +void sha1_creator::reset() +{ + m_cnt = 0U; + m_st[0] = 0xc3d2e1f0U; + m_st[1] = 0x10325476U; + m_st[2] = 0x98badcfeU; + m_st[3] = 0xefcdab89U; + m_st[4] = 0x67452301U; +} + + +//------------------------------------------------- +// append - digest a block of data +//------------------------------------------------- + +void sha1_creator::append(const void *data, uint32_t length) +{ +#ifdef LSB_FIRST + constexpr unsigned swizzle = 3U; +#else + constexpr unsigned swizzle = 0U; +#endif + uint32_t residual = (uint32_t(m_cnt) >> 3) & 63U; + m_cnt += uint64_t(length) << 3; + uint32_t offset = 0U; + if (length >= (64U - residual)) + { + if (residual) + { + for (offset = 0U; (offset + residual) < 64U; offset++) + reinterpret_cast<uint8_t *>(m_buf)[(offset + residual) ^ swizzle] = reinterpret_cast<const uint8_t *>(data)[offset]; + sha1_process(m_st, m_buf); + } + while ((length - offset) >= 64U) + { + for (residual = 0U; residual < 64U; residual++, offset++) + reinterpret_cast<uint8_t *>(m_buf)[residual ^ swizzle] = reinterpret_cast<const uint8_t *>(data)[offset]; + sha1_process(m_st, m_buf); + } + residual = 0U; + } + for ( ; offset < length; residual++, offset++) + reinterpret_cast<uint8_t *>(m_buf)[residual ^ swizzle] = reinterpret_cast<const uint8_t *>(data)[offset]; +} + + +//------------------------------------------------- +// finish - compute final hash +//------------------------------------------------- + +sha1_t sha1_creator::finish() +{ + const unsigned padlen = 64U - (63U & ((unsigned(m_cnt) >> 3) + 8U)); + uint8_t padbuf[64]; + padbuf[0] = 0x80; + for (unsigned i = 1U; i < padlen; i++) + padbuf[i] = 0x00; + uint8_t lenbuf[8]; + for (unsigned i = 0U; i < 8U; i++) + lenbuf[i] = uint8_t(m_cnt >> ((7U - i) << 3)); + append(padbuf, padlen); + append(lenbuf, sizeof(lenbuf)); + sha1_t result; + for (unsigned i = 0U; i < 20U; i++) + result.m_raw[i] = uint8_t(m_st[4U - (i >> 2)] >> ((3U - (i & 3)) << 3)); + return result; +} + + + //************************************************************************** // MD-5 HELPERS //************************************************************************** |