1
0
Fork 0
mirror of https://github.com/LadybirdBrowser/ladybird.git synced 2025-06-09 09:34:57 +09:00

LibCrypto: Refactor HMAC implementations with OpenSSL

This commit is contained in:
devgianlu 2025-02-23 12:10:27 +01:00 committed by Ali Mohammad Pur
parent c5d0af54d0
commit 80fe259dab
Notes: github-actions[bot] 2025-03-02 14:12:54 +00:00
7 changed files with 153 additions and 123 deletions

View file

@ -0,0 +1,69 @@
/*
* Copyright (c) 2025, Altomani Gianluca <altomanigianluca@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibCrypto/Authentication/HMAC.h>
#include <openssl/core_names.h>
#include <openssl/evp.h>
namespace Crypto::Authentication {
HMAC::HMAC(Hash::HashKind hash_kind, ReadonlyBytes key)
: m_hash_kind(hash_kind)
, m_key(key)
, m_mac(EVP_MAC_fetch(nullptr, "HMAC", nullptr))
{
reset();
}
HMAC::~HMAC()
{
EVP_MAC_free(m_mac);
EVP_MAC_CTX_free(m_ctx);
}
size_t HMAC::digest_size() const
{
return EVP_MAC_CTX_get_mac_size(m_ctx);
}
void HMAC::update(u8 const* message, size_t length)
{
if (EVP_MAC_update(m_ctx, message, length) != 1) {
VERIFY_NOT_REACHED();
}
}
ByteBuffer HMAC::digest()
{
auto buf = MUST(ByteBuffer::create_uninitialized(digest_size()));
auto size = digest_size();
if (EVP_MAC_final(m_ctx, buf.data(), &size, size) != 1) {
VERIFY_NOT_REACHED();
}
return MUST(buf.slice(0, size));
}
void HMAC::reset()
{
EVP_MAC_CTX_free(m_ctx);
m_ctx = EVP_MAC_CTX_new(m_mac);
auto hash_name = MUST(hash_kind_to_openssl_digest_name(m_hash_kind));
OSSL_PARAM params[] = {
OSSL_PARAM_utf8_string(OSSL_MAC_PARAM_DIGEST, const_cast<char*>(hash_name.characters_without_null_termination()), hash_name.length()),
OSSL_PARAM_END
};
if (EVP_MAC_init(m_ctx, m_key.data(), m_key.size(), params) != 1) {
VERIFY_NOT_REACHED();
}
}
}

View file

@ -1,5 +1,6 @@
/*
* Copyright (c) 2020, Ali Mohammad Pur <mpfard@serenityos.org>
* Copyright (c) 2025, Altomani Gianluca <altomanigianluca@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -8,110 +9,51 @@
#include <AK/ByteBuffer.h>
#include <AK/ByteString.h>
#include <AK/StringBuilder.h>
#include <AK/StringView.h>
#include <AK/Types.h>
#include <AK/Vector.h>
constexpr static auto IPAD = 0x36;
constexpr static auto OPAD = 0x5c;
#include <LibCrypto/Hash/HashManager.h>
#include <LibCrypto/OpenSSL.h>
#include <LibCrypto/OpenSSLForward.h>
namespace Crypto::Authentication {
template<typename HashT>
class HMAC {
public:
using HashType = HashT;
using TagType = typename HashType::DigestType;
explicit HMAC(Hash::HashKind hash, ReadonlyBytes key);
~HMAC();
size_t digest_size() const { return m_inner_hasher->digest_size(); }
size_t digest_size() const;
template<typename KeyBufferType, typename... Args>
HMAC(KeyBufferType key, Args... args)
: m_inner_hasher(move(HashT::create(args...)))
, m_outer_hasher(move(HashT::create(args...)))
{
derive_key(key);
reset();
}
void update(u8 const* message, size_t length);
void update(ReadonlyBytes span) { return update(span.data(), span.size()); }
void update(StringView string) { return update((u8 const*)string.characters_without_null_termination(), string.length()); }
TagType process(u8 const* message, size_t length)
ByteBuffer process(u8 const* message, size_t length)
{
reset();
update(message, length);
return digest();
}
ByteBuffer process(ReadonlyBytes span) { return process(span.data(), span.size()); }
ByteBuffer process(StringView string) { return process((u8 const*)string.characters_without_null_termination(), string.length()); }
void update(u8 const* message, size_t length)
{
m_inner_hasher->update(message, length);
}
ByteBuffer digest();
TagType process(ReadonlyBytes span) { return process(span.data(), span.size()); }
TagType process(StringView string) { return process((u8 const*)string.characters_without_null_termination(), string.length()); }
void update(ReadonlyBytes span) { return update(span.data(), span.size()); }
void update(StringView string) { return update((u8 const*)string.characters_without_null_termination(), string.length()); }
TagType 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());
}
void reset();
ByteString class_name() const
{
auto hash_name = MUST(hash_kind_to_openssl_digest_name(m_hash_kind));
StringBuilder builder;
builder.append("HMAC-"sv);
builder.append(m_inner_hasher->class_name());
builder.append(hash_name);
return builder.to_byte_string();
}
private:
void derive_key(u8 const* key, size_t length)
{
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);
auto key_buffer = v_key.span();
// m_key_data is zero'd, so copying the data in
// 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();
// 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());
} else if (length > 0) {
key_buffer.overwrite(0, key, length);
}
// fill out the inner and outer padded keys
auto* i_key = m_key_data;
auto* o_key = m_key_data + block_size;
for (size_t i = 0; i < block_size; ++i) {
auto key_byte = key_buffer[i];
i_key[i] = key_byte ^ IPAD;
o_key[i] = key_byte ^ OPAD;
}
}
void derive_key(ReadonlyBytes key) { derive_key(key.data(), key.size()); }
void derive_key(StringView key) { derive_key(key.bytes()); }
NonnullOwnPtr<HashType> m_inner_hasher, m_outer_hasher;
u8 m_key_data[2048];
Hash::HashKind m_hash_kind;
ReadonlyBytes m_key;
EVP_MAC* m_mac { nullptr };
EVP_MAC_CTX* m_ctx { nullptr };
};
}