diff --git a/doc/crypt.adoc b/doc/crypt.adoc index f3919ee7..f7ab0e27 100644 --- a/doc/crypt.adoc +++ b/doc/crypt.adoc @@ -4,7 +4,6 @@ Distributed under the Boost Software License, Version 1.0. https://www.boost.org/LICENSE_1_0.txt //// -= Crypt: A Modern Cryptographic Module in C++20 :toc: left :toclevels: 4 :idprefix: @@ -15,6 +14,9 @@ https://www.boost.org/LICENSE_1_0.txt :leveloffset: +1 += Crypt: A Modern Cryptographic Module in C++20 +Matt Borland and Chris Kormanyos + include::crypt/overview.adoc[] include::crypt/api_reference.adoc[] @@ -42,9 +44,13 @@ include::crypt/sha3_256.adoc[] include::crypt/sha3_384.adoc[] include::crypt/sha3_512.adoc[] -//// -include::crypt/hmac.adoc[] +include::crypt/shake128.adoc[] + +include::crypt/shake256.adoc[] + +include::crypt/hmac.adoc[] +//// include::crypt/hash_drbg.adoc[] include::crypt/hmac_drbg.adoc[] diff --git a/doc/crypt/api_reference.adoc b/doc/crypt/api_reference.adoc index 013002e9..ebb992dd 100644 --- a/doc/crypt/api_reference.adoc +++ b/doc/crypt/api_reference.adoc @@ -26,7 +26,6 @@ https://www.boost.org/LICENSE_1_0.txt ==== SHA2 Family of Hashers - <> -//// - <> - <> - <> @@ -39,9 +38,14 @@ https://www.boost.org/LICENSE_1_0.txt - <> - <> +==== Extendable-Output Functions +- <> +- <> + === Hash-Based Message Authentication Codes (HMAC) - <> +//// === Deterministic Random Bit Generators (DRBG) ==== Hash-Based ===== Non-Prediction Resistant diff --git a/doc/crypt/concepts.adoc b/doc/crypt/concepts.adoc index 2b9c5fec..64b70bc2 100644 --- a/doc/crypt/concepts.adoc +++ b/doc/crypt/concepts.adoc @@ -8,7 +8,7 @@ https://www.boost.org/LICENSE_1_0.txt = Concepts :idprefix: concepts_ -The following are the defintions of the concepts used throughout the library to ensure consistency. +The following are the definitions of the concepts used throughout the library to ensure consistency. [#file_system_path] == File System Path @@ -36,7 +36,7 @@ concept file_system_path = } // namespace boost::crypt::concepts ---- -[#writable_output_range] +[#writeable_output_range] == Writeable Output Range This concept is used to define the ranges that we can write to such as the `get_digest(Range&& data)` function of the hashers. diff --git a/doc/crypt/hmac.adoc b/doc/crypt/hmac.adoc index 1512257e..b47cf5b8 100644 --- a/doc/crypt/hmac.adoc +++ b/doc/crypt/hmac.adoc @@ -24,10 +24,11 @@ boost::crypt::hmac hmac; const auto state_1 {hmac.init("key", 3)}; BOOST_TEST(state_1 == boost::crypt::state::success); -const char* msg {"The quick brown fox jumps over the lazy dog"}; -const auto state_2 {hmac.process_bytes(msg, std::strlen(msg))}; +std::string msg {"The quick brown fox jumps over the lazy dog"}; +const auto state_2 {hmac.process_bytes(msg)}; BOOST_TEST(state_2 == boost::crypt::state::success); +hmac.finalize(); const auto res {hmac.get_digest()}; ---- @@ -40,13 +41,15 @@ Continuing from our above example: [source, c++] ---- boost::crypt::hmac hmac; -const auto state_1 {hmac.init("key", 3)}; +const auto state_1 {hmac.init(std::string{"key"})}; BOOST_TEST(state_1 == boost::crypt::state::success); -const char* msg {"The quick brown fox jumps over the lazy dog"}; -const auto state_2 {hmac.process_bytes(msg, std::strlen(msg))}; +std::string msg {"The quick brown fox jumps over the lazy dog"}; +const auto state_2 {hmac.process_bytes(msg)}; BOOST_TEST(state_2 == boost::crypt::state::success); +BOOST_TEST(hmac.finalize() == boost::crypt::state::success); + const auto res {hmac.get_digest()}; const auto outer_key {hmac.get_outer_key()}; @@ -54,12 +57,15 @@ const auto inner_key {hmac.get_inner_key()}; // Do some stuff -boost::crypt::hmac hmac2(inner_key, outer_key); +boost::crypt::hmac hmac2; + +hmac2.init_from_keys(inner_key, outer_key); -const char* msg2 {"The quick brown fox jumps over the lazy dog"}; -const auto state_3 {hmac2.process_bytes(msg, std::strlen(msg))}; +std::string msg2 {"The quick brown fox jumps over the lazy dog"}; +const auto state_3 {hmac2.process_bytes(msg)}; BOOST_TEST(state_3 == boost::crypt::state::success); +hmac2.finalize(); const auto res2 {hmac2.get_digest()}; ---- @@ -80,40 +86,46 @@ class hmac { public: - static constexpr boost::crypt::size_t block_size_ {HasherType::block_size}; + static constexpr boost::crypt::size_t block_size {HasherType::block_size}; using return_type = typename HasherType::return_type; - using key_type = boost::crypt::array; + using key_type = compat::array; + +BOOST_CRYPT_GPU_ENABLED_CONSTEXPR hmac() noexcept = default; + + template + explicit BOOST_CRYPT_GPU_ENABLED_CONSTEXPR hmac(const compat::span key) noexcept; - BOOST_CRYPT_GPU_ENABLED constexpr hmac() noexcept = default; + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR ~hmac() noexcept; - template - BOOST_CRYPT_GPU_ENABLED constexpr hmac(ForwardIter key, boost::crypt::size_t size) noexcept; + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto init_from_keys(const key_type& inner_key, + const key_type& outer_key) noexcept -> state; - template - BOOST_CRYPT_GPU_ENABLED constexpr hmac(const Container& c) noexcept; + template + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto init(compat::span data) noexcept -> state; - BOOST_CRYPT_GPU_ENABLED constexpr hmac(const key_type& inner_key, const key_type& outer_key) noexcept; + template + BOOST_CRYPT_GPU_ENABLED auto init(SizedRange&& data) noexcept -> state; - template - BOOST_CRYPT_GPU_ENABLED constexpr auto init(ForwardIter key, boost::crypt::size_t size) noexcept -> state; + template + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto process_bytes(compat::span data) noexcept -> state; - template - BOOST_CRYPT_GPU_ENABLED constexpr auto init(const Container& c) noexcept -> state; + template + BOOST_CRYPT_GPU_ENABLED auto process_bytes(SizedRange&& data) noexcept -> state; - template - BOOST_CRYPT_GPU_ENABLED constexpr auto init_from_keys(const Container& inner_key, const Container& outer_key) noexcept -> state; + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto finalize() noexcept -> state; - template - BOOST_CRYPT_GPU_ENABLED constexpr auto process_bytes(ForwardIter data, boost::crypt::size_t size) noexcept -> state; + [[nodiscard]] BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto get_digest() const noexcept -> compat::expected; - template - BOOST_CRYPT_GPU_ENABLED constexpr auto process_bytes(const Container& c) noexcept -> state; + template + [[nodiscard]] BOOST_CRYPT_GPU_ENABLED_CONSTEXPR + auto get_digest(compat::span data) const noexcept -> state; - BOOST_CRYPT_GPU_ENABLED constexpr auto get_digest() noexcept -> return_type; + template + [[nodiscard]] BOOST_CRYPT_GPU_ENABLED auto get_digest(Range&& data) const noexcept -> state; - BOOST_CRYPT_GPU_ENABLED constexpr auto get_outer_key() noexcept -> key_type; + [[nodiscard]] BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto get_outer_key() const noexcept -> key_type; - BOOST_CRYPT_GPU_ENABLED constexpr auto get_inner_key() noexcept -> key_type; + [[nodiscard]] BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto get_inner_key() const noexcept -> key_type; } //namespace crypt } //namespace boost diff --git a/doc/crypt/sha1.adoc b/doc/crypt/sha1.adoc index a30fb595..a41b9287 100644 --- a/doc/crypt/sha1.adoc +++ b/doc/crypt/sha1.adoc @@ -33,7 +33,7 @@ public: // Process bytes piecewise BOOST_CRYPT_GPU_ENABLED constexpr state process_bytes(compat::span data) noexcept; - template + template BOOST_CRYPT_GPU_ENABLED constexpr state process_bytes(Range&& data) noexcept; // Finalize the calculation of the hash @@ -59,7 +59,7 @@ namespace boost::crypt { [[nodiscard]] BOOST_CRYPT_GPU_ENABLED constexpr auto sha1(compat::span data) noexcept -> expected; -template +template [[nodiscard]] BOOST_CRYPT_GPU_ENABLED auto sha1(SizedRange&& data) noexcept -> expected; } // namespace boost::crypt diff --git a/doc/crypt/sha224.adoc b/doc/crypt/sha224.adoc index 469452e7..9fe93660 100644 --- a/doc/crypt/sha224.adoc +++ b/doc/crypt/sha224.adoc @@ -33,7 +33,7 @@ public: // Process bytes piecewise BOOST_CRYPT_GPU_ENABLED constexpr state process_bytes(compat::span data) noexcept; - template + template BOOST_CRYPT_GPU_ENABLED constexpr state process_bytes(Range&& data) noexcept; // Finalize the calculation of the hash @@ -59,7 +59,7 @@ namespace boost::crypt { [[nodiscard]] BOOST_CRYPT_GPU_ENABLED constexpr auto sha224(compat::span data) noexcept -> expected; -template +template [[nodiscard]] BOOST_CRYPT_GPU_ENABLED auto sha224(SizedRange&& data) noexcept -> expected; } // namespace boost::crypt diff --git a/doc/crypt/sha256.adoc b/doc/crypt/sha256.adoc index 9525875a..b4c23d08 100644 --- a/doc/crypt/sha256.adoc +++ b/doc/crypt/sha256.adoc @@ -33,7 +33,7 @@ public: // Process bytes piecewise BOOST_CRYPT_GPU_ENABLED constexpr state process_bytes(compat::span data) noexcept; - template + template BOOST_CRYPT_GPU_ENABLED constexpr state process_bytes(Range&& data) noexcept; // Finalize the calculation of the hash @@ -59,7 +59,7 @@ namespace boost::crypt { [[nodiscard]] BOOST_CRYPT_GPU_ENABLED constexpr auto sha256(compat::span data) noexcept -> expected; -template +template [[nodiscard]] BOOST_CRYPT_GPU_ENABLED auto sha256(SizedRange&& data) noexcept -> expected; } // namespace boost::crypt diff --git a/doc/crypt/sha384.adoc b/doc/crypt/sha384.adoc index 6e0f8068..5b5f3021 100644 --- a/doc/crypt/sha384.adoc +++ b/doc/crypt/sha384.adoc @@ -33,7 +33,7 @@ public: // Process bytes piecewise BOOST_CRYPT_GPU_ENABLED constexpr state process_bytes(compat::span data) noexcept; - template + template BOOST_CRYPT_GPU_ENABLED constexpr state process_bytes(Range&& data) noexcept; // Finalize the calculation of the hash @@ -59,7 +59,7 @@ namespace boost::crypt { [[nodiscard]] BOOST_CRYPT_GPU_ENABLED constexpr auto sha384(compat::span data) noexcept -> expected; -template +template [[nodiscard]] BOOST_CRYPT_GPU_ENABLED auto sha384(SizedRange&& data) noexcept -> expected; } // namespace boost::crypt diff --git a/doc/crypt/sha3_224.adoc b/doc/crypt/sha3_224.adoc index 52ff6e90..91df05d1 100644 --- a/doc/crypt/sha3_224.adoc +++ b/doc/crypt/sha3_224.adoc @@ -33,7 +33,7 @@ public: // Process bytes piecewise BOOST_CRYPT_GPU_ENABLED constexpr state process_bytes(compat::span data) noexcept; - template + template BOOST_CRYPT_GPU_ENABLED constexpr state process_bytes(Range&& data) noexcept; // Finalize the calculation of the hash @@ -59,7 +59,7 @@ namespace boost::crypt { [[nodiscard]] BOOST_CRYPT_GPU_ENABLED constexpr auto sha3_224(compat::span data) noexcept -> expected; -template +template [[nodiscard]] BOOST_CRYPT_GPU_ENABLED auto sha3_224(SizedRange&& data) noexcept -> expected; } // namespace boost::crypt diff --git a/doc/crypt/sha3_256.adoc b/doc/crypt/sha3_256.adoc index ad72761a..df0e0ab3 100644 --- a/doc/crypt/sha3_256.adoc +++ b/doc/crypt/sha3_256.adoc @@ -33,7 +33,7 @@ public: // Process bytes piecewise BOOST_CRYPT_GPU_ENABLED constexpr state process_bytes(compat::span data) noexcept; - template + template BOOST_CRYPT_GPU_ENABLED constexpr state process_bytes(Range&& data) noexcept; // Finalize the calculation of the hash @@ -59,7 +59,7 @@ namespace boost::crypt { [[nodiscard]] BOOST_CRYPT_GPU_ENABLED constexpr auto sha3_256(compat::span data) noexcept -> expected; -template +template [[nodiscard]] BOOST_CRYPT_GPU_ENABLED auto sha3_256(SizedRange&& data) noexcept -> expected; } // namespace boost::crypt diff --git a/doc/crypt/sha3_384.adoc b/doc/crypt/sha3_384.adoc index 63c63728..89493f61 100644 --- a/doc/crypt/sha3_384.adoc +++ b/doc/crypt/sha3_384.adoc @@ -33,7 +33,7 @@ public: // Process bytes piecewise BOOST_CRYPT_GPU_ENABLED constexpr state process_bytes(compat::span data) noexcept; - template + template BOOST_CRYPT_GPU_ENABLED constexpr state process_bytes(Range&& data) noexcept; // Finalize the calculation of the hash @@ -59,7 +59,7 @@ namespace boost::crypt { [[nodiscard]] BOOST_CRYPT_GPU_ENABLED constexpr auto sha3_384(compat::span data) noexcept -> expected; -template +template [[nodiscard]] BOOST_CRYPT_GPU_ENABLED auto sha3_384(SizedRange&& data) noexcept -> expected; } // namespace boost::crypt diff --git a/doc/crypt/sha3_512.adoc b/doc/crypt/sha3_512.adoc index d7275f6b..4de2037b 100644 --- a/doc/crypt/sha3_512.adoc +++ b/doc/crypt/sha3_512.adoc @@ -33,7 +33,7 @@ public: // Process bytes piecewise BOOST_CRYPT_GPU_ENABLED constexpr state process_bytes(compat::span data) noexcept; - template + template BOOST_CRYPT_GPU_ENABLED constexpr state process_bytes(Range&& data) noexcept; // Finalize the calculation of the hash @@ -59,7 +59,7 @@ namespace boost::crypt { [[nodiscard]] BOOST_CRYPT_GPU_ENABLED constexpr auto sha3_512(compat::span data) noexcept -> expected; -template +template [[nodiscard]] BOOST_CRYPT_GPU_ENABLED auto sha3_512(SizedRange&& data) noexcept -> expected; } // namespace boost::crypt diff --git a/doc/crypt/sha512.adoc b/doc/crypt/sha512.adoc index b441cd02..c87421d2 100644 --- a/doc/crypt/sha512.adoc +++ b/doc/crypt/sha512.adoc @@ -33,7 +33,7 @@ public: // Process bytes piecewise BOOST_CRYPT_GPU_ENABLED constexpr state process_bytes(compat::span data) noexcept; - template + template BOOST_CRYPT_GPU_ENABLED constexpr state process_bytes(Range&& data) noexcept; // Finalize the calculation of the hash @@ -59,7 +59,7 @@ namespace boost::crypt { [[nodiscard]] BOOST_CRYPT_GPU_ENABLED constexpr auto sha512(compat::span data) noexcept -> expected; -template +template [[nodiscard]] BOOST_CRYPT_GPU_ENABLED auto sha512(SizedRange&& data) noexcept -> expected; } // namespace boost::crypt diff --git a/doc/crypt/sha512_224.adoc b/doc/crypt/sha512_224.adoc index 118a093e..c7154deb 100644 --- a/doc/crypt/sha512_224.adoc +++ b/doc/crypt/sha512_224.adoc @@ -33,7 +33,7 @@ public: // Process bytes piecewise BOOST_CRYPT_GPU_ENABLED constexpr state process_bytes(compat::span data) noexcept; - template + template BOOST_CRYPT_GPU_ENABLED constexpr state process_bytes(Range&& data) noexcept; // Finalize the calculation of the hash @@ -59,7 +59,7 @@ namespace boost::crypt { [[nodiscard]] BOOST_CRYPT_GPU_ENABLED constexpr auto sha512_224(compat::span data) noexcept -> expected; -template +template [[nodiscard]] BOOST_CRYPT_GPU_ENABLED auto sha512_224(SizedRange&& data) noexcept -> expected; } // namespace boost::crypt diff --git a/doc/crypt/sha512_256.adoc b/doc/crypt/sha512_256.adoc index dbe1ec8c..92424308 100644 --- a/doc/crypt/sha512_256.adoc +++ b/doc/crypt/sha512_256.adoc @@ -33,7 +33,7 @@ public: // Process bytes piecewise BOOST_CRYPT_GPU_ENABLED constexpr state process_bytes(compat::span data) noexcept; - template + template BOOST_CRYPT_GPU_ENABLED constexpr state process_bytes(Range&& data) noexcept; // Finalize the calculation of the hash @@ -59,7 +59,7 @@ namespace boost::crypt { [[nodiscard]] BOOST_CRYPT_GPU_ENABLED constexpr auto sha512_256(compat::span data) noexcept -> expected; -template +template [[nodiscard]] BOOST_CRYPT_GPU_ENABLED auto sha512_256(SizedRange&& data) noexcept -> expected; } // namespace boost::crypt diff --git a/doc/crypt/shake128.adoc b/doc/crypt/shake128.adoc new file mode 100644 index 00000000..976f507a --- /dev/null +++ b/doc/crypt/shake128.adoc @@ -0,0 +1,111 @@ +//// +Copyright 2025 Matt Borland +Distributed under the Boost Software License, Version 1.0. +https://www.boost.org/LICENSE_1_0.txt +//// + +[#shake128] +:idprefix: shake128_ + += SHAKE128 + +This library supports shake128 as described in https://doi.org/10.6028/NIST.FIPS.202[SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions]. +There is a wide range of acceptable inputs for the base shake128 function: + +== Hashing Object + +[#shake128_hasher] +Lastly, there is also the ability to create a shake128 hashing object and feed it bytes as the user parses them. +This class does not use any dynamic memory allocation. + +[source, c++] +---- +namespace boost::crypt { + +class shake128_hasher +{ +public: + uisng return_type = compat::array; + + // Initialize the hasher + BOOST_CRYPT_GPU_ENABLED constexpr void init() noexcept; + + // Process bytes piecewise + BOOST_CRYPT_GPU_ENABLED constexpr state process_bytes(compat::span data) noexcept; + + template + BOOST_CRYPT_GPU_ENABLED constexpr state process_bytes(Range&& data) noexcept; + + // Finalize the calculation of the hash + BOOST_CRYPT_GPU_ENABLED constexpr state finalize() noexcept; + + // Get the digest including variable length output + [[nodiscard]] constexpr expected get_digest() noexcept; + + [[nodiscard]] BOOST_CRYPT_GPU_ENABLED_CONSTEXPR state get_digest(compat::span data) noexcept; + + template + [[nodiscard]] BOOST_CRYPT_GPU_ENABLED state get_digest(Range&& data) noexcept; + + [[nodiscard]] BOOST_CRYPT_GPU_ENABLED_CONSTEXPR state get_digest(compat::span data, compat::size_t amount) noexcept; + + template + [[nodiscard]] BOOST_CRYPT_GPU_ENABLED state get_digest(Range&& data, compat::size_t amount) noexcept; +}; + +} // namespace boost::crypt +---- + +IMPORTANT: The `get_digest` methods here are not marked `const` as each time you call `get_digest` the state is updated and you will receive a different digest. + +When a container is passed without the `amount` parameter passed the hasher will fill the complete span or range being passed. + +== One-Shot Hashing Functions + +[source, c++] +---- +namespace boost::crypt { + +[[nodiscard]] BOOST_CRYPT_GPU_ENABLED constexpr auto shake128(compat::span data) noexcept -> expected; + +template +[[nodiscard]] BOOST_CRYPT_GPU_ENABLED auto shake128(SizedRange&& data) noexcept -> expected; + +[[nodiscard]] BOOST_CRYPT_GPU_ENABLED constexpr auto shake128(compat::span data, compat::span return_container) noexcept -> expected; + +template +[[nodiscard]] BOOST_CRYPT_GPU_ENABLED auto shake128(SizedRange&& data, OutputRange&& output) noexcept -> expected; + +[[nodiscard]] BOOST_CRYPT_GPU_ENABLED constexpr auto shake128(compat::span data, compat::span return_container, compat::size_t amount) noexcept -> expected; + +template +[[nodiscard]] BOOST_CRYPT_GPU_ENABLED auto shake128(SizedRange&& data, OutputRange&& output, std::size_t amount) noexcept -> expected; + +} // namespace boost::crypt +---- + +== File Hashing Functions + +We also have the ability to scan files and return the shake128 value: + +[source, c++] +---- +namespace boost::crypt { + +template +[[nodiscard]] inline auto shake128_file(const T& filepath) -> expected; + +template +[[nodiscard]] inline auto shake128_file(const T& filepath, std::span out) -> state; + +template +[[nodiscard]] inline auto shake128_file(const T& filepath, std::span out, std::size_t amount) -> state; + +template +[[nodiscard]] inline auto shake128_file(const T& filepath, OutputRange&& out) -> state; + +template +[[nodiscard]] inline auto shake128_file(const T& filepath, OutputRange&& out, std::size_t amount) -> state; + +} // namespace boost::crypt +---- diff --git a/doc/crypt/shake256.adoc b/doc/crypt/shake256.adoc new file mode 100644 index 00000000..e9090404 --- /dev/null +++ b/doc/crypt/shake256.adoc @@ -0,0 +1,111 @@ +//// +Copyright 2025 Matt Borland +Distributed under the Boost Software License, Version 1.0. +https://www.boost.org/LICENSE_1_0.txt +//// + +[#shake256] +:idprefix: shake256_ + += SHAKE128 + +This library supports shake256 as described in https://doi.org/10.6028/NIST.FIPS.202[SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions]. +There is a wide range of acceptable inputs for the base shake256 function: + +== Hashing Object + +[#shake256_hasher] +Lastly, there is also the ability to create a shake256 hashing object and feed it bytes as the user parses them. +This class does not use any dynamic memory allocation. + +[source, c++] +---- +namespace boost::crypt { + +class shake256_hasher +{ +public: + uisng return_type = compat::array; + + // Initialize the hasher + BOOST_CRYPT_GPU_ENABLED constexpr void init() noexcept; + + // Process bytes piecewise + BOOST_CRYPT_GPU_ENABLED constexpr state process_bytes(compat::span data) noexcept; + + template + BOOST_CRYPT_GPU_ENABLED constexpr state process_bytes(Range&& data) noexcept; + + // Finalize the calculation of the hash + BOOST_CRYPT_GPU_ENABLED constexpr state finalize() noexcept; + + // Get the digest including variable length output + [[nodiscard]] constexpr expected get_digest() noexcept; + + [[nodiscard]] BOOST_CRYPT_GPU_ENABLED_CONSTEXPR state get_digest(compat::span data) noexcept; + + template + [[nodiscard]] BOOST_CRYPT_GPU_ENABLED state get_digest(Range&& data) noexcept; + + [[nodiscard]] BOOST_CRYPT_GPU_ENABLED_CONSTEXPR state get_digest(compat::span data, compat::size_t amount) noexcept; + + template + [[nodiscard]] BOOST_CRYPT_GPU_ENABLED state get_digest(Range&& data, compat::size_t amount) noexcept; +}; + +} // namespace boost::crypt +---- + +IMPORTANT: The `get_digest` methods here are not marked `const` as each time you call `get_digest` the state is updated and you will receive a different digest. + +When a container is passed without the `amount` parameter passed the hasher will fill the complete span or range being passed. + +== One-Shot Hashing Functions + +[source, c++] +---- +namespace boost::crypt { + +[[nodiscard]] BOOST_CRYPT_GPU_ENABLED constexpr auto shake256(compat::span data) noexcept -> expected; + +template +[[nodiscard]] BOOST_CRYPT_GPU_ENABLED auto shake256(SizedRange&& data) noexcept -> expected; + +[[nodiscard]] BOOST_CRYPT_GPU_ENABLED constexpr auto shake256(compat::span data, compat::span return_container) noexcept -> expected; + +template +[[nodiscard]] BOOST_CRYPT_GPU_ENABLED auto shake256(SizedRange&& data, OutputRange&& output) noexcept -> expected; + +[[nodiscard]] BOOST_CRYPT_GPU_ENABLED constexpr auto shake256(compat::span data, compat::span return_container, compat::size_t amount) noexcept -> expected; + +template +[[nodiscard]] BOOST_CRYPT_GPU_ENABLED auto shake256(SizedRange&& data, OutputRange&& output, std::size_t amount) noexcept -> expected; + +} // namespace boost::crypt +---- + +== File Hashing Functions + +We also have the ability to scan files and return the shake256 value: + +[source, c++] +---- +namespace boost::crypt { + +template +[[nodiscard]] inline auto shake256_file(const T& filepath) -> expected; + +template +[[nodiscard]] inline auto shake256_file(const T& filepath, std::span out) -> state; + +template +[[nodiscard]] inline auto shake256_file(const T& filepath, std::span out, std::size_t amount) -> state; + +template +[[nodiscard]] inline auto shake256_file(const T& filepath, OutputRange&& out) -> state; + +template +[[nodiscard]] inline auto shake256_file(const T& filepath, OutputRange&& out, std::size_t amount) -> state; + +} // namespace boost::crypt +---- diff --git a/include/boost/crypt2/hash/detail/hash_file.hpp b/include/boost/crypt2/hash/detail/hash_file.hpp index e350ba04..fdbc5c1a 100644 --- a/include/boost/crypt2/hash/detail/hash_file.hpp +++ b/include/boost/crypt2/hash/detail/hash_file.hpp @@ -49,6 +49,31 @@ template return hasher.get_digest(); } +template +[[nodiscard]] auto hash_file_impl(const T& filepath, std::span out, std::size_t amount) -> state +{ + if constexpr (std::is_pointer_v>) + { + if (filepath == nullptr) + { + throw std::runtime_error("Invalid file path"); + } + } + + detail::file_reader reader(filepath); + HasherType hasher; + + while (!reader.eof()) + { + const auto buffer_iter {reader.read_next_block()}; + const auto len {reader.get_bytes_read()}; + const auto buffer_span {std::span(buffer_iter, len)}; + hasher.process_bytes(buffer_span); + } + + hasher.finalize(); + return hasher.get_digest(out, amount); +} #if defined(__clang__) && __clang_major__ >= 19 #pragma clang diagnostic pop diff --git a/include/boost/crypt2/hash/shake128.hpp b/include/boost/crypt2/hash/shake128.hpp index aa63d3d2..a967a1e3 100644 --- a/include/boost/crypt2/hash/shake128.hpp +++ b/include/boost/crypt2/hash/shake128.hpp @@ -102,6 +102,40 @@ auto shake128_file(const T& filepath) -> compat::expected(filepath); } +template +[[nodiscard]] BOOST_CRYPT_EXPORT +auto shake128_file(const T& filepath, compat::span out) -> state +{ + return hash_detail::hash_file_impl(filepath, out); +} + +template +[[nodiscard]] BOOST_CRYPT_EXPORT +auto shake128_file(const T& filepath, compat::span out, compat::size_t amount) -> state +{ + return hash_detail::hash_file_impl(filepath, out, amount); +} + +template +[[nodiscard]] BOOST_CRYPT_EXPORT +auto shake128_file(const T& filepath, OutputRange&& out) -> state +{ + using value_type = compat::range_value_t; + auto data_span {compat::span(compat::forward(out))}; + + return hash_detail::hash_file_impl(filepath, compat::span(compat::as_writable_bytes(data_span).data(), data_span.size_bytes()), data_span.size_bytes()); +} + +template +[[nodiscard]] BOOST_CRYPT_EXPORT +auto shake128_file(const T& filepath, OutputRange&& out, compat::size_t amount) -> state +{ + using value_type = compat::range_value_t; + auto data_span {compat::span(compat::forward(out))}; + + return hash_detail::hash_file_impl(filepath, compat::span(compat::as_writable_bytes(data_span).data(), data_span.size_bytes()), amount); +} + #endif // BOOST_CRYPT_HAS_CUDA } // namespace boost::crypt diff --git a/include/boost/crypt2/hash/shake256.hpp b/include/boost/crypt2/hash/shake256.hpp index 0d257620..1f8df357 100644 --- a/include/boost/crypt2/hash/shake256.hpp +++ b/include/boost/crypt2/hash/shake256.hpp @@ -102,6 +102,40 @@ auto shake256_file(const T& filepath) -> compat::expected(filepath); } +template +[[nodiscard]] BOOST_CRYPT_EXPORT +auto shake256_file(const T& filepath, compat::span out) -> state +{ + return hash_detail::hash_file_impl(filepath, out); +} + +template +[[nodiscard]] BOOST_CRYPT_EXPORT +auto shake256_file(const T& filepath, compat::span out, compat::size_t amount) -> state +{ + return hash_detail::hash_file_impl(filepath, out, amount); +} + +template +[[nodiscard]] BOOST_CRYPT_EXPORT +auto shake256_file(const T& filepath, OutputRange&& out) -> state +{ + using value_type = compat::range_value_t; + auto data_span {compat::span(compat::forward(out))}; + + return hash_detail::hash_file_impl(filepath, compat::span(compat::as_writable_bytes(data_span).data(), data_span.size_bytes()), data_span.size_bytes()); +} + +template +[[nodiscard]] BOOST_CRYPT_EXPORT +auto shake256_file(const T& filepath, OutputRange&& out, compat::size_t amount) -> state +{ + using value_type = compat::range_value_t; + auto data_span {compat::span(compat::forward(out))}; + + return hash_detail::hash_file_impl(filepath, compat::span(compat::as_writable_bytes(data_span).data(), data_span.size_bytes()), amount); +} + #endif // BOOST_CRYPT_HAS_CUDA } // namespace boost::crypt diff --git a/test/test_shake128.cpp b/test/test_shake128.cpp index 1f7e8913..583c8aa8 100644 --- a/test/test_shake128.cpp +++ b/test/test_shake128.cpp @@ -338,6 +338,37 @@ void files_test() std::filesystem::path bad_path = "path.txt"; BOOST_TEST_THROWS([[maybe_unused]] const auto trash5 = boost::crypt::shake128_file(bad_path), std::runtime_error); + + // Now test XOF file capabilities + std::array byte_array {}; + std::span byte_span {byte_array}; + + BOOST_TEST(boost::crypt::shake128_file(filename, byte_array) == boost::crypt::state::success); + + std::size_t zero_counter {}; + for (const auto val : byte_array) + { + if (val == std::byte{}) + { + ++zero_counter; // LCOV_EXCL_LINE + } + } + BOOST_TEST(zero_counter < byte_array.size()); + + byte_array.fill(std::byte{}); + + BOOST_TEST(boost::crypt::shake128_file(filename, byte_span, 100U) == boost::crypt::state::success); + + // Does not matter that we know 100 are zeros + // If the other 100 are zeros there is a deep problem + for (const auto val : byte_array) + { + if (val == std::byte{}) + { + ++zero_counter; + } + } + BOOST_TEST(zero_counter < byte_array.size()); } consteval bool immediate_test() diff --git a/test/test_shake256.cpp b/test/test_shake256.cpp index e4e74e02..897d8b47 100644 --- a/test/test_shake256.cpp +++ b/test/test_shake256.cpp @@ -362,6 +362,37 @@ void files_test() std::filesystem::path bad_path = "path.txt"; BOOST_TEST_THROWS([[maybe_unused]] const auto trash5 = boost::crypt::shake256_file(bad_path), std::runtime_error); + + // Now test XOF file capabilities + std::array byte_array {}; + std::span byte_span {byte_array}; + + BOOST_TEST(boost::crypt::shake256_file(filename, byte_array) == boost::crypt::state::success); + + std::size_t zero_counter {}; + for (const auto val : byte_array) + { + if (val == std::byte{}) + { + ++zero_counter; // LCOV_EXCL_LINE + } + } + BOOST_TEST(zero_counter < byte_array.size()); + + byte_array.fill(std::byte{}); + + BOOST_TEST(boost::crypt::shake256_file(filename, byte_span, 100U) == boost::crypt::state::success); + + // Does not matter that we know 100 are zeros + // If the other 100 are zeros there is a deep problem + for (const auto val : byte_array) + { + if (val == std::byte{}) + { + ++zero_counter; + } + } + BOOST_TEST(zero_counter < byte_array.size()); } consteval bool immediate_test()