Coverage Report

Created: 2026-05-16 07:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/serenity/Userland/Libraries/LibCrypto/Hash/HashManager.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/Optional.h>
10
#include <AK/OwnPtr.h>
11
#include <AK/Variant.h>
12
#include <LibCrypto/Hash/BLAKE2b.h>
13
#include <LibCrypto/Hash/HashFunction.h>
14
#include <LibCrypto/Hash/MD5.h>
15
#include <LibCrypto/Hash/SHA1.h>
16
#include <LibCrypto/Hash/SHA2.h>
17
18
namespace Crypto::Hash {
19
20
enum class HashKind {
21
    Unknown,
22
    None,
23
    BLAKE2b,
24
    MD5,
25
    SHA1,
26
    SHA256,
27
    SHA384,
28
    SHA512,
29
};
30
31
struct MultiHashDigestVariant {
32
    constexpr static size_t Size = 0;
33
34
    MultiHashDigestVariant(Empty digest)
35
        : m_digest(move(digest))
36
0
    {
37
0
    }
38
39
    MultiHashDigestVariant(MD5::DigestType digest)
40
0
        : m_digest(move(digest))
41
0
    {
42
0
    }
43
44
    MultiHashDigestVariant(SHA1::DigestType digest)
45
0
        : m_digest(move(digest))
46
0
    {
47
0
    }
48
49
    MultiHashDigestVariant(SHA256::DigestType digest)
50
0
        : m_digest(move(digest))
51
0
    {
52
0
    }
53
54
    MultiHashDigestVariant(SHA384::DigestType digest)
55
0
        : m_digest(move(digest))
56
0
    {
57
0
    }
58
59
    MultiHashDigestVariant(SHA512::DigestType digest)
60
0
        : m_digest(move(digest))
61
0
    {
62
0
    }
63
64
    [[nodiscard]] u8 const* immutable_data() const
65
0
    {
66
0
        return m_digest.visit(
67
0
            [&](Empty const&) -> u8 const* { VERIFY_NOT_REACHED(); },
68
0
            [&](auto const& value) { return value.immutable_data(); });
Unexecuted instantiation: auto Crypto::Hash::MultiHashDigestVariant::immutable_data() const::{lambda(auto:1 const&)#1}::operator()<Crypto::Hash::Digest<128ul> >(Crypto::Hash::Digest<128ul> const&) const
Unexecuted instantiation: auto Crypto::Hash::MultiHashDigestVariant::immutable_data() const::{lambda(auto:1 const&)#1}::operator()<Crypto::Hash::Digest<160ul> >(Crypto::Hash::Digest<160ul> const&) const
Unexecuted instantiation: auto Crypto::Hash::MultiHashDigestVariant::immutable_data() const::{lambda(auto:1 const&)#1}::operator()<Crypto::Hash::Digest<256ul> >(Crypto::Hash::Digest<256ul> const&) const
Unexecuted instantiation: auto Crypto::Hash::MultiHashDigestVariant::immutable_data() const::{lambda(auto:1 const&)#1}::operator()<Crypto::Hash::Digest<384ul> >(Crypto::Hash::Digest<384ul> const&) const
Unexecuted instantiation: auto Crypto::Hash::MultiHashDigestVariant::immutable_data() const::{lambda(auto:1 const&)#1}::operator()<Crypto::Hash::Digest<512ul> >(Crypto::Hash::Digest<512ul> const&) const
69
0
    }
70
71
    [[nodiscard]] size_t data_length() const
72
0
    {
73
0
        return m_digest.visit(
74
0
            [&](Empty const&) -> size_t { VERIFY_NOT_REACHED(); },
75
0
            [&](auto const& value) { return value.data_length(); });
76
0
    }
77
78
    [[nodiscard]] ReadonlyBytes bytes() const
79
0
    {
80
0
        return m_digest.visit(
81
0
            [&](Empty const&) -> ReadonlyBytes { VERIFY_NOT_REACHED(); },
82
0
            [&](auto const& value) { return value.bytes(); });
Unexecuted instantiation: auto Crypto::Hash::MultiHashDigestVariant::bytes() const::{lambda(auto:1 const&)#1}::operator()<Crypto::Hash::Digest<128ul> >(Crypto::Hash::Digest<128ul> const&) const
Unexecuted instantiation: auto Crypto::Hash::MultiHashDigestVariant::bytes() const::{lambda(auto:1 const&)#1}::operator()<Crypto::Hash::Digest<160ul> >(Crypto::Hash::Digest<160ul> const&) const
Unexecuted instantiation: auto Crypto::Hash::MultiHashDigestVariant::bytes() const::{lambda(auto:1 const&)#1}::operator()<Crypto::Hash::Digest<256ul> >(Crypto::Hash::Digest<256ul> const&) const
Unexecuted instantiation: auto Crypto::Hash::MultiHashDigestVariant::bytes() const::{lambda(auto:1 const&)#1}::operator()<Crypto::Hash::Digest<384ul> >(Crypto::Hash::Digest<384ul> const&) const
Unexecuted instantiation: auto Crypto::Hash::MultiHashDigestVariant::bytes() const::{lambda(auto:1 const&)#1}::operator()<Crypto::Hash::Digest<512ul> >(Crypto::Hash::Digest<512ul> const&) const
83
0
    }
84
85
    using DigestVariant = Variant<Empty, MD5::DigestType, SHA1::DigestType, SHA256::DigestType, SHA384::DigestType, SHA512::DigestType>;
86
    DigestVariant m_digest {};
87
};
88
89
class Manager final : public HashFunction<0, 0, MultiHashDigestVariant> {
90
public:
91
    using HashFunction::update;
92
93
    Manager()
94
0
    {
95
0
        m_pre_init_buffer = ByteBuffer();
96
0
    }
97
98
    Manager(Manager const& other) // NOT a copy constructor!
99
0
    {
100
0
        m_pre_init_buffer = ByteBuffer(); // will not be used
101
0
        initialize(other.m_kind);
102
0
    }
103
104
    Manager(HashKind kind)
105
0
    {
106
0
        m_pre_init_buffer = ByteBuffer();
107
0
        initialize(kind);
108
0
    }
109
110
    ~Manager()
111
0
    {
112
0
        m_algorithm = Empty {};
113
0
    }
114
115
    inline size_t digest_size() const
116
0
    {
117
0
        return m_algorithm.visit(
118
0
            [&](Empty const&) -> size_t { return 0; },
119
0
            [&](auto const& hash) { return hash.digest_size(); });
Unexecuted instantiation: auto Crypto::Hash::Manager::digest_size() const::{lambda(auto:1 const&)#1}::operator()<Crypto::Hash::BLAKE2b>(Crypto::Hash::BLAKE2b const&) const
Unexecuted instantiation: auto Crypto::Hash::Manager::digest_size() const::{lambda(auto:1 const&)#1}::operator()<Crypto::Hash::MD5>(Crypto::Hash::MD5 const&) const
Unexecuted instantiation: auto Crypto::Hash::Manager::digest_size() const::{lambda(auto:1 const&)#1}::operator()<Crypto::Hash::SHA1>(Crypto::Hash::SHA1 const&) const
Unexecuted instantiation: auto Crypto::Hash::Manager::digest_size() const::{lambda(auto:1 const&)#1}::operator()<Crypto::Hash::SHA256>(Crypto::Hash::SHA256 const&) const
Unexecuted instantiation: auto Crypto::Hash::Manager::digest_size() const::{lambda(auto:1 const&)#1}::operator()<Crypto::Hash::SHA384>(Crypto::Hash::SHA384 const&) const
Unexecuted instantiation: auto Crypto::Hash::Manager::digest_size() const::{lambda(auto:1 const&)#1}::operator()<Crypto::Hash::SHA512>(Crypto::Hash::SHA512 const&) const
120
0
    }
121
122
    inline size_t block_size() const
123
0
    {
124
0
        return m_algorithm.visit(
125
0
            [&](Empty const&) -> size_t { return 0; },
126
0
            [&](auto const& hash) { return hash.block_size(); });
127
0
    }
128
129
    inline void initialize(HashKind kind)
130
0
    {
131
0
        if (!m_algorithm.has<Empty>()) {
132
0
            VERIFY_NOT_REACHED();
133
0
        }
134
135
0
        m_kind = kind;
136
0
        switch (kind) {
137
0
        case HashKind::BLAKE2b:
138
0
            m_algorithm = BLAKE2b();
139
0
            break;
140
0
        case HashKind::MD5:
141
0
            m_algorithm = MD5();
142
0
            break;
143
0
        case HashKind::SHA1:
144
0
            m_algorithm = SHA1();
145
0
            break;
146
0
        case HashKind::SHA256:
147
0
            m_algorithm = SHA256();
148
0
            break;
149
0
        case HashKind::SHA384:
150
0
            m_algorithm = SHA384();
151
0
            break;
152
0
        case HashKind::SHA512:
153
0
            m_algorithm = SHA512();
154
0
            break;
155
0
        default:
156
0
        case HashKind::None:
157
0
            m_algorithm = Empty {};
158
0
            break;
159
0
        }
160
0
    }
161
162
    virtual void update(u8 const* data, size_t length) override
163
0
    {
164
0
        auto size = m_pre_init_buffer.size();
165
0
        if (size) {
166
0
            m_algorithm.visit(
167
0
                [&](Empty&) {},
168
0
                [&](auto& hash) { hash.update(m_pre_init_buffer); });
Unexecuted instantiation: auto Crypto::Hash::Manager::update(unsigned char const*, unsigned long)::{lambda(auto:1&)#1}::operator()<Crypto::Hash::BLAKE2b>(Crypto::Hash::BLAKE2b&) const
Unexecuted instantiation: auto Crypto::Hash::Manager::update(unsigned char const*, unsigned long)::{lambda(auto:1&)#1}::operator()<Crypto::Hash::MD5>(Crypto::Hash::MD5&) const
Unexecuted instantiation: auto Crypto::Hash::Manager::update(unsigned char const*, unsigned long)::{lambda(auto:1&)#1}::operator()<Crypto::Hash::SHA1>(Crypto::Hash::SHA1&) const
Unexecuted instantiation: auto Crypto::Hash::Manager::update(unsigned char const*, unsigned long)::{lambda(auto:1&)#1}::operator()<Crypto::Hash::SHA256>(Crypto::Hash::SHA256&) const
Unexecuted instantiation: auto Crypto::Hash::Manager::update(unsigned char const*, unsigned long)::{lambda(auto:1&)#1}::operator()<Crypto::Hash::SHA384>(Crypto::Hash::SHA384&) const
Unexecuted instantiation: auto Crypto::Hash::Manager::update(unsigned char const*, unsigned long)::{lambda(auto:1&)#1}::operator()<Crypto::Hash::SHA512>(Crypto::Hash::SHA512&) const
169
0
        }
170
0
        m_algorithm.visit(
171
0
            [&](Empty&) { m_pre_init_buffer.append(data, length); },
172
0
            [&](auto& hash) { hash.update(data, length); });
Unexecuted instantiation: auto Crypto::Hash::Manager::update(unsigned char const*, unsigned long)::{lambda(auto:1&)#2}::operator()<Crypto::Hash::BLAKE2b>(Crypto::Hash::BLAKE2b&) const
Unexecuted instantiation: auto Crypto::Hash::Manager::update(unsigned char const*, unsigned long)::{lambda(auto:1&)#2}::operator()<Crypto::Hash::MD5>(Crypto::Hash::MD5&) const
Unexecuted instantiation: auto Crypto::Hash::Manager::update(unsigned char const*, unsigned long)::{lambda(auto:1&)#2}::operator()<Crypto::Hash::SHA1>(Crypto::Hash::SHA1&) const
Unexecuted instantiation: auto Crypto::Hash::Manager::update(unsigned char const*, unsigned long)::{lambda(auto:1&)#2}::operator()<Crypto::Hash::SHA256>(Crypto::Hash::SHA256&) const
Unexecuted instantiation: auto Crypto::Hash::Manager::update(unsigned char const*, unsigned long)::{lambda(auto:1&)#2}::operator()<Crypto::Hash::SHA384>(Crypto::Hash::SHA384&) const
Unexecuted instantiation: auto Crypto::Hash::Manager::update(unsigned char const*, unsigned long)::{lambda(auto:1&)#2}::operator()<Crypto::Hash::SHA512>(Crypto::Hash::SHA512&) const
173
0
        if (size && m_kind != HashKind::None)
174
0
            m_pre_init_buffer.clear();
175
0
    }
176
177
    virtual DigestType peek() override
178
0
    {
179
0
        return m_algorithm.visit(
180
0
            [&](Empty&) -> DigestType { VERIFY_NOT_REACHED(); },
181
0
            [&](auto& hash) -> DigestType { return hash.peek(); });
Unexecuted instantiation: Crypto::Hash::MultiHashDigestVariant Crypto::Hash::Manager::peek()::{lambda(auto:1&)#1}::operator()<Crypto::Hash::BLAKE2b>(Crypto::Hash::BLAKE2b&) const
Unexecuted instantiation: Crypto::Hash::MultiHashDigestVariant Crypto::Hash::Manager::peek()::{lambda(auto:1&)#1}::operator()<Crypto::Hash::MD5>(Crypto::Hash::MD5&) const
Unexecuted instantiation: Crypto::Hash::MultiHashDigestVariant Crypto::Hash::Manager::peek()::{lambda(auto:1&)#1}::operator()<Crypto::Hash::SHA1>(Crypto::Hash::SHA1&) const
Unexecuted instantiation: Crypto::Hash::MultiHashDigestVariant Crypto::Hash::Manager::peek()::{lambda(auto:1&)#1}::operator()<Crypto::Hash::SHA256>(Crypto::Hash::SHA256&) const
Unexecuted instantiation: Crypto::Hash::MultiHashDigestVariant Crypto::Hash::Manager::peek()::{lambda(auto:1&)#1}::operator()<Crypto::Hash::SHA384>(Crypto::Hash::SHA384&) const
Unexecuted instantiation: Crypto::Hash::MultiHashDigestVariant Crypto::Hash::Manager::peek()::{lambda(auto:1&)#1}::operator()<Crypto::Hash::SHA512>(Crypto::Hash::SHA512&) const
182
0
    }
183
184
    virtual DigestType digest() override
185
0
    {
186
0
        auto digest = peek();
187
0
        reset();
188
0
        return digest;
189
0
    }
190
191
    virtual void reset() override
192
0
    {
193
0
        m_pre_init_buffer.clear();
194
0
        m_algorithm.visit(
195
0
            [&](Empty&) {},
196
0
            [&](auto& hash) { hash.reset(); });
Unexecuted instantiation: auto Crypto::Hash::Manager::reset()::{lambda(auto:1&)#1}::operator()<Crypto::Hash::BLAKE2b>(Crypto::Hash::BLAKE2b&) const
Unexecuted instantiation: auto Crypto::Hash::Manager::reset()::{lambda(auto:1&)#1}::operator()<Crypto::Hash::MD5>(Crypto::Hash::MD5&) const
Unexecuted instantiation: auto Crypto::Hash::Manager::reset()::{lambda(auto:1&)#1}::operator()<Crypto::Hash::SHA1>(Crypto::Hash::SHA1&) const
Unexecuted instantiation: auto Crypto::Hash::Manager::reset()::{lambda(auto:1&)#1}::operator()<Crypto::Hash::SHA256>(Crypto::Hash::SHA256&) const
Unexecuted instantiation: auto Crypto::Hash::Manager::reset()::{lambda(auto:1&)#1}::operator()<Crypto::Hash::SHA384>(Crypto::Hash::SHA384&) const
Unexecuted instantiation: auto Crypto::Hash::Manager::reset()::{lambda(auto:1&)#1}::operator()<Crypto::Hash::SHA512>(Crypto::Hash::SHA512&) const
197
0
    }
198
199
#ifndef KERNEL
200
    virtual ByteString class_name() const override
201
0
    {
202
0
        return m_algorithm.visit(
203
0
            [&](Empty const&) -> ByteString { return "UninitializedHashManager"; },
204
0
            [&](auto const& hash) { return hash.class_name(); });
Unexecuted instantiation: auto Crypto::Hash::Manager::class_name() const::{lambda(auto:1 const&)#1}::operator()<Crypto::Hash::BLAKE2b>(Crypto::Hash::BLAKE2b const&) const
Unexecuted instantiation: auto Crypto::Hash::Manager::class_name() const::{lambda(auto:1 const&)#1}::operator()<Crypto::Hash::MD5>(Crypto::Hash::MD5 const&) const
Unexecuted instantiation: auto Crypto::Hash::Manager::class_name() const::{lambda(auto:1 const&)#1}::operator()<Crypto::Hash::SHA1>(Crypto::Hash::SHA1 const&) const
Unexecuted instantiation: auto Crypto::Hash::Manager::class_name() const::{lambda(auto:1 const&)#1}::operator()<Crypto::Hash::SHA256>(Crypto::Hash::SHA256 const&) const
Unexecuted instantiation: auto Crypto::Hash::Manager::class_name() const::{lambda(auto:1 const&)#1}::operator()<Crypto::Hash::SHA384>(Crypto::Hash::SHA384 const&) const
Unexecuted instantiation: auto Crypto::Hash::Manager::class_name() const::{lambda(auto:1 const&)#1}::operator()<Crypto::Hash::SHA512>(Crypto::Hash::SHA512 const&) const
205
0
    }
206
#endif
207
208
    inline HashKind kind() const
209
0
    {
210
0
        return m_kind;
211
0
    }
212
213
    inline bool is(HashKind kind) const
214
0
    {
215
0
        return m_kind == kind;
216
0
    }
217
218
    inline Manager copy() const
219
0
    {
220
0
        Manager result;
221
0
        result.m_algorithm = m_algorithm;
222
0
        result.m_kind = m_kind;
223
0
        result.m_pre_init_buffer = m_pre_init_buffer;
224
0
        return result;
225
0
    }
226
227
private:
228
    using AlgorithmVariant = Variant<Empty, BLAKE2b, MD5, SHA1, SHA256, SHA384, SHA512>;
229
    AlgorithmVariant m_algorithm {};
230
    HashKind m_kind { HashKind::None };
231
    ByteBuffer m_pre_init_buffer;
232
};
233
234
}