Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SHAKE128 #76

Merged
merged 18 commits into from
Oct 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions fuzzing/fuzz_shake128.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// 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/shake128.hpp>
#include <iostream>
#include <exception>
#include <string>
#include <cstdlib>

extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t* data, std::size_t size)
{
try
{
auto c_data = reinterpret_cast<const char*>(data);
std::string c_data_str {c_data, size}; // Guarantee null termination since we can't pass the size argument

boost::crypt::shake128(c_data_str);
boost::crypt::shake128(c_data, size);
boost::crypt::shake128(data, size);

#ifdef BOOST_CRYPT_HAS_STRING_VIEW
std::string_view view {c_data_str};
boost::crypt::shake128(view);
#endif

#ifdef BOOST_CRYPT_HAS_SPAN
std::span data_span {c_data, size};
boost::crypt::shake128(data_span);
#endif

// Fuzz the hasher object
boost::crypt::shake128_hasher hasher;
hasher.process_bytes(data, size);
hasher.process_bytes(data, size);
hasher.process_bytes(data, size);
hasher.get_digest();
hasher.process_bytes(data, size); // State is invalid but should not crash

hasher.init();
std::uint8_t* return_buffer = static_cast<std::uint8_t*>(std::malloc(size));
hasher.process_bytes(data, size);
hasher.get_digest(return_buffer, size);
if (return_buffer != nullptr)
{
std::free(return_buffer);
return_buffer = nullptr;
}
hasher.get_digest(return_buffer, size);
}
catch(...)
{
std::cerr << "Error with: " << data << std::endl;
std::terminate();
}

return 0;
}
18 changes: 18 additions & 0 deletions fuzzing/seedcorpus/fuzz_shake128/shake128.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"The quick brown fox jumps over the lazy dog"
"The quick brown fox jumps over the lazy dog."
""
"aB3$x9Yz"
"12345"
"!@#$%^&*()"
"FuzzTest123"
" "
"Lorem ipsum dolor sit amet"
"a"
"9876543210"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"ñÑáéíóúÁÉÍÓÚ"
"\n\r\t"
"0"
"ThisIsAVeryLongStringWithNoSpacesOrPunctuationToTestEdgeCases"
"<?php echo 'test'; ?>"
"SELECT * FROM users;"
107 changes: 97 additions & 10 deletions include/boost/crypt/hash/detail/sha3_base.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class sha3_base

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<boost::crypt::uint64_t, 25U> state_array_ {};
boost::crypt::array<boost::crypt::uint8_t, 200U - 2U * digest_size> buffer_ {};
boost::crypt::size_t buffer_index_ {};
Expand All @@ -52,6 +52,8 @@ class sha3_base

BOOST_CRYPT_GPU_ENABLED constexpr auto process_message_block() noexcept -> void;

template <typename ForwardIter>
BOOST_CRYPT_GPU_ENABLED constexpr auto xof_digest_impl(ForwardIter return_buffer, boost::crypt::size_t len) noexcept -> boost::crypt::size_t;

public:

Expand Down Expand Up @@ -101,6 +103,11 @@ class sha3_base

BOOST_CRYPT_GPU_ENABLED constexpr auto get_digest() noexcept -> return_type;

template <typename ForwardIter>
BOOST_CRYPT_GPU_ENABLED constexpr auto get_digest(ForwardIter return_buffer, boost::crypt::size_t len) noexcept -> boost::crypt::size_t;

template <typename Container>
BOOST_CRYPT_GPU_ENABLED constexpr auto get_digest(Container& container) noexcept -> boost::crypt::size_t;
};

template <boost::crypt::size_t digest_size, bool is_xof>
Expand Down Expand Up @@ -330,31 +337,111 @@ BOOST_CRYPT_GPU_ENABLED constexpr auto sha3_base<digest_size, is_xof>::process_m
}

