Coverage Report

Created: 2025-11-16 07:46

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