Skip to content

Commit

Permalink
Add basic sha224 testing
Browse files Browse the repository at this point in the history
  • Loading branch information
mborland committed Oct 23, 2024
1 parent e7d9f8d commit c2a5ff9
Show file tree
Hide file tree
Showing 2 changed files with 353 additions and 0 deletions.
1 change: 1 addition & 0 deletions test/Jamfile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
352 changes: 352 additions & 0 deletions test/test_sha224.cpp
Original file line number Diff line number Diff line change
@@ -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 <boost/crypt/hash/sha224.hpp>
#include <boost/core/lightweight_test.hpp>
#include "generate_random_strings.hpp"
#include <random>
#include <iostream>
#include <string>
#include <array>
#include <tuple>
#include <fstream>
#include <cstdlib>
#include <ctime>
#include <cstring>

constexpr std::array<std::tuple<const char*, boost::crypt::sha224_hasher::return_type>, 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<const char*>(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<const char*>(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<const std::uint8_t*>(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<const std::uint8_t*>(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 <typename T>
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 <typename T>
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<std::uint8_t>(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<const std::byte> 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();
}

0 comments on commit c2a5ff9

Please sign in to comment.