#include <array>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <span>
#include <string>
#include <string_view>
#include "sha256.hpp"
namespace ddwaf {
namespace {
#define ROTATE(a, n) (((a) << (n)) | (((a) & 0xffffffff) >> (32 - (n))))
#define CHAR_TO_UINT32(c, l) \
{ \
(l) = ((static_cast<uint32_t>(*((c)++))) << 24); \
(l) |= ((static_cast<uint32_t>(*((c)++))) << 16); \
(l) |= ((static_cast<uint32_t>(*((c)++))) << 8); \
(l) |= ((static_cast<uint32_t>(*((c)++)))); \
}
#define UINT8_TO_HEX_CHAR(u) static_cast<char>((u) < 10 ? (u) + '0' : (u)-10 + 'a')
#define Sigma0(x) (ROTATE((x), 30) ^ ROTATE((x), 19) ^ ROTATE((x), 10))
#define Sigma1(x) (ROTATE((x), 26) ^ ROTATE((x), 21) ^ ROTATE((x), 7))
#define sigma0(x) (ROTATE((x), 25) ^ ROTATE((x), 14) ^ ((x) >> 3))
#define sigma1(x) (ROTATE((x), 15) ^ ROTATE((x), 13) ^ ((x) >> 10))
#define Ch(x, y, z) (((x) & (y)) ^ ((~(x)) & (z)))
#define Maj(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
#define ROUND_00_15(i, a, b, c, d, e, f, g, h) \
{ \
T1 += (h) + Sigma1(e) + Ch(e, f, g) + K256[i]; \
(h) = Sigma0(a) + Maj(a, b, c); \
(d) += T1; \
(h) += T1; \
}
#define ROUND_16_63(i, a, b, c, d, e, f, g, h, X) \
{ \
s0 = (X)[((i) + 1) & 0x0f]; \
s0 = sigma0(s0); \
s1 = (X)[((i) + 14) & 0x0f]; \
s1 = sigma1(s1); \
T1 = (X)[(i) & 0x0f] += s0 + s1 + (X)[((i) + 9) & 0x0f]; \
ROUND_00_15(i, a, b, c, d, e, f, g, h); \
}
constexpr std::array<uint32_t, 64> K256 = {0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL,
0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL,
0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL,
0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, 0x2de92c6fUL, 0x4a7484aaUL,
0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL,
0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL,
0x4d2c6dfcUL, 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL, 0xd6990624UL,
0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL,
0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL,
0x84c87814UL, 0x8cc70208UL, 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL};
}
sha256_hash &sha256_hash::operator<<(std::string_view str)
{
uint8_t *p;
uint32_t l;
size_t n;
if (str.empty()) {
return *this;
}
auto len = static_cast<uint32_t>(str.length());
const auto *data = reinterpret_cast<const uint8_t *>(str.data());
l = (length_low + ((len) << 3)) & 0xffffffffUL;
if (l < length_low) {
length_high++;
}
length_high += (len >> 29);
length_low = l;
n = num;
if (n != 0) {
p = buffer.data();
if (len >= block_size || len + n >= block_size) {
memcpy(p + n, data, block_size - n);
sha_block_data_order(p, 1);
n = block_size - n;
data += n;
len -= n;
num = 0;
memset(p, 0, block_size);
} else {
memcpy(p + n, data, len);
num += len;
return *this;
}
}
n = len / block_size;
if (n > 0) {
sha_block_data_order(data, n);
n *= block_size;
data += n;
len -= n;
}
if (len != 0) {
p = buffer.data();
num = len;
memcpy(p, data, len);
}
return *this;
}
template <std::size_t DigestLength>
std::string sha256_hash::digest()
requires(DigestLength % 8 == 0 && DigestLength <= 64)
{
std::string final_digest;
final_digest.resize(DigestLength);
write_digest(std::span<char, DigestLength>{final_digest});
return final_digest;
}
template std::string sha256_hash::digest<64>();
template std::string sha256_hash::digest<8>();
template <std::size_t DigestLength>
void sha256_hash::write_digest(std::span<char, DigestLength> output)
requires(DigestLength % 8 == 0 && DigestLength <= 64)
{
auto *p = buffer.data();
size_t n = num;
p[n] = 0x80;
n++;
if (n > (block_size - 8)) {
memset(p + n, 0, block_size - n);
n = 0;
sha_block_data_order(p, 1);
}
memset(p + n, 0, block_size - 8 - n);
p += block_size - 8;
*(p++) = static_cast<uint8_t>((length_high >> 24) & 0xff);
*(p++) = static_cast<uint8_t>((length_high >> 16) & 0xff);
*(p++) = static_cast<uint8_t>((length_high >> 8) & 0xff);
*(p++) = static_cast<uint8_t>(length_high & 0xff);
*(p++) = static_cast<uint8_t>((length_low >> 24) & 0xff);
*(p++) = static_cast<uint8_t>((length_low >> 16) & 0xff);
*(p++) = static_cast<uint8_t>((length_low >> 8) & 0xff);
*(p++) = static_cast<uint8_t>(length_low & 0xff);
p -= block_size;
sha_block_data_order(p, 1);
num = 0;
memset(p, 0, block_size);
for (unsigned int nn = 0; nn < DigestLength; nn += 8) {
const uint32_t ll = hash[nn >> 3];
output[nn + 0] = UINT8_TO_HEX_CHAR(static_cast<uint8_t>((ll >> 28) & 0x0f));
output[nn + 1] = UINT8_TO_HEX_CHAR(static_cast<uint8_t>((ll >> 24) & 0x0f));
output[nn + 2] = UINT8_TO_HEX_CHAR(static_cast<uint8_t>((ll >> 20) & 0x0f));
output[nn + 3] = UINT8_TO_HEX_CHAR(static_cast<uint8_t>((ll >> 16) & 0x0f));
output[nn + 4] = UINT8_TO_HEX_CHAR(static_cast<uint8_t>((ll >> 12) & 0x0f));
output[nn + 5] = UINT8_TO_HEX_CHAR(static_cast<uint8_t>((ll >> 8) & 0x0f));
output[nn + 6] = UINT8_TO_HEX_CHAR(static_cast<uint8_t>((ll >> 4) & 0x0f));
output[nn + 7] = UINT8_TO_HEX_CHAR(static_cast<uint8_t>(ll & 0x0f));
}
reset();
}
template void sha256_hash::write_digest<8>(std::span<char, 8> output);
template void sha256_hash::write_digest<64>(std::span<char, 64> output);
void sha256_hash::sha_block_data_order(const uint8_t *data, size_t len)
{
unsigned int a;
unsigned int b;
unsigned int c;
unsigned int d;
unsigned int e;
unsigned int f;
unsigned int g;
unsigned int h;
unsigned int s0;
unsigned int s1;
unsigned int T1;
std::array<uint32_t, 16> X{0};
int i;
while ((len--) != 0) {
a = hash[0];
b = hash[1];
c = hash[2];
d = hash[3];
e = hash[4];
f = hash[5];
g = hash[6];
h = hash[7];
uint32_t l;
CHAR_TO_UINT32(data, l);
T1 = X[0] = l;
ROUND_00_15(0, a, b, c, d, e, f, g, h);
CHAR_TO_UINT32(data, l);
T1 = X[1] = l;
ROUND_00_15(1, h, a, b, c, d, e, f, g);
CHAR_TO_UINT32(data, l);
T1 = X[2] = l;
ROUND_00_15(2, g, h, a, b, c, d, e, f);
CHAR_TO_UINT32(data, l);
T1 = X[3] = l;
ROUND_00_15(3, f, g, h, a, b, c, d, e);
CHAR_TO_UINT32(data, l);
T1 = X[4] = l;
ROUND_00_15(4, e, f, g, h, a, b, c, d);
CHAR_TO_UINT32(data, l);
T1 = X[5] = l;
ROUND_00_15(5, d, e, f, g, h, a, b, c);
CHAR_TO_UINT32(data, l);
T1 = X[6] = l;
ROUND_00_15(6, c, d, e, f, g, h, a, b);
CHAR_TO_UINT32(data, l);
T1 = X[7] = l;
ROUND_00_15(7, b, c, d, e, f, g, h, a);
CHAR_TO_UINT32(data, l);
T1 = X[8] = l;
ROUND_00_15(8, a, b, c, d, e, f, g, h);
CHAR_TO_UINT32(data, l);
T1 = X[9] = l;
ROUND_00_15(9, h, a, b, c, d, e, f, g);
CHAR_TO_UINT32(data, l);
T1 = X[10] = l;
ROUND_00_15(10, g, h, a, b, c, d, e, f);
CHAR_TO_UINT32(data, l);
T1 = X[11] = l;
ROUND_00_15(11, f, g, h, a, b, c, d, e);
CHAR_TO_UINT32(data, l);
T1 = X[12] = l;
ROUND_00_15(12, e, f, g, h, a, b, c, d);
CHAR_TO_UINT32(data, l);
T1 = X[13] = l;
ROUND_00_15(13, d, e, f, g, h, a, b, c);
CHAR_TO_UINT32(data, l);
T1 = X[14] = l;
ROUND_00_15(14, c, d, e, f, g, h, a, b);
CHAR_TO_UINT32(data, l);
T1 = X[15] = l;
ROUND_00_15(15, b, c, d, e, f, g, h, a);
for (i = 16; i < 64; i += 8) {
ROUND_16_63(i + 0, a, b, c, d, e, f, g, h, X);
ROUND_16_63(i + 1, h, a, b, c, d, e, f, g, X);
ROUND_16_63(i + 2, g, h, a, b, c, d, e, f, X);
ROUND_16_63(i + 3, f, g, h, a, b, c, d, e, X);
ROUND_16_63(i + 4, e, f, g, h, a, b, c, d, X);
ROUND_16_63(i + 5, d, e, f, g, h, a, b, c, X);
ROUND_16_63(i + 6, c, d, e, f, g, h, a, b, X);
ROUND_16_63(i + 7, b, c, d, e, f, g, h, a, X);
}
hash[0] += a;
hash[1] += b;
hash[2] += c;
hash[3] += d;
hash[4] += e;
hash[5] += f;
hash[6] += g;
hash[7] += h;
}
}
}