diff --git a/include/boost/crypt2/drbg/detail/hmac_drbg.hpp b/include/boost/crypt2/drbg/detail/hmac_drbg.hpp new file mode 100644 index 00000000..ca3ea589 --- /dev/null +++ b/include/boost/crypt2/drbg/detail/hmac_drbg.hpp @@ -0,0 +1,530 @@ +// Copyright 2024 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CRYPT2_DRBG_DETAIL_HMAC_DRBG_HPP +#define BOOST_CRYPT2_DRBG_DETAIL_HMAC_DRBG_HPP + +#include +#include +#include +#include +#include + +namespace boost::crypt::drbg_detail { + +// Max hasher security is defined in NIST SP 800-57 Table 3: +// See: https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-57pt1r5.pdf +// +// 112: None +// 128: SHA-1 +// 192: SHA-224, SHA-512/224, SHA3-224 +// 256: SHA-256, SHA-512/256, SHA-384, SHA-512, SHA3-256, SHA3-384, SHA3-512 +// +// Outlen is defined in NIST SP 800-90A Rev 1 Section 10.1 table 2 +// 160: SHA-1 +// 224: SHA-224, SHA-512/224 +// 256: SHA-256, SHA-512/256 +// 384: SHA-384 +// 512: SHA-512 +template +class hmac_drbg +{ + static_assert(max_hasher_security == 128 || max_hasher_security == 192 || max_hasher_security == 256, "Invalid value for max hasher security"); + static_assert(outlen == 160 || outlen == 224 || outlen == 256 || outlen == 384 || outlen == 512, "Invalid outlen value"); + + static consteval bool valid_combinations() + { + switch (max_hasher_security) + { + case 128U: + return outlen == 160; + case 192U: + return outlen == 224; + default: + return outlen >= 256; + } + } + + static_assert(valid_combinations(), "Invalid combination of values"); + + static constexpr compat::size_t outlen_bytes {outlen / 8U}; + static constexpr compat::size_t max_bytes_per_request {65536U}; + static constexpr compat::size_t min_length {max_hasher_security / 8U}; + static constexpr compat::size_t min_entropy {min_length * 3U / 2U}; + + static constexpr compat::uint64_t max_length {4294967296ULL}; // 2^35 / 8 + static constexpr compat::uint64_t reseed_interval {281474976710656ULL}; // 2^48 + + typename HMACType::return_type key_ {}; + compat::span key_span_ {key_}; + typename HMACType::return_type value_ {}; + compat::span value_span_ {value_}; + compat::size_t reseed_counter_ {}; + bool initialized_ {}; + + template + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto update(compat::span provided_data_1, + compat::span provided_data_2 = compat::span{}, + compat::span provided_data_3 = compat::span{}) noexcept -> state; + + template + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto no_pr_generate_impl(compat::span return_data, compat::size_t requested_bits, + compat::span additional_data = compat::span{}) noexcept -> state; + + template + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto pr_generate_impl(compat::span return_data, compat::size_t requested_bits, + compat::span entropy, + compat::span additional_data = compat::span {}) noexcept -> state; + +public: + + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR hmac_drbg() noexcept = default; + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR ~hmac_drbg() noexcept; + + template + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto init(compat::span entropy, + compat::span nonce = compat::span {}, + compat::span personalization = compat::span{}) noexcept -> state; + + template , + concepts::sized_range SizedRange3 = compat::span> + BOOST_CRYPT_GPU_ENABLED auto init(SizedRange1&& entropy, + SizedRange2&& nonce = compat::span{}, + SizedRange3&& personalization = compat::span{}) noexcept -> state; + + template + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto reseed(compat::span entropy, + compat::span additional_input = compat::span{}) noexcept -> state; + + template > + BOOST_CRYPT_GPU_ENABLED auto reseed(SizedRange1&& entropy, + SizedRange2&& additional_data = compat::span{}) noexcept -> state; + + template + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto generate(compat::span return_data, compat::size_t requested_bits, + compat::span additional_data_1 = compat::span{}, + compat::span additional_data_2 = compat::span{}) noexcept -> state; + + template , + concepts::sized_range SizedRange3 = compat::span> + BOOST_CRYPT_GPU_ENABLED auto generate(SizedRange1&& return_data, compat::size_t requested_bits, + SizedRange2&& additional_data_1 = compat::span{}, + SizedRange3&& additional_data_2 = compat::span{}) noexcept -> state; +}; + +template +BOOST_CRYPT_GPU_ENABLED_CONSTEXPR hmac_drbg::~hmac_drbg() noexcept +{ + detail::clear_mem(key_); + detail::clear_mem(value_); + reseed_counter_ = 0U; + initialized_ = false; +} + +template +template +BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto hmac_drbg::update( + compat::span provided_data_1, + compat::span provided_data_2, + compat::span provided_data_3) noexcept -> state +{ + const auto provided_data_size {provided_data_1.size() + provided_data_2.size() + provided_data_3.size()}; + + // Step 1: V || 0x00 || provided data + compat::array storage_gap {std::byte{0x00}}; + compat::span storage_gap_span {storage_gap}; + + HMACType hmac; + hmac.init(key_span_); + hmac.process_bytes(value_span_); + hmac.process_bytes(storage_gap_span); + if constexpr (Extent1 != 0) + { + hmac.process_bytes(provided_data_1); + } + if constexpr (Extent2 != 0) + { + hmac.process_bytes(provided_data_2); + } + if constexpr (Extent3 != 0) + { + hmac.process_bytes(provided_data_3); + } + + hmac.finalize(); + auto hmac_return {hmac.get_digest()}; + if (!hmac_return.has_value()) [[unlikely]] + { + return hmac_return.error(); // LCOV_EXCL_LINE + } + + key_ = hmac_return.value(); + + hmac.init(key_span_); + hmac.process_bytes(value_span_); + hmac.finalize(); + hmac_return = hmac.get_digest(); + if (!hmac_return.has_value()) [[unlikely]] + { + return hmac_return.error(); // LCOV_EXCL_LINE + } + value_ = hmac_return.value(); + + #ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable : 4127) // Conditional expression is constant + #endif + + if (provided_data_size != 0U) + { + // Step 2: V || 0x01 || provided data + storage_gap[0] = compat::byte{0x01}; + hmac.init(key_span_); + hmac.process_bytes(value_span_); + hmac.process_bytes(storage_gap_span); + if constexpr (Extent1 != 0) + { + hmac.process_bytes(provided_data_1); + } + if constexpr (Extent2 != 0) + { + hmac.process_bytes(provided_data_2); + } + if constexpr (Extent3 != 0) + { + hmac.process_bytes(provided_data_3); + } + + hmac.finalize(); + hmac_return = hmac.get_digest(); + if (!hmac_return.has_value()) [[unlikely]] + { + return hmac_return.error(); // LCOV_EXCL_LINE + } + + key_ = hmac_return.value(); + + // Step 3: Update value + hmac.init(key_span_); + hmac.process_bytes(value_span_); + hmac.finalize(); + hmac_return = hmac.get_digest(); + if (!hmac_return.has_value()) [[unlikely]] + { + return hmac_return.error(); // LCOV_EXCL_LINE + } + + value_ = hmac_return.value(); + } + + #ifdef _MSC_VER + #pragma warning(pop) + #endif + + return state::success; +} + +template +template +BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto hmac_drbg::no_pr_generate_impl( + compat::span return_data, compat::size_t requested_bits, + compat::span additional_data) noexcept -> state +{ + if (reseed_counter_ > reseed_interval) + { + return state::requires_reseed; // LCOV_EXCL_LINE + } + if (!initialized_) + { + return state::uninitialized; + } + + const auto requested_bytes {requested_bits / 8U}; + if (requested_bytes > max_bytes_per_request) + { + return state::requested_too_many_bits; + } + + if constexpr (Extent2 != 0) + { + if (!additional_data.empty()) + { + // If we are on a different 32 bit or smaller platform and using clang ignore the warning + #ifdef __clang__ + # pragma clang diagnostic push + # pragma clang diagnostic ignored "-Wtautological-constant-out-of-range-compare" + #endif + + #if !defined(__i386__) && !defined(_M_IX86) + if (additional_data.size() > max_length) + { + return state::input_too_long; // LCOV_EXCL_LINE + } + #endif // 32-bit platforms + + #ifdef __clang__ + # pragma clang diagnostic pop + #endif + + const auto update_return {update(additional_data)}; + if (update_return != state::success) [[unlikely]] + { + return update_return; // LCOV_EXCL_LINE + } + } + } + + compat::size_t bytes {}; + HMACType hmac; + while (bytes < requested_bytes) + { + hmac.init(key_span_); + hmac.process_bytes(value_span_); + hmac.finalize(); + const auto hmac_return {hmac.get_digest()}; + if (!hmac_return.has_value()) [[unlikely]] + { + return hmac_return.error(); // LCOV_EXCL_LINE + } + + value_ = hmac_return.value(); + + if (bytes + value_.size() < requested_bytes) + { + for (const auto val : value_span_) + { + return_data[bytes++] = val; + } + } + else + { + for (compat::size_t i {}; bytes < requested_bytes && i < value_.size(); ++i) + { + return_data[bytes++] = value_span_[i]; + } + } + } + + const auto update_return {update(additional_data)}; + if (update_return != state::success) [[unlikely]] + { + return update_return; // LCOV_EXCL_LINE + } + + ++reseed_counter_; + return state::success; +} + +template +template +BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto hmac_drbg::pr_generate_impl( + compat::span return_data, compat::size_t requested_bits, + compat::span entropy, + compat::span additional_data) noexcept -> state +{ + // 9.3.3 Reseed using the entropy and the additional data, then set additional data to NULL + if (reseed_counter_ > reseed_interval) + { + return state::requires_reseed; // LCOV_EXCL_LINE + } + if (!initialized_) + { + return state::uninitialized; + } + + const auto requested_bytes {requested_bits / 8U}; + if (requested_bytes > max_bytes_per_request) + { + return state::requested_too_many_bits; + } + + const auto reseed_return {reseed(entropy, additional_data)}; + if (reseed_return != state::success) [[unlikely]] + { + return reseed_return; // LCOV_EXCL_LINE + } + + return no_pr_generate_impl(return_data, requested_bits); +} + +template +template +BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto hmac_drbg::init( + compat::span entropy, + compat::span nonce, + compat::span personalization) noexcept -> state +{ + // Nonce is to be at least >= 0.5 * max_hasher_security + // Unless entropy + nonce >= 1.5 * max_hasher_security + if (entropy.size() + nonce.size() < min_entropy) + { + return state::insufficient_entropy; + } + + // Key needs to be set to all 0x00 + for (auto& byte : key_) + { + byte = static_cast(0x00); + } + // Value needs to be set to all 0x01 + for (auto& byte : value_) + { + byte = static_cast(0x01); + } + + const auto update_return {update(entropy, nonce, personalization)}; + if (update_return != state::success) [[unlikely]] + { + return update_return; // LCOV_EXCL_LINE + } + + reseed_counter_ = 1U; + initialized_ = true; + return state::success; +} + +template +template +BOOST_CRYPT_GPU_ENABLED auto hmac_drbg::init( + SizedRange1&& entropy, + SizedRange2&& nonce, + SizedRange3&& personalization) noexcept -> state +{ + #if defined(__clang__) && __clang_major__ >= 19 + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-container" + #endif + + // Since these are sized ranges we can safely convert them into spans + auto entropy_span {compat::make_span(compat::forward(entropy))}; + auto nonce_span {compat::make_span(compat::forward(nonce))}; + auto personalization_span {compat::make_span(compat::forward(personalization))}; + + return init(compat::as_bytes(entropy_span), + compat::as_bytes(nonce_span), + compat::as_bytes(personalization_span)); + + #if defined(__clang__) && __clang_major__ >= 19 + #pragma clang diagnostic pop + #endif +} + +template +template +BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto hmac_drbg::reseed( + compat::span entropy, + compat::span additional_input) noexcept -> state +{ + constexpr auto min_reseed_entropy {max_hasher_security / 8U}; + + if (entropy.size() < min_reseed_entropy) + { + return state::insufficient_entropy; + } + + const auto update_return {update(entropy, additional_input)}; + if (update_return != state::success) [[unlikely]] + { + return update_return; // LCOV_EXCL_LINE + } + + reseed_counter_ = 1U; + return state::success; +} + +template +template +BOOST_CRYPT_GPU_ENABLED auto hmac_drbg::reseed( + SizedRange1&& entropy, + SizedRange2&& additional_input) noexcept -> state +{ + #if defined(__clang__) && __clang_major__ >= 19 + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-container" + #endif + + // Since these are sized ranges we can safely convert them into spans + auto entropy_span {compat::make_span(compat::forward(entropy))}; + auto additional_input_span {compat::make_span(compat::forward(additional_input))}; + + return reseed(compat::as_bytes(entropy_span), + compat::as_bytes(additional_input_span)); + + #if defined(__clang__) && __clang_major__ >= 19 + #pragma clang diagnostic pop + #endif +} + +template +template +BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto hmac_drbg::generate( + compat::span return_data, compat::size_t requested_bits, + compat::span additional_data_1, + compat::span additional_data_2) noexcept -> state +{ + if constexpr (prediction_resistance) + { + return pr_generate_impl(return_data, requested_bits, additional_data_1, additional_data_2); + } + else + { + return no_pr_generate_impl(return_data, requested_bits, additional_data_1); + } +} + +template +template +BOOST_CRYPT_GPU_ENABLED auto hmac_drbg::generate( + SizedRange1&& return_data, compat::size_t requested_bits, + SizedRange2&& additional_data_1, + SizedRange3&& additional_data_2) noexcept -> state +{ + if constexpr (prediction_resistance) + { + #if defined(__clang__) && __clang_major__ >= 19 + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-container" + #endif + + // Since these are sized ranges we can safely convert them into spans + auto return_data_span {compat::make_span(compat::forward(return_data))}; + auto additional_data1_span {compat::make_span(compat::forward(additional_data_1))}; + auto additional_data2_span {compat::make_span(compat::forward(additional_data_2))}; + + return pr_generate_impl(compat::as_writable_bytes(return_data_span), requested_bits, + compat::as_bytes(additional_data1_span), + compat::as_bytes(additional_data2_span)); + + #if defined(__clang__) && __clang_major__ >= 19 + #pragma clang diagnostic pop + #endif + } + else + { + #if defined(__clang__) && __clang_major__ >= 19 + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-container" + #endif + + // Since these are sized ranges we can safely convert them into spans + auto return_data_span {compat::make_span(compat::forward(return_data))}; + auto additional_data1_span {compat::make_span(compat::forward(additional_data_1))}; + + return no_pr_generate_impl(compat::as_writable_bytes(return_data_span), requested_bits, + compat::as_bytes(additional_data1_span)); + + #if defined(__clang__) && __clang_major__ >= 19 + #pragma clang diagnostic pop + #endif + } +} + +} // namespace boost::crypt::drbg_detail + +#endif // BOOST_CRYPT2_DRBG_DETAIL_HMAC_DRBG_HPP diff --git a/include/boost/crypt2/drbg/sha1_drbg.hpp b/include/boost/crypt2/drbg/sha1_drbg.hpp index 3443f632..e991fcc6 100644 --- a/include/boost/crypt2/drbg/sha1_drbg.hpp +++ b/include/boost/crypt2/drbg/sha1_drbg.hpp @@ -6,6 +6,8 @@ #define BOOST_CRYPT2_DRBG_SHA1_DRBG_HPP #include +#include +#include #include namespace boost::crypt { @@ -15,11 +17,17 @@ namespace drbg_detail { template using sha1_hash_drbg_t = hash_drbg; +template +using sha1_hmac_drbg_t = hmac_drbg, 128U, 160U, prediction_resistance>; + } // namespace drbg_detail BOOST_CRYPT_EXPORT using sha1_hash_drbg = drbg_detail::sha1_hash_drbg_t; BOOST_CRYPT_EXPORT using sha1_hash_drbg_pr = drbg_detail::sha1_hash_drbg_t; +BOOST_CRYPT_EXPORT using sha1_hmac_drbg = drbg_detail::sha1_hmac_drbg_t; +BOOST_CRYPT_EXPORT using sha1_hmac_drbg_pr = drbg_detail::sha1_hmac_drbg_t; + } // namespace boost::crypt #endif // BOOST_CRYPT2_DRBG_SHA1_DRBG_HPP diff --git a/test/Jamfile b/test/Jamfile index 97541f28..2e1e9af0 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -77,7 +77,7 @@ run test_shake256.cpp ; run test_hmac.cpp ; -#run test_hmac_drbg.cpp ; +run test_hmac_drbg.cpp ; run test_hash_drbg.cpp ; diff --git a/test/test_hmac_drbg.cpp b/test/test_hmac_drbg.cpp index 54b65d78..406b150d 100644 --- a/test/test_hmac_drbg.cpp +++ b/test/test_hmac_drbg.cpp @@ -2,7 +2,7 @@ // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt -#include +#include #include #include #include @@ -12,37 +12,37 @@ void sha1_basic_correctness() { boost::crypt::sha1_hmac_drbg rng; - boost::crypt::array entropy = { + std::array entropy = { 0xe9, 0x1b, 0x63, 0x30, 0x9e, 0x93, 0xd1, 0xd0, 0x8e, 0x30, 0xe8, 0xd5, 0x56, 0x90, 0x68, 0x75 }; - boost::crypt::array nonce = { + std::array nonce = { 0xf5, 0x97, 0x47, 0xc4, 0x68, 0xb0, 0xd0, 0xda }; - boost::crypt::array return_bits {}; + std::array return_bits {}; // Test process is: // 1) Instantiate drbg // 2) Generate bits, do not compare // 3) Generate bits, compare // 4) Destroy drbg - BOOST_TEST(rng.init(entropy, entropy.size(), nonce, nonce.size()) == boost::crypt::state::success); + BOOST_TEST(rng.init(entropy, nonce) == boost::crypt::state::success); // ** INSTANTIATE: // V = 7ea45af5f8fcba082fa40bcbea2748dfe7e09f6a // Key = be3976a33f77e0155b7ca84a5732d44f319e5f3a - BOOST_TEST(rng.generate(return_bits.begin(), 640U) == boost::crypt::state::success); + BOOST_TEST(rng.generate(return_bits, 640U) == boost::crypt::state::success); // ** GENERATE (FIRST CALL): // V = 0e28fe04dd16482f8e4b048675318adcd5e6e6cf // Key = 764d4f1fb7b04624bcb14642acb24d70eff3c0c8 - BOOST_TEST(rng.generate(return_bits.begin(), 640U) == boost::crypt::state::success); + BOOST_TEST(rng.generate(return_bits, 640U) == boost::crypt::state::success); // ** GENERATE (SECOND CALL): // V = 749a95f0882e0179d66d8ae2697802f8f568ce2f // Key = bfcd86fcb4c2efce22f6e9b69742751a17b0056c - constexpr boost::crypt::array nist_return = { + constexpr std::array nist_return = { 0xb7, 0x92, 0x8f, 0x95, 0x03, 0xa4, 0x17, 0x11, 0x07, 0x88, 0xf9, 0xd0, 0xc2, 0x58, 0x5f, 0x8a, 0xee, 0x6f, 0xb7, 0x3b, 0x22, 0x0a, 0x62, 0x6b, 0x3a, 0xb9, 0x82, 0x5b, 0x7a, 0x9f, @@ -53,32 +53,28 @@ void sha1_basic_correctness() 0x74, 0x3f, 0x41, 0xc8, 0xb0, 0xee, 0x73, 0x22, 0x53, 0x47 }; - for (boost::crypt::size_t i {}; i < return_bits.size(); ++i) + for (std::size_t i {}; i < return_bits.size(); ++i) { if (!BOOST_TEST_EQ(return_bits[i], nist_return[i])) { // LCOV_EXCL_START std::cerr << std::hex - << "Got: " << static_cast(return_bits[i]) - << "\nExpected: " << static_cast(nist_return[i]) << std::endl; + << "Got: " << static_cast(return_bits[i]) + << "\nExpected: " << static_cast(nist_return[i]) << std::endl; // LCOV_EXCL_STOP } } - const char* big_additional_input = "749a95f0882e0179d66d8ae2697802f8f568ce2fbfcd86fcb4c2efce22f6e9b69742751a17b0056c"; - BOOST_TEST(rng.init(entropy.begin(), entropy.size(), - nonce.begin(), nonce.size(), - big_additional_input, std::strlen(big_additional_input)) == boost::crypt::state::success); - - BOOST_TEST(rng.generate(return_bits.begin(), 640U, big_additional_input, std::strlen(big_additional_input)) == boost::crypt::state::success); - BOOST_TEST(rng.reseed(big_additional_input, std::strlen(big_additional_input), big_additional_input, std::strlen(big_additional_input)) == boost::crypt::state::success); + std::string big_additional_input = "749a95f0882e0179d66d8ae2697802f8f568ce2fbfcd86fcb4c2efce22f6e9b69742751a17b0056c"; + BOOST_TEST(rng.init(entropy, + nonce, + big_additional_input) == boost::crypt::state::success); - std::string str_additional_input {big_additional_input}; - BOOST_TEST(rng.reseed(str_additional_input) == boost::crypt::state::success); - BOOST_TEST(rng.reseed(str_additional_input, str_additional_input) == boost::crypt::state::success); + BOOST_TEST(rng.generate(return_bits, 640U, big_additional_input) == boost::crypt::state::success); + BOOST_TEST(rng.reseed(big_additional_input, big_additional_input) == boost::crypt::state::success); #ifdef BOOST_CRYPT_HAS_STRING_VIEW - std::string_view str_view {str_additional_input}; + std::string_view str_view {big_additional_input}; BOOST_TEST(rng.reseed(str_view) == boost::crypt::state::success); BOOST_TEST(rng.reseed(str_view, str_view) == boost::crypt::state::success); #endif @@ -87,36 +83,36 @@ void sha1_basic_correctness() void sha1_additional_input() { boost::crypt::sha1_hmac_drbg rng; - constexpr boost::crypt::array entropy = { + constexpr std::array entropy = { 0x49, 0x05, 0x8e, 0x67, 0x73, 0xed, 0x2b, 0x7a, 0xb3, 0x09, 0xc0, 0x94, 0x9f, 0xdf, 0x9c, 0x9e }; - constexpr boost::crypt::array nonce = { + constexpr std::array nonce = { 0xa4, 0x57, 0xcb, 0x8e, 0xc0, 0xe7, 0xfd, 0x01 }; - constexpr boost::crypt::array personalization = { + constexpr std::array personalization = { 0xdc, 0x47, 0x76, 0x41, 0xd8, 0x9c, 0x7f, 0xc4, 0xa3, 0x0f, 0x14, 0x30, 0x19, 0x7d, 0xd1, 0x59 }; - BOOST_TEST(rng.init(entropy.begin(), entropy.size(), - nonce.begin(), nonce.size(), - personalization.begin(), personalization.size()) == boost::crypt::state::success); + BOOST_TEST(rng.init(entropy, + nonce, + personalization) == boost::crypt::state::success); // ** INSTANTIATE: // V = 9c530ef5f1e277aab4e1e129091a273f0342d5c9 // Key = 7006c1c0c03c4ca267b19c50928f35891d8d8807 - boost::crypt::array return_bits {}; + std::array return_bits {}; - BOOST_TEST(rng.generate(return_bits.begin(), 640U) == boost::crypt::state::success); + BOOST_TEST(rng.generate(return_bits, 640U) == boost::crypt::state::success); // ** GENERATE (FIRST CALL): // V = 5b1508d16daad5aff52273cd549ce6bd9e259b0d // Key = b7e28116a16856b9e81bda776d421bb56e8f902f - BOOST_TEST(rng.generate(return_bits) == boost::crypt::state::success); + BOOST_TEST(rng.generate(return_bits, return_bits.size() * 8U) == boost::crypt::state::success); // ** GENERATE (SECOND CALL): // V = 71fa823bc53bfd307d6438edd7e5c581fffc27cc // Key = cfccf80b126cea770b468fb8652abbd5eeea2a5e - constexpr boost::crypt::array nist_return = { + constexpr std::array nist_return = { 0x4e, 0x89, 0x1f, 0x4e, 0x28, 0x11, 0x00, 0x45, 0x3b, 0x70, 0x78, 0x89, 0x29, 0xec, 0x74, 0x3a, 0x3c, 0x5e, 0xdd, 0x9b, 0x81, 0xdc, 0x79, 0x8b, 0xc9, 0x37, 0x71, 0x36, 0x8c, 0x39, 0xb6, 0x12, 0x03, @@ -127,14 +123,14 @@ void sha1_additional_input() 0x93, 0xb0, 0xdc }; - for (boost::crypt::size_t i {}; i < return_bits.size(); ++i) + for (std::size_t i {}; i < return_bits.size(); ++i) { if (!BOOST_TEST_EQ(return_bits[i], nist_return[i])) { // LCOV_EXCL_START std::cerr << std::hex - << "Got: " << static_cast(return_bits[i]) - << "\nExpected: " << static_cast(nist_return[i]) << std::endl; + << "Got: " << static_cast(return_bits[i]) + << "\nExpected: " << static_cast(nist_return[i]) << std::endl; // LCOV_EXCL_STOP } } @@ -143,22 +139,22 @@ void sha1_additional_input() void sha1_pr() { boost::crypt::sha1_hmac_drbg_pr rng; - constexpr std::array entropy = { + constexpr std::array entropy = { 0xa0, 0xc9, 0xab, 0x58, 0xf1, 0xe2, 0xe5, 0xa4, 0xde, 0x3e, 0xbd, 0x4f, 0xf7, 0x3e, 0x9c, 0x5b }; - constexpr std::array nonce = { + constexpr std::array nonce = { 0x64, 0xef, 0xd8, 0xca, 0x02, 0x8c, 0xf8, 0x11 }; - constexpr boost::crypt::array entropy_gen_1 = { + constexpr std::array entropy_gen_1 = { 0x48, 0xa5, 0x84, 0xfe, 0x69, 0xab, 0x5a, 0xee, 0x42, 0xaa, 0x4d, 0x42, 0x17, 0x60, 0x99, 0xd4 }; - constexpr boost::crypt::array entropy_gen_2 = { + constexpr std::array entropy_gen_2 = { 0x5e, 0x13, 0x97, 0xdc, 0x40, 0x4d, 0x86, 0xa3, 0x7b, 0xf5, 0x59, 0x54, 0x75, 0x69, 0x51, 0xe4 }; - constexpr boost::crypt::array nist_return = { + constexpr std::array nist_return = { 0x9a, 0x00, 0xa2, 0xd0, 0x0e, 0xd5, 0x9b, 0xfe, 0x31, 0xec, 0xb1, 0x39, 0x9b, 0x60, 0x81, 0x48, 0xd1, 0x96, 0x9d, 0x25, 0x0d, 0x3c, 0x1e, 0x94, 0x10, 0x10, 0x98, 0x12, 0x93, 0x25, @@ -169,45 +165,48 @@ void sha1_pr() 0xee, 0xf3, 0xe1, 0x5c, 0x02, 0x9b, 0x44, 0xaf, 0x03, 0x44 }; - boost::crypt::array return_bits {}; + std::array return_bits {}; - BOOST_TEST(rng.init(entropy.begin(), entropy.size(), nonce.begin(), nonce.size()) == boost::crypt::state::success); + BOOST_TEST(rng.init(entropy, nonce) == boost::crypt::state::success); - BOOST_TEST(rng.generate(return_bits.begin(), 640U, entropy_gen_1.begin(), entropy_gen_1.size()) == boost::crypt::state::success); + BOOST_TEST(rng.generate(return_bits, 640U, entropy_gen_1) == boost::crypt::state::success); - BOOST_TEST(rng.generate(return_bits.begin(), 640U, entropy_gen_2.begin(), entropy_gen_2.size()) == boost::crypt::state::success); + BOOST_TEST(rng.generate(return_bits, 640U, entropy_gen_2) == boost::crypt::state::success); - for (boost::crypt::size_t i {}; i < return_bits.size(); ++i) + for (std::size_t i {}; i < return_bits.size(); ++i) { if (!BOOST_TEST_EQ(return_bits[i], nist_return[i])) { // LCOV_EXCL_START std::cerr << std::hex - << "Got: " << static_cast(return_bits[i]) - << "\nExpected: " << static_cast(nist_return[i]) << std::endl; + << "Got: " << static_cast(return_bits[i]) + << "\nExpected: " << static_cast(nist_return[i]) << std::endl; // LCOV_EXCL_STOP } } BOOST_TEST(rng.init(entropy, nonce, nonce) == boost::crypt::state::success); BOOST_TEST(rng.init(entropy, nonce) == boost::crypt::state::success); - BOOST_TEST(rng.init(entropy) == boost::crypt::state::success); - - #ifdef BOOST_CRYPT_HAS_SPAN - // Clang 14 with libc++ can't deduce the span - // Clang 15+ has no issues according to CI - #if !defined(__clang__) || (__clang_major__ > 14) - - std::span entropy_span {entropy}; - std::span nonce_span {nonce}; - BOOST_TEST(rng.init(entropy_span, nonce_span, nonce_span) == boost::crypt::state::success); - BOOST_TEST(rng.init(entropy_span, nonce_span) == boost::crypt::state::success); - BOOST_TEST(rng.init(entropy_span) == boost::crypt::state::success); + BOOST_TEST(rng.init(entropy) == boost::crypt::state::insufficient_entropy); +} - #endif - #endif +template +void error_states() +{ + constexpr std::array entropy = { + 0xa0, 0xc9, 0xab, 0x58, 0xf1, 0xe2, 0xe5, 0xa4, 0xde, 0x3e, 0xbd, 0x4f, 0xf7, 0x3e, 0x9c, 0x5b + }; + constexpr std::array nonce = { + 0x64, 0xef, 0xd8, 0xca, 0x02, 0x8c, 0xf8, 0x11 + }; - rng.destroy(); + HMACDRBGType rng; + std::array bad_return {}; + BOOST_TEST(rng.generate(bad_return, 8) == boost::crypt::state::uninitialized); + BOOST_TEST(rng.init(entropy) == boost::crypt::state::insufficient_entropy); + BOOST_TEST(rng.init(entropy, nonce) == boost::crypt::state::success); + BOOST_TEST(rng.generate(bad_return, 65537*8U) == boost::crypt::state::requested_too_many_bits); + BOOST_TEST(rng.reseed(bad_return) == boost::crypt::state::insufficient_entropy); } int main() @@ -216,5 +215,8 @@ int main() sha1_additional_input(); sha1_pr(); + error_states(); + error_states(); + return boost::report_errors(); }