/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&) constUnexecuted instantiation: auto Crypto::Hash::MultiHashDigestVariant::immutable_data() const::{lambda(auto:1 const&)#1}::operator()<Crypto::Hash::Digest<160ul> >(Crypto::Hash::Digest<160ul> const&) constUnexecuted instantiation: auto Crypto::Hash::MultiHashDigestVariant::immutable_data() const::{lambda(auto:1 const&)#1}::operator()<Crypto::Hash::Digest<256ul> >(Crypto::Hash::Digest<256ul> const&) constUnexecuted instantiation: auto Crypto::Hash::MultiHashDigestVariant::immutable_data() const::{lambda(auto:1 const&)#1}::operator()<Crypto::Hash::Digest<384ul> >(Crypto::Hash::Digest<384ul> const&) constUnexecuted 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&) constUnexecuted instantiation: auto Crypto::Hash::MultiHashDigestVariant::bytes() const::{lambda(auto:1 const&)#1}::operator()<Crypto::Hash::Digest<160ul> >(Crypto::Hash::Digest<160ul> const&) constUnexecuted instantiation: auto Crypto::Hash::MultiHashDigestVariant::bytes() const::{lambda(auto:1 const&)#1}::operator()<Crypto::Hash::Digest<256ul> >(Crypto::Hash::Digest<256ul> const&) constUnexecuted instantiation: auto Crypto::Hash::MultiHashDigestVariant::bytes() const::{lambda(auto:1 const&)#1}::operator()<Crypto::Hash::Digest<384ul> >(Crypto::Hash::Digest<384ul> const&) constUnexecuted 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&) constUnexecuted instantiation: auto Crypto::Hash::Manager::digest_size() const::{lambda(auto:1 const&)#1}::operator()<Crypto::Hash::MD5>(Crypto::Hash::MD5 const&) constUnexecuted instantiation: auto Crypto::Hash::Manager::digest_size() const::{lambda(auto:1 const&)#1}::operator()<Crypto::Hash::SHA1>(Crypto::Hash::SHA1 const&) constUnexecuted instantiation: auto Crypto::Hash::Manager::digest_size() const::{lambda(auto:1 const&)#1}::operator()<Crypto::Hash::SHA256>(Crypto::Hash::SHA256 const&) constUnexecuted instantiation: auto Crypto::Hash::Manager::digest_size() const::{lambda(auto:1 const&)#1}::operator()<Crypto::Hash::SHA384>(Crypto::Hash::SHA384 const&) constUnexecuted 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&) constUnexecuted instantiation: auto Crypto::Hash::Manager::update(unsigned char const*, unsigned long)::{lambda(auto:1&)#1}::operator()<Crypto::Hash::MD5>(Crypto::Hash::MD5&) constUnexecuted instantiation: auto Crypto::Hash::Manager::update(unsigned char const*, unsigned long)::{lambda(auto:1&)#1}::operator()<Crypto::Hash::SHA1>(Crypto::Hash::SHA1&) constUnexecuted instantiation: auto Crypto::Hash::Manager::update(unsigned char const*, unsigned long)::{lambda(auto:1&)#1}::operator()<Crypto::Hash::SHA256>(Crypto::Hash::SHA256&) constUnexecuted instantiation: auto Crypto::Hash::Manager::update(unsigned char const*, unsigned long)::{lambda(auto:1&)#1}::operator()<Crypto::Hash::SHA384>(Crypto::Hash::SHA384&) constUnexecuted 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&) constUnexecuted instantiation: auto Crypto::Hash::Manager::update(unsigned char const*, unsigned long)::{lambda(auto:1&)#2}::operator()<Crypto::Hash::MD5>(Crypto::Hash::MD5&) constUnexecuted instantiation: auto Crypto::Hash::Manager::update(unsigned char const*, unsigned long)::{lambda(auto:1&)#2}::operator()<Crypto::Hash::SHA1>(Crypto::Hash::SHA1&) constUnexecuted instantiation: auto Crypto::Hash::Manager::update(unsigned char const*, unsigned long)::{lambda(auto:1&)#2}::operator()<Crypto::Hash::SHA256>(Crypto::Hash::SHA256&) constUnexecuted instantiation: auto Crypto::Hash::Manager::update(unsigned char const*, unsigned long)::{lambda(auto:1&)#2}::operator()<Crypto::Hash::SHA384>(Crypto::Hash::SHA384&) constUnexecuted 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&) constUnexecuted instantiation: Crypto::Hash::MultiHashDigestVariant Crypto::Hash::Manager::peek()::{lambda(auto:1&)#1}::operator()<Crypto::Hash::MD5>(Crypto::Hash::MD5&) constUnexecuted instantiation: Crypto::Hash::MultiHashDigestVariant Crypto::Hash::Manager::peek()::{lambda(auto:1&)#1}::operator()<Crypto::Hash::SHA1>(Crypto::Hash::SHA1&) constUnexecuted instantiation: Crypto::Hash::MultiHashDigestVariant Crypto::Hash::Manager::peek()::{lambda(auto:1&)#1}::operator()<Crypto::Hash::SHA256>(Crypto::Hash::SHA256&) constUnexecuted instantiation: Crypto::Hash::MultiHashDigestVariant Crypto::Hash::Manager::peek()::{lambda(auto:1&)#1}::operator()<Crypto::Hash::SHA384>(Crypto::Hash::SHA384&) constUnexecuted 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&) constUnexecuted instantiation: auto Crypto::Hash::Manager::reset()::{lambda(auto:1&)#1}::operator()<Crypto::Hash::MD5>(Crypto::Hash::MD5&) constUnexecuted instantiation: auto Crypto::Hash::Manager::reset()::{lambda(auto:1&)#1}::operator()<Crypto::Hash::SHA1>(Crypto::Hash::SHA1&) constUnexecuted instantiation: auto Crypto::Hash::Manager::reset()::{lambda(auto:1&)#1}::operator()<Crypto::Hash::SHA256>(Crypto::Hash::SHA256&) constUnexecuted instantiation: auto Crypto::Hash::Manager::reset()::{lambda(auto:1&)#1}::operator()<Crypto::Hash::SHA384>(Crypto::Hash::SHA384&) constUnexecuted 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&) constUnexecuted instantiation: auto Crypto::Hash::Manager::class_name() const::{lambda(auto:1 const&)#1}::operator()<Crypto::Hash::MD5>(Crypto::Hash::MD5 const&) constUnexecuted instantiation: auto Crypto::Hash::Manager::class_name() const::{lambda(auto:1 const&)#1}::operator()<Crypto::Hash::SHA1>(Crypto::Hash::SHA1 const&) constUnexecuted instantiation: auto Crypto::Hash::Manager::class_name() const::{lambda(auto:1 const&)#1}::operator()<Crypto::Hash::SHA256>(Crypto::Hash::SHA256 const&) constUnexecuted instantiation: auto Crypto::Hash::Manager::class_name() const::{lambda(auto:1 const&)#1}::operator()<Crypto::Hash::SHA384>(Crypto::Hash::SHA384 const&) constUnexecuted 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 | | } |