Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LibCrypto: Replace hashes implementation with OpenSSL #2989

Merged
merged 3 commits into from
Dec 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 16 additions & 16 deletions Libraries/LibCrypto/Authentication/HMAC.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<typename KeyBufferType, typename... Args>
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();
Expand All @@ -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()); }
Expand All @@ -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<u8, 64> v_key;
v_key.resize(block_size);
Expand All @@ -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);
}
Expand All @@ -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<HashType> m_inner_hasher, m_outer_hasher;
u8 m_key_data[2048];
};

Expand Down
7 changes: 3 additions & 4 deletions Libraries/LibCrypto/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,13 @@ set(SOURCES
Curves/Ed25519.cpp
Curves/X25519.cpp
Curves/X448.cpp
Hash/BLAKE2b.cpp
Hash/MD5.cpp
Hash/SHA1.cpp
Hash/SHA2.cpp
ADKaster marked this conversation as resolved.
Show resolved Hide resolved
NumberTheory/ModularFunctions.cpp
PK/RSA.cpp
PK/EC.cpp
)

serenity_lib(LibCrypto crypto)
target_link_libraries(LibCrypto PRIVATE LibCore)

find_package(OpenSSL REQUIRED)
target_link_libraries(LibCrypto PUBLIC OpenSSL::Crypto)
26 changes: 13 additions & 13 deletions Libraries/LibCrypto/Curves/Ed25519.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,15 @@ ErrorOr<ByteBuffer> 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.
Expand All @@ -100,13 +100,13 @@ ErrorOr<ByteBuffer> 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);

Expand Down Expand Up @@ -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'.
Expand Down
126 changes: 0 additions & 126 deletions Libraries/LibCrypto/Hash/BLAKE2b.cpp

This file was deleted.

69 changes: 5 additions & 64 deletions Libraries/LibCrypto/Hash/BLAKE2b.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,82 +7,23 @@
#pragma once

#include <AK/ByteString.h>
#include <LibCrypto/Hash/HashFunction.h>
#include <LibCrypto/Hash/SHA2.h>
#include <LibCrypto/Hash/OpenSSLHashFunction.h>

namespace Crypto::Hash {

namespace BLAKE2bConstants {
static constexpr auto blockbytes { 128 };
static constexpr auto hash_length { 64 };
};
class BLAKE2b final : public OpenSSLHashFunction<BLAKE2b, 1024, 512> {
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*);
};

};
Loading
Loading