diff --git a/include/boost/crypt2/hash/detail/sha3_base.hpp b/include/boost/crypt2/hash/detail/sha3_base.hpp index 3485aaf0..697c3397 100644 --- a/include/boost/crypt2/hash/detail/sha3_base.hpp +++ b/include/boost/crypt2/hash/detail/sha3_base.hpp @@ -37,11 +37,13 @@ class sha3_base final { BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto process_message_block() noexcept -> void; + template [[nodiscard]] BOOST_CRYPT_GPU_ENABLED_CONSTEXPR - auto update(compat::span data) noexcept -> state; + auto update(compat::span data) noexcept -> state; + template BOOST_CRYPT_GPU_ENABLED_CONSTEXPR - auto xof_digest_impl(compat::span data, compat::size_t amount) noexcept -> void; + auto xof_digest_impl(compat::span data, compat::size_t amount) noexcept -> void; BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto sha_digest_impl(compat::span data) const noexcept -> void; @@ -57,7 +59,8 @@ class sha3_base final { BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto init() noexcept -> void; - BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto process_bytes(compat::span data) noexcept -> state; + template + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto process_bytes(compat::span data) noexcept -> state; template BOOST_CRYPT_GPU_ENABLED auto process_bytes(SizedRange&& data) noexcept -> state; @@ -241,14 +244,30 @@ BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto sha3_base::process_m buffer_index_ = 0U; } +// In the fixed extent case where we check Extent == 0 this can make the rest of the code unreachable +// We consider this a good thing since this means our compile time checks are working +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4702) +#endif + template +template [[nodiscard]] BOOST_CRYPT_GPU_ENABLED_CONSTEXPR -auto sha3_base::update(compat::span data) noexcept -> state +auto sha3_base::update(compat::span data) noexcept -> state { - if (data.empty()) + if constexpr (Extent == compat::dynamic_extent) + { + if (data.empty()) + { + return state::success; + } + } + else if constexpr (Extent == 0U) { return state::success; } + if (computed_) { corrupted_ = true; @@ -271,6 +290,10 @@ auto sha3_base::update(compat::span dat return state::success; } +#ifdef _MSC_VER +#pragma warning(pop) +#endif + template BOOST_CRYPT_GPU_ENABLED_CONSTEXPR sha3_base::~sha3_base() noexcept { @@ -292,8 +315,9 @@ BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto sha3_base::init() no } template +template BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto -sha3_base::process_bytes(compat::span data) noexcept -> state +sha3_base::process_bytes(compat::span data) noexcept -> state { return update(data); } @@ -333,8 +357,9 @@ BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto sha3_base::finalize( } template +template BOOST_CRYPT_GPU_ENABLED_CONSTEXPR -auto sha3_base::xof_digest_impl(compat::span data, std::size_t amount) noexcept -> void +auto sha3_base::xof_digest_impl(compat::span data, std::size_t amount) noexcept -> void { static_assert(is_xof, "Calling for variable amounts of data is not allowed with non-XOF hashers"); @@ -390,11 +415,19 @@ sha3_base::get_digest() noexcept } return_type digest {}; - xof_digest_impl(digest, digest_size); + compat::span digest_span {digest}; + xof_digest_impl(digest_span, digest_size); return digest; } +// In the fixed extent case where we check Extent < digest_size this can make the rest of the code unreachable +// We consider this a good thing since this means our compile time checks are working +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4702) +#endif + template template [[nodiscard]] BOOST_CRYPT_GPU_ENABLED_CONSTEXPR @@ -404,7 +437,15 @@ compat::enable_if_t sha3_base::get_digest(com { return state::state_error; } - if (data.size() < digest_size) + + if constexpr (Extent == compat::dynamic_extent) + { + if (data.size() < digest_size) + { + return state::insufficient_output_length; + } + } + else if constexpr (Extent < digest_size) { return state::insufficient_output_length; } @@ -431,6 +472,10 @@ compat::enable_if_t sha3_base::get_digest(com return state::success; } +#ifdef _MSC_VER +#pragma warning(pop) +#endif + template template [[nodiscard]] BOOST_CRYPT_GPU_ENABLED_CONSTEXPR @@ -459,15 +504,13 @@ compat::enable_if_t sha3_base::get_digest(Ran return state::state_error; } - const auto data_size {std::size(data)}; + auto data_span {compat::span(compat::forward(data))}; - if (data_size < digest_size) + if (data_span.size_bytes() < digest_size) { return state::insufficient_output_length; } - auto data_span {compat::span(compat::forward(data))}; - #if defined(__clang__) && __clang_major__ >= 19 #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-container" @@ -499,7 +542,6 @@ compat::enable_if_t sha3_base::get_digest(Ran return state::state_error; } - const auto data_size {std::size(data)}; auto data_span {compat::span(compat::forward(data))}; #if defined(__clang__) && __clang_major__ >= 19 @@ -507,7 +549,7 @@ compat::enable_if_t sha3_base::get_digest(Ran #pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-container" #endif - xof_digest_impl(compat::span(compat::as_writable_bytes(data_span).data(), data_size), data_size); + xof_digest_impl(compat::span(compat::as_writable_bytes(data_span).data(), data_span.size_bytes()), data_span.size_bytes()); #if defined(__clang__) && __clang_major__ >= 19 #pragma clang diagnostic pop @@ -526,7 +568,7 @@ compat::enable_if_t sha3_base::get_digest(com return state::state_error; } - if (data.size() < amount) + if (data.size_bytes() < amount) { return state::insufficient_output_length; } @@ -549,13 +591,13 @@ compat::enable_if_t sha3_base::get_digest(Ran return state::state_error; } - if (std::size(data) < amount) + auto data_span {compat::span(compat::forward(data))}; + + if (data_span.size_bytes() < amount) { return state::insufficient_output_length; } - auto data_span {compat::span(compat::forward(data))}; - #if defined(__clang__) && __clang_major__ >= 19 #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-container" diff --git a/include/boost/crypt2/hash/detail/sha512_base.hpp b/include/boost/crypt2/hash/detail/sha512_base.hpp index c0eaf717..8efb740f 100644 --- a/include/boost/crypt2/hash/detail/sha512_base.hpp +++ b/include/boost/crypt2/hash/detail/sha512_base.hpp @@ -42,7 +42,8 @@ class sha512_base final BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto process_message_block() noexcept -> void; - [[nodiscard]] BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto update(compat::span data) noexcept -> state; + template + [[nodiscard]] BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto update(compat::span data) noexcept -> state; BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto pad_message() noexcept -> void; @@ -56,7 +57,8 @@ class sha512_base final BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto init() noexcept -> void; - BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto process_bytes(compat::span data) noexcept -> state; + template + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto process_bytes(compat::span data) noexcept -> state; template BOOST_CRYPT_GPU_ENABLED auto process_bytes(SizedRange&& data) noexcept -> state; @@ -193,13 +195,22 @@ BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto sha512_base::finalize() noex } template +template [[nodiscard]] BOOST_CRYPT_GPU_ENABLED_CONSTEXPR -auto sha512_base::update(compat::span data) noexcept -> state +auto sha512_base::update(compat::span data) noexcept -> state { - if (data.empty()) + if constexpr (Extent == compat::dynamic_extent) + { + if (data.empty()) + { + return state::success; + } + } + else if constexpr (Extent == 0U) { return state::success; } + if (computed_) { corrupted_ = true; @@ -485,7 +496,8 @@ BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto sha512_base::process_message } template -BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto sha512_base::process_bytes(compat::span data) noexcept -> state +template +BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto sha512_base::process_bytes(compat::span data) noexcept -> state { return update(data); } diff --git a/include/boost/crypt2/hash/detail/sha_1_2_hasher_base.hpp b/include/boost/crypt2/hash/detail/sha_1_2_hasher_base.hpp index d80699b7..551ab560 100644 --- a/include/boost/crypt2/hash/detail/sha_1_2_hasher_base.hpp +++ b/include/boost/crypt2/hash/detail/sha_1_2_hasher_base.hpp @@ -36,7 +36,8 @@ class sha_1_2_hasher_base bool computed_ {}; bool corrupted_ {}; - [[nodiscard]] BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto update(compat::span data) noexcept -> state; + template + [[nodiscard]] BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto update(compat::span data) noexcept -> state; [[nodiscard]] BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto get_digest_impl(compat::span data) const noexcept -> state; @@ -47,7 +48,8 @@ class sha_1_2_hasher_base BOOST_CRYPT_GPU_ENABLED_CONSTEXPR sha_1_2_hasher_base() noexcept { base_init(); } BOOST_CRYPT_GPU_ENABLED_CONSTEXPR ~sha_1_2_hasher_base() noexcept; - BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto process_bytes(compat::span data) noexcept -> state; + template + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto process_bytes(compat::span data) noexcept -> state; template BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto process_bytes(SizedRange&& data) noexcept -> state; @@ -236,19 +238,29 @@ BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto sha_1_2_hasher_base -BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto sha_1_2_hasher_base::process_bytes(compat::span data) noexcept -> state +template +BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto sha_1_2_hasher_base::process_bytes(compat::span data) noexcept -> state { return update(data); } template +template [[nodiscard]] BOOST_CRYPT_GPU_ENABLED_CONSTEXPR -auto sha_1_2_hasher_base::update(compat::span data) noexcept -> state +auto sha_1_2_hasher_base::update(compat::span data) noexcept -> state { - if (data.empty()) + if constexpr (Extent == compat::dynamic_extent) + { + if (data.empty()) + { + return state::success; + } + } + else if constexpr (Extent == 0U) { return state::success; } + if (computed_) { corrupted_ = true; diff --git a/include/boost/crypt2/mac/hmac.hpp b/include/boost/crypt2/mac/hmac.hpp index 8a4eb53a..bf1c671d 100644 --- a/include/boost/crypt2/mac/hmac.hpp +++ b/include/boost/crypt2/mac/hmac.hpp @@ -26,6 +26,8 @@ class hmac private: + using key_span = compat::span; + key_type inner_key_ {}; key_type outer_key_ {}; HasherType inner_hash_; @@ -125,8 +127,8 @@ hmac::init_impl(const compat::span data) outer_key_[i] = k0[i] ^ compat::byte{0x5C}; } - const auto inner_result {inner_hash_.process_bytes(inner_key_)}; - const auto outer_result {outer_hash_.process_bytes(outer_key_)}; + const auto inner_result {inner_hash_.process_bytes(key_span{inner_key_})}; + const auto outer_result {outer_hash_.process_bytes(key_span{outer_key_})}; if (inner_result == state::success && outer_result == state::success) [[likely]] { @@ -177,8 +179,8 @@ hmac::init_from_keys(const hmac::key_type& inner_key, const hmac::ke inner_key_ = inner_key; outer_key_ = outer_key; - const auto inner_result {inner_hash_.process_bytes(inner_key)}; - const auto outer_result {outer_hash_.process_bytes(outer_key)}; + const auto inner_result {inner_hash_.process_bytes(key_span{inner_key})}; + const auto outer_result {outer_hash_.process_bytes(key_span{outer_key})}; if (inner_result == state::success && outer_result == state::success) [[likely]] { @@ -275,7 +277,8 @@ BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto hmac::finalize() noexcept -> const auto r_inner {inner_hash_.get_digest()}; BOOST_CRYPT_ASSERT(r_inner.has_value()); - outer_hash_.process_bytes(r_inner.value()); + compat::span r_inner_span {r_inner.value()}; + outer_hash_.process_bytes(r_inner_span); [[maybe_unused]] const auto outer_final_state {outer_hash_.finalize()}; BOOST_CRYPT_ASSERT(outer_final_state == state::success); diff --git a/test/test_hmac.cpp b/test/test_hmac.cpp index 0600ff24..3feb5064 100644 --- a/test/test_hmac.cpp +++ b/test/test_hmac.cpp @@ -4,8 +4,16 @@ #include #include +#include #include +#include #include +#include +#include +#include +#include +#include +#include #include template @@ -66,6 +74,19 @@ void basic_tests() BOOST_TEST(res[i] == static_cast(soln[i])); } } + else + { + std::size_t zero_counter {}; + for (const auto val : res) + { + if (val == std::byte{}) + { + ++zero_counter; + } + } + + BOOST_TEST(zero_counter < res.size()); + } } template @@ -128,15 +149,84 @@ void test_edges() BOOST_TEST(hmac_tester.finalize() == boost::crypt::state::state_error); } +template +consteval bool immediate_test() +{ + const std::byte vals[] = {std::byte{0x61}, std::byte{0x62}, std::byte{0x63}}; + std::span byte_span {vals}; + constexpr std::array message { + std::byte{0xdd}, std::byte{0xaf}, std::byte{0x35}, std::byte{0xa1}, std::byte{0x93}, std::byte{0x61}, + std::byte{0x7a}, std::byte{0xba}, std::byte{0xcc}, std::byte{0x41}, std::byte{0x73}, std::byte{0x49}, + std::byte{0xae}, std::byte{0x20}, std::byte{0x41}, std::byte{0x31}, std::byte{0x12}, std::byte{0xe6}, + std::byte{0xfa}, std::byte{0x4e}, std::byte{0x89}, std::byte{0xa9}, std::byte{0x7e}, std::byte{0xa2}, + std::byte{0x0a}, std::byte{0x9e}, std::byte{0xee}, std::byte{0xe6}, std::byte{0x4b}, std::byte{0x55}, + std::byte{0xd3}, std::byte{0x9a}, std::byte{0x21}, std::byte{0x92}, std::byte{0x99}, std::byte{0x2a}, + std::byte{0x27}, std::byte{0x4f}, std::byte{0xc1}, std::byte{0xa8}, std::byte{0x36}, std::byte{0xba}, + std::byte{0x3c}, std::byte{0x23}, std::byte{0xa3}, std::byte{0xfe}, std::byte{0xeb}, std::byte{0xbd}, + std::byte{0x45}, std::byte{0x4d}, std::byte{0x44}, std::byte{0x23}, std::byte{0x64}, std::byte{0x3c}, + std::byte{0xe8}, std::byte{0x0e}, std::byte{0x2a}, std::byte{0x9a}, std::byte{0xc9}, std::byte{0x4f}, + std::byte{0xa5}, std::byte{0x4c}, std::byte{0xa4}, std::byte{0x9f} + }; + std::span message_span {message}; + + boost::crypt::hmac hmac_tester; + hmac_tester.init(byte_span); + hmac_tester.process_bytes(message_span); + hmac_tester.finalize(); + const auto res = hmac_tester.get_digest().value(); + + std::size_t zero_counter {}; + for (const auto val : res) + { + if (val == std::byte{}) + { + ++zero_counter; + } + } + + return zero_counter != res.size(); +} + int main() { basic_tests(); + basic_tests(); basic_tests(); + basic_tests(); basic_tests(); + basic_tests(); + basic_tests(); + basic_tests(); + basic_tests(); + basic_tests(); + basic_tests(); test_edges(); + test_edges(); test_edges(); + test_edges(); test_edges(); + test_edges(); + test_edges(); + test_edges(); + test_edges(); + test_edges(); + test_edges(); + + // GCC-14 has an internal compiler error here + #if defined(__GNUC__) && __GNUC__ != 14 + static_assert(immediate_test()); + static_assert(immediate_test()); + static_assert(immediate_test()); + static_assert(immediate_test()); + static_assert(immediate_test()); + static_assert(immediate_test()); + static_assert(immediate_test()); + static_assert(immediate_test()); + static_assert(immediate_test()); + static_assert(immediate_test()); + static_assert(immediate_test()); + #endif return boost::report_errors(); }