From ba899878e99788dd39dc2f1b0954734067edfa3e Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 1 Nov 2024 11:36:56 -0400 Subject: [PATCH 01/14] Add block size member to each hasher base --- include/boost/crypt/hash/detail/hasher_base_512.hpp | 5 ++++- include/boost/crypt/hash/detail/sha3_base.hpp | 6 +++++- include/boost/crypt/hash/detail/sha512_base.hpp | 4 ++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/include/boost/crypt/hash/detail/hasher_base_512.hpp b/include/boost/crypt/hash/detail/hasher_base_512.hpp index 10b941a7..4b2ac5ec 100644 --- a/include/boost/crypt/hash/detail/hasher_base_512.hpp +++ b/include/boost/crypt/hash/detail/hasher_base_512.hpp @@ -35,6 +35,9 @@ template class hasher_base_512 { +public: + static constexpr boost::crypt::size_t block_size {64U}; + protected: // Use CRTP to make this constexpr with C++14 @@ -46,7 +49,7 @@ class hasher_base_512 BOOST_CRYPT_GPU_ENABLED constexpr auto update(ForwardIter data, boost::crypt::size_t size) noexcept -> hasher_state; boost::crypt::array intermediate_hash_ {}; - boost::crypt::array buffer_ {}; + boost::crypt::array buffer_ {}; boost::crypt::size_t buffer_index_ {}; boost::crypt::size_t low_ {}; boost::crypt::size_t high_ {}; diff --git a/include/boost/crypt/hash/detail/sha3_base.hpp b/include/boost/crypt/hash/detail/sha3_base.hpp index 96e435c1..6e4a4659 100644 --- a/include/boost/crypt/hash/detail/sha3_base.hpp +++ b/include/boost/crypt/hash/detail/sha3_base.hpp @@ -36,13 +36,17 @@ namespace hash_detail { template class sha3_base { +public: + + static constexpr boost::crypt::size_t block_size {200U - 2U * digest_size}; + private: static_assert((!is_xof && (digest_size == 28U || digest_size == 32U || digest_size == 48U || digest_size == 64U)) || is_xof, "Digest size must be 28 (SHA3-224), 32 (SHA3-256), 48 (SHA3-384), or 64(SHA3-512) or this must be an xof"); boost::crypt::array state_array_ {}; - boost::crypt::array buffer_ {}; + boost::crypt::array buffer_ {}; boost::crypt::size_t buffer_index_ {}; bool computed_ {}; bool corrupted_ {}; diff --git a/include/boost/crypt/hash/detail/sha512_base.hpp b/include/boost/crypt/hash/detail/sha512_base.hpp index a41186a5..0f403371 100644 --- a/include/boost/crypt/hash/detail/sha512_base.hpp +++ b/include/boost/crypt/hash/detail/sha512_base.hpp @@ -35,6 +35,10 @@ namespace hash_detail { template class sha512_base final { +public: + + static constexpr boost::crypt::size_t block_size {128U}; + private: static_assert(digest_size == 28U || digest_size == 32U || digest_size == 48U || digest_size == 64U, From a1e2843387573bb09655a4a444da2e5ad345c217 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 4 Nov 2024 16:43:08 -0500 Subject: [PATCH 02/14] Begin adding basic testing --- test/Jamfile | 2 ++ test/test_hmac.cpp | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 test/test_hmac.cpp diff --git a/test/Jamfile b/test/Jamfile index a72f7747..15621daf 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -64,6 +64,8 @@ run test_sha3_224.cpp ; run test_shake128.cpp ; run test_shake256.cpp ; +run test_hmac.cpp ; + # NIST standard testing run test_nist_cavs_sha1_monte.cpp ; run test_nist_cavs_sha1_short_long.cpp ; diff --git a/test/test_hmac.cpp b/test/test_hmac.cpp new file mode 100644 index 00000000..f2658088 --- /dev/null +++ b/test/test_hmac.cpp @@ -0,0 +1,42 @@ +// Copyright 2024 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#define BOOST_CRYPT_ENABLE_MD5 + +#include +#include +#include + +template +void basic_tests() +{ + boost::crypt::hmac hmac_tester; + const auto state_1 {hmac_tester.init("key", 3)}; + BOOST_TEST(state_1 == boost::crypt::hasher_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))}; + BOOST_TEST(state_2 == boost::crypt::hasher_state::success); + + const auto res {hmac_tester.get_digest()}; + + BOOST_CRYPT_IF_CONSTEXPR (boost::crypt::is_same_v) + { + constexpr boost::crypt::array 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]); + } + } +} + +int main() +{ + basic_tests(); + + return boost::report_errors(); +} From f80ff09eb51f8d3326397d8a5af1acf45864a38b Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 4 Nov 2024 16:43:19 -0500 Subject: [PATCH 03/14] Add default hmac --- include/boost/crypt/hash/md5.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/boost/crypt/hash/md5.hpp b/include/boost/crypt/hash/md5.hpp index a36ac655..ea70e0cf 100644 --- a/include/boost/crypt/hash/md5.hpp +++ b/include/boost/crypt/hash/md5.hpp @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -51,6 +52,8 @@ BOOST_CRYPT_EXPORT class md5_hasher final : public hash_detail::hasher_base_512< BOOST_CRYPT_GPU_ENABLED constexpr auto process_message_block() noexcept -> void; }; +BOOST_CRYPT_EXPORT using hmac_md5 = hmac; + BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::init() noexcept -> void { hash_detail::hasher_base_512<16U, 4U, md5_hasher>::base_init(); From 4fefbaf8eb661792a9f43b15a1f16255c77ad795 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 4 Nov 2024 16:43:29 -0500 Subject: [PATCH 04/14] Add basic hmac impl --- include/boost/crypt/hash/hmac.hpp | 235 ++++++++++++++++++++++++++++++ 1 file changed, 235 insertions(+) create mode 100644 include/boost/crypt/hash/hmac.hpp diff --git a/include/boost/crypt/hash/hmac.hpp b/include/boost/crypt/hash/hmac.hpp new file mode 100644 index 00000000..2a402d45 --- /dev/null +++ b/include/boost/crypt/hash/hmac.hpp @@ -0,0 +1,235 @@ +// Copyright 2024 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CRYPT_HASH_HMAC_HPP +#define BOOST_CRYPT_HASH_HMAC_HPP + +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace crypt { + +BOOST_CRYPT_EXPORT template +class hmac +{ +public: + + static constexpr boost::crypt::size_t block_size_ {HasherType::block_size}; + using return_type = typename HasherType::return_type; + using key_type = boost::crypt::array; + +private: + + key_type inner_key_ {}; + key_type outer_key_ {}; + HasherType inner_hash_; + HasherType outer_hash_; + bool initialized_ {false}; + bool computed_ {false}; + bool corrupted_ {false}; + +public: + + BOOST_CRYPT_GPU_ENABLED constexpr hmac() noexcept {} + + template + BOOST_CRYPT_GPU_ENABLED constexpr hmac(ForwardIter key, boost::crypt::size_t size) noexcept { init(key, size); } + + BOOST_CRYPT_GPU_ENABLED constexpr hmac(const key_type& inner_key, const key_type& outer_key) noexcept { init_from_keys(inner_key, outer_key); } + + template + BOOST_CRYPT_GPU_ENABLED constexpr auto init(ForwardIter key, boost::crypt::size_t size) noexcept -> hasher_state; + + BOOST_CRYPT_GPU_ENABLED constexpr auto init_from_keys(const key_type& inner_key, + const key_type& outer_key) noexcept -> hasher_state; + + template + BOOST_CRYPT_GPU_ENABLED constexpr auto process_bytes(ForwardIter key, boost::crypt::size_t size) noexcept -> hasher_state; + + BOOST_CRYPT_GPU_ENABLED constexpr auto get_digest() noexcept -> return_type; + + BOOST_CRYPT_GPU_ENABLED constexpr auto get_outer_key() noexcept -> key_type; + + BOOST_CRYPT_GPU_ENABLED constexpr auto get_inner_key() noexcept -> key_type; +}; + +template +constexpr auto hmac::get_inner_key() noexcept -> key_type +{ + return inner_key_; +} + +template +constexpr auto hmac::get_outer_key() noexcept -> key_type +{ + return outer_key_; +} + +template +constexpr auto +hmac::init_from_keys(const boost::crypt::array &inner_key, + const boost::crypt::array &outer_key) noexcept -> hasher_state +{ + inner_key_ = inner_key; + outer_key_ = outer_key; + + const auto inner_result {inner_hash_.process_bytes(inner_key_.begin(), inner_key_.size())}; + const auto outer_result {outer_hash_.process_bytes(outer_hash_.begin(), outer_key_.size())}; + + if (BOOST_CRYPT_LIKELY(inner_result == hasher_state::success && outer_result == hasher_state::success)) + { + initialized_ = true; + return hasher_state::success; + } + else + { + // If we have some weird OOM result + // LCOV_EXCL_START + if (inner_result != hasher_state::success) + { + return inner_result; + } + else + { + return outer_result; + } + // LCOV_EXCL_STOP + } +} + +template +constexpr auto hmac::get_digest() noexcept -> return_type +{ + if (computed_) + { + corrupted_ = true; + } + if (corrupted_) + { + return return_type {}; + } + + computed_ = true; + const auto r_inner {inner_hash_.get_digest()}; + outer_hash_.process_bytes(r_inner.begin(), r_inner.size()); + return outer_hash_.get_digest(); +} + +template +template +constexpr auto hmac::process_bytes(ForwardIter key, boost::crypt::size_t size) noexcept -> hasher_state +{ + if (utility::is_null(key) || size == 0U) + { + return hasher_state::null; + } + else if (!initialized_ || corrupted_) + { + return hasher_state::state_error; + } + + const auto status_code {inner_hash_.process_bytes(key, size)}; + if (BOOST_CRYPT_LIKELY(status_code == hasher_state::success)) + { + return hasher_state::success; + } + else + { + // Cannot test 64 and 128 bit OOM + // LCOV_EXCL_START + switch (status_code) + { + case hasher_state::state_error: + corrupted_ = true; + return hasher_state::state_error; + case hasher_state::input_too_long: + corrupted_ = true; + return hasher_state::input_too_long; + default: + BOOST_CRYPT_UNREACHABLE; + return status_code; + } + // LCOV_EXCL_STOP + } +} + +template +template +constexpr auto hmac::init(ForwardIter key, boost::crypt::size_t size) noexcept -> hasher_state +{ + boost::crypt::array k0 {}; + + if (utility::is_null(key) || size == 0U) + { + return hasher_state::null; + } + + // 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 (size <= block_size_) + { + auto key_iter {key}; + for (boost::crypt::size_t i {}; i < size; ++i) + { + k0[i] = static_cast(*key_iter++); + } + } + // Step 2: If the length of K > B: hash K to obtain an L byte string + else if (size > block_size_) + { + HasherType hasher; + hasher.process_bytes(key, size); + const auto res {hasher.get_digest()}; + + BOOST_CRYPT_ASSERT(res.size() == k0.size()); + + auto key_iter {res.begin()}; + for (auto& byte : k0) + { + byte = *key_iter++; + } + } + + // 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 (boost::crypt::size_t i {}; i < k0.size(); ++i) + { + inner_key_[i] = static_cast(k0[i] ^ static_cast(0x36)); + outer_key_[i] = static_cast(k0[i] ^ static_cast(0x5c)); + } + + const auto inner_result {inner_hash_.process_bytes(inner_key_.begin(), inner_key_.size())}; + const auto outer_result {outer_hash_.process_bytes(outer_key_.begin(), outer_key_.size())}; + + if (BOOST_CRYPT_LIKELY(inner_result == hasher_state::success && outer_result == hasher_state::success)) + { + initialized_ = true; + return hasher_state::success; + } + else + { + // If we have some weird OOM result + // LCOV_EXCL_START + if (inner_result != hasher_state::success) + { + return inner_result; + } + else + { + return outer_result; + } + // LCOV_EXCL_STOP + } +} + +} // namespace crypt +} // namespace boost + +#endif //BOOST_CRYPT_HASH_HMAC_HPP From 07e59378a03d74ba58e593467cdfb0aaf3c9645f Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 4 Nov 2024 16:50:43 -0500 Subject: [PATCH 05/14] Add SHA1 test --- include/boost/crypt/hash/sha1.hpp | 3 +++ test/test_hmac.cpp | 13 +++++++++++++ 2 files changed, 16 insertions(+) diff --git a/include/boost/crypt/hash/sha1.hpp b/include/boost/crypt/hash/sha1.hpp index 7ea87b12..8bd3fbda 100644 --- a/include/boost/crypt/hash/sha1.hpp +++ b/include/boost/crypt/hash/sha1.hpp @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -48,6 +49,8 @@ BOOST_CRYPT_EXPORT class sha1_hasher final : public hash_detail::hasher_base_512 BOOST_CRYPT_GPU_ENABLED constexpr auto get_digest() noexcept -> sha1_hasher::return_type { return get_base_digest(); } }; +BOOST_CRYPT_EXPORT using hmac_sha1 = hmac; + BOOST_CRYPT_GPU_ENABLED constexpr auto sha1_hasher::init() noexcept -> void { hash_detail::hasher_base_512<20U, 5U, sha1_hasher>::base_init(); diff --git a/test/test_hmac.cpp b/test/test_hmac.cpp index f2658088..6875353b 100644 --- a/test/test_hmac.cpp +++ b/test/test_hmac.cpp @@ -6,6 +6,7 @@ #include #include +#include #include template @@ -27,6 +28,17 @@ void basic_tests() 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) + { + constexpr boost::crypt::array 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) { BOOST_TEST_EQ(res[i], soln[i]); @@ -37,6 +49,7 @@ void basic_tests() int main() { basic_tests(); + basic_tests(); return boost::report_errors(); } From d73ab3746cd01b9d4adc414418c686b1b7009ab2 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 4 Nov 2024 16:57:25 -0500 Subject: [PATCH 06/14] Trivial constructor --- include/boost/crypt/hash/hmac.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/crypt/hash/hmac.hpp b/include/boost/crypt/hash/hmac.hpp index 2a402d45..a69d4de8 100644 --- a/include/boost/crypt/hash/hmac.hpp +++ b/include/boost/crypt/hash/hmac.hpp @@ -36,7 +36,7 @@ class hmac public: - BOOST_CRYPT_GPU_ENABLED constexpr hmac() noexcept {} + BOOST_CRYPT_GPU_ENABLED constexpr hmac() noexcept = default; template BOOST_CRYPT_GPU_ENABLED constexpr hmac(ForwardIter key, boost::crypt::size_t size) noexcept { init(key, size); } From f31c699cdb89959072e1f53c89b89e7cc2447ab3 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 4 Nov 2024 16:57:32 -0500 Subject: [PATCH 07/14] Add SHA256 test --- test/test_hmac.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/test_hmac.cpp b/test/test_hmac.cpp index 6875353b..35a07893 100644 --- a/test/test_hmac.cpp +++ b/test/test_hmac.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include template @@ -39,6 +40,17 @@ void basic_tests() 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) + { + BOOST_TEST_EQ(res[i], soln[i]); + } + } + else BOOST_CRYPT_IF_CONSTEXPR (boost::crypt::is_same_v) + { + constexpr boost::crypt::array 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) { BOOST_TEST_EQ(res[i], soln[i]); @@ -50,6 +62,7 @@ int main() { basic_tests(); basic_tests(); + basic_tests(); return boost::report_errors(); } From 4d818edea1395e05aef6fa2386bce00967b323cd Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 4 Nov 2024 17:01:25 -0500 Subject: [PATCH 08/14] Add SHA512 test --- include/boost/crypt/hash/md5.hpp | 2 -- include/boost/crypt/hash/sha1.hpp | 2 -- test/test_hmac.cpp | 28 ++++++++++++++++++++++++++-- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/include/boost/crypt/hash/md5.hpp b/include/boost/crypt/hash/md5.hpp index ea70e0cf..e70cfc68 100644 --- a/include/boost/crypt/hash/md5.hpp +++ b/include/boost/crypt/hash/md5.hpp @@ -52,8 +52,6 @@ BOOST_CRYPT_EXPORT class md5_hasher final : public hash_detail::hasher_base_512< BOOST_CRYPT_GPU_ENABLED constexpr auto process_message_block() noexcept -> void; }; -BOOST_CRYPT_EXPORT using hmac_md5 = hmac; - BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::init() noexcept -> void { hash_detail::hasher_base_512<16U, 4U, md5_hasher>::base_init(); diff --git a/include/boost/crypt/hash/sha1.hpp b/include/boost/crypt/hash/sha1.hpp index 8bd3fbda..b47016b6 100644 --- a/include/boost/crypt/hash/sha1.hpp +++ b/include/boost/crypt/hash/sha1.hpp @@ -49,8 +49,6 @@ BOOST_CRYPT_EXPORT class sha1_hasher final : public hash_detail::hasher_base_512 BOOST_CRYPT_GPU_ENABLED constexpr auto get_digest() noexcept -> sha1_hasher::return_type { return get_base_digest(); } }; -BOOST_CRYPT_EXPORT using hmac_sha1 = hmac; - BOOST_CRYPT_GPU_ENABLED constexpr auto sha1_hasher::init() noexcept -> void { hash_detail::hasher_base_512<20U, 5U, sha1_hasher>::base_init(); diff --git a/test/test_hmac.cpp b/test/test_hmac.cpp index 35a07893..5c5dcd97 100644 --- a/test/test_hmac.cpp +++ b/test/test_hmac.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include template @@ -37,7 +38,8 @@ void basic_tests() else BOOST_CRYPT_IF_CONSTEXPR (boost::crypt::is_same_v) { constexpr boost::crypt::array soln = { - 0xde, 0x7c, 0x9b, 0x85, 0xb8, 0xb7, 0x8a, 0xa6, 0xbc, 0x8a, 0x7a, 0x36, 0xf7, 0x0a, 0x90, 0x70, 0x1c, 0x9d, 0xb4, 0xd9 + 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) @@ -48,7 +50,28 @@ void basic_tests() else BOOST_CRYPT_IF_CONSTEXPR (boost::crypt::is_same_v) { constexpr boost::crypt::array 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 + 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) + { + BOOST_TEST_EQ(res[i], soln[i]); + } + } + else BOOST_CRYPT_IF_CONSTEXPR (boost::crypt::is_same_v) + { + constexpr boost::crypt::array 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, + 0xe8, 0x66, 0x53, 0xc7, 0x3d, 0xd2, 0x48, 0xfb, + 0x82, 0xf9, 0x48, 0xa5, 0x49, 0xf7, 0xb7, 0x91, + 0xa5, 0xb4, 0x19, 0x15, 0xee, 0x4d, 0x1e, 0xc3, + 0x93, 0x53, 0x57, 0xe4, 0xe2, 0x31, 0x72, 0x50, + 0xd0, 0x37, 0x2a, 0xfa, 0x2e, 0xbe, 0xeb, 0x3a }; for (boost::crypt::size_t i {}; i < res.size(); ++i) @@ -63,6 +86,7 @@ int main() basic_tests(); basic_tests(); basic_tests(); + basic_tests(); return boost::report_errors(); } From 8dcc83c77f6a071e1401a777f332f1c137a4246d Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 4 Nov 2024 17:20:57 -0500 Subject: [PATCH 09/14] Refactor name --- include/boost/crypt/hash/hmac.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/boost/crypt/hash/hmac.hpp b/include/boost/crypt/hash/hmac.hpp index a69d4de8..a567663e 100644 --- a/include/boost/crypt/hash/hmac.hpp +++ b/include/boost/crypt/hash/hmac.hpp @@ -50,7 +50,7 @@ class hmac const key_type& outer_key) noexcept -> hasher_state; template - BOOST_CRYPT_GPU_ENABLED constexpr auto process_bytes(ForwardIter key, boost::crypt::size_t size) noexcept -> hasher_state; + BOOST_CRYPT_GPU_ENABLED constexpr auto process_bytes(ForwardIter data, boost::crypt::size_t size) noexcept -> hasher_state; BOOST_CRYPT_GPU_ENABLED constexpr auto get_digest() noexcept -> return_type; @@ -123,9 +123,9 @@ constexpr auto hmac::get_digest() noexcept -> return_type template template -constexpr auto hmac::process_bytes(ForwardIter key, boost::crypt::size_t size) noexcept -> hasher_state +constexpr auto hmac::process_bytes(ForwardIter data, boost::crypt::size_t size) noexcept -> hasher_state { - if (utility::is_null(key) || size == 0U) + if (utility::is_null(data) || size == 0U) { return hasher_state::null; } @@ -134,7 +134,7 @@ constexpr auto hmac::process_bytes(ForwardIter key, boost::crypt::si return hasher_state::state_error; } - const auto status_code {inner_hash_.process_bytes(key, size)}; + const auto status_code {inner_hash_.process_bytes(data, size)}; if (BOOST_CRYPT_LIKELY(status_code == hasher_state::success)) { return hasher_state::success; From 331d9fd62eb2b7710beebdfd74652ae4b145f6fd Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 4 Nov 2024 17:21:05 -0500 Subject: [PATCH 10/14] Fix assertion --- include/boost/crypt/hash/hmac.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/crypt/hash/hmac.hpp b/include/boost/crypt/hash/hmac.hpp index a567663e..0ab3a3fc 100644 --- a/include/boost/crypt/hash/hmac.hpp +++ b/include/boost/crypt/hash/hmac.hpp @@ -188,7 +188,7 @@ constexpr auto hmac::init(ForwardIter key, boost::crypt::size_t size hasher.process_bytes(key, size); const auto res {hasher.get_digest()}; - BOOST_CRYPT_ASSERT(res.size() == k0.size()); + BOOST_CRYPT_ASSERT(res.size() <= k0.size()); auto key_iter {res.begin()}; for (auto& byte : k0) From a93583cfd8127a9474904a8c3367e546f79a8a30 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 4 Nov 2024 17:21:17 -0500 Subject: [PATCH 11/14] Make sure internal hashers are also reset --- include/boost/crypt/hash/hmac.hpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/include/boost/crypt/hash/hmac.hpp b/include/boost/crypt/hash/hmac.hpp index 0ab3a3fc..d5f414f8 100644 --- a/include/boost/crypt/hash/hmac.hpp +++ b/include/boost/crypt/hash/hmac.hpp @@ -76,11 +76,16 @@ constexpr auto hmac::init_from_keys(const boost::crypt::array &inner_key, const boost::crypt::array &outer_key) noexcept -> hasher_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_.begin(), inner_key_.size())}; - const auto outer_result {outer_hash_.process_bytes(outer_hash_.begin(), outer_key_.size())}; + const auto outer_result {outer_hash_.process_bytes(outer_key_.begin(), outer_key_.size())}; if (BOOST_CRYPT_LIKELY(inner_result == hasher_state::success && outer_result == hasher_state::success)) { @@ -163,6 +168,11 @@ template template constexpr auto hmac::init(ForwardIter key, boost::crypt::size_t size) noexcept -> hasher_state { + computed_ = false; + corrupted_ = false; + inner_hash_.init(); + outer_hash_.init(); + boost::crypt::array k0 {}; if (utility::is_null(key) || size == 0U) From 4ff254311ac65d8ec1ebae76a8d259c24d741150 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 4 Nov 2024 17:21:50 -0500 Subject: [PATCH 12/14] Add edge case tests --- test/test_hmac.cpp | 72 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/test/test_hmac.cpp b/test/test_hmac.cpp index 5c5dcd97..93da74f0 100644 --- a/test/test_hmac.cpp +++ b/test/test_hmac.cpp @@ -81,6 +81,73 @@ void basic_tests() } } +template +void test_edges() +{ + boost::crypt::hmac hmac_tester; + const char* msg {"The quick brown fox jumps over the lazy dog"}; + + // Usage before init + const auto state1 {hmac_tester.process_bytes(msg, std::strlen(msg))}; + BOOST_TEST(state1 == boost::crypt::hasher_state::state_error); + + // Init with nullptr + const auto state2 {hmac_tester.init("nullptr", 0)}; + BOOST_TEST(state2 == boost::crypt::hasher_state::null); + + // Good init + const auto state3 {hmac_tester.init("key", 3)}; + BOOST_TEST(state3 == boost::crypt::hasher_state::success); + + // Pass in nullptr + const auto state4 {hmac_tester.process_bytes("msg", 0)}; + BOOST_TEST(state4 == boost::crypt::hasher_state::null); + + // Good pass + const auto state5 {hmac_tester.process_bytes(msg, std::strlen(msg))}; + BOOST_TEST(state5 == boost::crypt::hasher_state::success); + + // Get digest twice + hmac_tester.get_digest(); + const auto res {hmac_tester.get_digest()}; + + for (const auto byte : res) + { + BOOST_TEST_EQ(byte, static_cast(0)); + } + + const char* 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" + " 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" + " really really really really really really really really really really" + " really really really really really really really really really really" + " long key"}; + + const auto state6 {hmac_tester.init(big_key, std::strlen(big_key))}; + BOOST_TEST(state6 == boost::crypt::hasher_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.init_from_keys(inner_key, outer_key); + hmac_tester.process_bytes(msg, std::strlen(msg)); + const auto res3 {hmac_tester.get_digest()}; + + for (std::size_t i {}; i < res2.size(); ++i) + { + BOOST_TEST_EQ(res2[i], res3[i]); + } +} + int main() { basic_tests(); @@ -88,5 +155,10 @@ int main() basic_tests(); basic_tests(); + test_edges(); + test_edges(); + test_edges(); + test_edges(); + return boost::report_errors(); } From 113fb36a6f51c4f3fd8b2a0906ccf36476697486 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 4 Nov 2024 18:07:49 -0500 Subject: [PATCH 13/14] Fix unreachable code error MSVC --- include/boost/crypt/hash/hmac.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/include/boost/crypt/hash/hmac.hpp b/include/boost/crypt/hash/hmac.hpp index d5f414f8..a2edf8a1 100644 --- a/include/boost/crypt/hash/hmac.hpp +++ b/include/boost/crypt/hash/hmac.hpp @@ -158,7 +158,6 @@ constexpr auto hmac::process_bytes(ForwardIter data, boost::crypt::s return hasher_state::input_too_long; default: BOOST_CRYPT_UNREACHABLE; - return status_code; } // LCOV_EXCL_STOP } From 17a616bec6aab0fedaae73e1dfe35e2555d1e7b3 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 4 Nov 2024 18:07:56 -0500 Subject: [PATCH 14/14] Fix memcpy --- include/boost/crypt/hash/hmac.hpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/include/boost/crypt/hash/hmac.hpp b/include/boost/crypt/hash/hmac.hpp index a2edf8a1..9982cf3a 100644 --- a/include/boost/crypt/hash/hmac.hpp +++ b/include/boost/crypt/hash/hmac.hpp @@ -199,10 +199,9 @@ constexpr auto hmac::init(ForwardIter key, boost::crypt::size_t size BOOST_CRYPT_ASSERT(res.size() <= k0.size()); - auto key_iter {res.begin()}; - for (auto& byte : k0) + for (boost::crypt::size_t i {}; i < res.size(); ++i) { - byte = *key_iter++; + k0[i] = res[i]; } }