-
Notifications
You must be signed in to change notification settings - Fork 725
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
281 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com> | ||
// SPDX-License-Identifier: CC-BY-NC-ND-4.0 | ||
|
||
#include "common/sha256_digest.h" | ||
|
||
#include <gtest/gtest.h> | ||
|
||
TEST(SHA256Digest, Simple) | ||
{ | ||
// https://github.com/B-Con/crypto-algorithms/blob/master/sha256_test.c | ||
|
||
static constexpr const char text1[] = "abc"; | ||
static constexpr const char text2[] = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; | ||
static constexpr const char text3[] = "aaaaaaaaaa"; | ||
|
||
static constexpr SHA256Digest::Digest hash1 = {{0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, | ||
0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, | ||
0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad}}; | ||
static constexpr SHA256Digest::Digest hash2 = {{0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26, | ||
0x93, 0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, | ||
0x21, 0x67, 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1}}; | ||
static constexpr SHA256Digest::Digest hash3 = {{0xcd, 0xc7, 0x6e, 0x5c, 0x99, 0x14, 0xfb, 0x92, 0x81, 0xa1, 0xc7, | ||
0xe2, 0x84, 0xd7, 0x3e, 0x67, 0xf1, 0x80, 0x9a, 0x48, 0xa4, 0x97, | ||
0x20, 0x0e, 0x04, 0x6d, 0x39, 0xcc, 0xc7, 0x11, 0x2c, 0xd0}}; | ||
|
||
ASSERT_EQ(SHA256Digest::GetDigest(text1, std::size(text1) - 1), hash1); | ||
ASSERT_EQ(SHA256Digest::GetDigest(text2, std::size(text2) - 1), hash2); | ||
|
||
SHA256Digest ldigest; | ||
for (u32 i = 0; i < 100000; i++) | ||
ldigest.Update(text3, std::size(text3) - 1); | ||
|
||
ASSERT_EQ(ldigest.Final(), hash3); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,193 @@ | ||
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com> | ||
// SPDX-License-Identifier: CC-BY-NC-ND-4.0 | ||
|
||
// Based on https://github.com/B-Con/crypto-algorithms/blob/master/sha256.c | ||
// By Brad Conte (brad AT bradconte.com) | ||
|
||
#include "sha256_digest.h" | ||
#include "string_util.h" | ||
|
||
#include <cstring> | ||
|
||
SHA256Digest::SHA256Digest() | ||
{ | ||
Reset(); | ||
} | ||
|
||
std::string SHA256Digest::DigestToString(const std::span<const u8, DIGEST_SIZE> digest) | ||
{ | ||
return StringUtil::EncodeHex<u8>(digest); | ||
} | ||
|
||
SHA256Digest::Digest SHA256Digest::GetDigest(const void* data, size_t len) | ||
{ | ||
Digest ret; | ||
SHA256Digest digest; | ||
digest.Update(data, len); | ||
digest.Final(ret); | ||
return ret; | ||
} | ||
|
||
SHA256Digest::Digest SHA256Digest::GetDigest(std::span<const u8> data) | ||
{ | ||
Digest ret; | ||
SHA256Digest digest; | ||
digest.Update(data); | ||
digest.Final(ret); | ||
return ret; | ||
} | ||
|
||
#define ROTLEFT(a, b) (((a) << (b)) | ((a) >> (32 - (b)))) | ||
#define ROTRIGHT(a, b) (((a) >> (b)) | ((a) << (32 - (b)))) | ||
|
||
#define CH(x, y, z) (((x) & (y)) ^ (~(x) & (z))) | ||
#define MAJ(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) | ||
#define EP0(x) (ROTRIGHT(x, 2) ^ ROTRIGHT(x, 13) ^ ROTRIGHT(x, 22)) | ||
#define EP1(x) (ROTRIGHT(x, 6) ^ ROTRIGHT(x, 11) ^ ROTRIGHT(x, 25)) | ||
#define SIG0(x) (ROTRIGHT(x, 7) ^ ROTRIGHT(x, 18) ^ ((x) >> 3)) | ||
#define SIG1(x) (ROTRIGHT(x, 17) ^ ROTRIGHT(x, 19) ^ ((x) >> 10)) | ||
|
||
static constexpr std::array<u32, 64> k = { | ||
{0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, | ||
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, | ||
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, | ||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, | ||
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, | ||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, | ||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, | ||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}}; | ||
|
||
void SHA256Digest::TransformBlock() | ||
{ | ||
std::array<u32, 64> m; | ||
|
||
size_t i = 0; | ||
for (size_t j = 0; i < 16; ++i, j += 4) | ||
m[i] = (m_block[j] << 24) | (m_block[j + 1] << 16) | (m_block[j + 2] << 8) | (m_block[j + 3]); | ||
for (; i < 64; ++i) | ||
m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16]; | ||
|
||
u32 a = m_state[0]; | ||
u32 b = m_state[1]; | ||
u32 c = m_state[2]; | ||
u32 d = m_state[3]; | ||
u32 e = m_state[4]; | ||
u32 f = m_state[5]; | ||
u32 g = m_state[6]; | ||
u32 h = m_state[7]; | ||
|
||
for (i = 0; i < 64; ++i) | ||
{ | ||
u32 t1 = h + EP1(e) + CH(e, f, g) + k[i] + m[i]; | ||
u32 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; | ||
} | ||
|
||
m_state[0] += a; | ||
m_state[1] += b; | ||
m_state[2] += c; | ||
m_state[3] += d; | ||
m_state[4] += e; | ||
m_state[5] += f; | ||
m_state[6] += g; | ||
m_state[7] += h; | ||
} | ||
|
||
void SHA256Digest::Reset() | ||
{ | ||
m_block_length = 0; | ||
m_bit_length = 0; | ||
m_state[0] = 0x6a09e667; | ||
m_state[1] = 0xbb67ae85; | ||
m_state[2] = 0x3c6ef372; | ||
m_state[3] = 0xa54ff53a; | ||
m_state[4] = 0x510e527f; | ||
m_state[5] = 0x9b05688c; | ||
m_state[6] = 0x1f83d9ab; | ||
m_state[7] = 0x5be0cd19; | ||
} | ||
|
||
void SHA256Digest::Update(std::span<const u8> data) | ||
{ | ||
const size_t len = data.size(); | ||
for (size_t pos = 0; pos < len;) | ||
{ | ||
const u32 copy_len = static_cast<u32>(std::min<size_t>(len - pos, BLOCK_SIZE - m_block_length)); | ||
std::memcpy(&m_block[m_block_length], &data[pos], copy_len); | ||
m_block_length += copy_len; | ||
pos += copy_len; | ||
|
||
if (m_block_length == BLOCK_SIZE) | ||
{ | ||
TransformBlock(); | ||
m_bit_length += 512; | ||
m_block_length = 0; | ||
} | ||
} | ||
} | ||
|
||
void SHA256Digest::Update(const void* data, size_t len) | ||
{ | ||
Update(std::span<const u8>(static_cast<const u8*>(data), len)); | ||
} | ||
|
||
void SHA256Digest::Final(std::span<u8, DIGEST_SIZE> digest) | ||
{ | ||
// Pad whatever data is left in the buffer. | ||
if (m_block_length < 56) | ||
{ | ||
size_t i = m_block_length; | ||
m_block[i++] = 0x80; | ||
while (i < 56) | ||
m_block[i++] = 0x00; | ||
} | ||
else | ||
{ | ||
size_t i = m_block_length; | ||
m_block[i++] = 0x80; | ||
while (i < 64) | ||
m_block[i++] = 0x00; | ||
TransformBlock(); | ||
m_block = {}; | ||
} | ||
|
||
// Append to the padding the total message's length in bits and transform. | ||
m_bit_length += m_block_length * 8; | ||
m_block[63] = static_cast<u8>(m_bit_length); | ||
m_block[62] = static_cast<u8>(m_bit_length >> 8); | ||
m_block[61] = static_cast<u8>(m_bit_length >> 16); | ||
m_block[60] = static_cast<u8>(m_bit_length >> 24); | ||
m_block[59] = static_cast<u8>(m_bit_length >> 32); | ||
m_block[58] = static_cast<u8>(m_bit_length >> 40); | ||
m_block[57] = static_cast<u8>(m_bit_length >> 48); | ||
m_block[56] = static_cast<u8>(m_bit_length >> 56); | ||
TransformBlock(); | ||
|
||
// Since this implementation uses little endian byte ordering and SHA uses big endian, | ||
// reverse all the bytes when copying the final state to the output hash. | ||
for (size_t i = 0; i < 4; ++i) | ||
{ | ||
digest[i] = (m_state[0] >> (24 - i * 8)) & 0x000000ff; | ||
digest[i + 4] = (m_state[1] >> (24 - i * 8)) & 0x000000ff; | ||
digest[i + 8] = (m_state[2] >> (24 - i * 8)) & 0x000000ff; | ||
digest[i + 12] = (m_state[3] >> (24 - i * 8)) & 0x000000ff; | ||
digest[i + 16] = (m_state[4] >> (24 - i * 8)) & 0x000000ff; | ||
digest[i + 20] = (m_state[5] >> (24 - i * 8)) & 0x000000ff; | ||
digest[i + 24] = (m_state[6] >> (24 - i * 8)) & 0x000000ff; | ||
digest[i + 28] = (m_state[7] >> (24 - i * 8)) & 0x000000ff; | ||
} | ||
} | ||
|
||
SHA256Digest::Digest SHA256Digest::Final() | ||
{ | ||
Digest ret; | ||
Final(ret); | ||
return ret; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com> | ||
// SPDX-License-Identifier: CC-BY-NC-ND-4.0 | ||
|
||
#pragma once | ||
|
||
#include "types.h" | ||
|
||
#include <array> | ||
#include <span> | ||
#include <string> | ||
|
||
class SHA256Digest | ||
{ | ||
public: | ||
enum : u32 | ||
{ | ||
DIGEST_SIZE = 32, | ||
BLOCK_SIZE = 64, | ||
}; | ||
|
||
using Digest = std::array<u8, DIGEST_SIZE>; | ||
|
||
SHA256Digest(); | ||
|
||
void Update(const void* data, size_t len); | ||
void Update(std::span<const u8> data); | ||
void Final(std::span<u8, DIGEST_SIZE> digest); | ||
Digest Final(); | ||
void Reset(); | ||
|
||
static std::string DigestToString(const std::span<const u8, DIGEST_SIZE> digest); | ||
|
||
static Digest GetDigest(const void* data, size_t len); | ||
static Digest GetDigest(std::span<const u8> data); | ||
|
||
private: | ||
void TransformBlock(); | ||
|
||
u64 m_bit_length = 0; | ||
std::array<u32, 8> m_state = {}; | ||
u32 m_block_length = 0; | ||
std::array<u8, BLOCK_SIZE> m_block = {}; | ||
}; |