Skip to content

Commit

Permalink
Merge pull request #22 from cppalliance/sha1_cavs_testing
Browse files Browse the repository at this point in the history
Fix #21 via finishing sha1 nist cavs testing
  • Loading branch information
ckormanyos authored Oct 21, 2024
2 parents f2e49e7 + 2be2c7f commit 5894397
Show file tree
Hide file tree
Showing 8 changed files with 281 additions and 46 deletions.
38 changes: 19 additions & 19 deletions include/boost/crypt/hash/sha1.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,25 +32,6 @@ namespace crypt {

class sha1_hasher
{
private:

boost::crypt::array<boost::crypt::uint32_t, 5> intermediate_hash_ {0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0};
boost::crypt::array<boost::crypt::uint8_t, 64> buffer_ {};

boost::crypt::size_t buffer_index_ {};
boost::crypt::size_t low_ {};
boost::crypt::size_t high_ {};

bool computed {};
bool corrupted {};

BOOST_CRYPT_GPU_ENABLED constexpr auto sha1_process_message_block() -> void;

template <typename ForwardIter>
BOOST_CRYPT_GPU_ENABLED constexpr auto sha1_update(ForwardIter data, boost::crypt::size_t size) noexcept -> hasher_state;

BOOST_CRYPT_GPU_ENABLED constexpr auto pad_message() noexcept -> void;

public:

using return_type = boost::crypt::array<boost::crypt::uint8_t, 20>;
Expand All @@ -71,6 +52,25 @@ class sha1_hasher


BOOST_CRYPT_GPU_ENABLED constexpr auto get_digest() noexcept -> return_type ;

private:

boost::crypt::array<boost::crypt::uint32_t, 5> intermediate_hash_ { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 };
boost::crypt::array<boost::crypt::uint8_t, 64> buffer_ {};

boost::crypt::size_t buffer_index_ {};
boost::crypt::size_t low_ {};
boost::crypt::size_t high_ {};

bool computed {};
bool corrupted {};

BOOST_CRYPT_GPU_ENABLED constexpr auto sha1_process_message_block() -> void;

template <typename ForwardIter>
BOOST_CRYPT_GPU_ENABLED constexpr auto sha1_update(ForwardIter data, boost::crypt::size_t size) noexcept -> hasher_state;

BOOST_CRYPT_GPU_ENABLED constexpr auto pad_message() noexcept -> void;
};

namespace detail {
Expand Down
3 changes: 2 additions & 1 deletion test/Jamfile
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,6 @@ project : requirements

run quick.cpp ;
run test_md5.cpp ;
run test_nist_cavs_sha1_short.cpp ;
run test_nist_cavs_sha1_monte.cpp ;
run test_nist_cavs_sha1_short_long.cpp ;
run test_sha1.cpp ;
Binary file added test/nist_cavs/vectors/shavs.pdf
Binary file not shown.
4 changes: 2 additions & 2 deletions test/test_cavs_nist_detail.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ struct test_object_hash

using test_vector_container_type = std::deque<test_object_hash>;

auto where_file(const std::string& test_vectors_filename) -> std::string
auto where_file_shabytesvectors(const std::string& test_vectors_filename) -> std::string
{
// Try to open the file in each of the known relative paths
// in order to find out where it is located.
Expand Down Expand Up @@ -159,7 +159,7 @@ auto parse_file_vectors(const std::string& test_vectors_filename, test_vector_co
{
bool result_parse_is_ok { false };

const std::string test_vectors_filename_relative { where_file(test_vectors_filename) };
const std::string test_vectors_filename_relative { where_file_shabytesvectors(test_vectors_filename) };

const bool result_filename_plausible_is_ok { (!test_vectors_filename_relative.empty()) };

Expand Down
190 changes: 187 additions & 3 deletions test/test_nist_cavs_detail.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,23 @@ struct test_object_hash

test_object_hash() = delete;

// Construct this hash test object by setting the result only.
// There is no message and there is no length available for
// this hash test object.

explicit test_object_hash(const std::string& str_result)
: my_result // LCOV_EXCL_LINE
{
[&str_result]()
{
const auto byte_data { detail::convert_hex_string_to_byte_container(str_result) };
return message_type(byte_data.cbegin(), byte_data.cend());
}()
}
{ }

// Construct this hash test object with all of message, length and result.

explicit test_object_hash(const std::string& str_data, const std::string& str_result)
: my_length { str_data.size() / static_cast<size_type>(UINT8_C(2)) },
my_msg
Expand All @@ -61,7 +78,7 @@ struct test_object_hash
[&str_result]()
{
const auto byte_data { detail::convert_hex_string_to_byte_container(str_result) };
return message_type(byte_data.cbegin(), byte_data.cend());
return message_type(byte_data.cbegin(), byte_data.cend());
}()
}
{ }
Expand All @@ -73,7 +90,7 @@ struct test_object_hash

using test_vector_container_type = std::deque<test_object_hash>;

auto where_file(const std::string& test_vectors_filename) -> std::string
auto where_file_shabytesvectors(const std::string& test_vectors_filename) -> std::string
{
// Try to open the file in each of the known relative paths
// in order to find out where it is located.
Expand Down Expand Up @@ -159,10 +176,12 @@ auto parse_file_vectors(const std::string& test_vectors_filename, test_vector_co
{
bool result_parse_is_ok { false };

const std::string test_vectors_filename_relative { where_file(test_vectors_filename) };
const std::string test_vectors_filename_relative { where_file_shabytesvectors(test_vectors_filename) };

const bool result_filename_plausible_is_ok { (!test_vectors_filename_relative.empty()) };

BOOST_TEST(result_filename_plausible_is_ok);

if(result_filename_plausible_is_ok)
{
std::string str_message { };
Expand Down Expand Up @@ -232,6 +251,77 @@ auto parse_file_vectors(const std::string& test_vectors_filename, test_vector_co
}
}

BOOST_TEST(result_parse_is_ok);

return result_parse_is_ok;
}

auto parse_file_monte(const std::string& test_monte_filename, test_vector_container_type& test_vectors_to_get) -> bool
{
bool result_parse_is_ok { false };

const std::string test_vectors_filename_relative { where_file_shabytesvectors(test_monte_filename) };

const bool result_filename_plausible_is_ok { (!test_vectors_filename_relative.empty()) };

BOOST_TEST(result_filename_plausible_is_ok);

if(result_filename_plausible_is_ok)
{
std::string str_result { };

// Read the file for creating the test cases.
std::ifstream in(test_vectors_filename_relative.c_str());

const bool file_is_open = in.is_open();

unsigned count { };

if(file_is_open)
{
result_parse_is_ok = true;

std::string line { };
std::string result { };

while(getline(in, line))
{
const std::string::size_type pos_cnt = line.find("COUNT =", 0U);
const std::string::size_type pos_md = line.find("MD =", 0U);

const bool line_is_representation_is_cnt = (pos_cnt != std::string::npos);
const bool line_is_representation_is_md = (pos_md != std::string::npos);

// Get the next count.
if(line_is_representation_is_cnt)
{
const std::string str_cnt = line.substr(8U, line.length() - 8U);

const unsigned long count_from_file = std::strtoul(str_cnt.c_str(), nullptr, 10U);

count = static_cast<unsigned>(count_from_file);
}

// Get the next (expected) result.
if(line_is_representation_is_md)
{
result = line.substr(5U, line.length() - 5U);

// Add the new test object to v.
const test_object_hash test_obj(result);

test_vectors_to_get.push_back(test_obj);
}
}

in.close();

result_parse_is_ok = ((!test_vectors_to_get.empty()) && (count == 99U) && result_parse_is_ok);
}
}

BOOST_TEST(result_parse_is_ok);

return result_parse_is_ok;
}

Expand All @@ -246,6 +336,8 @@ auto test_vectors_oneshot(const test_vector_container_type& test_vectors) -> boo
using local_hasher_type = HasherType;
using local_result_type = typename local_hasher_type::return_type;

BOOST_TEST((!test_vectors.empty()));

bool result_is_ok { true };

for(const auto& test_vector : test_vectors)
Expand All @@ -267,6 +359,9 @@ auto test_vectors_oneshot(const test_vector_container_type& test_vectors) -> boo

// Make pass 2 through the messages.
// Use the triple-combination of init/process/get-result functions.
// Even though this is not required in CAVS testing, it is
// done in order to ensure that the init() function properly
// puts the hasher-object into its initialized state.

this_hash.init();

Expand All @@ -287,6 +382,95 @@ auto test_vectors_oneshot(const test_vector_container_type& test_vectors) -> boo
return result_is_ok;
}

template<typename HasherType>
auto test_vectors_monte(const nist::cavs::test_vector_container_type& test_vectors_monte, const std::vector<std::uint8_t>& seed_init) -> bool
{
using local_hasher_type = HasherType;
using local_result_type = typename local_hasher_type::return_type;

using local_array_type = local_result_type;

// Obtain the test-specific initial seed.
local_array_type Seed { };

const std::size_t
copy_len
{
(std::min)(static_cast<std::size_t>(Seed.size()), static_cast<std::size_t>(seed_init.size()))
};

std::copy
(
seed_init.cbegin(),
seed_init.cbegin() + static_cast<typename std::vector<std::uint8_t>::difference_type>(copy_len),
Seed.begin()
);

bool result_is_ok { (!test_vectors_monte.empty()) };

if(result_is_ok)
{
local_array_type MD[3U] { { }, { }, { } };

local_array_type MDi { };
local_array_type MDj { };

constexpr local_array_type dummy_array { };

// See pseudocode on page 9 of "The Secure Hash Algorithm Validation System (SHAVS)".

for(std::size_t j { }; j < 100U; ++j)
{
MD[0U] = MD[1U] = MD[2U] = Seed;

for(std::size_t i { 3U } ; i < 1003U; ++i)
{
using local_wide_array_type = boost::crypt::array<std::uint8_t, dummy_array.size() * 3U>;

std::vector<std::uint8_t> result_vector;

result_vector.reserve(dummy_array.size() * 3U);

result_vector.insert(result_vector.end(), MD[0U].cbegin(), MD[0U].cend());
result_vector.insert(result_vector.end(), MD[1U].cbegin(), MD[1U].cend());
result_vector.insert(result_vector.end(), MD[2U].cbegin(), MD[2U].cend());

local_wide_array_type Mi { };

std::copy(result_vector.cbegin(), result_vector.cend(), Mi.begin());

local_hasher_type this_hash { };

this_hash.init();

this_hash.process_bytes(Mi.data(), Mi.size());

MDi = this_hash.get_digest();

MD[0U] = MD[1U];
MD[1U] = MD[2U];
MD[2U] = MDi;
}

MDj = Seed = MDi;

const bool result_this_monte_step_is_ok =
std::equal
(
MDj.cbegin(),
MDj.cend(),
test_vectors_monte[j].my_result.cbegin()
);

result_is_ok = (result_this_monte_step_is_ok && result_is_ok);

BOOST_TEST(result_this_monte_step_is_ok);
}
}

return result_is_ok;
}

} // namespace cavs
} // namespace nist

Expand Down
35 changes: 35 additions & 0 deletions test/test_nist_cavs_sha1_monte.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright 2024 Matt Borland
// Copyright 2024 Christopher Kormanyos
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt

#include <boost/crypt/hash/sha1.hpp>

#include "test_nist_cavs_detail.hpp"

auto main() -> int
{
bool result_is_ok { true };

{
nist::cavs::test_vector_container_type my_test_vectors_monte { };

std::vector<std::uint8_t>
seed_init
(
{
0xDDU, 0x4DU, 0xF6U, 0x44U, 0xEAU, 0xF3U, 0xD8U, 0x5BU,
0xACU, 0xE2U, 0xB2U, 0x1AU, 0xCCU, 0xAAU, 0x22U, 0xB2U,
0x88U, 0x21U, 0xF5U, 0xCDU
}
);

static_cast<void>(nist::cavs::detail::parse_file_monte("SHA1Monte.rsp", my_test_vectors_monte));

result_is_ok = (nist::cavs::test_vectors_monte<boost::crypt::sha1_hasher>(my_test_vectors_monte, seed_init) && result_is_ok);

BOOST_TEST(result_is_ok);
}

return boost::report_errors();
}
21 changes: 0 additions & 21 deletions test/test_nist_cavs_sha1_short.cpp

This file was deleted.

Loading

0 comments on commit 5894397

Please sign in to comment.