diff --git a/include/boost/crypt2/detail/clear_mem.hpp b/include/boost/crypt2/detail/clear_mem.hpp index a9c32fdc..2cd83a89 100644 --- a/include/boost/crypt2/detail/clear_mem.hpp +++ b/include/boost/crypt2/detail/clear_mem.hpp @@ -93,9 +93,9 @@ constexpr void clear_mem(std::span<std::byte> data) } */ -using generic_meset_t = void(*)(void*, size_t); +using generic_meset_t = void(*)(void*, compat::size_t); -inline void generic_runtime_memset_func_impl(void* ptr, size_t size) +inline void generic_runtime_memset_func_impl(void* ptr, compat::size_t size) { #if defined(__clang__) && __clang_major__ >= 20 #pragma clang diagnostic push @@ -120,7 +120,7 @@ constexpr void clear_mem(T& data) } else { - generic_runtime_memset_func_impl(data.data(), data.size()); + generic_runtime_memset_func(data.data(), data.size()); } } diff --git a/include/boost/crypt2/detail/compat.hpp b/include/boost/crypt2/detail/compat.hpp index 9d6941db..c84f19ea 100644 --- a/include/boost/crypt2/detail/compat.hpp +++ b/include/boost/crypt2/detail/compat.hpp @@ -214,9 +214,9 @@ BOOST_CRYPT_GPU_ENABLED constexpr auto make_span(R&& r) else { #if BOOST_CRYPT_HAS_CUDA - return cuda::std::span(cuda::std::forward<R>(r)); + return cuda::std::span{cuda::std::forward<R>(r).data(), cuda::std::forward<R>(r).size()}; #else - return std::span(std::forward<R>(r)); + return std::span{std::forward<R>(r).data(), std::forward<R>(r).size()}; #endif } } diff --git a/include/boost/crypt2/detail/unreachable.hpp b/include/boost/crypt2/detail/unreachable.hpp new file mode 100644 index 00000000..7705faee --- /dev/null +++ b/include/boost/crypt2/detail/unreachable.hpp @@ -0,0 +1,29 @@ +// Copyright 2024 - 2025 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CRYPT_DETAIL_UNREACHABLE_HPP +#define BOOST_CRYPT_DETAIL_UNREACHABLE_HPP + +#include <boost/crypt2/detail/config.hpp> +#include <boost/crypt2/detail/compat.hpp> + +namespace boost::crypt::detail { + +// LCOV_EXCL_START +[[noreturn]] inline void unreachable() +{ + // Uses compiler specific extensions if possible. + // Even if no extension is used, undefined behavior is still raised by + // an empty function body and the noreturn attribute. +#if defined(_MSC_VER) && !defined(__clang__) // MSVC + __assume(false); +#else // GCC, Clang, NVCC + __builtin_unreachable(); +#endif +} +// LCOV_EXCL_STOP + +} // namespace boost::crypt::detail + +#endif // BOOST_CRYPT_DETAIL_UNREACHABLE_HPP 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 32d5859e..d80699b7 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 @@ -55,7 +55,7 @@ class sha_1_2_hasher_base BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto finalize() noexcept -> state; // TODO(mborland): Allow this to take dynamic extent, check the length and then use a fixed amount. See sha512_base - [[nodiscard("Digest is the function return value")]] BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto get_digest() noexcept -> compat::expected<return_type, state>; + [[nodiscard("Digest is the function return value")]] BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto get_digest() const noexcept -> compat::expected<return_type, state>; template <compat::size_t Extent = compat::dynamic_extent> [[nodiscard]] BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto get_digest(compat::span<compat::byte, Extent> data) const noexcept -> state; @@ -145,7 +145,7 @@ sha_1_2_hasher_base<digest_size, intermediate_hash_size>::get_digest(compat::spa template <compat::size_t digest_size, compat::size_t intermediate_hash_size> BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto -sha_1_2_hasher_base<digest_size, intermediate_hash_size>::get_digest() noexcept -> compat::expected<return_type, state> +sha_1_2_hasher_base<digest_size, intermediate_hash_size>::get_digest() const noexcept -> compat::expected<return_type, state> { if (corrupted_ || !computed_) { diff --git a/include/boost/crypt2/mac/hmac.hpp b/include/boost/crypt2/mac/hmac.hpp new file mode 100644 index 00000000..8a4eb53a --- /dev/null +++ b/include/boost/crypt2/mac/hmac.hpp @@ -0,0 +1,322 @@ +// Copyright 2024 - 2025 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CRYPT2_MAC_HMAC_HPP +#define BOOST_CRYPT2_MAC_HMAC_HPP + +#include <boost/crypt2/detail/config.hpp> +#include <boost/crypt2/detail/concepts.hpp> +#include <boost/crypt2/detail/compat.hpp> +#include <boost/crypt2/detail/clear_mem.hpp> +#include <boost/crypt2/detail/expected.hpp> +#include <boost/crypt2/detail/unreachable.hpp> +#include <boost/crypt2/state.hpp> + +namespace boost::crypt { + +BOOST_CRYPT_EXPORT template <typename HasherType> +class hmac +{ +public: + + static constexpr compat::size_t block_size {HasherType::block_size}; + using return_type = typename HasherType::return_type; + using key_type = compat::array<compat::byte, block_size>; + +private: + + key_type inner_key_ {}; + key_type outer_key_ {}; + HasherType inner_hash_; + HasherType outer_hash_; + bool initialized_ {false}; + bool computed_ {false}; + bool corrupted_ {false}; + + template <compat::size_t Extent = compat::dynamic_extent> + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto init_impl(compat::span<const compat::byte, Extent> data) noexcept -> state; + +public: + + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR hmac() noexcept = default; + + template <compat::size_t Extent = compat::dynamic_extent> + explicit BOOST_CRYPT_GPU_ENABLED_CONSTEXPR hmac(const compat::span<const compat::byte, Extent> key) noexcept { init(key); } + + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR ~hmac() noexcept; + + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto init_from_keys(const key_type& inner_key, + const key_type& outer_key) noexcept -> state; + + template <compat::size_t Extent = compat::dynamic_extent> + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto init(compat::span<const compat::byte, Extent> data) noexcept -> state; + + template <concepts::sized_range SizedRange> + BOOST_CRYPT_GPU_ENABLED auto init(SizedRange&& data) noexcept -> state; + + template <compat::size_t Extent = compat::dynamic_extent> + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto process_bytes(compat::span<const compat::byte, Extent> data) noexcept -> state; + + template <concepts::sized_range SizedRange> + BOOST_CRYPT_GPU_ENABLED auto process_bytes(SizedRange&& data) noexcept -> state; + + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto finalize() noexcept -> state; + + [[nodiscard]] BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto get_digest() const noexcept -> compat::expected<return_type, state>; + + template <compat::size_t Extent = compat::dynamic_extent> + [[nodiscard]] BOOST_CRYPT_GPU_ENABLED_CONSTEXPR + auto get_digest(compat::span<compat::byte, Extent> data) const noexcept -> state; + + template <concepts::writable_output_range Range> + [[nodiscard]] BOOST_CRYPT_GPU_ENABLED auto get_digest(Range&& data) const noexcept -> state; + + [[nodiscard]] BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto get_outer_key() const noexcept -> key_type; + + [[nodiscard]] BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto get_inner_key() const noexcept -> key_type; +}; + +template <typename HasherType> +template <compat::size_t Extent> +BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto +hmac<HasherType>::init_impl(const compat::span<const compat::byte, Extent> data) noexcept -> state +{ + computed_ = false; + corrupted_ = false; + inner_hash_.init(); + outer_hash_.init(); + + key_type k0 {}; + + // Step 1: If the length of K = B set K0 = K. Go to step 4 + // OR + // Step 3: If the length of K < B: append zeros to the end of K. + if (data.size() <= block_size) + { + for (compat::size_t i {}; i < data.size() && i < block_size; ++i) + { + k0[i] = data[i]; + } + } + // Step 2: If the length of K > B: hash K to obtain an L byte string + else + { + HasherType hasher; + hasher.process_bytes(data); + hasher.finalize(); + const auto res {hasher.get_digest()}; + BOOST_CRYPT_ASSERT(res.has_value()); + + const auto data_hash {res.value()}; + BOOST_CRYPT_ASSERT(data_hash.size() <= k0.size()); + + for (compat::size_t i {}; i < data_hash.size(); ++i) + { + k0[i] = data_hash[i]; + } + } + + // Step 4: XOR k0 with ipad to produce a B-byte string K0 ^ ipad + // Step 7: XOR k0 with opad to produce a B-byte string K0 ^ opad + for (compat::size_t i {}; i < k0.size(); ++i) + { + inner_key_[i] = k0[i] ^ compat::byte{0x36}; + 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_)}; + + if (inner_result == state::success && outer_result == state::success) [[likely]] + { + initialized_ = true; + return state::success; + } + else + { + // If we have some weird OOM result + // LCOV_EXCL_START + if (inner_result != state::success) + { + return inner_result; + } + else + { + return outer_result; + } + // LCOV_EXCL_STOP + } +} + +template <typename HasherType> +template <compat::size_t Extent> +BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto +hmac<HasherType>::init(const compat::span<const compat::byte, Extent> data) noexcept -> state +{ + return init_impl(data); +} + +template <typename HasherType> +template <concepts::sized_range SizedRange> +BOOST_CRYPT_GPU_ENABLED auto hmac<HasherType>::init(SizedRange&& data) noexcept -> state +{ + const auto data_span {compat::make_span(compat::forward<SizedRange>(data))}; + return init_impl(compat::as_bytes(data_span)); +} + +template <typename HasherType> +BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto +hmac<HasherType>::init_from_keys(const hmac::key_type& inner_key, const hmac::key_type& outer_key) noexcept -> state +{ + computed_ = false; + corrupted_ = false; + inner_hash_.init(); + outer_hash_.init(); + + 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)}; + + if (inner_result == state::success && outer_result == state::success) [[likely]] + { + initialized_ = true; + return state::success; + } + else + { + // These fail states would imply something deeply wrong with the hasher or key + // LCOV_EXCL_START + initialized_ = false; + + if (inner_result != state::success) + { + return inner_result; + } + else + { + return outer_result; + } + // LCOV_EXCL_STOP + } +} + +template <typename HasherType> +BOOST_CRYPT_GPU_ENABLED_CONSTEXPR hmac<HasherType>::~hmac() noexcept +{ + // Inner and outer has will clear their own memory on destruction + + detail::clear_mem(inner_key_); + detail::clear_mem(outer_key_); + initialized_ = false; + computed_ = false; + corrupted_ = false; +} + +template <typename HasherType> +template <compat::size_t Extent> +BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto +hmac<HasherType>::process_bytes(const compat::span<const compat::byte, Extent> data) noexcept -> state +{ + if (!initialized_ || corrupted_) + { + return state::state_error; + } + + const auto return_code {inner_hash_.process_bytes(data)}; + if (return_code == state::success) + { + return state::success; + } + else + { + // Cannot test 64 and 128 bit OOM + // LCOV_EXCL_START + switch (return_code) + { + case state::state_error: + corrupted_ = true; + return state::state_error; + case state::input_too_long: + corrupted_ = true; + return state::input_too_long; + default: + detail::unreachable(); + } + // LCOV_EXCL_STOP + } +} + +template <typename HasherType> +template <concepts::sized_range SizedRange> +BOOST_CRYPT_GPU_ENABLED auto hmac<HasherType>::process_bytes(SizedRange&& data) noexcept -> state +{ + const auto data_span {compat::make_span(compat::forward<SizedRange>(data))}; + return process_bytes(compat::as_bytes(data_span)); +} + +template <typename HasherType> +BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto hmac<HasherType>::finalize() noexcept -> state +{ + if (computed_) + { + corrupted_ = true; + } + if (corrupted_) + { + return state::state_error; + } + + computed_ = true; + [[maybe_unused]] const auto inner_final_state {inner_hash_.finalize()}; + BOOST_CRYPT_ASSERT(inner_final_state == state::success); + const auto r_inner {inner_hash_.get_digest()}; + BOOST_CRYPT_ASSERT(r_inner.has_value()); + + outer_hash_.process_bytes(r_inner.value()); + [[maybe_unused]] const auto outer_final_state {outer_hash_.finalize()}; + BOOST_CRYPT_ASSERT(outer_final_state == state::success); + + return state::success; +} + +template <typename HasherType> +BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto +hmac<HasherType>::get_digest() const noexcept -> compat::expected<return_type, state> +{ + return outer_hash_.get_digest(); +} + +template <typename HasherType> +template <concepts::writable_output_range Range> +BOOST_CRYPT_GPU_ENABLED auto +hmac<HasherType>::get_digest(Range&& data) const noexcept -> state +{ + return outer_hash_.get_digest(data); +} + +template <typename HasherType> +template <compat::size_t Extent> +BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto +hmac<HasherType>::get_digest(compat::span<compat::byte, Extent> data) const noexcept -> state +{ + return outer_hash_.get_digest(data); +} + +template <typename HasherType> +BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto hmac<HasherType>::get_outer_key() const noexcept -> hmac::key_type +{ + return outer_key_; +} + +template <typename HasherType> +BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto hmac<HasherType>::get_inner_key() const noexcept -> hmac::key_type +{ + return inner_key_; +} + +} // namespace boost::crypt + +#endif //BOOST_CRYPT2_MAC_HMAC_HPP diff --git a/test/Jamfile b/test/Jamfile index 3d744097..b1846d6a 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -73,7 +73,7 @@ run test_sha3_224.cpp ; run test_shake128.cpp ; run test_shake256.cpp ; -#run test_hmac.cpp ; +run test_hmac.cpp ; #run test_hmac_drbg.cpp ; diff --git a/test/test_hmac.cpp b/test/test_hmac.cpp index 65d2bfb5..0600ff24 100644 --- a/test/test_hmac.cpp +++ b/test/test_hmac.cpp @@ -2,68 +2,55 @@ // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt -#define BOOST_CRYPT_ENABLE_MD5 - -#include "boost/crypt/mac/hmac.hpp" -#include <boost/crypt/hash/md5.hpp> -#include <boost/crypt/hash/sha1.hpp> -#include <boost/crypt/hash/sha256.hpp> -#include <boost/crypt/hash/sha512.hpp> +#include <boost/crypt2/mac/hmac.hpp> +#include <boost/crypt2/hash/sha1.hpp> +#include <boost/crypt2/hash/sha256.hpp> +#include <boost/crypt2/hash/sha512.hpp> #include <boost/core/lightweight_test.hpp> template <typename HasherType> void basic_tests() { boost::crypt::hmac<HasherType> hmac_tester; - const auto state_1 {hmac_tester.init("key", 3)}; + const auto state_1 {hmac_tester.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_tester.process_bytes(msg, std::strlen(msg))}; + std::string msg {"The quick brown fox jumps over the lazy dog"}; + const auto state_2 {hmac_tester.process_bytes(msg)}; BOOST_TEST(state_2 == boost::crypt::state::success); - const auto res {hmac_tester.get_digest()}; - - BOOST_CRYPT_IF_CONSTEXPR (boost::crypt::is_same_v<HasherType, boost::crypt::md5_hasher>) - { - constexpr boost::crypt::array<boost::crypt::uint8_t, 16U> soln = { - 0x80, 0x07, 0x07, 0x13, 0x46, 0x3e, 0x77, 0x49, 0xb9, 0x0c, 0x2d, 0xc2, 0x49, 0x11, 0xe2, 0x75 - }; - - for (boost::crypt::size_t i {}; i < res.size(); ++i) - { - BOOST_TEST_EQ(res[i], soln[i]); - } - } - else BOOST_CRYPT_IF_CONSTEXPR (boost::crypt::is_same_v<HasherType, boost::crypt::sha1_hasher>) + hmac_tester.finalize(); + const auto res {hmac_tester.get_digest().value()}; + + if constexpr (std::is_same_v<HasherType, boost::crypt::sha1_hasher>) { - constexpr boost::crypt::array<boost::crypt::uint8_t, 20U> soln = { + constexpr std::array<std::uint8_t, 20U> soln = { 0xde, 0x7c, 0x9b, 0x85, 0xb8, 0xb7, 0x8a, 0xa6, 0xbc, 0x8a, 0x7a, 0x36, 0xf7, 0x0a, 0x90, 0x70, 0x1c, 0x9d, 0xb4, 0xd9 }; - for (boost::crypt::size_t i {}; i < res.size(); ++i) + for (std::size_t i {}; i < res.size(); ++i) { - BOOST_TEST_EQ(res[i], soln[i]); + BOOST_TEST(res[i] == static_cast<std::byte>(soln[i])); } } - else BOOST_CRYPT_IF_CONSTEXPR (boost::crypt::is_same_v<HasherType, boost::crypt::sha256_hasher>) + else if constexpr (std::is_same_v<HasherType, boost::crypt::sha256_hasher>) { - constexpr boost::crypt::array<boost::crypt::uint8_t, 32U> soln = { + constexpr std::array<std::uint8_t, 32U> soln = { 0xf7, 0xbc, 0x83, 0xf4, 0x30, 0x53, 0x84, 0x24, 0xb1, 0x32, 0x98, 0xe6, 0xaa, 0x6f, 0xb1, 0x43, 0xef, 0x4d, 0x59, 0xa1, 0x49, 0x46, 0x17, 0x59, 0x97, 0x47, 0x9d, 0xbc, 0x2d, 0x1a, 0x3c, 0xd8 }; - for (boost::crypt::size_t i {}; i < res.size(); ++i) + for (std::size_t i {}; i < res.size(); ++i) { - BOOST_TEST_EQ(res[i], soln[i]); + BOOST_TEST(res[i] == static_cast<std::byte>(soln[i])); } } - else BOOST_CRYPT_IF_CONSTEXPR (boost::crypt::is_same_v<HasherType, boost::crypt::sha512_hasher>) + else if constexpr (std::is_same_v<HasherType, boost::crypt::sha512_hasher>) { - constexpr boost::crypt::array<boost::crypt::uint8_t, 64U> soln = { + constexpr std::array<std::uint8_t, 64U> soln = { 0xb4, 0x2a, 0xf0, 0x90, 0x57, 0xba, 0xc1, 0xe2, 0xd4, 0x17, 0x08, 0xe4, 0x8a, 0x90, 0x2e, 0x09, 0xb5, 0xff, 0x7f, 0x12, 0xab, 0x42, 0x8a, 0x4f, @@ -74,51 +61,38 @@ void basic_tests() 0xd0, 0x37, 0x2a, 0xfa, 0x2e, 0xbe, 0xeb, 0x3a }; - for (boost::crypt::size_t i {}; i < res.size(); ++i) + for (std::size_t i {}; i < res.size(); ++i) { - BOOST_TEST_EQ(res[i], soln[i]); + BOOST_TEST(res[i] == static_cast<std::byte>(soln[i])); } } - - hmac_tester.destroy(); } template <typename HasherType> void test_edges() { boost::crypt::hmac<HasherType> hmac_tester; - const char* msg {"The quick brown fox jumps over the lazy dog"}; + std::string msg {"The quick brown fox jumps over the lazy dog"}; // Usage before init - const auto state1 {hmac_tester.process_bytes(msg, std::strlen(msg))}; + const auto state1 {hmac_tester.process_bytes(msg)}; BOOST_TEST(state1 == boost::crypt::state::state_error); - // Init with nullptr - const auto state2 {hmac_tester.init("nullptr", 0)}; - BOOST_TEST(state2 == boost::crypt::state::null); - // Good init - const auto state3 {hmac_tester.init("key", 3)}; + const auto state3 {hmac_tester.init(std::string{"key"})}; BOOST_TEST(state3 == boost::crypt::state::success); - // Pass in nullptr - const auto state4 {hmac_tester.process_bytes("msg", 0)}; - BOOST_TEST(state4 == boost::crypt::state::null); - // Good pass - const auto state5 {hmac_tester.process_bytes(msg, std::strlen(msg))}; + const auto state5 {hmac_tester.process_bytes(msg)}; BOOST_TEST(state5 == boost::crypt::state::success); // Get digest twice - hmac_tester.get_digest(); + hmac_tester.finalize(); + [[maybe_unused]] const auto garbage = hmac_tester.get_digest(); const auto res {hmac_tester.get_digest()}; + BOOST_TEST(res.has_value()); - for (const auto byte : res) - { - BOOST_TEST_EQ(byte, static_cast<std::uint8_t>(0)); - } - - const char* big_key {"This is a really really really really really really really really really really" + std::string big_key {"This is a really really really really really really really really really really" " really really really really really really really really really really" " really really really really really really really really really really" " really really really really really really really really really really" @@ -130,34 +104,36 @@ void test_edges() " really really really really really really really really really really" " long key"}; - const auto state6 {hmac_tester.init(big_key, std::strlen(big_key))}; + const auto state6 {hmac_tester.init(big_key)}; BOOST_TEST(state6 == boost::crypt::state::success); // Init from keys const auto outer_key {hmac_tester.get_outer_key()}; const auto inner_key {hmac_tester.get_inner_key()}; - hmac_tester.process_bytes(msg, std::strlen(msg)); - const auto res2 {hmac_tester.get_digest()}; + hmac_tester.process_bytes(msg); + hmac_tester.finalize(); + const auto res2 {hmac_tester.get_digest().value()}; hmac_tester.init_from_keys(inner_key, outer_key); - hmac_tester.process_bytes(msg, std::strlen(msg)); - const auto res3 {hmac_tester.get_digest()}; + hmac_tester.process_bytes(msg); + hmac_tester.finalize(); + const auto res3 {hmac_tester.get_digest().value()}; for (std::size_t i {}; i < res2.size(); ++i) { - BOOST_TEST_EQ(res2[i], res3[i]); + BOOST_TEST(res2[i] == res3[i]); } + + BOOST_TEST(hmac_tester.finalize() == boost::crypt::state::state_error); } int main() { - basic_tests<boost::crypt::md5_hasher>(); basic_tests<boost::crypt::sha1_hasher>(); basic_tests<boost::crypt::sha256_hasher>(); basic_tests<boost::crypt::sha512_hasher>(); - test_edges<boost::crypt::md5_hasher>(); test_edges<boost::crypt::sha1_hasher>(); test_edges<boost::crypt::sha256_hasher>(); test_edges<boost::crypt::sha512_hasher>(); diff --git a/test/test_nist_cavs_detail.hpp b/test/test_nist_cavs_detail.hpp index de0f1bc0..032fff19 100644 --- a/test/test_nist_cavs_detail.hpp +++ b/test/test_nist_cavs_detail.hpp @@ -2133,9 +2133,19 @@ auto test_vectors_hmac(const nist::cavs::test_vector_container_type& test_vector this_hash.process_bytes(test_vector.my_msg.data(), test_vector.my_msg.size()); + this_hash.finalize(); + const local_result_type result_01 { this_hash.get_digest() }; - const bool result_hash_01_is_ok { std::equal(test_vector.my_result.cbegin(), test_vector.my_result.cend(), result_01.cbegin()) }; + bool result_hash_01_is_ok {true}; + for (std::size_t i {}; i < test_vector.my_result.size(); ++i) + { + if (static_cast<std::byte>(test_vector.my_result[i]) != result_01[i]) + { + result_hash_01_is_ok = false; + break; + } + } BOOST_TEST(result_hash_01_is_ok); @@ -2149,9 +2159,19 @@ auto test_vectors_hmac(const nist::cavs::test_vector_container_type& test_vector this_hash.process_bytes(test_vector.my_msg); + this_hash.finalize(); + const local_result_type result_02 { this_hash.get_digest() }; - const bool result_hash_02_is_ok { std::equal(test_vector.my_result.cbegin(), test_vector.my_result.cend(), result_02.cbegin()) }; + bool result_hash_02_is_ok {true}; + for (std::size_t i {}; i < test_vector.my_result.size(); ++i) + { + if (static_cast<std::byte>(test_vector.my_result[i]) != result_02[i]) + { + result_hash_02_is_ok = false; + break; + } + } BOOST_TEST(result_hash_02_is_ok);