diff --git a/fuzzing/fuzz_hmac.cpp b/fuzzing/fuzz_hmac.cpp new file mode 100644 index 00000000..7b1d8fc9 --- /dev/null +++ b/fuzzing/fuzz_hmac.cpp @@ -0,0 +1,75 @@ +// Copyright 2025 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace boost::crypt; + +// Type list to store hasher types +template +struct type_list {}; + +// Helper to iterate over types +template class F> +struct for_each_type; + +template class F, typename... Ts> +struct for_each_type, F> { + static void apply(const std::uint8_t* data, std::size_t size) { + (F::apply(data, size), ...); + } +}; + +// Functor to process each hash type +template +struct process_hash { + static void apply(const std::uint8_t* data, std::size_t size) { + auto c_data = reinterpret_cast(data); + std::string c_data_str{c_data, size}; + std::span c_data_span{data, size}; + std::string_view c_data_str_view{c_data_str}; + + hmac hmac_tester; + hmac_tester.init(c_data_str); + hmac_tester.process_bytes(c_data_span); + hmac_tester.process_bytes(c_data_str_view); + hmac_tester.finalize(); + std::vector return_vector(size); + [[maybe_unused]] const auto code = hmac_tester.get_digest(return_vector); + } +}; + +extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t* data, std::size_t size) { + if (data == nullptr || size == 0) { + return 0; + } + + try { + using hasher_types = type_list< + sha1_hasher, + sha512_hasher, + sha3_256_hasher + >; + + for_each_type::apply(data, size); + } + catch (...) { + return 0; // Silent failure for fuzzing + } + + return 0; +} diff --git a/fuzzing/fuzz_sha3_224.cpp b/fuzzing/fuzz_sha3_224.cpp new file mode 100644 index 00000000..d562fb59 --- /dev/null +++ b/fuzzing/fuzz_sha3_224.cpp @@ -0,0 +1,41 @@ +// Copyright 2024 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t* data, std::size_t size) +{ + try + { + auto c_data = reinterpret_cast(data); + std::string c_data_str {c_data, size}; // Guarantee null termination since we can't pass the size argument + + boost::crypt::sha3_224(c_data_str); + + std::string_view view {c_data_str}; + boost::crypt::sha3_224(view); + + std::span data_span {c_data, size}; + boost::crypt::sha3_224(data_span); + + // Fuzz the hasher object + boost::crypt::sha3_224_hasher hasher; + hasher.process_bytes(data_span); + hasher.process_bytes(data_span); + hasher.process_bytes(data_span); + hasher.finalize(); + [[maybe_unused]] const auto res = hasher.get_digest(); + hasher.process_bytes(data_span); // State is invalid but should not crash + } + catch(...) + { + std::cerr << "Error with: " << data << std::endl; + std::terminate(); + } + + return 0; +} diff --git a/fuzzing/fuzz_sha3_256.cpp b/fuzzing/fuzz_sha3_256.cpp new file mode 100644 index 00000000..d39bf02a --- /dev/null +++ b/fuzzing/fuzz_sha3_256.cpp @@ -0,0 +1,41 @@ +// Copyright 2024 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t* data, std::size_t size) +{ + try + { + auto c_data = reinterpret_cast(data); + std::string c_data_str {c_data, size}; // Guarantee null termination since we can't pass the size argument + + boost::crypt::sha3_256(c_data_str); + + std::string_view view {c_data_str}; + boost::crypt::sha3_256(view); + + std::span data_span {c_data, size}; + boost::crypt::sha3_256(data_span); + + // Fuzz the hasher object + boost::crypt::sha3_256_hasher hasher; + hasher.process_bytes(data_span); + hasher.process_bytes(data_span); + hasher.process_bytes(data_span); + hasher.finalize(); + [[maybe_unused]] const auto res = hasher.get_digest(); + hasher.process_bytes(data_span); // State is invalid but should not crash + } + catch(...) + { + std::cerr << "Error with: " << data << std::endl; + std::terminate(); + } + + return 0; +} diff --git a/fuzzing/fuzz_sha3_384.cpp b/fuzzing/fuzz_sha3_384.cpp new file mode 100644 index 00000000..0abb1ba1 --- /dev/null +++ b/fuzzing/fuzz_sha3_384.cpp @@ -0,0 +1,41 @@ +// Copyright 2024 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t* data, std::size_t size) +{ + try + { + auto c_data = reinterpret_cast(data); + std::string c_data_str {c_data, size}; // Guarantee null termination since we can't pass the size argument + + boost::crypt::sha3_384(c_data_str); + + std::string_view view {c_data_str}; + boost::crypt::sha3_384(view); + + std::span data_span {c_data, size}; + boost::crypt::sha3_384(data_span); + + // Fuzz the hasher object + boost::crypt::sha3_384_hasher hasher; + hasher.process_bytes(data_span); + hasher.process_bytes(data_span); + hasher.process_bytes(data_span); + hasher.finalize(); + [[maybe_unused]] const auto res = hasher.get_digest(); + hasher.process_bytes(data_span); // State is invalid but should not crash + } + catch(...) + { + std::cerr << "Error with: " << data << std::endl; + std::terminate(); + } + + return 0; +} diff --git a/fuzzing/fuzz_shake128.cpp b/fuzzing/fuzz_shake128.cpp new file mode 100644 index 00000000..90853fbc --- /dev/null +++ b/fuzzing/fuzz_shake128.cpp @@ -0,0 +1,41 @@ +// Copyright 2024 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t* data, std::size_t size) +{ + try + { + auto c_data = reinterpret_cast(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); + + std::string_view view {c_data_str}; + boost::crypt::shake128(view); + + std::span data_span {c_data, size}; + boost::crypt::shake128(data_span); + + // Fuzz the hasher object + boost::crypt::shake128_hasher hasher; + hasher.process_bytes(data_span); + hasher.process_bytes(data_span); + hasher.process_bytes(data_span); + hasher.finalize(); + [[maybe_unused]] const auto res = hasher.get_digest(); + hasher.process_bytes(data_span); // State is invalid but should not crash + } + catch(...) + { + std::cerr << "Error with: " << data << std::endl; + std::terminate(); + } + + return 0; +} diff --git a/fuzzing/fuzz_shake256.cpp b/fuzzing/fuzz_shake256.cpp new file mode 100644 index 00000000..d0b243d3 --- /dev/null +++ b/fuzzing/fuzz_shake256.cpp @@ -0,0 +1,41 @@ +// Copyright 2024 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t* data, std::size_t size) +{ + try + { + auto c_data = reinterpret_cast(data); + std::string c_data_str {c_data, size}; // Guarantee null termination since we can't pass the size argument + + boost::crypt::shake256(c_data_str); + + std::string_view view {c_data_str}; + boost::crypt::shake256(view); + + std::span data_span {c_data, size}; + boost::crypt::shake256(data_span); + + // Fuzz the hasher object + boost::crypt::shake256_hasher hasher; + hasher.process_bytes(data_span); + hasher.process_bytes(data_span); + hasher.process_bytes(data_span); + hasher.finalize(); + [[maybe_unused]] const auto res = hasher.get_digest(); + hasher.process_bytes(data_span); // State is invalid but should not crash + } + catch(...) + { + std::cerr << "Error with: " << data << std::endl; + std::terminate(); + } + + return 0; +} diff --git a/fuzzing/seedcorpus/fuzz_md5/md5.txt b/fuzzing/seedcorpus/fuzz_hmac/hmac.txt similarity index 100% rename from fuzzing/seedcorpus/fuzz_md5/md5.txt rename to fuzzing/seedcorpus/fuzz_hmac/hmac.txt