template <boost::crypt::size_t digest_size, bool is_xof>
BOOST_CRYPT_GPU_ENABLED constexpr auto sha3_base<digest_size, is_xof>::get_digest() noexcept -> sha3_base<digest_size, is_xof>::return_type
template <typename ForwardIter>
BOOST_CRYPT_GPU_ENABLED constexpr auto sha3_base<digest_size, is_xof>::xof_digest_impl(ForwardIter return_buffer, boost::crypt::size_t len) noexcept -> boost::crypt::size_t
{
return_type digest{};
BOOST_CRYPT_ASSERT_MSG(is_xof, "Producing a digest of variable size is only allowed with SHAKE128 and SHAKE256 (XOF hashers)");

if (corrupted_)
{
return digest;
return 0U;
}
if (!computed_)
{
buffer_[buffer_index_] ^= static_cast<boost::crypt::uint8_t>(0x06U);
buffer_[buffer_index_] ^= static_cast<boost::crypt::uint8_t>(0x1FU);
buffer_.back() ^= static_cast<boost::crypt::uint8_t>(0x80U);
process_message_block();
computed_ = true;
}

for (boost::crypt::size_t i {}; i < digest_size; ++i)
for (boost::crypt::size_t i {}; i < len; ++i)
{
digest[i] = buffer_[i];
if (buffer_index_ == buffer_.size())
{
process_message_block();
}

*return_buffer++ = buffer_[buffer_index_++];
}

// Clear out the buffer in case of sensitive materials
buffer_.fill(0);
return len;
}

return digest;
template <boost::crypt::size_t digest_size, bool is_xof>
BOOST_CRYPT_GPU_ENABLED constexpr auto sha3_base<digest_size, is_xof>::get_digest() noexcept -> sha3_base<digest_size, is_xof>::return_type
{
BOOST_CRYPT_IF_CONSTEXPR (!is_xof)
{
return_type digest{};

if (corrupted_)
{
return digest;
}
if (!computed_)
{
buffer_[buffer_index_] ^= static_cast<boost::crypt::uint8_t>(0x06U);
buffer_.back() ^= static_cast<boost::crypt::uint8_t>(0x80U);
process_message_block();
computed_ = true;
}

for (boost::crypt::size_t i {}; i < digest_size; ++i)
{
digest[i] = buffer_[i];
}

// Clear out the buffer in case of sensitive materials
buffer_.fill(0);

return digest;
}
else
{
return_type digest {};
xof_digest_impl(digest.begin(), digest.size());
return digest;
}
}

template <boost::crypt::size_t digest_size, bool is_xof>
template <typename ForwardIter>
BOOST_CRYPT_GPU_ENABLED constexpr auto sha3_base<digest_size, is_xof>::get_digest(ForwardIter return_buffer, boost::crypt::size_t len) noexcept -> boost::crypt::size_t
{
#ifndef BOOST_CRYPT_HAS_CUDA

if (!utility::is_null(return_buffer))
{
auto* char_ptr {reinterpret_cast<char*>(std::addressof(*return_buffer))};
auto* data {reinterpret_cast<unsigned char*>(char_ptr)};
return xof_digest_impl(data, len);
}
else
{
return 0U;
}

#else

if (!utility::is_null(return_buffer))
{
auto* data {reinterpret_cast<const unsigned char*>(return_buffer)};
return xof_digest_impl(data, len);
}
else
{
return 0U;
}

#endif
}

template <boost::crypt::size_t digest_size, bool is_xof>
template <typename Container>
BOOST_CRYPT_GPU_ENABLED constexpr auto sha3_base<digest_size, is_xof>::get_digest(Container& container) noexcept -> boost::crypt::size_t
{
static_assert(boost::crypt::is_convertible_v<typename Container::value_type, boost::crypt::uint8_t>, "The container must be capable of holding bytes");
return get_digest(container.begin(), container.size());
}

template <boost::crypt::size_t digest_size, bool is_xof>
Expand Down
Loading
Loading