| 
									
										
										
										
											2020-04-25 05:06:33 +04:30
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2021-04-23 00:43:01 +04:30
										 |  |  |  * Copyright (c) 2020, Ali Mohammad Pur <mpfard@serenityos.org> | 
					
						
							| 
									
										
										
										
											2020-04-25 05:06:33 +04:30
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2021-04-22 01:24:48 -07:00
										 |  |  |  * SPDX-License-Identifier: BSD-2-Clause | 
					
						
							| 
									
										
										
										
											2020-04-25 05:06:33 +04:30
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #pragma once
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <AK/Optional.h>
 | 
					
						
							| 
									
										
										
										
											2020-04-25 05:07:24 +04:30
										 |  |  | #include <AK/OwnPtr.h>
 | 
					
						
							| 
									
										
										
										
											2021-05-18 20:15:20 +02:00
										 |  |  | #include <AK/Variant.h>
 | 
					
						
							| 
									
										
										
										
											2020-04-25 05:06:33 +04:30
										 |  |  | #include <LibCrypto/Hash/HashFunction.h>
 | 
					
						
							|  |  |  | #include <LibCrypto/Hash/MD5.h>
 | 
					
						
							|  |  |  | #include <LibCrypto/Hash/SHA1.h>
 | 
					
						
							|  |  |  | #include <LibCrypto/Hash/SHA2.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace Crypto { | 
					
						
							|  |  |  | namespace Hash { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | enum class HashKind { | 
					
						
							|  |  |  |     None, | 
					
						
							|  |  |  |     SHA1, | 
					
						
							|  |  |  |     SHA256, | 
					
						
							| 
									
										
										
										
											2021-05-17 22:24:32 +02:00
										 |  |  |     SHA384, | 
					
						
							| 
									
										
										
										
											2020-04-25 05:06:33 +04:30
										 |  |  |     SHA512, | 
					
						
							|  |  |  |     MD5, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct MultiHashDigestVariant { | 
					
						
							|  |  |  |     constexpr static size_t Size = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-18 20:41:00 +02:00
										 |  |  |     MultiHashDigestVariant(Empty digest) | 
					
						
							|  |  |  |         : m_digest(move(digest)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-18 20:15:20 +02:00
										 |  |  |     MultiHashDigestVariant(MD5::DigestType digest) | 
					
						
							|  |  |  |         : m_digest(move(digest)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-25 05:06:33 +04:30
										 |  |  |     MultiHashDigestVariant(SHA1::DigestType digest) | 
					
						
							| 
									
										
										
										
											2021-05-18 20:15:20 +02:00
										 |  |  |         : m_digest(move(digest)) | 
					
						
							| 
									
										
										
										
											2020-04-25 05:06:33 +04:30
										 |  |  |     { | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     MultiHashDigestVariant(SHA256::DigestType digest) | 
					
						
							| 
									
										
										
										
											2021-05-18 20:15:20 +02:00
										 |  |  |         : m_digest(move(digest)) | 
					
						
							| 
									
										
										
										
											2020-04-25 05:06:33 +04:30
										 |  |  |     { | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-17 22:24:32 +02:00
										 |  |  |     MultiHashDigestVariant(SHA384::DigestType digest) | 
					
						
							| 
									
										
										
										
											2021-05-18 20:15:20 +02:00
										 |  |  |         : m_digest(move(digest)) | 
					
						
							| 
									
										
										
										
											2021-05-17 22:24:32 +02:00
										 |  |  |     { | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-25 05:06:33 +04:30
										 |  |  |     MultiHashDigestVariant(SHA512::DigestType digest) | 
					
						
							| 
									
										
										
										
											2021-05-18 20:15:20 +02:00
										 |  |  |         : m_digest(move(digest)) | 
					
						
							| 
									
										
										
										
											2020-04-25 05:06:33 +04:30
										 |  |  |     { | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const u8* immutable_data() const | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2021-05-20 00:32:42 +04:30
										 |  |  |         return m_digest.visit( | 
					
						
							|  |  |  |             [&](const Empty&) -> const u8* { VERIFY_NOT_REACHED(); }, | 
					
						
							|  |  |  |             [&](const auto& value) { return value.immutable_data(); }); | 
					
						
							| 
									
										
										
										
											2020-04-25 05:06:33 +04:30
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     size_t data_length() | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2021-05-20 00:32:42 +04:30
										 |  |  |         return m_digest.visit( | 
					
						
							|  |  |  |             [&](const Empty&) -> size_t { VERIFY_NOT_REACHED(); }, | 
					
						
							|  |  |  |             [&](const auto& value) { return value.data_length(); }); | 
					
						
							| 
									
										
										
										
											2020-04-25 05:06:33 +04:30
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-18 20:15:20 +02:00
										 |  |  |     using DigestVariant = Variant<Empty, MD5::DigestType, SHA1::DigestType, SHA256::DigestType, SHA384::DigestType, SHA512::DigestType>; | 
					
						
							|  |  |  |     DigestVariant m_digest { Empty {} }; | 
					
						
							| 
									
										
										
										
											2020-04-25 05:06:33 +04:30
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Manager final : public HashFunction<0, MultiHashDigestVariant> { | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2020-12-19 15:56:15 +01:00
										 |  |  |     using HashFunction::update; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-25 05:06:33 +04:30
										 |  |  |     Manager() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         m_pre_init_buffer = ByteBuffer::create_zeroed(0); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Manager(const Manager& other) // NOT a copy constructor!
 | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         m_pre_init_buffer = ByteBuffer::create_zeroed(0); // will not be used
 | 
					
						
							| 
									
										
										
										
											2020-04-25 05:07:24 +04:30
										 |  |  |         initialize(other.m_kind); | 
					
						
							| 
									
										
										
										
											2020-04-25 05:06:33 +04:30
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Manager(HashKind kind) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         m_pre_init_buffer = ByteBuffer::create_zeroed(0); | 
					
						
							|  |  |  |         initialize(kind); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ~Manager() | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2021-05-18 20:41:00 +02:00
										 |  |  |         m_algorithm = Empty {}; | 
					
						
							| 
									
										
										
										
											2020-04-25 05:06:33 +04:30
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     inline size_t digest_size() const | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2021-05-20 00:32:42 +04:30
										 |  |  |         return m_algorithm.visit( | 
					
						
							|  |  |  |             [&](const Empty&) -> size_t { return 0; }, | 
					
						
							|  |  |  |             [&](const auto& hash) { return hash.digest_size(); }); | 
					
						
							| 
									
										
										
										
											2020-04-25 05:06:33 +04:30
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-05-18 20:41:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-25 05:06:33 +04:30
										 |  |  |     inline size_t block_size() const | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2021-05-20 00:32:42 +04:30
										 |  |  |         return m_algorithm.visit( | 
					
						
							|  |  |  |             [&](const Empty&) -> size_t { return 0; }, | 
					
						
							|  |  |  |             [&](const auto& hash) { return hash.block_size(); }); | 
					
						
							| 
									
										
										
										
											2020-04-25 05:06:33 +04:30
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-05-18 20:41:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-25 05:06:33 +04:30
										 |  |  |     inline void initialize(HashKind kind) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2021-05-18 20:41:00 +02:00
										 |  |  |         if (!m_algorithm.has<Empty>()) { | 
					
						
							| 
									
										
										
										
											2021-02-23 20:42:32 +01:00
										 |  |  |             VERIFY_NOT_REACHED(); | 
					
						
							| 
									
										
										
										
											2020-04-25 05:06:33 +04:30
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         m_kind = kind; | 
					
						
							|  |  |  |         switch (kind) { | 
					
						
							|  |  |  |         case HashKind::MD5: | 
					
						
							| 
									
										
										
										
											2021-05-18 20:41:00 +02:00
										 |  |  |             m_algorithm = MD5(); | 
					
						
							| 
									
										
										
										
											2020-04-25 05:06:33 +04:30
										 |  |  |             break; | 
					
						
							|  |  |  |         case HashKind::SHA1: | 
					
						
							| 
									
										
										
										
											2021-05-18 20:41:00 +02:00
										 |  |  |             m_algorithm = SHA1(); | 
					
						
							| 
									
										
										
										
											2020-04-25 05:06:33 +04:30
										 |  |  |             break; | 
					
						
							|  |  |  |         case HashKind::SHA256: | 
					
						
							| 
									
										
										
										
											2021-05-18 20:41:00 +02:00
										 |  |  |             m_algorithm = SHA256(); | 
					
						
							| 
									
										
										
										
											2020-04-25 05:06:33 +04:30
										 |  |  |             break; | 
					
						
							| 
									
										
										
										
											2021-05-17 22:24:32 +02:00
										 |  |  |         case HashKind::SHA384: | 
					
						
							| 
									
										
										
										
											2021-05-18 20:41:00 +02:00
										 |  |  |             m_algorithm = SHA384(); | 
					
						
							| 
									
										
										
										
											2021-05-17 22:24:32 +02:00
										 |  |  |             break; | 
					
						
							| 
									
										
										
										
											2020-04-25 05:06:33 +04:30
										 |  |  |         case HashKind::SHA512: | 
					
						
							| 
									
										
										
										
											2021-05-18 20:41:00 +02:00
										 |  |  |             m_algorithm = SHA512(); | 
					
						
							| 
									
										
										
										
											2020-04-25 05:06:33 +04:30
										 |  |  |             break; | 
					
						
							|  |  |  |         default: | 
					
						
							|  |  |  |         case HashKind::None: | 
					
						
							| 
									
										
										
										
											2021-05-18 20:41:00 +02:00
										 |  |  |             m_algorithm = Empty {}; | 
					
						
							| 
									
										
										
										
											2020-04-25 05:06:33 +04:30
										 |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     virtual void update(const u8* data, size_t length) override | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2020-04-25 05:07:24 +04:30
										 |  |  |         auto size = m_pre_init_buffer.size(); | 
					
						
							| 
									
										
										
										
											2021-05-18 20:41:00 +02:00
										 |  |  |         if (size) { | 
					
						
							|  |  |  |             m_algorithm.visit( | 
					
						
							|  |  |  |                 [&](Empty&) {}, | 
					
						
							|  |  |  |                 [&](auto& hash) { hash.update(m_pre_init_buffer); }); | 
					
						
							| 
									
										
										
										
											2020-04-25 05:06:33 +04:30
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-05-18 20:41:00 +02:00
										 |  |  |         m_algorithm.visit( | 
					
						
							|  |  |  |             [&](Empty&) { m_pre_init_buffer.append(data, length); }, | 
					
						
							|  |  |  |             [&](auto& hash) { hash.update(data, length); }); | 
					
						
							|  |  |  |         if (size && m_kind != HashKind::None) | 
					
						
							| 
									
										
										
										
											2020-04-25 05:07:24 +04:30
										 |  |  |             m_pre_init_buffer.clear(); | 
					
						
							| 
									
										
										
										
											2020-04-25 05:06:33 +04:30
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     virtual DigestType peek() override | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2021-05-20 00:32:42 +04:30
										 |  |  |         return m_algorithm.visit( | 
					
						
							|  |  |  |             [&](Empty&) -> DigestType { VERIFY_NOT_REACHED(); }, | 
					
						
							|  |  |  |             [&](auto& hash) -> DigestType { return hash.peek(); }); | 
					
						
							| 
									
										
										
										
											2020-04-25 05:06:33 +04:30
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     virtual DigestType digest() override | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         auto digest = peek(); | 
					
						
							|  |  |  |         reset(); | 
					
						
							|  |  |  |         return digest; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     virtual void reset() override | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2020-04-25 05:07:24 +04:30
										 |  |  |         m_pre_init_buffer.clear(); | 
					
						
							| 
									
										
										
										
											2021-05-18 20:41:00 +02:00
										 |  |  |         m_algorithm.visit( | 
					
						
							|  |  |  |             [&](Empty&) {}, | 
					
						
							|  |  |  |             [&](auto& hash) { hash.reset(); }); | 
					
						
							| 
									
										
										
										
											2020-04-25 05:06:33 +04:30
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     virtual String class_name() const override | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2021-05-20 00:32:42 +04:30
										 |  |  |         return m_algorithm.visit( | 
					
						
							|  |  |  |             [&](const Empty&) -> String { return "UninitializedHashManager"; }, | 
					
						
							|  |  |  |             [&](const auto& hash) { return hash.class_name(); }); | 
					
						
							| 
									
										
										
										
											2020-04-25 05:06:33 +04:30
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     inline bool is(HashKind kind) const | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return m_kind == kind; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | private: | 
					
						
							| 
									
										
										
										
											2021-05-18 20:41:00 +02:00
										 |  |  |     using AlgorithmVariant = Variant<Empty, MD5, SHA1, SHA256, SHA384, SHA512>; | 
					
						
							|  |  |  |     AlgorithmVariant m_algorithm { Empty {} }; | 
					
						
							| 
									
										
										
										
											2020-04-25 05:06:33 +04:30
										 |  |  |     HashKind m_kind { HashKind::None }; | 
					
						
							|  |  |  |     ByteBuffer m_pre_init_buffer; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | } |