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
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) 2020, Ali Mohammad Pur <mpfard@serenityos.org>
* Copyright (c) 2025, Altomani Gianluca <altomanigianluca@gmail.com>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
@ -8,110 +9,51 @@
#include <AK/ByteBuffer.h> #include <AK/ByteBuffer.h>
#include <AK/ByteString.h> #include <AK/ByteString.h>
#include <AK/StringBuilder.h> #include <LibCrypto/Hash/HashManager.h>
#include <AK/StringView.h> #include <LibCrypto/OpenSSL.h>
#include <AK/Types.h> #include <LibCrypto/OpenSSLForward.h>
#include <AK/Vector.h>
constexpr static auto IPAD = 0x36;
constexpr static auto OPAD = 0x5c;
namespace Crypto::Authentication { namespace Crypto::Authentication {
template<typename HashT>
class HMAC { class HMAC {
public: public:
using HashType = HashT; explicit HMAC(Hash::HashKind hash, ReadonlyBytes key);
using TagType = typename HashType::DigestType; ~HMAC();
size_t digest_size() const { return m_inner_hasher->digest_size(); } size_t digest_size() const;
template<typename KeyBufferType, typename... Args> void update(u8 const* message, size_t length);
HMAC(KeyBufferType key, Args... args) void update(ReadonlyBytes span) { return update(span.data(), span.size()); }
: m_inner_hasher(move(HashT::create(args...))) void update(StringView string) { return update((u8 const*)string.characters_without_null_termination(), string.length()); }
, m_outer_hasher(move(HashT::create(args...)))
{
derive_key(key);
reset();
}
TagType process(u8 const* message, size_t length) ByteBuffer process(u8 const* message, size_t length)
{ {
reset(); reset();
update(message, length); update(message, length);
return digest(); 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) ByteBuffer digest();
{
m_inner_hasher->update(message, length);
}
TagType process(ReadonlyBytes span) { return process(span.data(), span.size()); } void reset();
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());
}
ByteString class_name() const ByteString class_name() const
{ {
auto hash_name = MUST(hash_kind_to_openssl_digest_name(m_hash_kind));
StringBuilder builder; StringBuilder builder;
builder.append("HMAC-"sv); builder.append("HMAC-"sv);
builder.append(m_inner_hasher->class_name()); builder.append(hash_name);
return builder.to_byte_string(); return builder.to_byte_string();
} }
private: private:
void derive_key(u8 const* key, size_t length) Hash::HashKind m_hash_kind;
{ ReadonlyBytes m_key;
auto block_size = m_inner_hasher->block_size(); EVP_MAC* m_mac { nullptr };
// Note: The block size of all the current hash functions is 512 bits. EVP_MAC_CTX* m_ctx { nullptr };
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];
}; };
} }

View file

@ -6,6 +6,7 @@ set(SOURCES
ASN1/DER.cpp ASN1/DER.cpp
ASN1/PEM.cpp ASN1/PEM.cpp
Authentication/GHash.cpp Authentication/GHash.cpp
Authentication/HMAC.cpp
BigFraction/BigFraction.cpp BigFraction/BigFraction.cpp
BigInt/Algorithms/BitwiseOperations.cpp BigInt/Algorithms/BitwiseOperations.cpp
BigInt/Algorithms/Division.cpp BigInt/Algorithms/Division.cpp

View file

@ -47,6 +47,8 @@ ErrorOr<UnsignedBigInteger> openssl_bignum_to_unsigned_big_integer(OpenSSL_BN co
ErrorOr<StringView> hash_kind_to_openssl_digest_name(Hash::HashKind hash) ErrorOr<StringView> hash_kind_to_openssl_digest_name(Hash::HashKind hash)
{ {
switch (hash) { switch (hash) {
case Hash::HashKind::MD5:
return "MD5"sv;
case Hash::HashKind::SHA1: case Hash::HashKind::SHA1:
return "SHA1"sv; return "SHA1"sv;
case Hash::HashKind::SHA256: case Hash::HashKind::SHA256:

View file

@ -15,6 +15,8 @@ typedef struct evp_pkey_st EVP_PKEY;
typedef struct evp_pkey_ctx_st EVP_PKEY_CTX; typedef struct evp_pkey_ctx_st EVP_PKEY_CTX;
typedef struct evp_kdf_st EVP_KDF; typedef struct evp_kdf_st EVP_KDF;
typedef struct evp_kdf_ctx_st EVP_KDF_CTX; typedef struct evp_kdf_ctx_st EVP_KDF_CTX;
typedef struct evp_mac_st EVP_MAC;
typedef struct evp_mac_ctx_st EVP_MAC_CTX;
void ERR_print_errors_cb(int (*cb)(char const* str, size_t len, void* u), void* u); void ERR_print_errors_cb(int (*cb)(char const* str, size_t len, void* u), void* u);

View file

@ -7781,21 +7781,21 @@ WebIDL::ExceptionOr<GC::Ref<CryptoKey>> X448::import_key(
static WebIDL::ExceptionOr<ByteBuffer> hmac_calculate_message_digest(JS::Realm& realm, GC::Ptr<KeyAlgorithm> hash, ReadonlyBytes key, ReadonlyBytes message) static WebIDL::ExceptionOr<ByteBuffer> hmac_calculate_message_digest(JS::Realm& realm, GC::Ptr<KeyAlgorithm> hash, ReadonlyBytes key, ReadonlyBytes message)
{ {
auto calculate_digest = [&]<typename T>() -> ByteBuffer {
::Crypto::Authentication::HMAC<T> hmac(key);
auto digest = hmac.process(message);
return MUST(ByteBuffer::copy(digest.bytes()));
};
auto hash_name = hash->name(); auto hash_name = hash->name();
if (hash_name == "SHA-1") auto hash_kind = TRY([&] -> WebIDL::ExceptionOr<::Crypto::Hash::HashKind> {
return calculate_digest.operator()<::Crypto::Hash::SHA1>(); if (hash_name == "SHA-1")
if (hash_name == "SHA-256") return ::Crypto::Hash::HashKind::SHA1;
return calculate_digest.operator()<::Crypto::Hash::SHA256>(); if (hash_name == "SHA-256")
if (hash_name == "SHA-384") return ::Crypto::Hash::HashKind::SHA256;
return calculate_digest.operator()<::Crypto::Hash::SHA384>(); if (hash_name == "SHA-384")
if (hash_name == "SHA-512") return ::Crypto::Hash::HashKind::SHA384;
return calculate_digest.operator()<::Crypto::Hash::SHA512>(); if (hash_name == "SHA-512")
return WebIDL::NotSupportedError::create(realm, "Invalid algorithm"_string); return ::Crypto::Hash::HashKind::SHA512;
return WebIDL::NotSupportedError::create(realm, MUST(String::formatted("Invalid hash function '{}'", hash_name)));
}());
::Crypto::Authentication::HMAC hmac(hash_kind, key);
return hmac.process(message);
} }
static WebIDL::ExceptionOr<WebIDL::UnsignedLong> hmac_hash_block_size(JS::Realm& realm, HashAlgorithmIdentifier hash) static WebIDL::ExceptionOr<WebIDL::UnsignedLong> hmac_hash_block_size(JS::Realm& realm, HashAlgorithmIdentifier hash)

View file

@ -1,52 +1,58 @@
/* /*
* Copyright (c) 2021, [your name here] <[your email here]> * Copyright (c) 2021, the Ladybird developers.
* Copyright (c) 2025, Altomani Gianluca <altomanigianluca@gmail.com>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
#include <LibCrypto/Authentication/HMAC.h> #include <LibCrypto/Authentication/HMAC.h>
#include <LibCrypto/Hash/MD5.h>
#include <LibCrypto/Hash/SHA1.h>
#include <LibCrypto/Hash/SHA2.h>
#include <LibTest/TestCase.h> #include <LibTest/TestCase.h>
#include <cstring>
static ByteBuffer operator""_b(char const* string, size_t length)
{
return MUST(ByteBuffer::copy(string, length));
}
TEST_CASE(test_hmac_md5_name) TEST_CASE(test_hmac_md5_name)
{ {
Crypto::Authentication::HMAC<Crypto::Hash::MD5> hmac("Well Hello Friends"sv); auto key = "Well Hello Friends"_b;
Crypto::Authentication::HMAC hmac(Crypto::Hash::HashKind::MD5, key);
EXPECT_EQ(hmac.class_name(), "HMAC-MD5"sv); EXPECT_EQ(hmac.class_name(), "HMAC-MD5"sv);
} }
TEST_CASE(test_hmac_md5_process) TEST_CASE(test_hmac_md5_process)
{ {
Crypto::Authentication::HMAC<Crypto::Hash::MD5> hmac("Well Hello Friends"sv); auto key = "Well Hello Friends"_b;
Crypto::Authentication::HMAC hmac(Crypto::Hash::HashKind::MD5, key);
u8 result[] { u8 result[] {
0x3b, 0x5b, 0xde, 0x30, 0x3a, 0x54, 0x7b, 0xbb, 0x09, 0xfe, 0x78, 0x89, 0xbc, 0x9f, 0x22, 0xa3 0x3b, 0x5b, 0xde, 0x30, 0x3a, 0x54, 0x7b, 0xbb, 0x09, 0xfe, 0x78, 0x89, 0xbc, 0x9f, 0x22, 0xa3
}; };
auto mac = hmac.process("Some bogus data"sv); auto mac = hmac.process("Some bogus data"sv);
EXPECT(memcmp(result, mac.data, hmac.digest_size()) == 0); EXPECT(memcmp(result, mac.data(), hmac.digest_size()) == 0);
} }
TEST_CASE(test_hmac_md5_process_reuse) TEST_CASE(test_hmac_md5_process_reuse)
{ {
Crypto::Authentication::HMAC<Crypto::Hash::MD5> hmac("Well Hello Friends"sv); auto key = "Well Hello Friends"_b;
Crypto::Authentication::HMAC hmac(Crypto::Hash::HashKind::MD5, key);
auto mac_0 = hmac.process("Some bogus data"sv); auto mac_0 = hmac.process("Some bogus data"sv);
auto mac_1 = hmac.process("Some bogus data"sv); auto mac_1 = hmac.process("Some bogus data"sv);
EXPECT(memcmp(mac_0.data, mac_1.data, hmac.digest_size()) == 0); EXPECT(memcmp(mac_0.data(), mac_1.data(), hmac.digest_size()) == 0);
} }
TEST_CASE(test_hmac_sha1_name) TEST_CASE(test_hmac_sha1_name)
{ {
Crypto::Authentication::HMAC<Crypto::Hash::SHA1> hmac("Well Hello Friends"sv); auto key = "Well Hello Friends"_b;
Crypto::Authentication::HMAC hmac(Crypto::Hash::HashKind::SHA1, key);
EXPECT_EQ(hmac.class_name(), "HMAC-SHA1"sv); EXPECT_EQ(hmac.class_name(), "HMAC-SHA1"sv);
} }
TEST_CASE(test_hmac_sha1_process) TEST_CASE(test_hmac_sha1_process)
{ {
u8 key[] { 0xc8, 0x52, 0xe5, 0x4a, 0x2c, 0x03, 0x2b, 0xc9, 0x63, 0xd3, 0xc2, 0x79, 0x0f, 0x76, 0x43, 0xef, 0x36, 0xc3, 0x7a, 0xca }; u8 key[] { 0xc8, 0x52, 0xe5, 0x4a, 0x2c, 0x03, 0x2b, 0xc9, 0x63, 0xd3, 0xc2, 0x79, 0x0f, 0x76, 0x43, 0xef, 0x36, 0xc3, 0x7a, 0xca };
Crypto::Authentication::HMAC<Crypto::Hash::SHA1> hmac(ReadonlyBytes { key, sizeof(key) }); Crypto::Authentication::HMAC hmac(Crypto::Hash::HashKind::SHA1, ReadonlyBytes { key, sizeof(key) });
u8 result[] { u8 result[] {
0x2c, 0x57, 0x32, 0x61, 0x3b, 0xa7, 0x84, 0x87, 0x0e, 0x4f, 0x42, 0x07, 0x2f, 0xf0, 0xe7, 0x41, 0xd7, 0x15, 0xf4, 0x56 0x2c, 0x57, 0x32, 0x61, 0x3b, 0xa7, 0x84, 0x87, 0x0e, 0x4f, 0x42, 0x07, 0x2f, 0xf0, 0xe7, 0x41, 0xd7, 0x15, 0xf4, 0x56
}; };
@ -54,13 +60,13 @@ TEST_CASE(test_hmac_sha1_process)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x03, 0x03, 0x00, 0x10, 0x14, 0x00, 0x00, 0x0c, 0xa1, 0x91, 0x1a, 0x20, 0x59, 0xb5, 0x45, 0xa9, 0xb4, 0xad, 0x75, 0x3e 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x03, 0x03, 0x00, 0x10, 0x14, 0x00, 0x00, 0x0c, 0xa1, 0x91, 0x1a, 0x20, 0x59, 0xb5, 0x45, 0xa9, 0xb4, 0xad, 0x75, 0x3e
}; };
auto mac = hmac.process(value, 29); auto mac = hmac.process(value, 29);
EXPECT(memcmp(result, mac.data, hmac.digest_size()) == 0); EXPECT(memcmp(result, mac.data(), hmac.digest_size()) == 0);
} }
TEST_CASE(test_hmac_sha1_process_reuse) TEST_CASE(test_hmac_sha1_process_reuse)
{ {
u8 key[] { 0xc8, 0x52, 0xe5, 0x4a, 0x2c, 0x03, 0x2b, 0xc9, 0x63, 0xd3, 0xc2, 0x79, 0x0f, 0x76, 0x43, 0xef, 0x36, 0xc3, 0x7a, 0xca }; u8 key[] { 0xc8, 0x52, 0xe5, 0x4a, 0x2c, 0x03, 0x2b, 0xc9, 0x63, 0xd3, 0xc2, 0x79, 0x0f, 0x76, 0x43, 0xef, 0x36, 0xc3, 0x7a, 0xca };
Crypto::Authentication::HMAC<Crypto::Hash::SHA1> hmac(ReadonlyBytes { key, sizeof(key) }); Crypto::Authentication::HMAC hmac(Crypto::Hash::HashKind::SHA1, ReadonlyBytes { key, sizeof(key) });
u8 result[] { u8 result[] {
0x2c, 0x57, 0x32, 0x61, 0x3b, 0xa7, 0x84, 0x87, 0x0e, 0x4f, 0x42, 0x07, 0x2f, 0xf0, 0xe7, 0x41, 0xd7, 0x15, 0xf4, 0x56 0x2c, 0x57, 0x32, 0x61, 0x3b, 0xa7, 0x84, 0x87, 0x0e, 0x4f, 0x42, 0x07, 0x2f, 0xf0, 0xe7, 0x41, 0xd7, 0x15, 0xf4, 0x56
}; };
@ -71,77 +77,85 @@ TEST_CASE(test_hmac_sha1_process_reuse)
hmac.update(value + 8, 5); hmac.update(value + 8, 5);
hmac.update(value + 13, 16); hmac.update(value + 13, 16);
auto mac = hmac.digest(); auto mac = hmac.digest();
EXPECT(memcmp(result, mac.data, hmac.digest_size()) == 0); EXPECT(memcmp(result, mac.data(), hmac.digest_size()) == 0);
} }
TEST_CASE(test_hmac_sha256_name) TEST_CASE(test_hmac_sha256_name)
{ {
Crypto::Authentication::HMAC<Crypto::Hash::SHA256> hmac("Well Hello Friends"sv); auto key = "Well Hello Friends"_b;
Crypto::Authentication::HMAC hmac(Crypto::Hash::HashKind::SHA256, key);
EXPECT_EQ(hmac.class_name(), "HMAC-SHA256"sv); EXPECT_EQ(hmac.class_name(), "HMAC-SHA256"sv);
} }
TEST_CASE(test_hmac_sha256_process) TEST_CASE(test_hmac_sha256_process)
{ {
Crypto::Authentication::HMAC<Crypto::Hash::SHA256> hmac("Well Hello Friends"sv); auto key = "Well Hello Friends"_b;
Crypto::Authentication::HMAC hmac(Crypto::Hash::HashKind::SHA256, key);
u8 result[] { u8 result[] {
0x1a, 0xf2, 0x20, 0x62, 0xde, 0x3b, 0x84, 0x65, 0xc1, 0x25, 0x23, 0x99, 0x76, 0x15, 0x1b, 0xec, 0x15, 0x21, 0x82, 0x1f, 0x23, 0xca, 0x11, 0x66, 0xdd, 0x8c, 0x6e, 0xf1, 0x81, 0x3b, 0x7f, 0x1b 0x1a, 0xf2, 0x20, 0x62, 0xde, 0x3b, 0x84, 0x65, 0xc1, 0x25, 0x23, 0x99, 0x76, 0x15, 0x1b, 0xec, 0x15, 0x21, 0x82, 0x1f, 0x23, 0xca, 0x11, 0x66, 0xdd, 0x8c, 0x6e, 0xf1, 0x81, 0x3b, 0x7f, 0x1b
}; };
auto mac = hmac.process("Some bogus data"sv); auto mac = hmac.process("Some bogus data"sv);
EXPECT(memcmp(result, mac.data, hmac.digest_size()) == 0); EXPECT(memcmp(result, mac.data(), hmac.digest_size()) == 0);
} }
TEST_CASE(test_hmac_sha256_reuse) TEST_CASE(test_hmac_sha256_reuse)
{ {
Crypto::Authentication::HMAC<Crypto::Hash::SHA256> hmac("Well Hello Friends"sv); auto key = "Well Hello Friends"_b;
Crypto::Authentication::HMAC hmac(Crypto::Hash::HashKind::SHA256, key);
auto mac_0 = hmac.process("Some bogus data"sv); auto mac_0 = hmac.process("Some bogus data"sv);
auto mac_1 = hmac.process("Some bogus data"sv); auto mac_1 = hmac.process("Some bogus data"sv);
EXPECT(memcmp(mac_0.data, mac_1.data, hmac.digest_size()) == 0); EXPECT(memcmp(mac_0.data(), mac_1.data(), hmac.digest_size()) == 0);
} }
TEST_CASE(test_hmac_sha256_data_is_same_size_as_block) TEST_CASE(test_hmac_sha256_data_is_same_size_as_block)
{ {
Crypto::Authentication::HMAC<Crypto::Hash::SHA256> hmac("Well Hello Friends"sv); auto key = "Well Hello Friends"_b;
Crypto::Authentication::HMAC hmac(Crypto::Hash::HashKind::SHA256, key);
u8 result[] = { u8 result[] = {
0x1d, 0x90, 0xce, 0x68, 0x45, 0x0b, 0xba, 0xd6, 0xbe, 0x1c, 0xb2, 0x3a, 0xea, 0x7f, 0xac, 0x4b, 0x68, 0x08, 0xa4, 0x77, 0x81, 0x2a, 0xad, 0x5d, 0x05, 0xe2, 0x15, 0xe8, 0xf4, 0xcb, 0x06, 0xaf 0x1d, 0x90, 0xce, 0x68, 0x45, 0x0b, 0xba, 0xd6, 0xbe, 0x1c, 0xb2, 0x3a, 0xea, 0x7f, 0xac, 0x4b, 0x68, 0x08, 0xa4, 0x77, 0x81, 0x2a, 0xad, 0x5d, 0x05, 0xe2, 0x15, 0xe8, 0xf4, 0xcb, 0x06, 0xaf
}; };
auto mac = hmac.process("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"sv); auto mac = hmac.process("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"sv);
EXPECT(memcmp(result, mac.data, hmac.digest_size()) == 0); EXPECT(memcmp(result, mac.data(), hmac.digest_size()) == 0);
} }
TEST_CASE(test_hmac_sha256_data_is_bigger_size_as_block) TEST_CASE(test_hmac_sha256_data_is_bigger_size_as_block)
{ {
Crypto::Authentication::HMAC<Crypto::Hash::SHA256> hmac("Well Hello Friends"sv); auto key = "Well Hello Friends"_b;
Crypto::Authentication::HMAC hmac(Crypto::Hash::HashKind::SHA256, key);
u8 result[] = { u8 result[] = {
0x9b, 0xa3, 0x9e, 0xf3, 0xb4, 0x30, 0x5f, 0x6f, 0x67, 0xd0, 0xa8, 0xb0, 0xf0, 0xcb, 0x12, 0xf5, 0x85, 0xe2, 0x19, 0xba, 0x0c, 0x8b, 0xe5, 0x43, 0xf0, 0x93, 0x39, 0xa8, 0xa3, 0x07, 0xf1, 0x95 0x9b, 0xa3, 0x9e, 0xf3, 0xb4, 0x30, 0x5f, 0x6f, 0x67, 0xd0, 0xa8, 0xb0, 0xf0, 0xcb, 0x12, 0xf5, 0x85, 0xe2, 0x19, 0xba, 0x0c, 0x8b, 0xe5, 0x43, 0xf0, 0x93, 0x39, 0xa8, 0xa3, 0x07, 0xf1, 0x95
}; };
auto mac = hmac.process("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"sv); auto mac = hmac.process("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"sv);
EXPECT(memcmp(result, mac.data, hmac.digest_size()) == 0); EXPECT(memcmp(result, mac.data(), hmac.digest_size()) == 0);
} }
TEST_CASE(test_hmac_sha512_name) TEST_CASE(test_hmac_sha512_name)
{ {
Crypto::Authentication::HMAC<Crypto::Hash::SHA512> hmac("Well Hello Friends"sv); auto key = "Well Hello Friends"_b;
Crypto::Authentication::HMAC hmac(Crypto::Hash::HashKind::SHA512, key);
EXPECT_EQ(hmac.class_name(), "HMAC-SHA512"); EXPECT_EQ(hmac.class_name(), "HMAC-SHA512");
} }
TEST_CASE(test_hmac_sha512_process) TEST_CASE(test_hmac_sha512_process)
{ {
Crypto::Authentication::HMAC<Crypto::Hash::SHA512> hmac("Well Hello Friends"sv); auto key = "Well Hello Friends"_b;
Crypto::Authentication::HMAC hmac(Crypto::Hash::HashKind::SHA512, key);
u8 result[] { u8 result[] {
0xeb, 0xa8, 0x34, 0x11, 0xfd, 0x5b, 0x46, 0x5b, 0xef, 0xbb, 0x67, 0x5e, 0x7d, 0xc2, 0x7c, 0x2c, 0x6b, 0xe1, 0xcf, 0xe6, 0xc7, 0xe4, 0x7d, 0xeb, 0xca, 0x97, 0xb7, 0x4c, 0xd3, 0x4d, 0x6f, 0x08, 0x9f, 0x0d, 0x3a, 0xf1, 0xcb, 0x00, 0x79, 0x78, 0x2f, 0x05, 0x8e, 0xeb, 0x94, 0x48, 0x0d, 0x50, 0x64, 0x3b, 0xca, 0x70, 0xe2, 0x69, 0x38, 0x4f, 0xe4, 0xb0, 0x49, 0x0f, 0xc5, 0x4c, 0x7a, 0xa7 0xeb, 0xa8, 0x34, 0x11, 0xfd, 0x5b, 0x46, 0x5b, 0xef, 0xbb, 0x67, 0x5e, 0x7d, 0xc2, 0x7c, 0x2c, 0x6b, 0xe1, 0xcf, 0xe6, 0xc7, 0xe4, 0x7d, 0xeb, 0xca, 0x97, 0xb7, 0x4c, 0xd3, 0x4d, 0x6f, 0x08, 0x9f, 0x0d, 0x3a, 0xf1, 0xcb, 0x00, 0x79, 0x78, 0x2f, 0x05, 0x8e, 0xeb, 0x94, 0x48, 0x0d, 0x50, 0x64, 0x3b, 0xca, 0x70, 0xe2, 0x69, 0x38, 0x4f, 0xe4, 0xb0, 0x49, 0x0f, 0xc5, 0x4c, 0x7a, 0xa7
}; };
auto mac = hmac.process("Some bogus data"sv); auto mac = hmac.process("Some bogus data"sv);
EXPECT(memcmp(result, mac.data, hmac.digest_size()) == 0); EXPECT(memcmp(result, mac.data(), hmac.digest_size()) == 0);
} }
TEST_CASE(test_hmac_sha512_reuse) TEST_CASE(test_hmac_sha512_reuse)
{ {
Crypto::Authentication::HMAC<Crypto::Hash::SHA512> hmac("Well Hello Friends"sv); auto key = "Well Hello Friends"_b;
Crypto::Authentication::HMAC hmac(Crypto::Hash::HashKind::SHA512, key);
auto mac_0 = hmac.process("Some bogus data"sv); auto mac_0 = hmac.process("Some bogus data"sv);
auto mac_1 = hmac.process("Some bogus data"sv); auto mac_1 = hmac.process("Some bogus data"sv);
EXPECT(memcmp(mac_0.data, mac_1.data, hmac.digest_size()) == 0); EXPECT(memcmp(mac_0.data(), mac_1.data(), hmac.digest_size()) == 0);
} }