mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 06:47:35 +00:00
LibCrypto: Add the SHA-384 hash algorithm
This is a truncated version of SHA-512, so it was fairly trivial.
This commit is contained in:
parent
b985eb1613
commit
2c1916dd8d
4 changed files with 271 additions and 0 deletions
|
@ -20,6 +20,7 @@ enum class HashKind {
|
|||
None,
|
||||
SHA1,
|
||||
SHA256,
|
||||
SHA384,
|
||||
SHA512,
|
||||
MD5,
|
||||
};
|
||||
|
@ -40,6 +41,12 @@ struct MultiHashDigestVariant {
|
|||
{
|
||||
}
|
||||
|
||||
MultiHashDigestVariant(SHA384::DigestType digest)
|
||||
: sha384(digest)
|
||||
, kind(HashKind::SHA384)
|
||||
{
|
||||
}
|
||||
|
||||
MultiHashDigestVariant(SHA512::DigestType digest)
|
||||
: sha512(digest)
|
||||
, kind(HashKind::SHA512)
|
||||
|
@ -61,6 +68,8 @@ struct MultiHashDigestVariant {
|
|||
return sha1.value().immutable_data();
|
||||
case HashKind::SHA256:
|
||||
return sha256.value().immutable_data();
|
||||
case HashKind::SHA384:
|
||||
return sha384.value().immutable_data();
|
||||
case HashKind::SHA512:
|
||||
return sha512.value().immutable_data();
|
||||
default:
|
||||
|
@ -79,6 +88,8 @@ struct MultiHashDigestVariant {
|
|||
return sha1.value().data_length();
|
||||
case HashKind::SHA256:
|
||||
return sha256.value().data_length();
|
||||
case HashKind::SHA384:
|
||||
return sha384.value().data_length();
|
||||
case HashKind::SHA512:
|
||||
return sha512.value().data_length();
|
||||
default:
|
||||
|
@ -90,6 +101,7 @@ struct MultiHashDigestVariant {
|
|||
|
||||
Optional<SHA1::DigestType> sha1;
|
||||
Optional<SHA256::DigestType> sha256;
|
||||
Optional<SHA384::DigestType> sha384;
|
||||
Optional<SHA512::DigestType> sha512;
|
||||
Optional<MD5::DigestType> md5;
|
||||
HashKind kind { HashKind::None };
|
||||
|
@ -120,6 +132,7 @@ public:
|
|||
{
|
||||
m_sha1 = nullptr;
|
||||
m_sha256 = nullptr;
|
||||
m_sha384 = nullptr;
|
||||
m_sha512 = nullptr;
|
||||
m_md5 = nullptr;
|
||||
}
|
||||
|
@ -133,6 +146,8 @@ public:
|
|||
return m_sha1->digest_size();
|
||||
case HashKind::SHA256:
|
||||
return m_sha256->digest_size();
|
||||
case HashKind::SHA384:
|
||||
return m_sha384->digest_size();
|
||||
case HashKind::SHA512:
|
||||
return m_sha512->digest_size();
|
||||
default:
|
||||
|
@ -149,6 +164,8 @@ public:
|
|||
return m_sha1->block_size();
|
||||
case HashKind::SHA256:
|
||||
return m_sha256->block_size();
|
||||
case HashKind::SHA384:
|
||||
return m_sha384->block_size();
|
||||
case HashKind::SHA512:
|
||||
return m_sha512->block_size();
|
||||
default:
|
||||
|
@ -173,6 +190,9 @@ public:
|
|||
case HashKind::SHA256:
|
||||
m_sha256 = make<SHA256>();
|
||||
break;
|
||||
case HashKind::SHA384:
|
||||
m_sha384 = make<SHA384>();
|
||||
break;
|
||||
case HashKind::SHA512:
|
||||
m_sha512 = make<SHA512>();
|
||||
break;
|
||||
|
@ -201,6 +221,11 @@ public:
|
|||
m_sha256->update(m_pre_init_buffer);
|
||||
m_sha256->update(data, length);
|
||||
break;
|
||||
case HashKind::SHA384:
|
||||
if (size)
|
||||
m_sha384->update(m_pre_init_buffer);
|
||||
m_sha384->update(data, length);
|
||||
break;
|
||||
case HashKind::SHA512:
|
||||
if (size)
|
||||
m_sha512->update(m_pre_init_buffer);
|
||||
|
@ -224,6 +249,8 @@ public:
|
|||
return { m_sha1->peek() };
|
||||
case HashKind::SHA256:
|
||||
return { m_sha256->peek() };
|
||||
case HashKind::SHA384:
|
||||
return { m_sha384->peek() };
|
||||
case HashKind::SHA512:
|
||||
return { m_sha512->peek() };
|
||||
default:
|
||||
|
@ -253,6 +280,9 @@ public:
|
|||
case HashKind::SHA256:
|
||||
m_sha256->reset();
|
||||
break;
|
||||
case HashKind::SHA384:
|
||||
m_sha384->reset();
|
||||
break;
|
||||
case HashKind::SHA512:
|
||||
m_sha512->reset();
|
||||
break;
|
||||
|
@ -271,6 +301,8 @@ public:
|
|||
return m_sha1->class_name();
|
||||
case HashKind::SHA256:
|
||||
return m_sha256->class_name();
|
||||
case HashKind::SHA384:
|
||||
return m_sha384->class_name();
|
||||
case HashKind::SHA512:
|
||||
return m_sha512->class_name();
|
||||
default:
|
||||
|
@ -287,6 +319,7 @@ public:
|
|||
private:
|
||||
OwnPtr<SHA1> m_sha1;
|
||||
OwnPtr<SHA256> m_sha256;
|
||||
OwnPtr<SHA384> m_sha384;
|
||||
OwnPtr<SHA512> m_sha512;
|
||||
OwnPtr<MD5> m_md5;
|
||||
HashKind m_kind { HashKind::None };
|
||||
|
|
|
@ -142,6 +142,122 @@ SHA256::DigestType SHA256::peek()
|
|||
return digest;
|
||||
}
|
||||
|
||||
inline void SHA384::transform(const u8* data)
|
||||
{
|
||||
u64 m[80];
|
||||
|
||||
size_t i = 0;
|
||||
for (size_t j = 0; i < 16; ++i, j += 8) {
|
||||
m[i] = ((u64)data[j] << 56) | ((u64)data[j + 1] << 48) | ((u64)data[j + 2] << 40) | ((u64)data[j + 3] << 32) | ((u64)data[j + 4] << 24) | ((u64)data[j + 5] << 16) | ((u64)data[j + 6] << 8) | (u64)data[j + 7];
|
||||
}
|
||||
|
||||
for (; i < Rounds; ++i) {
|
||||
m[i] = SIGN1(m[i - 2]) + m[i - 7] + SIGN0(m[i - 15]) + m[i - 16];
|
||||
}
|
||||
|
||||
auto a = m_state[0], b = m_state[1],
|
||||
c = m_state[2], d = m_state[3],
|
||||
e = m_state[4], f = m_state[5],
|
||||
g = m_state[6], h = m_state[7];
|
||||
|
||||
for (size_t i = 0; i < Rounds; ++i) {
|
||||
// Note : SHA384 uses the SHA512 constants.
|
||||
auto temp0 = h + EP1(e) + CH(e, f, g) + SHA512Constants::RoundConstants[i] + m[i];
|
||||
auto temp1 = EP0(a) + MAJ(a, b, c);
|
||||
h = g;
|
||||
g = f;
|
||||
f = e;
|
||||
e = d + temp0;
|
||||
d = c;
|
||||
c = b;
|
||||
b = a;
|
||||
a = temp0 + temp1;
|
||||
}
|
||||
|
||||
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 SHA384::update(const u8* message, size_t length)
|
||||
{
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
if (m_data_length == BlockSize) {
|
||||
transform(m_data_buffer);
|
||||
m_bit_length += 1024;
|
||||
m_data_length = 0;
|
||||
}
|
||||
m_data_buffer[m_data_length++] = message[i];
|
||||
}
|
||||
}
|
||||
|
||||
SHA384::DigestType SHA384::digest()
|
||||
{
|
||||
auto digest = peek();
|
||||
reset();
|
||||
return digest;
|
||||
}
|
||||
|
||||
SHA384::DigestType SHA384::peek()
|
||||
{
|
||||
DigestType digest;
|
||||
size_t i = m_data_length;
|
||||
|
||||
if (BlockSize == m_data_length) {
|
||||
transform(m_data_buffer);
|
||||
m_bit_length += BlockSize * 8;
|
||||
m_data_length = 0;
|
||||
i = 0;
|
||||
}
|
||||
|
||||
if (m_data_length < FinalBlockDataSize) {
|
||||
m_data_buffer[i++] = 0x80;
|
||||
while (i < FinalBlockDataSize)
|
||||
m_data_buffer[i++] = 0x00;
|
||||
|
||||
} else {
|
||||
// First, complete a block with some padding.
|
||||
m_data_buffer[i++] = 0x80;
|
||||
while (i < BlockSize)
|
||||
m_data_buffer[i++] = 0x00;
|
||||
transform(m_data_buffer);
|
||||
|
||||
// Then start another block with BlockSize - 8 bytes of zeros
|
||||
__builtin_memset(m_data_buffer, 0, FinalBlockDataSize);
|
||||
}
|
||||
|
||||
// append total message length
|
||||
m_bit_length += m_data_length * 8;
|
||||
m_data_buffer[BlockSize - 1] = m_bit_length;
|
||||
m_data_buffer[BlockSize - 2] = m_bit_length >> 8;
|
||||
m_data_buffer[BlockSize - 3] = m_bit_length >> 16;
|
||||
m_data_buffer[BlockSize - 4] = m_bit_length >> 24;
|
||||
m_data_buffer[BlockSize - 5] = m_bit_length >> 32;
|
||||
m_data_buffer[BlockSize - 6] = m_bit_length >> 40;
|
||||
m_data_buffer[BlockSize - 7] = m_bit_length >> 48;
|
||||
m_data_buffer[BlockSize - 8] = m_bit_length >> 56;
|
||||
|
||||
transform(m_data_buffer);
|
||||
|
||||
// SHA uses big-endian and we assume little-endian
|
||||
// FIXME: looks like a thing for AK::NetworkOrdered,
|
||||
// but he doesn't support shifting operations
|
||||
for (size_t i = 0; i < 8; ++i) {
|
||||
digest.data[i + 0] = (m_state[0] >> (56 - i * 8)) & 0x000000ff;
|
||||
digest.data[i + 8] = (m_state[1] >> (56 - i * 8)) & 0x000000ff;
|
||||
digest.data[i + 16] = (m_state[2] >> (56 - i * 8)) & 0x000000ff;
|
||||
digest.data[i + 24] = (m_state[3] >> (56 - i * 8)) & 0x000000ff;
|
||||
digest.data[i + 32] = (m_state[4] >> (56 - i * 8)) & 0x000000ff;
|
||||
digest.data[i + 40] = (m_state[5] >> (56 - i * 8)) & 0x000000ff;
|
||||
}
|
||||
return digest;
|
||||
}
|
||||
|
||||
inline void SHA512::transform(const u8* data)
|
||||
{
|
||||
u64 m[80];
|
||||
|
|
|
@ -39,6 +39,13 @@ constexpr static u32 InitializationHashes[8] = {
|
|||
};
|
||||
}
|
||||
|
||||
namespace SHA384Constants {
|
||||
constexpr static u64 InitializationHashes[8] = {
|
||||
0xcbbb9d5dc1059ed8, 0x629a292a367cd507, 0x9159015a3070dd17, 0x152fecd8f70e5939,
|
||||
0x67332667ffc00b31, 0x8eb44a8768581511, 0xdb0c2e0d64f98fa7, 0x47b5481dbefa4fa4
|
||||
};
|
||||
}
|
||||
|
||||
namespace SHA512Constants {
|
||||
constexpr static u64 RoundConstants[80] {
|
||||
0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, 0x3956c25bf348b538,
|
||||
|
@ -124,6 +131,56 @@ private:
|
|||
constexpr static auto Rounds = 64;
|
||||
};
|
||||
|
||||
class SHA384 final : public HashFunction<1024, SHA2Digest<384 / 8>> {
|
||||
public:
|
||||
using HashFunction::update;
|
||||
|
||||
SHA384()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
virtual void update(const u8*, size_t) override;
|
||||
|
||||
virtual DigestType digest() override;
|
||||
virtual DigestType peek() override;
|
||||
|
||||
inline static DigestType hash(const u8* data, size_t length)
|
||||
{
|
||||
SHA384 sha;
|
||||
sha.update(data, length);
|
||||
return sha.digest();
|
||||
}
|
||||
|
||||
inline static DigestType hash(const ByteBuffer& buffer) { return hash(buffer.data(), buffer.size()); }
|
||||
inline static DigestType hash(const StringView& buffer) { return hash((const u8*)buffer.characters_without_null_termination(), buffer.length()); }
|
||||
|
||||
virtual String class_name() const override
|
||||
{
|
||||
return String::formatted("SHA{}", DigestSize * 8);
|
||||
}
|
||||
|
||||
inline virtual void reset() override
|
||||
{
|
||||
m_data_length = 0;
|
||||
m_bit_length = 0;
|
||||
for (size_t i = 0; i < 8; ++i)
|
||||
m_state[i] = SHA384Constants::InitializationHashes[i];
|
||||
}
|
||||
|
||||
private:
|
||||
inline void transform(const u8*);
|
||||
|
||||
u8 m_data_buffer[BlockSize];
|
||||
size_t m_data_length { 0 };
|
||||
|
||||
u64 m_bit_length { 0 };
|
||||
u64 m_state[8];
|
||||
|
||||
constexpr static auto FinalBlockDataSize = BlockSize - 8;
|
||||
constexpr static auto Rounds = 80;
|
||||
};
|
||||
|
||||
class SHA512 final : public HashFunction<1024, SHA2Digest<512 / 8>> {
|
||||
public:
|
||||
using HashFunction::update;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue