diff options
Diffstat (limited to 'Libraries')
-rw-r--r-- | Libraries/LibCrypto/Authentication/HMAC.h | 27 | ||||
-rw-r--r-- | Libraries/LibCrypto/Hash/HashFunction.h | 6 | ||||
-rw-r--r-- | Libraries/LibCrypto/Hash/HashManager.h | 309 | ||||
-rw-r--r-- | Libraries/LibCrypto/Hash/MD5.h | 6 | ||||
-rw-r--r-- | Libraries/LibCrypto/Hash/SHA1.h | 4 | ||||
-rw-r--r-- | Libraries/LibCrypto/Hash/SHA2.h | 3 |
6 files changed, 338 insertions, 17 deletions
diff --git a/Libraries/LibCrypto/Authentication/HMAC.h b/Libraries/LibCrypto/Authentication/HMAC.h index 25fccba310..fbe1a47eb2 100644 --- a/Libraries/LibCrypto/Authentication/HMAC.h +++ b/Libraries/LibCrypto/Authentication/HMAC.h @@ -44,8 +44,8 @@ class HMAC { public: using HashType = HashT; using TagType = typename HashType::DigestType; - static constexpr size_t BlockSize = HashType::BlockSize; - static constexpr size_t DigestSize = HashType::DigestSize; + + size_t digest_size() const { return m_inner_hasher.digest_size(); } template<typename KeyBufferType, typename... Args> HMAC(KeyBufferType key, Args... args) @@ -75,7 +75,7 @@ public: TagType digest() { - m_outer_hasher.update(m_inner_hasher.digest().data, m_inner_hasher.DigestSize); + m_outer_hasher.update(m_inner_hasher.digest().immutable_data(), m_inner_hasher.digest_size()); auto result = m_outer_hasher.digest(); reset(); return result; @@ -85,8 +85,8 @@ public: { m_inner_hasher.reset(); m_outer_hasher.reset(); - m_inner_hasher.update(m_key_data, BlockSize); - m_outer_hasher.update(m_key_data + BlockSize, BlockSize); + m_inner_hasher.update(m_key_data, m_inner_hasher.block_size()); + m_outer_hasher.update(m_key_data + m_inner_hasher.block_size(), m_outer_hasher.block_size()); } String class_name() const @@ -100,25 +100,26 @@ public: private: void derive_key(const u8* key, size_t length) { - u8 v_key[BlockSize]; - __builtin_memset(v_key, 0, BlockSize); - ByteBuffer key_buffer = ByteBuffer::wrap(v_key, BlockSize); + auto block_size = m_inner_hasher.block_size(); + u8 v_key[block_size]; + __builtin_memset(v_key, 0, block_size); + ByteBuffer key_buffer = ByteBuffer::wrap(v_key, block_size); // m_key_data is zero'd, so copying the data in // the first few bytes leaves the rest zero, which // is exactly what we want (zero padding) - if (length > BlockSize) { + if (length > block_size) { m_inner_hasher.update(key, length); auto digest = m_inner_hasher.digest(); // FIXME: should we check if the hash function creates more data than its block size? - key_buffer.overwrite(0, digest.data, sizeof(TagType)); + key_buffer.overwrite(0, digest.immutable_data(), m_inner_hasher.digest_size()); } else { key_buffer.overwrite(0, key, length); } // fill out the inner and outer padded keys auto* i_key = m_key_data; - auto* o_key = m_key_data + BlockSize; - for (size_t i = 0; i < BlockSize; ++i) { + auto* o_key = m_key_data + block_size; + for (size_t i = 0; i < block_size; ++i) { auto key_byte = key_buffer[i]; i_key[i] = key_byte ^ IPAD; o_key[i] = key_byte ^ OPAD; @@ -129,7 +130,7 @@ private: void derive_key(const StringView& key) { derive_key((const u8*)key.characters_without_null_termination(), key.length()); } HashType m_inner_hasher, m_outer_hasher; - u8 m_key_data[BlockSize * 2]; + u8 m_key_data[2048]; }; } diff --git a/Libraries/LibCrypto/Hash/HashFunction.h b/Libraries/LibCrypto/Hash/HashFunction.h index 19c2f0db05..e6d5887484 100644 --- a/Libraries/LibCrypto/Hash/HashFunction.h +++ b/Libraries/LibCrypto/Hash/HashFunction.h @@ -37,7 +37,7 @@ template<size_t BlockS, typename DigestT> class HashFunction { public: static constexpr auto BlockSize = BlockS / 8; - static constexpr auto DigestSize = sizeof(DigestT); + static constexpr auto DigestSize = DigestT::Size; using DigestType = DigestT; @@ -45,8 +45,8 @@ public: static size_t digest_size() { return DigestSize; }; virtual void update(const u8*, size_t) = 0; - virtual void update(const ByteBuffer& buffer) = 0; - virtual void update(const StringView& string) = 0; + virtual void update(const ByteBuffer& buffer) { update(buffer.data(), buffer.size()); }; + virtual void update(const StringView& string) { update((const u8*)string.characters_without_null_termination(), string.length()); }; virtual DigestType peek() = 0; virtual DigestType digest() = 0; diff --git a/Libraries/LibCrypto/Hash/HashManager.h b/Libraries/LibCrypto/Hash/HashManager.h new file mode 100644 index 0000000000..fb01db77b9 --- /dev/null +++ b/Libraries/LibCrypto/Hash/HashManager.h @@ -0,0 +1,309 @@ +/* + * Copyright (c) 2020, Ali Mohammad Pur <ali.mpfard@gmail.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include <AK/Optional.h> +#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, + SHA512, + MD5, +}; + +struct MultiHashDigestVariant { + + constexpr static size_t Size = 0; + + MultiHashDigestVariant(SHA1::DigestType digest) + : sha1(digest) + , kind(HashKind::SHA1) + { + } + + MultiHashDigestVariant(SHA256::DigestType digest) + : sha256(digest) + , kind(HashKind::SHA256) + { + } + + MultiHashDigestVariant(SHA512::DigestType digest) + : sha512(digest) + , kind(HashKind::SHA512) + { + } + + MultiHashDigestVariant(MD5::DigestType digest) + : md5(digest) + , kind(HashKind::MD5) + { + } + + const u8* immutable_data() const + { + switch (kind) { + case HashKind::MD5: + return md5.value().immutable_data(); + case HashKind::SHA1: + return sha1.value().immutable_data(); + case HashKind::SHA256: + return sha256.value().immutable_data(); + case HashKind::SHA512: + return sha512.value().immutable_data(); + default: + case HashKind::None: + ASSERT_NOT_REACHED(); + break; + } + } + + size_t data_length() + { + switch (kind) { + case HashKind::MD5: + return md5.value().data_length(); + case HashKind::SHA1: + return sha1.value().data_length(); + case HashKind::SHA256: + return sha256.value().data_length(); + case HashKind::SHA512: + return sha512.value().data_length(); + default: + case HashKind::None: + ASSERT_NOT_REACHED(); + break; + } + } + + Optional<SHA1::DigestType> sha1; + Optional<SHA256::DigestType> sha256; + Optional<SHA512::DigestType> sha512; + Optional<MD5::DigestType> md5; + HashKind kind { HashKind::None }; +}; + +class Manager final : public HashFunction<0, MultiHashDigestVariant> { +public: + 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 + initialise(other.m_kind); + } + + Manager(HashKind kind) + { + m_pre_init_buffer = ByteBuffer::create_zeroed(0); + initialize(kind); + } + + ~Manager() + { + } + + virtual void update(const ByteBuffer& buffer) override { update(buffer.data(), buffer.size()); }; + virtual void update(const StringView& string) override { update((const u8*)string.characters_without_null_termination(), string.length()); }; + inline size_t digest_size() const + { + switch (m_kind) { + case HashKind::MD5: + return md5.value().digest_size(); + case HashKind::SHA1: + return sha1.value().digest_size(); + case HashKind::SHA256: + return sha256.value().digest_size(); + case HashKind::SHA512: + return sha512.value().digest_size(); + default: + case HashKind::None: + return 0; + } + } + inline size_t block_size() const + { + switch (m_kind) { + case HashKind::MD5: + return m_md5->block_size(); + case HashKind::SHA1: + return m_sha1->block_size(); + case HashKind::SHA256: + return m_sha256->block_size(); + case HashKind::SHA512: + return m_sha512->block_size(); + default: + case HashKind::None: + return 0; + } + } + inline void initialize(HashKind kind) + { + if (m_kind != HashKind::None) { + ASSERT_NOT_REACHED(); + } + + m_kind = kind; + switch (kind) { + case HashKind::MD5: + md5 = MD5 {}; + break; + case HashKind::SHA1: + sha1 = SHA1 {}; + break; + case HashKind::SHA256: + sha256 = SHA256 {}; + break; + case HashKind::SHA512: + sha512 = SHA512 {}; + break; + default: + case HashKind::None: + break; + } + } + + virtual void update(const u8* data, size_t length) override + { + switch (m_kind) { + case HashKind::MD5: + if (m_pre_init_buffer.size()) + md5.value().update(m_pre_init_buffer); + md5.value().update(data, length); + break; + case HashKind::SHA1: + if (m_pre_init_buffer.size()) + sha1.value().update(m_pre_init_buffer); + sha1.value().update(data, length); + break; + case HashKind::SHA256: + if (m_pre_init_buffer.size()) + sha256.value().update(m_pre_init_buffer); + sha256.value().update(data, length); + break; + case HashKind::SHA512: + if (m_pre_init_buffer.size()) + sha512.value().update(m_pre_init_buffer); + sha512.value().update(data, length); + break; + default: + case HashKind::None: + m_pre_init_buffer.append(data, length); + return; + } + m_pre_init_buffer.clear(); + } + + virtual DigestType peek() override + { + switch (m_kind) { + case HashKind::MD5: + return { md5.value().peek() }; + case HashKind::SHA1: + return { sha1.value().peek() }; + case HashKind::SHA256: + return { sha256.value().peek() }; + case HashKind::SHA512: + return { sha512.value().peek() }; + default: + case HashKind::None: + ASSERT_NOT_REACHED(); + break; + } + } + + virtual DigestType digest() override + { + auto digest = peek(); + reset(); + return digest; + } + + virtual void reset() override + { + switch (m_kind) { + case HashKind::MD5: + md5.value().reset(); + break; + case HashKind::SHA1: + sha1.value().reset(); + break; + case HashKind::SHA256: + sha256.value().reset(); + break; + case HashKind::SHA512: + sha512.value().reset(); + break; + default: + case HashKind::None: + break; + } + } + + virtual String class_name() const override + { + switch (m_kind) { + case HashKind::MD5: + return md5.value().class_name(); + case HashKind::SHA1: + return sha1.value().class_name(); + case HashKind::SHA256: + return sha256.value().class_name(); + case HashKind::SHA512: + return sha512.value().class_name(); + default: + case HashKind::None: + return "UninitializedHashManager"; + } + } + + inline bool is(HashKind kind) const + { + return m_kind == kind; + } + +private: + Optional<SHA1> sha1; + Optional<SHA256> sha256; + Optional<SHA512> sha512; + Optional<MD5> md5; + HashKind m_kind { HashKind::None }; + ByteBuffer m_pre_init_buffer; +}; + +} +} diff --git a/Libraries/LibCrypto/Hash/MD5.h b/Libraries/LibCrypto/Hash/MD5.h index 883029527c..3219cb9260 100644 --- a/Libraries/LibCrypto/Hash/MD5.h +++ b/Libraries/LibCrypto/Hash/MD5.h @@ -34,7 +34,11 @@ namespace Crypto { namespace Hash { struct MD5Digest { - u8 data[16]; + constexpr static size_t Size = 16; + u8 data[Size]; + + const u8* immutable_data() const { return data; } + size_t data_length() { return Size; } }; namespace MD5Constants { diff --git a/Libraries/LibCrypto/Hash/SHA1.h b/Libraries/LibCrypto/Hash/SHA1.h index fd15c6b962..bb37296612 100644 --- a/Libraries/LibCrypto/Hash/SHA1.h +++ b/Libraries/LibCrypto/Hash/SHA1.h @@ -48,6 +48,10 @@ constexpr static u32 RoundConstants[4] { template<size_t Bytes> struct SHA1Digest { u8 data[Bytes]; + constexpr static size_t Size = Bytes; + + const u8* immutable_data() const { return data; } + size_t data_length() { return Bytes; } }; class SHA1 final : public HashFunction<512, SHA1Digest<160 / 8>> { diff --git a/Libraries/LibCrypto/Hash/SHA2.h b/Libraries/LibCrypto/Hash/SHA2.h index 2437cc17cc..ebb38d9888 100644 --- a/Libraries/LibCrypto/Hash/SHA2.h +++ b/Libraries/LibCrypto/Hash/SHA2.h @@ -88,6 +88,9 @@ constexpr static u64 InitializationHashes[8] = { template<size_t Bytes> struct SHA2Digest { u8 data[Bytes]; + constexpr static size_t Size = Bytes; + const u8* immutable_data() const { return data; } + size_t data_length() { return Bytes; } }; // FIXME: I want template<size_t BlockSize> but the compiler gets confused |