210 lines
5.4 KiB
C++
210 lines
5.4 KiB
C++
#include "ehs/SHA256.h"
|
||
|
||
#include "ehs/Util.h"
|
||
|
||
namespace ehs
|
||
{
|
||
UInt_32 SHA256::ROTR(const UInt_32 x, const UInt_32 n)
|
||
{
|
||
return (x >> n) | (x << (32 - n));
|
||
}
|
||
|
||
UInt_32 SHA256::CH(const UInt_32 x, const UInt_32 y, const UInt_32 z)
|
||
{
|
||
return (x & y) ^ (~x & z);
|
||
}
|
||
|
||
UInt_32 SHA256::MAJ(const UInt_32 x, const UInt_32 y, const UInt_32 z)
|
||
{
|
||
return (x & y) ^ (x & z) ^ (y & z);
|
||
}
|
||
|
||
UInt_32 SHA256::EP0(const UInt_32 x)
|
||
{
|
||
return ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22);
|
||
}
|
||
|
||
UInt_32 SHA256::EP1(const UInt_32 x)
|
||
{
|
||
return ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25);
|
||
}
|
||
|
||
UInt_32 SHA256::SIG0(const UInt_32 x)
|
||
{
|
||
return ROTR(x, 7) ^ ROTR(x, 18) ^ (x >> 3);
|
||
}
|
||
|
||
UInt_32 SHA256::SIG1(const UInt_32 x)
|
||
{
|
||
return ROTR(x,17) ^ ROTR(x, 19) ^ (x >> 10);
|
||
}
|
||
|
||
SHA256::SHA256()
|
||
: state{0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19},
|
||
bitLen(0), data{}, dataLen(0)
|
||
{
|
||
}
|
||
|
||
SHA256::SHA256(SHA256&& other) noexcept
|
||
: state{}, bitLen(0), data{}, dataLen(0)
|
||
{
|
||
Util::Copy(state, other.state, sizeof(state) / sizeof(UInt_32));
|
||
bitLen = other.bitLen;
|
||
Util::Copy(data, other.data, sizeof(data));
|
||
dataLen = other.dataLen;
|
||
|
||
Util::Zero(other.state, sizeof(state) / sizeof(UInt_32));
|
||
other.bitLen = 0;
|
||
Util::Zero(other.data, sizeof(data));
|
||
other.dataLen = 0;
|
||
}
|
||
|
||
SHA256::SHA256(const SHA256& other)
|
||
: state{}, bitLen(0), data{}, dataLen(0)
|
||
{
|
||
Util::Copy(state, other.state, sizeof(state) / sizeof(UInt_32));
|
||
bitLen = other.bitLen;
|
||
Util::Copy(data, other.data, sizeof(data));
|
||
dataLen = other.dataLen;
|
||
}
|
||
|
||
SHA256& SHA256::operator=(SHA256&& other) noexcept
|
||
{
|
||
if (this == &other)
|
||
return *this;
|
||
|
||
Util::Copy(state, other.state, sizeof(state) / sizeof(UInt_32));
|
||
bitLen = other.bitLen;
|
||
Util::Copy(data, other.data, sizeof(data));
|
||
dataLen = other.dataLen;
|
||
|
||
Util::Zero(other.state, sizeof(state) / sizeof(UInt_32));
|
||
other.bitLen = 0;
|
||
Util::Zero(other.data, sizeof(data));
|
||
other.dataLen = 0;
|
||
|
||
return *this;
|
||
}
|
||
|
||
SHA256& SHA256::operator=(const SHA256& other)
|
||
{
|
||
if (this == &other)
|
||
return *this;
|
||
|
||
Util::Copy(state, other.state, sizeof(state) / sizeof(UInt_32));
|
||
bitLen = other.bitLen;
|
||
Util::Copy(data, other.data, sizeof(data));
|
||
dataLen = other.dataLen;
|
||
|
||
return *this;
|
||
}
|
||
|
||
void SHA256::Update(const Byte* data, const UInt_64 len)
|
||
{
|
||
for(UInt_64 i = 0; i < len; ++i)
|
||
{
|
||
this->data[dataLen++] = data[i];
|
||
|
||
if(dataLen == 64)
|
||
{
|
||
Transform(this->data);
|
||
bitLen += 512;
|
||
dataLen = 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
void SHA256::Final(Byte hash[32])
|
||
{
|
||
UInt_32 i = dataLen;
|
||
|
||
/* Pad */
|
||
data[i++] = 0x80;
|
||
if(i > 56)
|
||
{
|
||
while(i < 64)
|
||
data[i++] = 0x00;
|
||
|
||
Transform(data);
|
||
|
||
i = 0;
|
||
}
|
||
|
||
while(i < 56)
|
||
data[i++] = 0x00;
|
||
|
||
/* Length in bits */
|
||
bitLen += dataLen * 8ULL;
|
||
data[63] = bitLen;
|
||
data[62] = bitLen >> 8;
|
||
data[61] = bitLen >> 16;
|
||
data[60] = bitLen >> 24;
|
||
data[59] = bitLen >> 32;
|
||
data[58] = bitLen >> 40;
|
||
data[57] = bitLen >> 48;
|
||
data[56] = bitLen >> 56;
|
||
Transform(data);
|
||
|
||
/* big‑endian output */
|
||
for(i = 0; i < 4; ++i) {
|
||
hash[i] = (state[0] >> (24 - i * 8)) & 0xff;
|
||
hash[i + 4] = (state[1] >> (24 - i * 8)) & 0xff;
|
||
hash[i + 8] = (state[2] >> (24 - i * 8)) & 0xff;
|
||
hash[i + 12] = (state[3] >> (24 - i * 8)) & 0xff;
|
||
hash[i + 16] = (state[4] >> (24 - i * 8)) & 0xff;
|
||
hash[i + 20] = (state[5] >> (24 - i * 8)) & 0xff;
|
||
hash[i + 24] = (state[6] >> (24 - i * 8)) & 0xff;
|
||
hash[i + 28] = (state[7] >> (24 - i * 8)) & 0xff;
|
||
}
|
||
}
|
||
|
||
void SHA256::Hash(const Byte* data, const UInt_64 len, Byte hash[32])
|
||
{
|
||
Update(data, len);
|
||
Final(hash);
|
||
}
|
||
|
||
void SHA256::Transform(const Byte data[64])
|
||
{
|
||
UInt_32 m[64];
|
||
UInt_32 a = state[0];
|
||
UInt_32 b = state[1];
|
||
UInt_32 c = state[2];
|
||
UInt_32 d = state[3];
|
||
UInt_32 e = state[4];
|
||
UInt_32 f = state[5];
|
||
UInt_32 g = state[6];
|
||
UInt_32 h = state[7];
|
||
UInt_32 i, t1, t2;
|
||
|
||
for (i = 0; i < 16; ++i)
|
||
m[i] = (UInt_32)data[i * 4] << 24 | (UInt_32)data[i * 4 + 1] << 16 | (UInt_32)data[i * 4 + 2] << 8 | (UInt_32)data[i * 4 + 3];
|
||
|
||
for (; i < 64; ++i)
|
||
m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16];
|
||
|
||
for(i = 0; i < 64; ++i)
|
||
{
|
||
t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i];
|
||
t2 = EP0(a) + MAJ(a,b,c);
|
||
h = g;
|
||
g = f;
|
||
f = e;
|
||
e = d + t1;
|
||
d = c;
|
||
c = b;
|
||
b = a;
|
||
a = t1 + t2;
|
||
}
|
||
|
||
state[0] += a;
|
||
state[1] += b;
|
||
state[2] += c;
|
||
state[3] += d;
|
||
state[4] += e;
|
||
state[5] += f;
|
||
state[6] += g;
|
||
state[7] += h;
|
||
}
|
||
}
|