HashManager.h 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. /*
  2. * Copyright (c) 2020, Ali Mohammad Pur <mpfard@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <AK/Optional.h>
  8. #include <AK/OwnPtr.h>
  9. #include <AK/Variant.h>
  10. #include <LibCrypto/Hash/BLAKE2b.h>
  11. #include <LibCrypto/Hash/HashFunction.h>
  12. #include <LibCrypto/Hash/MD5.h>
  13. #include <LibCrypto/Hash/SHA1.h>
  14. #include <LibCrypto/Hash/SHA2.h>
  15. namespace Crypto::Hash {
  16. enum class HashKind {
  17. Unknown,
  18. None,
  19. BLAKE2b,
  20. MD5,
  21. SHA1,
  22. SHA256,
  23. SHA384,
  24. SHA512,
  25. };
  26. struct MultiHashDigestVariant {
  27. constexpr static size_t Size = 0;
  28. MultiHashDigestVariant(Empty digest)
  29. : m_digest(move(digest))
  30. {
  31. }
  32. MultiHashDigestVariant(MD5::DigestType digest)
  33. : m_digest(move(digest))
  34. {
  35. }
  36. MultiHashDigestVariant(SHA1::DigestType digest)
  37. : m_digest(move(digest))
  38. {
  39. }
  40. MultiHashDigestVariant(SHA256::DigestType digest)
  41. : m_digest(move(digest))
  42. {
  43. }
  44. MultiHashDigestVariant(SHA384::DigestType digest)
  45. : m_digest(move(digest))
  46. {
  47. }
  48. MultiHashDigestVariant(SHA512::DigestType digest)
  49. : m_digest(move(digest))
  50. {
  51. }
  52. [[nodiscard]] u8 const* immutable_data() const
  53. {
  54. return m_digest.visit(
  55. [&](Empty const&) -> u8 const* { VERIFY_NOT_REACHED(); },
  56. [&](auto const& value) { return value.immutable_data(); });
  57. }
  58. [[nodiscard]] size_t data_length() const
  59. {
  60. return m_digest.visit(
  61. [&](Empty const&) -> size_t { VERIFY_NOT_REACHED(); },
  62. [&](auto const& value) { return value.data_length(); });
  63. }
  64. [[nodiscard]] ReadonlyBytes bytes() const
  65. {
  66. return m_digest.visit(
  67. [&](Empty const&) -> ReadonlyBytes { VERIFY_NOT_REACHED(); },
  68. [&](auto const& value) { return value.bytes(); });
  69. }
  70. using DigestVariant = Variant<Empty, MD5::DigestType, SHA1::DigestType, SHA256::DigestType, SHA384::DigestType, SHA512::DigestType>;
  71. DigestVariant m_digest {};
  72. };
  73. class Manager final : public HashFunction<0, 0, MultiHashDigestVariant> {
  74. public:
  75. using HashFunction::update;
  76. Manager()
  77. {
  78. m_pre_init_buffer = ByteBuffer();
  79. }
  80. Manager(Manager const& other) // NOT a copy constructor!
  81. {
  82. m_pre_init_buffer = ByteBuffer(); // will not be used
  83. initialize(other.m_kind);
  84. }
  85. Manager(HashKind kind)
  86. {
  87. m_pre_init_buffer = ByteBuffer();
  88. initialize(kind);
  89. }
  90. ~Manager()
  91. {
  92. m_algorithm = Empty {};
  93. }
  94. inline size_t digest_size() const
  95. {
  96. return m_algorithm.visit(
  97. [&](Empty const&) -> size_t { return 0; },
  98. [&](auto const& hash) { return hash.digest_size(); });
  99. }
  100. inline size_t block_size() const
  101. {
  102. return m_algorithm.visit(
  103. [&](Empty const&) -> size_t { return 0; },
  104. [&](auto const& hash) { return hash.block_size(); });
  105. }
  106. inline void initialize(HashKind kind)
  107. {
  108. if (!m_algorithm.has<Empty>()) {
  109. VERIFY_NOT_REACHED();
  110. }
  111. m_kind = kind;
  112. switch (kind) {
  113. case HashKind::BLAKE2b:
  114. m_algorithm = BLAKE2b();
  115. break;
  116. case HashKind::MD5:
  117. m_algorithm = MD5();
  118. break;
  119. case HashKind::SHA1:
  120. m_algorithm = SHA1();
  121. break;
  122. case HashKind::SHA256:
  123. m_algorithm = SHA256();
  124. break;
  125. case HashKind::SHA384:
  126. m_algorithm = SHA384();
  127. break;
  128. case HashKind::SHA512:
  129. m_algorithm = SHA512();
  130. break;
  131. default:
  132. case HashKind::None:
  133. m_algorithm = Empty {};
  134. break;
  135. }
  136. }
  137. virtual void update(u8 const* data, size_t length) override
  138. {
  139. auto size = m_pre_init_buffer.size();
  140. if (size) {
  141. m_algorithm.visit(
  142. [&](Empty&) {},
  143. [&](auto& hash) { hash.update(m_pre_init_buffer); });
  144. }
  145. m_algorithm.visit(
  146. [&](Empty&) { m_pre_init_buffer.append(data, length); },
  147. [&](auto& hash) { hash.update(data, length); });
  148. if (size && m_kind != HashKind::None)
  149. m_pre_init_buffer.clear();
  150. }
  151. virtual DigestType peek() override
  152. {
  153. return m_algorithm.visit(
  154. [&](Empty&) -> DigestType { VERIFY_NOT_REACHED(); },
  155. [&](auto& hash) -> DigestType { return hash.peek(); });
  156. }
  157. virtual DigestType digest() override
  158. {
  159. auto digest = peek();
  160. reset();
  161. return digest;
  162. }
  163. virtual void reset() override
  164. {
  165. m_pre_init_buffer.clear();
  166. m_algorithm.visit(
  167. [&](Empty&) {},
  168. [&](auto& hash) { hash.reset(); });
  169. }
  170. #ifndef KERNEL
  171. virtual ByteString class_name() const override
  172. {
  173. return m_algorithm.visit(
  174. [&](Empty const&) -> ByteString { return "UninitializedHashManager"; },
  175. [&](auto const& hash) { return hash.class_name(); });
  176. }
  177. #endif
  178. inline HashKind kind() const
  179. {
  180. return m_kind;
  181. }
  182. inline bool is(HashKind kind) const
  183. {
  184. return m_kind == kind;
  185. }
  186. inline Manager copy() const
  187. {
  188. Manager result;
  189. result.m_algorithm = m_algorithm;
  190. result.m_kind = m_kind;
  191. result.m_pre_init_buffer = m_pre_init_buffer;
  192. return result;
  193. }
  194. private:
  195. using AlgorithmVariant = Variant<Empty, BLAKE2b, MD5, SHA1, SHA256, SHA384, SHA512>;
  196. AlgorithmVariant m_algorithm {};
  197. HashKind m_kind { HashKind::None };
  198. ByteBuffer m_pre_init_buffer;
  199. };
  200. }