|
1 | 1 | /* |
2 | 2 | * Copyright (c) 2020, Ali Mohammad Pur <[email protected]> |
| 3 | + * Copyright (c) 2025, Altomani Gianluca <[email protected]> |
3 | 4 | * |
4 | 5 | * SPDX-License-Identifier: BSD-2-Clause |
5 | 6 | */ |
|
8 | 9 |
|
9 | 10 | #include <AK/ByteBuffer.h> |
10 | 11 | #include <AK/ByteString.h> |
11 | | -#include <AK/StringBuilder.h> |
12 | | -#include <AK/StringView.h> |
13 | | -#include <AK/Types.h> |
14 | | -#include <AK/Vector.h> |
15 | | - |
16 | | -constexpr static auto IPAD = 0x36; |
17 | | -constexpr static auto OPAD = 0x5c; |
| 12 | +#include <LibCrypto/Hash/HashManager.h> |
| 13 | +#include <LibCrypto/OpenSSL.h> |
| 14 | +#include <LibCrypto/OpenSSLForward.h> |
18 | 15 |
|
19 | 16 | namespace Crypto::Authentication { |
20 | 17 |
|
21 | | -template<typename HashT> |
22 | 18 | class HMAC { |
23 | 19 | public: |
24 | | - using HashType = HashT; |
25 | | - using TagType = typename HashType::DigestType; |
| 20 | + explicit HMAC(Hash::HashKind hash, ReadonlyBytes key); |
| 21 | + ~HMAC(); |
26 | 22 |
|
27 | | - size_t digest_size() const { return m_inner_hasher->digest_size(); } |
| 23 | + size_t digest_size() const; |
28 | 24 |
|
29 | | - template<typename KeyBufferType, typename... Args> |
30 | | - HMAC(KeyBufferType key, Args... args) |
31 | | - : m_inner_hasher(move(HashT::create(args...))) |
32 | | - , m_outer_hasher(move(HashT::create(args...))) |
33 | | - { |
34 | | - derive_key(key); |
35 | | - reset(); |
36 | | - } |
| 25 | + void update(u8 const* message, size_t length); |
| 26 | + void update(ReadonlyBytes span) { return update(span.data(), span.size()); } |
| 27 | + void update(StringView string) { return update((u8 const*)string.characters_without_null_termination(), string.length()); } |
37 | 28 |
|
38 | | - TagType process(u8 const* message, size_t length) |
| 29 | + ByteBuffer process(u8 const* message, size_t length) |
39 | 30 | { |
40 | 31 | reset(); |
41 | 32 | update(message, length); |
42 | 33 | return digest(); |
43 | 34 | } |
| 35 | + ByteBuffer process(ReadonlyBytes span) { return process(span.data(), span.size()); } |
| 36 | + ByteBuffer process(StringView string) { return process((u8 const*)string.characters_without_null_termination(), string.length()); } |
44 | 37 |
|
45 | | - void update(u8 const* message, size_t length) |
46 | | - { |
47 | | - m_inner_hasher->update(message, length); |
48 | | - } |
49 | | - |
50 | | - TagType process(ReadonlyBytes span) { return process(span.data(), span.size()); } |
51 | | - TagType process(StringView string) { return process((u8 const*)string.characters_without_null_termination(), string.length()); } |
52 | | - |
53 | | - void update(ReadonlyBytes span) { return update(span.data(), span.size()); } |
54 | | - void update(StringView string) { return update((u8 const*)string.characters_without_null_termination(), string.length()); } |
55 | | - |
56 | | - TagType digest() |
57 | | - { |
58 | | - m_outer_hasher->update(m_inner_hasher->digest().immutable_data(), m_inner_hasher->digest_size()); |
59 | | - auto result = m_outer_hasher->digest(); |
60 | | - reset(); |
61 | | - return result; |
62 | | - } |
| 38 | + ByteBuffer digest(); |
63 | 39 |
|
64 | | - void reset() |
65 | | - { |
66 | | - m_inner_hasher->reset(); |
67 | | - m_outer_hasher->reset(); |
68 | | - m_inner_hasher->update(m_key_data, m_inner_hasher->block_size()); |
69 | | - m_outer_hasher->update(m_key_data + m_inner_hasher->block_size(), m_outer_hasher->block_size()); |
70 | | - } |
| 40 | + void reset(); |
71 | 41 |
|
72 | 42 | ByteString class_name() const |
73 | 43 | { |
| 44 | + auto hash_name = MUST(hash_kind_to_openssl_digest_name(m_hash_kind)); |
| 45 | + |
74 | 46 | StringBuilder builder; |
75 | 47 | builder.append("HMAC-"sv); |
76 | | - builder.append(m_inner_hasher->class_name()); |
| 48 | + builder.append(hash_name); |
77 | 49 | return builder.to_byte_string(); |
78 | 50 | } |
79 | 51 |
|
80 | 52 | private: |
81 | | - void derive_key(u8 const* key, size_t length) |
82 | | - { |
83 | | - auto block_size = m_inner_hasher->block_size(); |
84 | | - // Note: The block size of all the current hash functions is 512 bits. |
85 | | - Vector<u8, 64> v_key; |
86 | | - v_key.resize(block_size); |
87 | | - auto key_buffer = v_key.span(); |
88 | | - // m_key_data is zero'd, so copying the data in |
89 | | - // the first few bytes leaves the rest zero, which |
90 | | - // is exactly what we want (zero padding) |
91 | | - if (length > block_size) { |
92 | | - m_inner_hasher->update(key, length); |
93 | | - auto digest = m_inner_hasher->digest(); |
94 | | - // FIXME: should we check if the hash function creates more data than its block size? |
95 | | - key_buffer.overwrite(0, digest.immutable_data(), m_inner_hasher->digest_size()); |
96 | | - } else if (length > 0) { |
97 | | - key_buffer.overwrite(0, key, length); |
98 | | - } |
99 | | - |
100 | | - // fill out the inner and outer padded keys |
101 | | - auto* i_key = m_key_data; |
102 | | - auto* o_key = m_key_data + block_size; |
103 | | - for (size_t i = 0; i < block_size; ++i) { |
104 | | - auto key_byte = key_buffer[i]; |
105 | | - i_key[i] = key_byte ^ IPAD; |
106 | | - o_key[i] = key_byte ^ OPAD; |
107 | | - } |
108 | | - } |
109 | | - |
110 | | - void derive_key(ReadonlyBytes key) { derive_key(key.data(), key.size()); } |
111 | | - void derive_key(StringView key) { derive_key(key.bytes()); } |
112 | | - |
113 | | - NonnullOwnPtr<HashType> m_inner_hasher, m_outer_hasher; |
114 | | - u8 m_key_data[2048]; |
| 53 | + Hash::HashKind m_hash_kind; |
| 54 | + ReadonlyBytes m_key; |
| 55 | + EVP_MAC* m_mac { nullptr }; |
| 56 | + EVP_MAC_CTX* m_ctx { nullptr }; |
115 | 57 | }; |
116 | 58 |
|
117 | 59 | } |
0 commit comments