diff --git a/Libraries/LibCrypto/Authentication/HMAC.h b/Libraries/LibCrypto/Authentication/HMAC.h index 772409ebc016..3409db847865 100644 --- a/Libraries/LibCrypto/Authentication/HMAC.h +++ b/Libraries/LibCrypto/Authentication/HMAC.h @@ -24,12 +24,12 @@ class HMAC { using HashType = HashT; using TagType = typename HashType::DigestType; - constexpr size_t digest_size() const { return m_inner_hasher.digest_size(); } + size_t digest_size() const { return m_inner_hasher->digest_size(); } template HMAC(KeyBufferType key, Args... args) - : m_inner_hasher(args...) - , m_outer_hasher(args...) + : m_inner_hasher(move(HashT::create(args...))) + , m_outer_hasher(move(HashT::create(args...))) { derive_key(key); reset(); @@ -44,7 +44,7 @@ class HMAC { void update(u8 const* message, size_t length) { - m_inner_hasher.update(message, length); + m_inner_hasher->update(message, length); } TagType process(ReadonlyBytes span) { return process(span.data(), span.size()); } @@ -55,32 +55,32 @@ class HMAC { TagType digest() { - m_outer_hasher.update(m_inner_hasher.digest().immutable_data(), m_inner_hasher.digest_size()); - auto result = m_outer_hasher.digest(); + m_outer_hasher->update(m_inner_hasher->digest().immutable_data(), m_inner_hasher->digest_size()); + auto result = m_outer_hasher->digest(); reset(); return result; } void reset() { - m_inner_hasher.reset(); - m_outer_hasher.reset(); - m_inner_hasher.update(m_key_data, m_inner_hasher.block_size()); - m_outer_hasher.update(m_key_data + m_inner_hasher.block_size(), m_outer_hasher.block_size()); + m_inner_hasher->reset(); + m_outer_hasher->reset(); + m_inner_hasher->update(m_key_data, m_inner_hasher->block_size()); + m_outer_hasher->update(m_key_data + m_inner_hasher->block_size(), m_outer_hasher->block_size()); } ByteString class_name() const { StringBuilder builder; builder.append("HMAC-"sv); - builder.append(m_inner_hasher.class_name()); + builder.append(m_inner_hasher->class_name()); return builder.to_byte_string(); } private: void derive_key(u8 const* key, size_t length) { - auto block_size = m_inner_hasher.block_size(); + auto block_size = m_inner_hasher->block_size(); // Note: The block size of all the current hash functions is 512 bits. Vector v_key; v_key.resize(block_size); @@ -89,10 +89,10 @@ class HMAC { // the first few bytes leaves the rest zero, which // is exactly what we want (zero padding) if (length > block_size) { - m_inner_hasher.update(key, length); - auto digest = m_inner_hasher.digest(); + m_inner_hasher->update(key, length); + auto digest = m_inner_hasher->digest(); // FIXME: should we check if the hash function creates more data than its block size? - key_buffer.overwrite(0, digest.immutable_data(), m_inner_hasher.digest_size()); + key_buffer.overwrite(0, digest.immutable_data(), m_inner_hasher->digest_size()); } else if (length > 0) { key_buffer.overwrite(0, key, length); } @@ -110,7 +110,7 @@ class HMAC { void derive_key(ReadonlyBytes key) { derive_key(key.data(), key.size()); } void derive_key(StringView key) { derive_key(key.bytes()); } - HashType m_inner_hasher, m_outer_hasher; + NonnullOwnPtr m_inner_hasher, m_outer_hasher; u8 m_key_data[2048]; }; diff --git a/Libraries/LibCrypto/CMakeLists.txt b/Libraries/LibCrypto/CMakeLists.txt index bbda3f54886f..7a1e38ce252b 100644 --- a/Libraries/LibCrypto/CMakeLists.txt +++ b/Libraries/LibCrypto/CMakeLists.txt @@ -28,10 +28,6 @@ set(SOURCES Curves/Ed25519.cpp Curves/X25519.cpp Curves/X448.cpp - Hash/BLAKE2b.cpp - Hash/MD5.cpp - Hash/SHA1.cpp - Hash/SHA2.cpp NumberTheory/ModularFunctions.cpp PK/RSA.cpp PK/EC.cpp diff --git a/Libraries/LibCrypto/Curves/Ed25519.cpp b/Libraries/LibCrypto/Curves/Ed25519.cpp index faad52257f53..2aac52c1222a 100644 --- a/Libraries/LibCrypto/Curves/Ed25519.cpp +++ b/Libraries/LibCrypto/Curves/Ed25519.cpp @@ -79,15 +79,15 @@ ErrorOr Ed25519::sign(ReadonlyBytes public_key, ReadonlyBytes privat memcpy(p, h.data + 32, 32); // 2. Compute SHA-512(dom2(F, C) || p || PH(M)), where M is the message to be signed. - Crypto::Hash::SHA512 hash; + auto hash = Hash::SHA512::create(); // NOTE: dom2(F, C) is a blank octet string when signing or verifying Ed25519 - hash.update(p, 32); + hash->update(p, 32); // NOTE: PH(M) = M - hash.update(message.data(), message.size()); + hash->update(message.data(), message.size()); // Interpret the 64-octet digest as a little-endian integer r. // For efficiency, do this by first reducing r modulo L, the group order of B. - auto digest = hash.digest(); + auto digest = hash->digest(); barrett_reduce(r, digest.data); // 3. Compute the point [r]B. @@ -100,13 +100,13 @@ ErrorOr Ed25519::sign(ReadonlyBytes public_key, ReadonlyBytes privat // 4. Compute SHA512(dom2(F, C) || R || A || PH(M)), // NOTE: We can reuse hash here, since digest() calls reset() // NOTE: dom2(F, C) is a blank octet string when signing or verifying Ed25519 - hash.update(R.data(), R.size()); + hash->update(R.data(), R.size()); // NOTE: A == public_key - hash.update(public_key.data(), public_key.size()); + hash->update(public_key.data(), public_key.size()); // NOTE: PH(M) = M - hash.update(message.data(), message.size()); + hash->update(message.data(), message.size()); - digest = hash.digest(); + digest = hash->digest(); // and interpret the 64-octet digest as a little-endian integer k. memcpy(k, digest.data, 64); @@ -160,15 +160,15 @@ bool Ed25519::verify(ReadonlyBytes public_key, ReadonlyBytes signature, Readonly not_valid |= decode_point(&ka, public_key.data()); // 2. Compute SHA512(dom2(F, C) || R || A || PH(M)), and interpret the 64-octet digest as a little-endian integer k. - Crypto::Hash::SHA512 hash; + auto hash = Hash::SHA512::create(); // NOTE: dom2(F, C) is a blank octet string when signing or verifying Ed25519 - hash.update(r, half_signature_size); + hash->update(r, half_signature_size); // NOTE: A == public_key - hash.update(public_key.data(), key_size()); + hash->update(public_key.data(), key_size()); // NOTE: PH(M) = M - hash.update(message.data(), message.size()); + hash->update(message.data(), message.size()); - auto digest = hash.digest(); + auto digest = hash->digest(); auto k = digest.data; // 3. Check the group equation [8][S]B = [8]R + [8][k]A'. diff --git a/Libraries/LibCrypto/Hash/BLAKE2b.cpp b/Libraries/LibCrypto/Hash/BLAKE2b.cpp deleted file mode 100644 index fa9ac331d82c..000000000000 --- a/Libraries/LibCrypto/Hash/BLAKE2b.cpp +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (c) 2023, the SerenityOS developers - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include - -namespace Crypto::Hash { -constexpr static auto ROTRIGHT(u64 a, size_t b) { return (a >> b) | (a << (64 - b)); } - -void BLAKE2b::update(u8 const* in, size_t inlen) -{ - if (inlen > 0) { - size_t left = m_internal_state.buffer_length; - size_t fill = BLAKE2bConstants::blockbytes - left; - if (inlen > fill) { - m_internal_state.buffer_length = 0; - // Fill the buffer. - __builtin_memcpy(m_internal_state.buffer + left, in, fill); - - increment_counter_by(BLAKE2bConstants::blockbytes); - transform(m_internal_state.buffer); - in += fill; - inlen -= fill; - while (inlen > BLAKE2bConstants::blockbytes) { - increment_counter_by(BLAKE2bConstants::blockbytes); - transform(in); - in += BLAKE2bConstants::blockbytes; - inlen -= BLAKE2bConstants::blockbytes; - } - } - __builtin_memcpy(m_internal_state.buffer + m_internal_state.buffer_length, in, inlen); - m_internal_state.buffer_length += inlen; - } -} - -BLAKE2b::DigestType BLAKE2b::peek() -{ - DigestType digest; - increment_counter_by(m_internal_state.buffer_length); - - // Set this as the last block - m_internal_state.is_at_last_block = UINT64_MAX; - - // Pad the buffer with zeros - __builtin_memset(m_internal_state.buffer + m_internal_state.buffer_length, 0, BLAKE2bConstants::blockbytes - m_internal_state.buffer_length); - transform(m_internal_state.buffer); - - for (size_t i = 0; i < 8; ++i) - __builtin_memcpy(&digest.data[0] + sizeof(m_internal_state.hash_state[i]) * i, &m_internal_state.hash_state[i], sizeof(m_internal_state.hash_state[i])); - - return digest; -} - -BLAKE2b::DigestType BLAKE2b::digest() -{ - auto digest = peek(); - reset(); - return digest; -} - -void BLAKE2b::increment_counter_by(u64 const amount) -{ - m_internal_state.message_byte_offset[0] += amount; - m_internal_state.message_byte_offset[1] += (m_internal_state.message_byte_offset[0] < amount); -} - -void BLAKE2b::mix(u64* work_array, u64 a, u64 b, u64 c, u64 d, u64 x, u64 y) -{ - constexpr auto rotation_constant_1 = 32; - constexpr auto rotation_constant_2 = 24; - constexpr auto rotation_constant_3 = 16; - constexpr auto rotation_constant_4 = 63; - - work_array[a] = work_array[a] + work_array[b] + x; - work_array[d] = ROTRIGHT(work_array[d] ^ work_array[a], rotation_constant_1); - work_array[c] = work_array[c] + work_array[d]; - work_array[b] = ROTRIGHT(work_array[b] ^ work_array[c], rotation_constant_2); - work_array[a] = work_array[a] + work_array[b] + y; - work_array[d] = ROTRIGHT(work_array[d] ^ work_array[a], rotation_constant_3); - work_array[c] = work_array[c] + work_array[d]; - work_array[b] = ROTRIGHT(work_array[b] ^ work_array[c], rotation_constant_4); -} - -void BLAKE2b::transform(u8 const* block) -{ - u64 m[16]; - u64 v[16]; - - for (size_t i = 0; i < 16; ++i) - m[i] = ByteReader::load64(block + i * sizeof(m[i])); - - for (size_t i = 0; i < 8; ++i) - v[i] = m_internal_state.hash_state[i]; - - v[8] = SHA512Constants::InitializationHashes[0]; - v[9] = SHA512Constants::InitializationHashes[1]; - v[10] = SHA512Constants::InitializationHashes[2]; - v[11] = SHA512Constants::InitializationHashes[3]; - v[12] = SHA512Constants::InitializationHashes[4] ^ m_internal_state.message_byte_offset[0]; - v[13] = SHA512Constants::InitializationHashes[5] ^ m_internal_state.message_byte_offset[1]; - v[14] = SHA512Constants::InitializationHashes[6] ^ m_internal_state.is_at_last_block; - v[15] = SHA512Constants::InitializationHashes[7]; - - for (size_t i = 0; i < 12; ++i) { - u64 sigma_selection[16]; - for (size_t j = 0; j < 16; ++j) - sigma_selection[j] = BLAKE2bSigma[i % 10][j]; - mix(v, 0, 4, 8, 12, m[sigma_selection[0]], m[sigma_selection[1]]); - mix(v, 1, 5, 9, 13, m[sigma_selection[2]], m[sigma_selection[3]]); - mix(v, 2, 6, 10, 14, m[sigma_selection[4]], m[sigma_selection[5]]); - mix(v, 3, 7, 11, 15, m[sigma_selection[6]], m[sigma_selection[7]]); - - mix(v, 0, 5, 10, 15, m[sigma_selection[8]], m[sigma_selection[9]]); - mix(v, 1, 6, 11, 12, m[sigma_selection[10]], m[sigma_selection[11]]); - mix(v, 2, 7, 8, 13, m[sigma_selection[12]], m[sigma_selection[13]]); - mix(v, 3, 4, 9, 14, m[sigma_selection[14]], m[sigma_selection[15]]); - } - - for (size_t i = 0; i < 8; ++i) - m_internal_state.hash_state[i] = m_internal_state.hash_state[i] ^ v[i] ^ v[i + 8]; -} - -} diff --git a/Libraries/LibCrypto/Hash/BLAKE2b.h b/Libraries/LibCrypto/Hash/BLAKE2b.h index fadfba1303a9..fddeec719192 100644 --- a/Libraries/LibCrypto/Hash/BLAKE2b.h +++ b/Libraries/LibCrypto/Hash/BLAKE2b.h @@ -7,82 +7,23 @@ #pragma once #include -#include -#include +#include namespace Crypto::Hash { -namespace BLAKE2bConstants { -static constexpr auto blockbytes { 128 }; -static constexpr auto hash_length { 64 }; -}; +class BLAKE2b final : public OpenSSLHashFunction { + AK_MAKE_NONCOPYABLE(BLAKE2b); -class BLAKE2b final : public HashFunction<1024, 512> { public: - using HashFunction::update; - - BLAKE2b() + explicit BLAKE2b(EVP_MD_CTX* context) + : OpenSSLHashFunction(EVP_blake2b512(), context) { - reset(); } - virtual void update(u8 const*, size_t) override; - virtual DigestType digest() override; - virtual DigestType peek() override; - - static DigestType hash(u8 const* data, size_t length) - { - BLAKE2b blake2b; - blake2b.update(data, length); - return blake2b.digest(); - } - - static DigestType hash(ByteBuffer const& buffer) { return hash(buffer.data(), buffer.size()); } - static DigestType hash(StringView buffer) { return hash((u8 const*)buffer.characters_without_null_termination(), buffer.length()); } - virtual ByteString class_name() const override { return "BLAKE2b"; } - - virtual void reset() override - { - m_internal_state = {}; - // BLAKE2b uses the same initialization vector as SHA512. - for (size_t i = 0; i < 8; ++i) - m_internal_state.hash_state[i] = SHA512Constants::InitializationHashes[i]; - m_internal_state.hash_state[0] ^= 0x01010000 ^ (0 << 8) ^ BLAKE2bConstants::hash_length; - } - -private: - static constexpr u8 BLAKE2bSigma[12][16] = { - { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, - { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }, - { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 }, - { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 }, - { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 }, - { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 }, - { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 }, - { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 }, - { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 }, - { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 }, - { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, - { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } - }; - - struct BLAKE2bState { - u64 hash_state[8] {}; - u64 message_byte_offset[2] {}; - u64 is_at_last_block { 0 }; - u8 buffer[BLAKE2bConstants::blockbytes] = {}; - size_t buffer_length { 0 }; - }; - - BLAKE2bState m_internal_state {}; - - void mix(u64* work_vector, u64 a, u64 b, u64 c, u64 d, u64 x, u64 y); - void increment_counter_by(u64 const amount); - void transform(u8 const*); }; }; diff --git a/Libraries/LibCrypto/Hash/HashManager.h b/Libraries/LibCrypto/Hash/HashManager.h index bbf71839c9a5..fb9ac9777f30 100644 --- a/Libraries/LibCrypto/Hash/HashManager.h +++ b/Libraries/LibCrypto/Hash/HashManager.h @@ -90,6 +90,11 @@ class Manager final : public HashFunction<0, 0, MultiHashDigestVariant> { public: using HashFunction::update; + static NonnullOwnPtr create(HashKind kind) + { + return make(kind); + } + Manager() { m_pre_init_buffer = ByteBuffer(); @@ -116,14 +121,14 @@ class Manager final : public HashFunction<0, 0, MultiHashDigestVariant> { { return m_algorithm.visit( [&](Empty const&) -> size_t { return 0; }, - [&](auto const& hash) { return hash.digest_size(); }); + [&](auto const& hash) { return hash->digest_size(); }); } inline size_t block_size() const { return m_algorithm.visit( [&](Empty const&) -> size_t { return 0; }, - [&](auto const& hash) { return hash.block_size(); }); + [&](auto const& hash) { return hash->block_size(); }); } inline void initialize(HashKind kind) @@ -135,22 +140,22 @@ class Manager final : public HashFunction<0, 0, MultiHashDigestVariant> { m_kind = kind; switch (kind) { case HashKind::BLAKE2b: - m_algorithm = BLAKE2b(); + m_algorithm = BLAKE2b::create(); break; case HashKind::MD5: - m_algorithm = MD5(); + m_algorithm = MD5::create(); break; case HashKind::SHA1: - m_algorithm = SHA1(); + m_algorithm = SHA1::create(); break; case HashKind::SHA256: - m_algorithm = SHA256(); + m_algorithm = SHA256::create(); break; case HashKind::SHA384: - m_algorithm = SHA384(); + m_algorithm = SHA384::create(); break; case HashKind::SHA512: - m_algorithm = SHA512(); + m_algorithm = SHA512::create(); break; default: case HashKind::None: @@ -165,11 +170,11 @@ class Manager final : public HashFunction<0, 0, MultiHashDigestVariant> { if (size) { m_algorithm.visit( [&](Empty&) {}, - [&](auto& hash) { hash.update(m_pre_init_buffer); }); + [&](auto& hash) { hash->update(m_pre_init_buffer); }); } m_algorithm.visit( [&](Empty&) { m_pre_init_buffer.append(data, length); }, - [&](auto& hash) { hash.update(data, length); }); + [&](auto& hash) { hash->update(data, length); }); if (size && m_kind != HashKind::None) m_pre_init_buffer.clear(); } @@ -178,14 +183,14 @@ class Manager final : public HashFunction<0, 0, MultiHashDigestVariant> { { return m_algorithm.visit( [&](Empty&) -> DigestType { VERIFY_NOT_REACHED(); }, - [&](auto& hash) -> DigestType { return hash.peek(); }); + [&](auto& hash) -> DigestType { return hash->peek(); }); } virtual DigestType digest() override { - auto digest = peek(); - reset(); - return digest; + return m_algorithm.visit( + [&](Empty&) -> DigestType { VERIFY_NOT_REACHED(); }, + [&](auto& hash) -> DigestType { return hash->digest(); }); } virtual void reset() override @@ -193,14 +198,14 @@ class Manager final : public HashFunction<0, 0, MultiHashDigestVariant> { m_pre_init_buffer.clear(); m_algorithm.visit( [&](Empty&) {}, - [&](auto& hash) { hash.reset(); }); + [&](auto& hash) { hash->reset(); }); } virtual ByteString class_name() const override { return m_algorithm.visit( [&](Empty const&) -> ByteString { return "UninitializedHashManager"; }, - [&](auto const& hash) { return hash.class_name(); }); + [&](auto const& hash) { return hash->class_name(); }); } inline HashKind kind() const @@ -215,15 +220,19 @@ class Manager final : public HashFunction<0, 0, MultiHashDigestVariant> { inline Manager copy() const { + auto algorithm = m_algorithm.visit( + [&](Empty const&) -> AlgorithmVariant { VERIFY_NOT_REACHED(); }, + [&](auto const& hash) -> AlgorithmVariant { return hash->copy(); }); + Manager result; - result.m_algorithm = m_algorithm; + result.m_algorithm = move(algorithm); result.m_kind = m_kind; result.m_pre_init_buffer = m_pre_init_buffer; return result; } private: - using AlgorithmVariant = Variant; + using AlgorithmVariant = Variant, NonnullOwnPtr, NonnullOwnPtr, NonnullOwnPtr, NonnullOwnPtr, NonnullOwnPtr>; AlgorithmVariant m_algorithm {}; HashKind m_kind { HashKind::None }; ByteBuffer m_pre_init_buffer; diff --git a/Libraries/LibCrypto/Hash/MD5.cpp b/Libraries/LibCrypto/Hash/MD5.cpp deleted file mode 100644 index 916e3b7c5746..000000000000 --- a/Libraries/LibCrypto/Hash/MD5.cpp +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright (c) 2020, Ali Mohammad Pur - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include - -static constexpr u32 F(u32 x, u32 y, u32 z) { return (x & y) | ((~x) & z); } -static constexpr u32 G(u32 x, u32 y, u32 z) { return (x & z) | ((~z) & y); } -static constexpr u32 H(u32 x, u32 y, u32 z) { return x ^ y ^ z; } -static constexpr u32 I(u32 x, u32 y, u32 z) { return y ^ (x | ~z); } -static constexpr u32 ROTATE_LEFT(u32 x, size_t n) -{ - return (x << n) | (x >> (32 - n)); -} - -static constexpr void round_1(u32& a, u32 b, u32 c, u32 d, u32 x, u32 s, u32 ac) -{ - a += F(b, c, d) + x + ac; - a = ROTATE_LEFT(a, s); - a += b; -} - -static constexpr void round_2(u32& a, u32 b, u32 c, u32 d, u32 x, u32 s, u32 ac) -{ - a += G(b, c, d) + x + ac; - a = ROTATE_LEFT(a, s); - a += b; -} - -static constexpr void round_3(u32& a, u32 b, u32 c, u32 d, u32 x, u32 s, u32 ac) -{ - a += H(b, c, d) + x + ac; - a = ROTATE_LEFT(a, s); - a += b; -} - -static constexpr void round_4(u32& a, u32 b, u32 c, u32 d, u32 x, u32 s, u32 ac) -{ - a += I(b, c, d) + x + ac; - a = ROTATE_LEFT(a, s); - a += b; -} - -namespace Crypto::Hash { - -void MD5::update(u8 const* input, size_t length) -{ - auto index = (u32)(m_count[0] >> 3) & 0x3f; - size_t offset { 0 }; - m_count[0] += (u32)length << 3; - if (m_count[0] < ((u32)length << 3)) { - ++m_count[1]; - } - m_count[1] += (u32)length >> 29; - - auto part_length = 64 - index; - auto buffer = Bytes { m_data_buffer, sizeof(m_data_buffer) }; - if (length >= part_length) { - buffer.overwrite(index, input, part_length); - transform(buffer.data()); - - for (offset = part_length; offset + 63 < length; offset += 64) - transform(&input[offset]); - - index = 0; - } - - VERIFY(length < part_length || length - offset <= 64); - buffer.overwrite(index, &input[offset], length - offset); -} -MD5::DigestType MD5::digest() -{ - auto digest = peek(); - reset(); - return digest; -} - -MD5::DigestType MD5::peek() -{ - DigestType digest; - u8 bits[8]; - - encode(m_count, bits, 8); - - // pad the data to 56%64 - u32 index = (u32)((m_count[0] >> 3) & 0x3f); - u32 pad_length = index < 56 ? 56 - index : 120 - index; - update(MD5Constants::PADDING, pad_length); - - // append length - update(bits, 8); - - // store state (4 registers ABCD) - encode(&m_A, digest.data, 4 * sizeof(m_A)); - - return digest; -} - -void MD5::encode(u32 const* from, u8* to, size_t length) -{ - for (size_t i = 0, j = 0; j < length; ++i, j += 4) { - to[j] = (u8)(from[i] & 0xff); - to[j + 1] = (u8)((from[i] >> 8) & 0xff); - to[j + 2] = (u8)((from[i] >> 16) & 0xff); - to[j + 3] = (u8)((from[i] >> 24) & 0xff); - } -} - -void MD5::decode(u8 const* from, u32* to, size_t length) -{ - for (size_t i = 0, j = 0; j < length; ++i, j += 4) - to[i] = (((u32)from[j]) | (((u32)from[j + 1]) << 8) | (((u32)from[j + 2]) << 16) | (((u32)from[j + 3]) << 24)); -} - -void MD5::transform(u8 const* block) -{ - auto a = m_A; - auto b = m_B; - auto c = m_C; - auto d = m_D; - u32 x[16]; - - decode(block, x, 64); - - round_1(a, b, c, d, x[0], MD5Constants::S11, 0xd76aa478); // 1 - round_1(d, a, b, c, x[1], MD5Constants::S12, 0xe8c7b756); // 2 - round_1(c, d, a, b, x[2], MD5Constants::S13, 0x242070db); // 3 - round_1(b, c, d, a, x[3], MD5Constants::S14, 0xc1bdceee); // 4 - round_1(a, b, c, d, x[4], MD5Constants::S11, 0xf57c0faf); // 5 - round_1(d, a, b, c, x[5], MD5Constants::S12, 0x4787c62a); // 6 - round_1(c, d, a, b, x[6], MD5Constants::S13, 0xa8304613); // 7 - round_1(b, c, d, a, x[7], MD5Constants::S14, 0xfd469501); // 8 - round_1(a, b, c, d, x[8], MD5Constants::S11, 0x698098d8); // 9 - round_1(d, a, b, c, x[9], MD5Constants::S12, 0x8b44f7af); // 10 - round_1(c, d, a, b, x[10], MD5Constants::S13, 0xffff5bb1); // 11 - round_1(b, c, d, a, x[11], MD5Constants::S14, 0x895cd7be); // 12 - round_1(a, b, c, d, x[12], MD5Constants::S11, 0x6b901122); // 13 - round_1(d, a, b, c, x[13], MD5Constants::S12, 0xfd987193); // 14 - round_1(c, d, a, b, x[14], MD5Constants::S13, 0xa679438e); // 15 - round_1(b, c, d, a, x[15], MD5Constants::S14, 0x49b40821); // 16 - - round_2(a, b, c, d, x[1], MD5Constants::S21, 0xf61e2562); // 17 - round_2(d, a, b, c, x[6], MD5Constants::S22, 0xc040b340); // 18 - round_2(c, d, a, b, x[11], MD5Constants::S23, 0x265e5a51); // 19 - round_2(b, c, d, a, x[0], MD5Constants::S24, 0xe9b6c7aa); // 20 - round_2(a, b, c, d, x[5], MD5Constants::S21, 0xd62f105d); // 21 - round_2(d, a, b, c, x[10], MD5Constants::S22, 0x2441453); // 22 - round_2(c, d, a, b, x[15], MD5Constants::S23, 0xd8a1e681); // 23 - round_2(b, c, d, a, x[4], MD5Constants::S24, 0xe7d3fbc8); // 24 - round_2(a, b, c, d, x[9], MD5Constants::S21, 0x21e1cde6); // 25 - round_2(d, a, b, c, x[14], MD5Constants::S22, 0xc33707d6); // 26 - round_2(c, d, a, b, x[3], MD5Constants::S23, 0xf4d50d87); // 27 - round_2(b, c, d, a, x[8], MD5Constants::S24, 0x455a14ed); // 28 - round_2(a, b, c, d, x[13], MD5Constants::S21, 0xa9e3e905); // 29 - round_2(d, a, b, c, x[2], MD5Constants::S22, 0xfcefa3f8); // 30 - round_2(c, d, a, b, x[7], MD5Constants::S23, 0x676f02d9); // 31 - round_2(b, c, d, a, x[12], MD5Constants::S24, 0x8d2a4c8a); // 32 - - round_3(a, b, c, d, x[5], MD5Constants::S31, 0xfffa3942); // 33 - round_3(d, a, b, c, x[8], MD5Constants::S32, 0x8771f681); // 34 - round_3(c, d, a, b, x[11], MD5Constants::S33, 0x6d9d6122); // 35 - round_3(b, c, d, a, x[14], MD5Constants::S34, 0xfde5380c); // 36 - round_3(a, b, c, d, x[1], MD5Constants::S31, 0xa4beea44); // 37 - round_3(d, a, b, c, x[4], MD5Constants::S32, 0x4bdecfa9); // 38 - round_3(c, d, a, b, x[7], MD5Constants::S33, 0xf6bb4b60); // 39 - round_3(b, c, d, a, x[10], MD5Constants::S34, 0xbebfbc70); // 40 - round_3(a, b, c, d, x[13], MD5Constants::S31, 0x289b7ec6); // 41 - round_3(d, a, b, c, x[0], MD5Constants::S32, 0xeaa127fa); // 42 - round_3(c, d, a, b, x[3], MD5Constants::S33, 0xd4ef3085); // 43 - round_3(b, c, d, a, x[6], MD5Constants::S34, 0x4881d05); // 44 - round_3(a, b, c, d, x[9], MD5Constants::S31, 0xd9d4d039); // 45 - round_3(d, a, b, c, x[12], MD5Constants::S32, 0xe6db99e5); // 46 - round_3(c, d, a, b, x[15], MD5Constants::S33, 0x1fa27cf8); // 47 - round_3(b, c, d, a, x[2], MD5Constants::S34, 0xc4ac5665); // 48 - - round_4(a, b, c, d, x[0], MD5Constants::S41, 0xf4292244); // 49 - round_4(d, a, b, c, x[7], MD5Constants::S42, 0x432aff97); // 50 - round_4(c, d, a, b, x[14], MD5Constants::S43, 0xab9423a7); // 51 - round_4(b, c, d, a, x[5], MD5Constants::S44, 0xfc93a039); // 52 - round_4(a, b, c, d, x[12], MD5Constants::S41, 0x655b59c3); // 53 - round_4(d, a, b, c, x[3], MD5Constants::S42, 0x8f0ccc92); // 54 - round_4(c, d, a, b, x[10], MD5Constants::S43, 0xffeff47d); // 55 - round_4(b, c, d, a, x[1], MD5Constants::S44, 0x85845dd1); // 56 - round_4(a, b, c, d, x[8], MD5Constants::S41, 0x6fa87e4f); // 57 - round_4(d, a, b, c, x[15], MD5Constants::S42, 0xfe2ce6e0); // 58 - round_4(c, d, a, b, x[6], MD5Constants::S43, 0xa3014314); // 59 - round_4(b, c, d, a, x[13], MD5Constants::S44, 0x4e0811a1); // 60 - round_4(a, b, c, d, x[4], MD5Constants::S41, 0xf7537e82); // 61 - round_4(d, a, b, c, x[11], MD5Constants::S42, 0xbd3af235); // 62 - round_4(c, d, a, b, x[2], MD5Constants::S43, 0x2ad7d2bb); // 63 - round_4(b, c, d, a, x[9], MD5Constants::S44, 0xeb86d391); // 64 - - m_A += a; - m_B += b; - m_C += c; - m_D += d; - - secure_zero(x, sizeof(x)); -} - -} diff --git a/Libraries/LibCrypto/Hash/MD5.h b/Libraries/LibCrypto/Hash/MD5.h index 229393c339f2..c1c92d2a1a97 100644 --- a/Libraries/LibCrypto/Hash/MD5.h +++ b/Libraries/LibCrypto/Hash/MD5.h @@ -7,88 +7,23 @@ #pragma once #include -#include -#include +#include namespace Crypto::Hash { -namespace MD5Constants { +class MD5 final : public OpenSSLHashFunction { + AK_MAKE_NONCOPYABLE(MD5); -constexpr u32 init_A = 0x67452301; -constexpr u32 init_B = 0xefcdab89; -constexpr u32 init_C = 0x98badcfe; -constexpr u32 init_D = 0x10325476; -constexpr u32 S11 = 7; -constexpr u32 S12 = 12; -constexpr u32 S13 = 17; -constexpr u32 S14 = 22; -constexpr u32 S21 = 5; -constexpr u32 S22 = 9; -constexpr u32 S23 = 14; -constexpr u32 S24 = 20; -constexpr u32 S31 = 4; -constexpr u32 S32 = 11; -constexpr u32 S33 = 16; -constexpr u32 S34 = 23; -constexpr u32 S41 = 6; -constexpr u32 S42 = 10; -constexpr u32 S43 = 15; -constexpr u32 S44 = 21; -constexpr u8 PADDING[] = { - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0 -}; - -} - -class MD5 final : public HashFunction<512, 128> { public: - using HashFunction::update; - - virtual void update(u8 const*, size_t) override; - virtual DigestType digest() override; - virtual DigestType peek() override; - - virtual ByteString class_name() const override + explicit MD5(EVP_MD_CTX* context) + : OpenSSLHashFunction(EVP_md5(), context) { - return "MD5"; } - static DigestType hash(u8 const* data, size_t length) - { - MD5 md5; - md5.update(data, length); - return md5.digest(); - } - - static DigestType hash(ByteBuffer const& buffer) { return hash(buffer.data(), buffer.size()); } - static DigestType hash(StringView buffer) { return hash((u8 const*)buffer.characters_without_null_termination(), buffer.length()); } - virtual void reset() override + virtual ByteString class_name() const override { - m_A = MD5Constants::init_A; - m_B = MD5Constants::init_B; - m_C = MD5Constants::init_C; - m_D = MD5Constants::init_D; - - m_count[0] = 0; - m_count[1] = 0; - - __builtin_memset(m_data_buffer, 0, sizeof(m_data_buffer)); + return "MD5"; } - -private: - inline void transform(u8 const*); - - static void encode(u32 const* from, u8* to, size_t length); - static void decode(u8 const* from, u32* to, size_t length); - - u32 m_A { MD5Constants::init_A }, m_B { MD5Constants::init_B }, m_C { MD5Constants::init_C }, m_D { MD5Constants::init_D }; - u32 m_count[2] { 0, 0 }; - - u8 m_data_buffer[64] {}; }; } diff --git a/Libraries/LibCrypto/Hash/MGF.h b/Libraries/LibCrypto/Hash/MGF.h index a97f2a46e262..43764c840224 100644 --- a/Libraries/LibCrypto/Hash/MGF.h +++ b/Libraries/LibCrypto/Hash/MGF.h @@ -19,9 +19,9 @@ class MGF { static ErrorOr mgf1(ReadonlyBytes seed, size_t length) requires requires { HashFunction::digest_size(); } { - HashFunction hash; + auto hash = HashFunction::create(); - size_t h_len = hash.digest_size(); + size_t h_len = hash->digest_size(); // 1. If length > 2^32(hLen), output "mask too long" and stop. if constexpr (sizeof(size_t) > 32) { @@ -42,9 +42,9 @@ class MGF { ByteReader::store(static_cast(c.data()), AK::convert_between_host_and_big_endian(static_cast(counter))); // b. Concatenate the hash of the seed Z and C to the octet string T: T = T || Hash (Z || C) - hash.update(seed); - hash.update(c); - auto digest = hash.digest(); + hash->update(seed); + hash->update(c); + auto digest = hash->digest(); TRY(t.try_append(digest.bytes())); } diff --git a/Libraries/LibCrypto/Hash/SHA1.cpp b/Libraries/LibCrypto/Hash/SHA1.cpp deleted file mode 100644 index fcdcecf694b5..000000000000 --- a/Libraries/LibCrypto/Hash/SHA1.cpp +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (c) 2020, Ali Mohammad Pur - * Copyright (c) 2023, Jelle Raaijmakers - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include - -namespace Crypto::Hash { - -static constexpr auto ROTATE_LEFT(u32 value, size_t bits) -{ - return (value << bits) | (value >> (32 - bits)); -} - -inline void SHA1::transform(u8 const* data) -{ - u32 blocks[80]; - for (size_t i = 0; i < 16; ++i) - blocks[i] = AK::convert_between_host_and_network_endian(((u32 const*)data)[i]); - - // w[i] = (w[i-3] xor w[i-8] xor w[i-14] xor w[i-16]) leftrotate 1 - for (size_t i = 16; i < Rounds; ++i) - blocks[i] = ROTATE_LEFT(blocks[i - 3] ^ blocks[i - 8] ^ blocks[i - 14] ^ blocks[i - 16], 1); - - auto a = m_state[0], b = m_state[1], c = m_state[2], d = m_state[3], e = m_state[4]; - u32 f, k; - - for (size_t i = 0; i < Rounds; ++i) { - if (i <= 19) { - f = (b & c) | ((~b) & d); - k = SHA1Constants::RoundConstants[0]; - } else if (i <= 39) { - f = b ^ c ^ d; - k = SHA1Constants::RoundConstants[1]; - } else if (i <= 59) { - f = (b & c) | (b & d) | (c & d); - k = SHA1Constants::RoundConstants[2]; - } else { - f = b ^ c ^ d; - k = SHA1Constants::RoundConstants[3]; - } - auto temp = ROTATE_LEFT(a, 5) + f + e + k + blocks[i]; - e = d; - d = c; - c = ROTATE_LEFT(b, 30); - b = a; - a = temp; - } - - m_state[0] += a; - m_state[1] += b; - m_state[2] += c; - m_state[3] += d; - m_state[4] += e; - - // "security" measures, as if SHA1 is secure - a = 0; - b = 0; - c = 0; - d = 0; - e = 0; - secure_zero(blocks, 16 * sizeof(u32)); -} - -void SHA1::update(u8 const* message, size_t length) -{ - while (length > 0) { - size_t copy_bytes = AK::min(length, BlockSize - m_data_length); - __builtin_memcpy(m_data_buffer + m_data_length, message, copy_bytes); - message += copy_bytes; - length -= copy_bytes; - m_data_length += copy_bytes; - if (m_data_length == BlockSize) { - transform(m_data_buffer); - m_bit_length += BlockSize * 8; - m_data_length = 0; - } - } -} - -SHA1::DigestType SHA1::digest() -{ - auto digest = peek(); - reset(); - return digest; -} - -SHA1::DigestType SHA1::peek() -{ - DigestType digest; - size_t i = m_data_length; - - // make a local copy of the data as we modify it - u8 data[BlockSize]; - u32 state[5]; - __builtin_memcpy(data, m_data_buffer, m_data_length); - __builtin_memcpy(state, m_state, 20); - - 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); - - for (i = 0; i < 4; ++i) { - digest.data[i + 0] = (m_state[0] >> (24 - i * 8)) & 0x000000ff; - digest.data[i + 4] = (m_state[1] >> (24 - i * 8)) & 0x000000ff; - digest.data[i + 8] = (m_state[2] >> (24 - i * 8)) & 0x000000ff; - digest.data[i + 12] = (m_state[3] >> (24 - i * 8)) & 0x000000ff; - digest.data[i + 16] = (m_state[4] >> (24 - i * 8)) & 0x000000ff; - } - // restore the data - __builtin_memcpy(m_data_buffer, data, m_data_length); - __builtin_memcpy(m_state, state, 20); - return digest; -} - -} diff --git a/Libraries/LibCrypto/Hash/SHA1.h b/Libraries/LibCrypto/Hash/SHA1.h index 47ca6477b910..c695c8b39ea8 100644 --- a/Libraries/LibCrypto/Hash/SHA1.h +++ b/Libraries/LibCrypto/Hash/SHA1.h @@ -7,71 +7,23 @@ #pragma once #include -#include +#include namespace Crypto::Hash { -namespace SHA1Constants { +class SHA1 final : public OpenSSLHashFunction { + AK_MAKE_NONCOPYABLE(SHA1); -constexpr static u32 InitializationHashes[5] { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 }; - -constexpr static u32 RoundConstants[4] { - 0X5a827999, - 0X6ed9eba1, - 0X8f1bbcdc, - 0Xca62c1d6, -}; - -} - -class SHA1 final : public HashFunction<512, 160> { public: - using HashFunction::update; - - SHA1() + explicit SHA1(EVP_MD_CTX* context) + : OpenSSLHashFunction(EVP_sha1(), context) { - reset(); } - virtual void update(u8 const*, size_t) override; - - virtual DigestType digest() override; - virtual DigestType peek() override; - - static DigestType hash(u8 const* data, size_t length) - { - SHA1 sha; - sha.update(data, length); - return sha.digest(); - } - - static DigestType hash(ByteBuffer const& buffer) { return hash(buffer.data(), buffer.size()); } - static DigestType hash(StringView buffer) { return hash((u8 const*)buffer.characters_without_null_termination(), buffer.length()); } - virtual ByteString class_name() const override { return "SHA1"; } - - virtual void reset() override - { - m_data_length = 0; - m_bit_length = 0; - for (auto i = 0; i < 5; ++i) - m_state[i] = SHA1Constants::InitializationHashes[i]; - } - -private: - inline void transform(u8 const*); - - u8 m_data_buffer[BlockSize] {}; - size_t m_data_length { 0 }; - - u64 m_bit_length { 0 }; - u32 m_state[5]; - - constexpr static auto FinalBlockDataSize = BlockSize - 8; - constexpr static auto Rounds = 80; }; } diff --git a/Libraries/LibCrypto/Hash/SHA2.cpp b/Libraries/LibCrypto/Hash/SHA2.cpp deleted file mode 100644 index f6fe62115cd2..000000000000 --- a/Libraries/LibCrypto/Hash/SHA2.cpp +++ /dev/null @@ -1,375 +0,0 @@ -/* - * Copyright (c) 2020, Ali Mohammad Pur - * Copyright (c) 2023, Jelle Raaijmakers - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include - -namespace Crypto::Hash { -constexpr static auto ROTRIGHT(u32 a, size_t b) { return (a >> b) | (a << (32 - b)); } -constexpr static auto CH(u32 x, u32 y, u32 z) { return (x & y) ^ (z & ~x); } -constexpr static auto MAJ(u32 x, u32 y, u32 z) { return (x & y) ^ (x & z) ^ (y & z); } -constexpr static auto EP0(u32 x) { return ROTRIGHT(x, 2) ^ ROTRIGHT(x, 13) ^ ROTRIGHT(x, 22); } -constexpr static auto EP1(u32 x) { return ROTRIGHT(x, 6) ^ ROTRIGHT(x, 11) ^ ROTRIGHT(x, 25); } -constexpr static auto SIGN0(u32 x) { return ROTRIGHT(x, 7) ^ ROTRIGHT(x, 18) ^ (x >> 3); } -constexpr static auto SIGN1(u32 x) { return ROTRIGHT(x, 17) ^ ROTRIGHT(x, 19) ^ (x >> 10); } - -constexpr static auto ROTRIGHT(u64 a, size_t b) { return (a >> b) | (a << (64 - b)); } -constexpr static auto CH(u64 x, u64 y, u64 z) { return (x & y) ^ (z & ~x); } -constexpr static auto MAJ(u64 x, u64 y, u64 z) { return (x & y) ^ (x & z) ^ (y & z); } -constexpr static auto EP0(u64 x) { return ROTRIGHT(x, 28) ^ ROTRIGHT(x, 34) ^ ROTRIGHT(x, 39); } -constexpr static auto EP1(u64 x) { return ROTRIGHT(x, 14) ^ ROTRIGHT(x, 18) ^ ROTRIGHT(x, 41); } -constexpr static auto SIGN0(u64 x) { return ROTRIGHT(x, 1) ^ ROTRIGHT(x, 8) ^ (x >> 7); } -constexpr static auto SIGN1(u64 x) { return ROTRIGHT(x, 19) ^ ROTRIGHT(x, 61) ^ (x >> 6); } - -inline void SHA256::transform(u8 const* data) -{ - u32 m[64]; - - size_t i = 0; - for (size_t j = 0; i < 16; ++i, j += 4) { - m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | data[j + 3]; - } - - for (; i < BlockSize; ++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 (i = 0; i < Rounds; ++i) { - auto temp0 = h + EP1(e) + CH(e, f, g) + SHA256Constants::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; -} - -template -void update_buffer(u8* buffer, u8 const* input, size_t length, size_t& data_length, Callback callback) -{ - while (length > 0) { - size_t copy_bytes = AK::min(length, BlockSize - data_length); - __builtin_memcpy(buffer + data_length, input, copy_bytes); - input += copy_bytes; - length -= copy_bytes; - data_length += copy_bytes; - if (data_length == BlockSize) { - callback(); - data_length = 0; - } - } -} - -void SHA256::update(u8 const* message, size_t length) -{ - update_buffer(m_data_buffer, message, length, m_data_length, [&]() { - transform(m_data_buffer); - m_bit_length += BlockSize * 8; - }); -} - -SHA256::DigestType SHA256::digest() -{ - auto digest = peek(); - reset(); - return digest; -} - -SHA256::DigestType SHA256::peek() -{ - DigestType digest; - size_t i = m_data_length; - - if (i < 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 that doesn't support shifting operations - for (i = 0; i < 4; ++i) { - digest.data[i + 0] = (m_state[0] >> (24 - i * 8)) & 0x000000ff; - digest.data[i + 4] = (m_state[1] >> (24 - i * 8)) & 0x000000ff; - digest.data[i + 8] = (m_state[2] >> (24 - i * 8)) & 0x000000ff; - digest.data[i + 12] = (m_state[3] >> (24 - i * 8)) & 0x000000ff; - digest.data[i + 16] = (m_state[4] >> (24 - i * 8)) & 0x000000ff; - digest.data[i + 20] = (m_state[5] >> (24 - i * 8)) & 0x000000ff; - digest.data[i + 24] = (m_state[6] >> (24 - i * 8)) & 0x000000ff; - digest.data[i + 28] = (m_state[7] >> (24 - i * 8)) & 0x000000ff; - } - return digest; -} - -inline void SHA384::transform(u8 const* 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 (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(u8 const* message, size_t length) -{ - update_buffer(m_data_buffer, message, length, m_data_length, [&]() { - transform(m_data_buffer); - m_bit_length += BlockSize * 8; - }); -} - -SHA384::DigestType SHA384::digest() -{ - auto digest = peek(); - reset(); - return digest; -} - -SHA384::DigestType SHA384::peek() -{ - DigestType digest; - size_t i = m_data_length; - - if (i < 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; - // FIXME: Theoretically we should keep track of the number of bits as a u128, now we can only hash up to 2 EiB. - m_data_buffer[BlockSize - 9] = 0; - m_data_buffer[BlockSize - 10] = 0; - m_data_buffer[BlockSize - 11] = 0; - m_data_buffer[BlockSize - 12] = 0; - m_data_buffer[BlockSize - 13] = 0; - m_data_buffer[BlockSize - 14] = 0; - m_data_buffer[BlockSize - 15] = 0; - m_data_buffer[BlockSize - 16] = 0; - - transform(m_data_buffer); - - // SHA uses big-endian and we assume little-endian - // FIXME: looks like a thing for AK::NetworkOrdered, - // but that doesn't support shifting operations - for (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(u8 const* 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 (i = 0; i < Rounds; ++i) { - 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 SHA512::update(u8 const* message, size_t length) -{ - update_buffer(m_data_buffer, message, length, m_data_length, [&]() { - transform(m_data_buffer); - m_bit_length += BlockSize * 8; - }); -} - -SHA512::DigestType SHA512::digest() -{ - auto digest = peek(); - reset(); - return digest; -} - -SHA512::DigestType SHA512::peek() -{ - DigestType digest; - size_t i = m_data_length; - - if (i < 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; - // FIXME: Theoretically we should keep track of the number of bits as a u128, now we can only hash up to 2 EiB. - m_data_buffer[BlockSize - 9] = 0; - m_data_buffer[BlockSize - 10] = 0; - m_data_buffer[BlockSize - 11] = 0; - m_data_buffer[BlockSize - 12] = 0; - m_data_buffer[BlockSize - 13] = 0; - m_data_buffer[BlockSize - 14] = 0; - m_data_buffer[BlockSize - 15] = 0; - m_data_buffer[BlockSize - 16] = 0; - - transform(m_data_buffer); - - // SHA uses big-endian and we assume little-endian - // FIXME: looks like a thing for AK::NetworkOrdered, - // but that doesn't support shifting operations - for (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; - digest.data[i + 48] = (m_state[6] >> (56 - i * 8)) & 0x000000ff; - digest.data[i + 56] = (m_state[7] >> (56 - i * 8)) & 0x000000ff; - } - return digest; -} -} diff --git a/Libraries/LibCrypto/Hash/SHA2.h b/Libraries/LibCrypto/Hash/SHA2.h index 1a4f30bbcdd9..5f715c478632 100644 --- a/Libraries/LibCrypto/Hash/SHA2.h +++ b/Libraries/LibCrypto/Hash/SHA2.h @@ -7,219 +7,53 @@ #pragma once #include -#include -#include +#include namespace Crypto::Hash { -namespace SHA256Constants { -constexpr static u32 RoundConstants[64] { - 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 -}; - -constexpr static u32 InitializationHashes[8] = { - 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, - 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 -}; -} - -namespace SHA384Constants { -constexpr static u64 InitializationHashes[8] = { - 0xcbbb9d5dc1059ed8, 0x629a292a367cd507, 0x9159015a3070dd17, 0x152fecd8f70e5939, - 0x67332667ffc00b31, 0x8eb44a8768581511, 0xdb0c2e0d64f98fa7, 0x47b5481dbefa4fa4 -}; -} +class SHA256 final : public OpenSSLHashFunction { + AK_MAKE_NONCOPYABLE(SHA256); -namespace SHA512Constants { -constexpr static u64 RoundConstants[80] { - 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, 0x3956c25bf348b538, - 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242, 0x12835b0145706fbe, - 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, - 0xc19bf174cf692694, 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, - 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, 0x983e5152ee66dfab, - 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4, 0xc6e00bf33da88fc2, 0xd5a79147930aa725, - 0x06ca6351e003826f, 0x142929670a0e6e70, 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, - 0x53380d139d95b3df, 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b, - 0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30, 0xd192e819d6ef5218, - 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, - 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, - 0x682e6ff3d6b2b8a3, 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec, - 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b, 0xca273eceea26619c, - 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, 0x06f067aa72176fba, 0x0a637dc5a2c898a6, - 0x113f9804bef90dae, 0x1b710b35131c471b, 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, - 0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817 -}; - -constexpr static u64 InitializationHashes[8] = { - 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, - 0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179 -}; -} - -// FIXME: I want template but the compiler gets confused -class SHA256 final : public HashFunction<512, 256> { public: - using HashFunction::update; - - SHA256() - { - reset(); - } - - virtual void update(u8 const*, size_t) override; - - virtual DigestType digest() override; - virtual DigestType peek() override; - - static DigestType hash(u8 const* data, size_t length) + explicit SHA256(EVP_MD_CTX* context) + : OpenSSLHashFunction(EVP_sha256(), context) { - SHA256 sha; - sha.update(data, length); - return sha.digest(); } - static DigestType hash(ByteBuffer const& buffer) { return hash(buffer.data(), buffer.size()); } - static DigestType hash(StringView buffer) { return hash((u8 const*)buffer.characters_without_null_termination(), buffer.length()); } - virtual ByteString class_name() const override { - return ByteString::formatted("SHA{}", DigestSize * 8); - } - - virtual void reset() override - { - m_data_length = 0; - m_bit_length = 0; - for (size_t i = 0; i < 8; ++i) - m_state[i] = SHA256Constants::InitializationHashes[i]; + return "SHA256"; } - -private: - inline void transform(u8 const*); - - u8 m_data_buffer[BlockSize] {}; - size_t m_data_length { 0 }; - - u64 m_bit_length { 0 }; - u32 m_state[8]; - - constexpr static auto FinalBlockDataSize = BlockSize - 8; - constexpr static auto Rounds = 64; }; -class SHA384 final : public HashFunction<1024, 384> { -public: - using HashFunction::update; - - SHA384() - { - reset(); - } - - virtual void update(u8 const*, size_t) override; - - virtual DigestType digest() override; - virtual DigestType peek() override; +class SHA384 final : public OpenSSLHashFunction { + AK_MAKE_NONCOPYABLE(SHA384); - static DigestType hash(u8 const* data, size_t length) +public: + explicit SHA384(EVP_MD_CTX* context) + : OpenSSLHashFunction(EVP_sha384(), context) { - SHA384 sha; - sha.update(data, length); - return sha.digest(); } - static DigestType hash(ByteBuffer const& buffer) { return hash(buffer.data(), buffer.size()); } - static DigestType hash(StringView buffer) { return hash((u8 const*)buffer.characters_without_null_termination(), buffer.length()); } - virtual ByteString class_name() const override { - return ByteString::formatted("SHA{}", DigestSize * 8); - } - - 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]; + return "SHA384"; } - -private: - inline void transform(u8 const*); - - 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 - 16; - constexpr static auto Rounds = 80; }; -class SHA512 final : public HashFunction<1024, 512> { -public: - using HashFunction::update; - - SHA512() - { - reset(); - } - - virtual void update(u8 const*, size_t) override; +class SHA512 final : public OpenSSLHashFunction { + AK_MAKE_NONCOPYABLE(SHA512); - virtual DigestType digest() override; - virtual DigestType peek() override; - - static DigestType hash(u8 const* data, size_t length) +public: + explicit SHA512(EVP_MD_CTX* context) + : OpenSSLHashFunction(EVP_sha512(), context) { - SHA512 sha; - sha.update(data, length); - return sha.digest(); } - static DigestType hash(ByteBuffer const& buffer) { return hash(buffer.data(), buffer.size()); } - static DigestType hash(StringView buffer) { return hash((u8 const*)buffer.characters_without_null_termination(), buffer.length()); } - virtual ByteString class_name() const override { - return ByteString::formatted("SHA{}", DigestSize * 8); + return "SHA512"; } - - virtual void reset() override - { - m_data_length = 0; - m_bit_length = 0; - for (size_t i = 0; i < 8; ++i) - m_state[i] = SHA512Constants::InitializationHashes[i]; - } - -private: - inline void transform(u8 const*); - - 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 - 16; - constexpr static auto Rounds = 80; }; } diff --git a/Libraries/LibCrypto/Padding/OAEP.h b/Libraries/LibCrypto/Padding/OAEP.h index ab920abc6496..6359c164d7e4 100644 --- a/Libraries/LibCrypto/Padding/OAEP.h +++ b/Libraries/LibCrypto/Padding/OAEP.h @@ -37,9 +37,9 @@ class OAEP { auto ps = TRY(ByteBuffer::create_zeroed(padding_size)); // 4. Let pHash = Hash(P), an octet string of length hLen. - HashFunction hash; - hash.update(parameters); - auto digest = hash.digest(); + auto hash = HashFunction::create(); + hash->update(parameters); + auto digest = hash->digest(); auto p_hash = digest.bytes(); // 5. Concatenate pHash, PS, the message M, and other padding to form a data block DB as: DB = pHash || PS || 01 || M @@ -92,9 +92,9 @@ class OAEP { return Error::from_string_view("message too long"sv); // 3. If the label L is not provided, let L be the empty string. Let lHash = Hash(L), an octet string of length hLen. - HashFunction hash; - hash.update(label); - auto digest = hash.digest(); + auto hash = HashFunction::create(); + hash->update(label); + auto digest = hash->digest(); auto l_hash = digest.bytes(); // 4. Generate an octet string PS consisting of k - mLen - 2hLen - 2 zero octets. The length of PS may be zero. @@ -207,9 +207,9 @@ class OAEP { // 1. If the label L is not provided, let L be the empty string. // Let lHash = Hash(L), an octet string of length hLen (see the note in Section 7.1.1). - HashFunction hash; - hash.update(label); - auto digest = hash.digest(); + auto hash = HashFunction::create(); + hash->update(label); + auto digest = hash->digest(); auto l_hash = digest.bytes(); // 2. Separate the encoded message EM into diff --git a/Libraries/LibTLS/TLSv12.cpp b/Libraries/LibTLS/TLSv12.cpp index 63ffb656e08b..d4517d7074c0 100644 --- a/Libraries/LibTLS/TLSv12.cpp +++ b/Libraries/LibTLS/TLSv12.cpp @@ -437,15 +437,14 @@ static void hmac_pseudorandom_function(Bytes output, ReadonlyBytes secret, u8 co HMACType hmac(secret); append_label_seed(hmac); - constexpr auto digest_size = hmac.digest_size(); - u8 digest[digest_size]; - auto digest_0 = Bytes { digest, digest_size }; + auto digest_size = hmac.digest_size(); + auto digest_0 = MUST(ByteBuffer::create_uninitialized(digest_size)); digest_0.overwrite(0, hmac.digest().immutable_data(), digest_size); size_t index = 0; while (index < output.size()) { - hmac.update(digest_0); + hmac.update(digest_0.bytes()); append_label_seed(hmac); auto digest_1 = hmac.digest(); @@ -454,7 +453,7 @@ static void hmac_pseudorandom_function(Bytes output, ReadonlyBytes secret, u8 co output.overwrite(index, digest_1.immutable_data(), copy_size); index += copy_size; - digest_0.overwrite(0, hmac.process(digest_0).immutable_data(), digest_size); + digest_0.overwrite(0, hmac.process(digest_0.bytes()).immutable_data(), digest_size); } } diff --git a/Tests/LibCrypto/TestHash.cpp b/Tests/LibCrypto/TestHash.cpp index b06f1796020e..264e66e89df3 100644 --- a/Tests/LibCrypto/TestHash.cpp +++ b/Tests/LibCrypto/TestHash.cpp @@ -15,8 +15,8 @@ TEST_CASE(test_BLAKE2b_name) { - Crypto::Hash::BLAKE2b blake2b; - EXPECT_EQ(blake2b.class_name(), "BLAKE2b"sv); + auto blake2b = Crypto::Hash::BLAKE2b::create(); + EXPECT_EQ(blake2b->class_name(), "BLAKE2b"sv); } TEST_CASE(test_BLAKE2b_hash_string) @@ -42,37 +42,37 @@ TEST_CASE(test_BLAKE2b_consecutive_multiple_updates) u8 result[] { 0x9d, 0xaa, 0x2e, 0x57, 0xc4, 0x94, 0xb6, 0xfd, 0x61, 0x6e, 0x39, 0x0b, 0x71, 0xf4, 0x19, 0x03, 0x41, 0x5c, 0x5c, 0x61, 0x7e, 0x30, 0x0a, 0xf0, 0x0b, 0x3e, 0x9c, 0x77, 0x23, 0x1f, 0x11, 0x4d, 0x83, 0x9d, 0xd6, 0xe0, 0x4a, 0x92, 0x19, 0xae, 0xec, 0xc9, 0x13, 0x57, 0xc6, 0xf1, 0x06, 0x92, 0xb9, 0xf9, 0x97, 0x3e, 0xfd, 0xb3, 0x6f, 0xc8, 0xe1, 0x94, 0xad, 0x8e, 0x33, 0xc2, 0x66, 0x3f }; - Crypto::Hash::BLAKE2b blake2b; + auto blake2b = Crypto::Hash::BLAKE2b::create(); - blake2b.update("Well"sv); - blake2b.update(" hello "sv); - blake2b.update("friends"sv); - auto digest = blake2b.digest(); + blake2b->update("Well"sv); + blake2b->update(" hello "sv); + blake2b->update("friends"sv); + auto digest = blake2b->digest(); EXPECT(memcmp(result, digest.data, Crypto::Hash::BLAKE2b::digest_size()) == 0); } TEST_CASE(test_BLAKE2b_consecutive_updates_reuse) { - Crypto::Hash::BLAKE2b blake2b; + auto blake2b = Crypto::Hash::BLAKE2b::create(); - blake2b.update("Well"sv); - blake2b.update(" hello "sv); - blake2b.update("friends"sv); - auto digest0 = blake2b.digest(); + blake2b->update("Well"sv); + blake2b->update(" hello "sv); + blake2b->update("friends"sv); + auto digest0 = blake2b->digest(); - blake2b.update("Well"sv); - blake2b.update(" hello "sv); - blake2b.update("friends"sv); - auto digest1 = blake2b.digest(); + blake2b->update("Well"sv); + blake2b->update(" hello "sv); + blake2b->update("friends"sv); + auto digest1 = blake2b->digest(); EXPECT(memcmp(digest0.data, digest1.data, Crypto::Hash::BLAKE2b::digest_size()) == 0); } TEST_CASE(test_MD5_name) { - Crypto::Hash::MD5 md5; - EXPECT(md5.class_name() == "MD5"); + auto md5 = Crypto::Hash::MD5::create(); + EXPECT(md5->class_name() == "MD5"); } TEST_CASE(test_MD5_hash_string) @@ -125,37 +125,37 @@ TEST_CASE(test_MD5_consecutive_multiple_updates) u8 result[] { 0xaf, 0x04, 0x3a, 0x08, 0x94, 0x38, 0x6e, 0x7f, 0xbf, 0x73, 0xe4, 0xaa, 0xf0, 0x8e, 0xee, 0x4c }; - Crypto::Hash::MD5 md5; + auto md5 = Crypto::Hash::MD5::create(); - md5.update("Well"sv); - md5.update(" hello "sv); - md5.update("friends"sv); - auto digest = md5.digest(); + md5->update("Well"sv); + md5->update(" hello "sv); + md5->update("friends"sv); + auto digest = md5->digest(); EXPECT(memcmp(result, digest.data, Crypto::Hash::MD5::digest_size()) == 0); } TEST_CASE(test_MD5_consecutive_updates_reuse) { - Crypto::Hash::MD5 md5; + auto md5 = Crypto::Hash::MD5::create(); - md5.update("Well"sv); - md5.update(" hello "sv); - md5.update("friends"sv); - auto digest0 = md5.digest(); + md5->update("Well"sv); + md5->update(" hello "sv); + md5->update("friends"sv); + auto digest0 = md5->digest(); - md5.update("Well"sv); - md5.update(" hello "sv); - md5.update("friends"sv); - auto digest1 = md5.digest(); + md5->update("Well"sv); + md5->update(" hello "sv); + md5->update("friends"sv); + auto digest1 = md5->digest(); EXPECT(memcmp(digest0.data, digest1.data, Crypto::Hash::MD5::digest_size()) == 0); } TEST_CASE(test_SHA1_name) { - Crypto::Hash::SHA1 sha; - EXPECT(sha.class_name() == "SHA1"sv); + auto sha = Crypto::Hash::SHA1::create(); + EXPECT(sha->class_name() == "SHA1"sv); } TEST_CASE(test_SHA1_hash_empty_string) @@ -181,21 +181,21 @@ TEST_CASE(test_SHA1_hash_successive_updates) u8 result[] { 0xd6, 0x6e, 0xce, 0xd1, 0xf4, 0x08, 0xc6, 0xd8, 0x35, 0xab, 0xf0, 0xc9, 0x05, 0x26, 0xa4, 0xb2, 0xb8, 0xa3, 0x7c, 0xd3 }; - auto hasher = Crypto::Hash::SHA1 {}; - hasher.update("aaaaaaaaaaaaaaa"sv); - hasher.update("aaaaaaaaaaaaaaa"sv); - hasher.update("aaaaaaaaaaaaaaa"sv); - hasher.update("aaaaaaaaaaaaaaa"sv); - hasher.update("aaaaaaaaaaaaaaa"sv); - hasher.update("aaaaaaaaaaaaaaa"sv); - hasher.update("aaaaaaaaaaaaaaa"sv); - hasher.update("aaaaaaaaaaaaaaa"sv); - hasher.update("aaaaaaaaaaaaaaa"sv); - hasher.update("aaaaaaaaaaaaaaa"sv); - hasher.update("aaaaaaaaaaaaaaa"sv); - hasher.update("aaaaaaaaaaaaaaa"sv); - hasher.update("aaaaaaaaa"sv); - auto digest = hasher.digest(); + auto hasher = Crypto::Hash::SHA1::create(); + hasher->update("aaaaaaaaaaaaaaa"sv); + hasher->update("aaaaaaaaaaaaaaa"sv); + hasher->update("aaaaaaaaaaaaaaa"sv); + hasher->update("aaaaaaaaaaaaaaa"sv); + hasher->update("aaaaaaaaaaaaaaa"sv); + hasher->update("aaaaaaaaaaaaaaa"sv); + hasher->update("aaaaaaaaaaaaaaa"sv); + hasher->update("aaaaaaaaaaaaaaa"sv); + hasher->update("aaaaaaaaaaaaaaa"sv); + hasher->update("aaaaaaaaaaaaaaa"sv); + hasher->update("aaaaaaaaaaaaaaa"sv); + hasher->update("aaaaaaaaaaaaaaa"sv); + hasher->update("aaaaaaaaa"sv); + auto digest = hasher->digest(); EXPECT(memcmp(result, digest.data, Crypto::Hash::SHA1::digest_size()) == 0); } @@ -210,8 +210,8 @@ TEST_CASE(test_SHA1_hash_split_into_blocks) TEST_CASE(test_SHA256_name) { - Crypto::Hash::SHA256 sha; - EXPECT_EQ(sha.class_name(), "SHA256"sv); + auto sha = Crypto::Hash::SHA256::create(); + EXPECT_EQ(sha->class_name(), "SHA256"sv); } TEST_CASE(test_SHA256_hash_string) @@ -243,8 +243,8 @@ TEST_CASE(test_SHA256_hash_split_into_blocks) TEST_CASE(test_SHA384_name) { - Crypto::Hash::SHA384 sha; - EXPECT_EQ(sha.class_name(), "SHA384"sv); + auto sha = Crypto::Hash::SHA384::create(); + EXPECT_EQ(sha->class_name(), "SHA384"sv); } TEST_CASE(test_SHA384_hash_string) @@ -268,8 +268,8 @@ TEST_CASE(test_SHA384_hash_bug) TEST_CASE(test_SHA512_name) { - Crypto::Hash::SHA512 sha; - EXPECT_EQ(sha.class_name(), "SHA512"sv); + auto sha = Crypto::Hash::SHA512::create(); + EXPECT_EQ(sha->class_name(), "SHA512"sv); } TEST_CASE(test_SHA512_hash_string)