From c2a5ff9339524507da41ad5a58d97b76f48096ef Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 23 Oct 2024 17:13:45 -0400 Subject: [PATCH] Add basic sha224 testing --- test/Jamfile | 1 + test/test_sha224.cpp | 352 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 353 insertions(+) create mode 100644 test/test_sha224.cpp diff --git a/test/Jamfile b/test/Jamfile index 2dbf2a0..95dba5f 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -51,6 +51,7 @@ run link_1.cpp link_2.cpp link_3.cpp ; run quick.cpp ; run test_md5.cpp ; run test_sha1.cpp ; +run test_sha224.cpp ; run test_sha256.cpp ; # NIST standard testing diff --git a/test/test_sha224.cpp b/test/test_sha224.cpp new file mode 100644 index 0000000..bc43698 --- /dev/null +++ b/test/test_sha224.cpp @@ -0,0 +1,352 @@ +// Copyright 2024 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include "generate_random_strings.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +constexpr std::array, 4> test_values = +{ + std::make_tuple("a", + boost::crypt::sha224_hasher::return_type{0xab, 0xd3, 0x75, 0x34, 0xc7, 0xd9, 0xa2, 0xef, 0xb9, 0x46, 0x5d, 0xe9, 0x31, 0xcd, 0x70, 0x55, 0xff, 0xdb, 0x88, 0x79, 0x56, 0x3a, 0xe9, 0x80, 0x78, 0xd6, 0xd6, 0xd5}), + std::make_tuple("The quick brown fox jumps over the lazy dog", + boost::crypt::sha224_hasher::return_type{0x73, 0x0e, 0x10, 0x9b, 0xd7, 0xa8, 0xa3, 0x2b, 0x1c, 0xb9, 0xd9, 0xa0, 0x9a, 0xa2, 0x32, 0x5d, 0x24, 0x30, 0x58, 0x7d, 0xdb, 0xc0, 0xc3, 0x8b, 0xad, 0x91, 0x15, 0x25}), + std::make_tuple("The quick brown fox jumps over the lazy dog.", + boost::crypt::sha224_hasher::return_type{0x61, 0x9c, 0xba, 0x8e, 0x8e, 0x05, 0x82, 0x6e, 0x9b, 0x8c, 0x51, 0x9c, 0x0a, 0x5c, 0x68, 0xf4, 0xfb, 0x65, 0x3e, 0x8a, 0x3d, 0x8a, 0xa0, 0x4b, 0xb2, 0xc8, 0xcd, 0x4c}), + std::make_tuple("", + boost::crypt::sha224_hasher::return_type {0xd1, 0x4a, 0x02, 0x8c, 0x2a, 0x3a, 0x2b, 0xc9, 0x47, 0x61, 0x02, 0xbb, 0x28, 0x82, 0x34, 0xc4, 0x15, 0xa2, 0xb0, 0x1f, 0x82, 0x8e, 0xa6, 0x2a, 0xc5, 0xb3, 0xe4, 0x2f}) +}; + +void basic_tests() +{ + for (const auto& test_value : test_values) + { + const auto message_result {boost::crypt::sha224(std::get<0>(test_value))}; + const auto valid_result {std::get<1>(test_value)}; + for (std::size_t i {}; i < message_result.size(); ++i) + { + if (!BOOST_TEST_EQ(message_result[i], valid_result[i])) + { + // LCOV_EXCL_START + std::cerr << "Failure with: " << std::get<0>(test_value) << '\n'; + break; + // LCOV_EXCL_STOP + } + } + } +} + +void string_test() +{ + for (const auto& test_value : test_values) + { + const std::string string_message {std::get<0>(test_value)}; + const auto message_result {boost::crypt::sha224(string_message)}; + const auto valid_result {std::get<1>(test_value)}; + for (std::size_t i {}; i < message_result.size(); ++i) + { + if (!BOOST_TEST_EQ(message_result[i], valid_result[i])) + { + // LCOV_EXCL_START + std::cerr << "Failure with: " << std::get<0>(test_value) << '\n'; + break; + // LCOV_EXCL_STOP + } + } + } +} + +void string_view_test() +{ + #ifdef BOOST_CRYPT_HAS_STRING_VIEW + for (const auto& test_value : test_values) + { + const std::string string_message {std::get<0>(test_value)}; + const std::string_view string_view_message {string_message}; + const auto message_result {boost::crypt::sha224(string_view_message)}; + const auto valid_result {std::get<1>(test_value)}; + for (std::size_t i {}; i < message_result.size(); ++i) + { + if (!BOOST_TEST_EQ(message_result[i], valid_result[i])) + { + // LCOV_EXCL_START + std::cerr << "Failure with: " << std::get<0>(test_value) << '\n'; + break; + // LCOV_EXCL_STOP + } + } + } + #endif +} + +void bad_input() +{ + const auto null_message {boost::crypt::sha224(static_cast(nullptr))}; + BOOST_TEST_EQ(null_message[0], 0x0); + BOOST_TEST_EQ(null_message[1], 0x0); + BOOST_TEST_EQ(null_message[2], 0x0); + BOOST_TEST_EQ(null_message[3], 0x0); + + const auto null_message_len {boost::crypt::sha224(static_cast(nullptr), 100)}; + BOOST_TEST_EQ(null_message_len[0], 0x0); + BOOST_TEST_EQ(null_message_len[1], 0x0); + BOOST_TEST_EQ(null_message_len[2], 0x0); + BOOST_TEST_EQ(null_message_len[3], 0x0); + + const auto unsigned_null_message {boost::crypt::sha224(static_cast(nullptr))}; + BOOST_TEST_EQ(unsigned_null_message[0], 0x0); + BOOST_TEST_EQ(unsigned_null_message[1], 0x0); + BOOST_TEST_EQ(unsigned_null_message[2], 0x0); + BOOST_TEST_EQ(unsigned_null_message[3], 0x0); + + const auto unsigned_null_message_len {boost::crypt::sha224(static_cast(nullptr), 100)}; + BOOST_TEST_EQ(unsigned_null_message_len[0], 0x0); + BOOST_TEST_EQ(unsigned_null_message_len[1], 0x0); + BOOST_TEST_EQ(unsigned_null_message_len[2], 0x0); + BOOST_TEST_EQ(unsigned_null_message_len[3], 0x0); + + std::string test_str {"Test string"}; + const auto reveresed_input {boost::crypt::detail::sha224(test_str.end(), test_str.begin())}; + BOOST_TEST_EQ(reveresed_input[0], 0x0); + BOOST_TEST_EQ(reveresed_input[1], 0x0); + BOOST_TEST_EQ(reveresed_input[2], 0x0); + BOOST_TEST_EQ(reveresed_input[3], 0x0); +} + +void test_class() +{ + boost::crypt::sha224_hasher hasher; + + for (const auto& test_value : test_values) + { + const auto msg {std::get<0>(test_value)}; + hasher.process_bytes(msg, std::strlen(msg)); + const auto message_result {hasher.get_digest()}; + + const auto valid_result {std::get<1>(test_value)}; + for (std::size_t i {}; i < message_result.size(); ++i) + { + if (!BOOST_TEST_EQ(message_result[i], valid_result[i])) + { + // LCOV_EXCL_START + std::cerr << "Failure with: " << std::get<0>(test_value) << '\n'; + break; + // LCOV_EXCL_STOP + } + } + + hasher.init(); + } +} + +template +void test_file(T filename, const boost::crypt::sha224_hasher::return_type& res) +{ + const auto crypt_res {boost::crypt::sha224_file(filename)}; + + for (std::size_t j {}; j < crypt_res.size(); ++j) + { + if (!BOOST_TEST_EQ(res[j], crypt_res[j])) + { + // LCOV_EXCL_START + std::cerr << "Failure with file: " << filename << std::endl; + break; + // LCOV_EXCL_STOP + } + } +} + +template +void test_invalid_file(T filename) +{ + constexpr boost::crypt::sha224_hasher::return_type res{}; + + const auto crypt_res {boost::crypt::sha224_file(filename)}; + + for (std::size_t j {}; j < crypt_res.size(); ++j) + { + if (!BOOST_TEST_EQ(res[j], crypt_res[j])) + { + // LCOV_EXCL_START + std::cerr << "Failure with file: " << filename << std::endl; + break; + // LCOV_EXCL_STOP + } + } +} + +void files_test() +{ + // Based off where we are testing from (test vs boost_root) we need to adjust our filepath + const char* filename; + const char* filename_2; + + // Boost-root + std::ifstream fd("libs/crypt/test/test_file_1.txt", std::ios::binary | std::ios::in); + filename = "libs/crypt/test/test_file_1.txt"; + filename_2 = "libs/crypt/test/test_file_2.txt"; + + // LCOV_EXCL_START + if (!fd.is_open()) + { + // Local test directory or IDE + std::ifstream fd2("test_file_1.txt", std::ios::binary | std::ios::in); + filename = "test_file_1.txt"; + filename_2 = "test_file_2.txt"; + + if (!fd2.is_open()) + { + // test/cover + std::ifstream fd3("../test_file_1.txt", std::ios::binary | std::ios::in); + filename = "../test_file_1.txt"; + filename_2 = "../test_file_2.txt"; + + if (!fd3.is_open()) + { + std::cerr << "Test not run due to file system issues" << std::endl; + return; + } + else + { + fd3.close(); + } + } + else + { + fd2.close(); + } + } + else + { + fd.close(); + } + // LCOV_EXCL_STOP + + // On macOS 15 + // sha224 test_file_1.txt + // sha224 (test_file_1.txt) = e88799b0d0d5becc6791837fa95388d4056f1250a511d14829766663 + constexpr boost::crypt::sha224_hasher::return_type res{0xe8, 0x87, 0x99, 0xb0, 0xd0, 0xd5, 0xbe, 0xcc, 0x67, 0x91, 0x83, 0x7f, 0xa9, 0x53, 0x88, 0xd4, 0x05, 0x6f, 0x12, 0x50, 0xa5, 0x11, 0xd1, 0x48, 0x29, 0x76, 0x66, 0x63}; + + test_file(filename, res); + + const std::string str_filename {filename}; + test_file(str_filename, res); + + #ifdef BOOST_CRYPT_HAS_STRING_VIEW + const std::string_view str_view_filename {str_filename}; + test_file(str_view_filename, res); + #endif + + const auto invalid_filename = "broken.bin"; + test_invalid_file(invalid_filename); + + const std::string str_invalid_filename {invalid_filename}; + test_invalid_file(str_invalid_filename); + + #ifdef BOOST_CRYPT_HAS_STRING_VIEW + const std::string_view str_view_invalid_filename {str_invalid_filename}; + test_invalid_file(str_view_invalid_filename); + #endif + + // On macOS 15 + // sha224 test_file_2.txt + // sha224 (test_file_2.txt) = c58605901d0923feb172e964ca6722378063574d18ff3efa7881bd91 + constexpr boost::crypt::sha224_hasher::return_type res_2{0xc5, 0x86, 0x05, 0x90, 0x1d, 0x09, 0x23, 0xfe, 0xb1, 0x72, 0xe9, 0x64, 0xca, 0x67, 0x22, 0x37, 0x80, 0x63, 0x57, 0x4d, 0x18, 0xff, 0x3e, 0xfa, 0x78, 0x81, 0xbd, 0x91}; + + test_file(filename_2, res_2); + + const char* test_null_file = nullptr; + test_invalid_file(test_null_file); +} + +void test_invalid_state() +{ + boost::crypt::sha224_hasher hasher; + auto current_state = hasher.process_bytes("test", 4); + BOOST_TEST(current_state == boost::crypt::hasher_state::success); + + hasher.get_digest(); + + const auto bad_state = hasher.process_bytes("test", 4); + BOOST_TEST(bad_state == boost::crypt::hasher_state::state_error); + + const auto digest = hasher.get_digest(); + + for (const auto& val : digest) + { + BOOST_TEST_EQ(val, static_cast(0)); + } + + hasher.init(); + + current_state = hasher.process_bytes("test", 4); + BOOST_TEST(current_state == boost::crypt::hasher_state::success); + current_state = hasher.process_byte(0x03); + BOOST_TEST(current_state == boost::crypt::hasher_state::success); + const char* ptr = nullptr; + current_state = hasher.process_bytes(ptr, 4); + BOOST_TEST(current_state == boost::crypt::hasher_state::null); + + const char16_t* ptr16 = nullptr; + current_state = hasher.process_bytes(ptr16, 4); + BOOST_TEST(current_state == boost::crypt::hasher_state::null); + + const char32_t* ptr32 = nullptr; + current_state = hasher.process_bytes(ptr32, 4); + BOOST_TEST(current_state == boost::crypt::hasher_state::null); + + const wchar_t* wptr = nullptr; + current_state = hasher.process_bytes(wptr, 4); + BOOST_TEST(current_state == boost::crypt::hasher_state::null); +} + +// This ends up being completely calculated in a constexpr fashion so Codecov complains +// LCOV_EXCL_START +void test_span() +{ + #ifdef BOOST_CRYPT_HAS_SPAN + + // "abc" in hex + const std::byte vals[] = {std::byte{0x61}, std::byte{0x62}, std::byte{0x63}}; + std::span byte_span {vals}; + const auto expected_res = boost::crypt::sha224_hasher::return_type{0x23, 0x09, 0x7d, 0x22, 0x34, 0x05, 0xd8, 0x22, 0x86, 0x42, 0xa4, 0x77, 0xbd, 0xa2, 0x55, 0xb3, 0x2a, 0xad, 0xbc, 0xe4, 0xbd, 0xa0, 0xb3, 0xf7, 0xe3, 0x6c, 0x9d, 0xa7}; + const auto res = boost::crypt::sha224(byte_span); + + for (std::size_t i {}; i < res.size(); ++i) + { + BOOST_TEST_EQ(res[i], expected_res[i]); + } + + #endif // BOOST_CRYPT_HAS_SPAN +} +// LCOV_EXCL_STOP + +int main() +{ + basic_tests(); + string_test(); + string_view_test(); + bad_input(); + test_class(); + + // The Windows file system returns a different result than on UNIX platforms + #if defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)) + files_test(); + #endif + + test_invalid_state(); + + test_span(); + + return boost::report_errors(); +}