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 native interfaces to wider character types for MD5 #5

Merged
merged 9 commits into from
Oct 15, 2024
157 changes: 152 additions & 5 deletions include/boost/crypt/hash/md5.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright 2024 Matt Borland
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
//
// See: https://www.ietf.org/rfc/rfc1321.txt

#ifndef BOOST_CRYPT_HASH_MD5_HPP
#define BOOST_CRYPT_HASH_MD5_HPP
Expand All @@ -13,8 +15,10 @@
#include <boost/crypt/utility/type_traits.hpp>
#include <boost/crypt/utility/strlen.hpp>
#include <boost/crypt/utility/cstddef.hpp>
#include <boost/crypt/utility/iterator.hpp>

#ifndef BOOST_CRYPT_BUILD_MODULE
#include <memory>
#include <string>
#include <cstdint>
#include <cstring>
Expand Down Expand Up @@ -54,7 +58,13 @@ class md5_hasher
BOOST_CRYPT_GPU_ENABLED constexpr auto process_byte(ByteType byte) noexcept
BOOST_CRYPT_REQUIRES_CONVERSION(ByteType, boost::crypt::uint8_t);

template <typename ForwardIter>
template <typename ForwardIter, boost::crypt::enable_if_t<sizeof(typename utility::iterator_traits<ForwardIter>::value_type) == 1, bool> = true>
BOOST_CRYPT_GPU_ENABLED constexpr auto process_bytes(ForwardIter buffer, boost::crypt::size_t byte_count) noexcept;

template <typename ForwardIter, boost::crypt::enable_if_t<sizeof(typename utility::iterator_traits<ForwardIter>::value_type) == 2, bool> = true>
BOOST_CRYPT_GPU_ENABLED constexpr auto process_bytes(ForwardIter buffer, boost::crypt::size_t byte_count) noexcept;

template <typename ForwardIter, boost::crypt::enable_if_t<sizeof(typename utility::iterator_traits<ForwardIter>::value_type) == 4, bool> = true>
BOOST_CRYPT_GPU_ENABLED constexpr auto process_bytes(ForwardIter buffer, boost::crypt::size_t byte_count) noexcept;

BOOST_CRYPT_GPU_ENABLED constexpr auto get_digest() noexcept -> boost::crypt::array<boost::crypt::uint8_t, 16>;
Expand Down Expand Up @@ -108,7 +118,8 @@ BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::md5_update(ForwardIter data,
low_ += input_bits;
if (low_ < old_low)
{
++high_;
// This should never happen as it indicates size_t roll over
++high_; // LCOV_EXCL_LINE
}
high_ += size >> 29U;

Expand Down Expand Up @@ -196,15 +207,50 @@ template <typename ByteType>
BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::process_byte(ByteType byte) noexcept
BOOST_CRYPT_REQUIRES_CONVERSION(ByteType, boost::crypt::uint8_t)
{
md5_update(&byte, 1UL);
const auto value {static_cast<boost::crypt::uint8_t>(byte)};
md5_update(&value, 1UL);
}

template <typename ForwardIter>
template <typename ForwardIter, boost::crypt::enable_if_t<sizeof(typename utility::iterator_traits<ForwardIter>::value_type) == 1, bool>>
BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::process_bytes(ForwardIter buffer, boost::crypt::size_t byte_count) noexcept
{
md5_update(buffer, byte_count);
}

template <typename ForwardIter, boost::crypt::enable_if_t<sizeof(typename utility::iterator_traits<ForwardIter>::value_type) == 2, bool>>
BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::process_bytes(ForwardIter buffer, boost::crypt::size_t byte_count) noexcept
{
#ifndef BOOST_CRYPT_HAS_CUDA

const auto* char_ptr {reinterpret_cast<const char*>(std::addressof(*buffer))};
const auto* data {reinterpret_cast<const unsigned char*>(char_ptr)};
md5_update(data, byte_count * 2U);

#else

const auto* data {reinterpret_cast<const unsigned char*>(buffer)};
md5_update(data, byte_count * 2U);

#endif
}

template <typename ForwardIter, boost::crypt::enable_if_t<sizeof(typename utility::iterator_traits<ForwardIter>::value_type) == 4, bool>>
BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::process_bytes(ForwardIter buffer, boost::crypt::size_t byte_count) noexcept
{
#ifndef BOOST_CRYPT_HAS_CUDA

const auto* char_ptr {reinterpret_cast<const char*>(std::addressof(*buffer))};
const auto* data {reinterpret_cast<const unsigned char*>(char_ptr)};
md5_update(data, byte_count * 4U);

#else

const auto* data {reinterpret_cast<const unsigned char*>(buffer)};
md5_update(data, byte_count * 4U);

#endif
}

// See: Applied Cryptography - Bruce Schneier
// Section 18.5
namespace md5_body_detail {
Expand Down Expand Up @@ -413,19 +459,120 @@ BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const boost::crypt::uint8_t* str, boo
return detail::md5(str, str + len);
}

BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const char16_t* str) noexcept -> boost::crypt::array<boost::crypt::uint8_t, 16>
{
if (str == nullptr)
{
return boost::crypt::array<boost::crypt::uint8_t, 16>{}; // LCOV_EXCL_LINE
}

const auto message_len {utility::strlen(str)};
return detail::md5(str, str + message_len);
}

BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const char16_t* str, boost::crypt::size_t len) noexcept -> boost::crypt::array<boost::crypt::uint8_t, 16>
{
if (str == nullptr)
{
return boost::crypt::array<boost::crypt::uint8_t, 16>{}; // LCOV_EXCL_LINE
}

return detail::md5(str, str + len);
}

BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const char32_t* str) noexcept -> boost::crypt::array<boost::crypt::uint8_t, 16>
{
if (str == nullptr)
{
return boost::crypt::array<boost::crypt::uint8_t, 16>{}; // LCOV_EXCL_LINE
}

const auto message_len {utility::strlen(str)};
return detail::md5(str, str + message_len);
}

BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const char32_t* str, boost::crypt::size_t len) noexcept -> boost::crypt::array<boost::crypt::uint8_t, 16>
{
if (str == nullptr)
{
return boost::crypt::array<boost::crypt::uint8_t, 16>{}; // LCOV_EXCL_LINE
}

return detail::md5(str, str + len);
}

// On some platforms wchar_t is 16 bits and others it's 32
// Since we check sizeof() the underlying with SFINAE in the actual implementation this is handled transparently
BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const wchar_t* str) noexcept -> boost::crypt::array<boost::crypt::uint8_t, 16>
{
if (str == nullptr)
{
return boost::crypt::array<boost::crypt::uint8_t, 16>{}; // LCOV_EXCL_LINE
}

const auto message_len {utility::strlen(str)};
return detail::md5(str, str + message_len);
}

BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const wchar_t* str, boost::crypt::size_t len) noexcept -> boost::crypt::array<boost::crypt::uint8_t, 16>
{
if (str == nullptr)
{
return boost::crypt::array<boost::crypt::uint8_t, 16>{}; // LCOV_EXCL_LINE
}

return detail::md5(str, str + len);
}

// ----- String and String view aren't in the libcu++ STL so they so not have device markers -----

#ifndef BOOST_CRYPT_HAS_CUDA

inline auto md5(const std::string& str) noexcept -> boost::crypt::array<boost::crypt::uint8_t, 16>
{
return detail::md5(str.begin(), str.end());
}

inline auto md5(const std::u16string& str) noexcept -> boost::crypt::array<boost::crypt::uint8_t, 16>
{
return detail::md5(str.begin(), str.end());
}

inline auto md5(const std::u32string& str) noexcept -> boost::crypt::array<boost::crypt::uint8_t, 16>
{
return detail::md5(str.begin(), str.end());
}

inline auto md5(const std::wstring& str) noexcept -> boost::crypt::array<boost::crypt::uint8_t, 16>
{
return detail::md5(str.begin(), str.end());
}

#ifdef BOOST_CRYPT_HAS_STRING_VIEW

inline auto md5(const std::string_view& str) -> boost::crypt::array<boost::crypt::uint8_t, 16>
{
return detail::md5(str.begin(), str.end());
}
#endif

inline auto md5(const std::u16string_view& str) -> boost::crypt::array<boost::crypt::uint8_t, 16>
{
return detail::md5(str.begin(), str.end());
}

inline auto md5(const std::u32string_view& str) -> boost::crypt::array<boost::crypt::uint8_t, 16>
{
return detail::md5(str.begin(), str.end());
}

inline auto md5(const std::wstring_view& str) -> boost::crypt::array<boost::crypt::uint8_t, 16>
{
return detail::md5(str.begin(), str.end());
}

#endif // BOOST_CRYPT_HAS_STRING_VIEW

#endif // BOOST_CRYPT_HAS_CUDA

} // namespace crypt
} // namespace boost
Expand Down
48 changes: 48 additions & 0 deletions include/boost/crypt/utility/iterator.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright 2024 Matt Borland
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt

#ifndef BOOST_CRYPT_UTILITES_ITERATOR_HPP
#define BOOST_CRYPT_UTILITES_ITERATOR_HPP

#include <boost/crypt/utility/config.hpp>

#ifdef BOOST_CRYPT_HAS_CUDA

#include <cuda/std/iterator>

namespace boost {
namespace crypt {

template <typename Iter>
struct iterator_traits : public cuda::std::iterator_traits<Iter> {};

template <typename T>
struct iterator_traits<T*> : public cuda::std::iterator_traits<T*> {};

} // namespace crypt
} // namespace boost

#else

#ifndef BOOST_CRYPT_BUILD_MODULE
#include <iterator>
#endif

namespace boost {
namespace crypt {
namespace utility {

template <typename Iter>
struct iterator_traits : public std::iterator_traits<Iter> {};

template <typename T>
struct iterator_traits<T*> : public std::iterator_traits<T*> {};

} // namespace utility
} // namespace crypt
} // namespace boost

#endif // BOOST_CRYPT_HAS_CUDA

#endif //BOOST_CRYPT_UTILITES_ITERATOR_HPP
2 changes: 2 additions & 0 deletions include/boost/crypt/utility/type_traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,9 @@ using cuda::std::underlying_type_t;

#else // STD versions

#ifndef BOOST_CRYPT_BUILD_MODULE
#include <type_traits>
#endif

namespace boost {
namespace crypt {
Expand Down
100 changes: 100 additions & 0 deletions test/generate_random_strings.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// Copyright 2024 Matt Borland
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt

#ifndef BOOST_CRYPT_TEST_GENERATE_RANDOM_STRINGS
#define BOOST_CRYPT_TEST_GENERATE_RANDOM_STRINGS

#include <random>
#include <cstdlib>
#include <ctime>
#include <cstring>

namespace boost {
namespace crypt {

inline void generate_random_string(char* str, std::size_t length)
{

const char charset[] = "0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";

const std::size_t charset_size = sizeof(charset) - 1;

std::mt19937_64 rng(42);
std::uniform_int_distribution<std::size_t> dist(0, charset_size);

for (std::size_t i = 0; i < length - 1; ++i)
{
const auto index = dist(rng);
str[i] = charset[index];
}

str[length - 1] = '\0';
}

inline void generate_random_string(char16_t* str, std::size_t length)
{
const char16_t charset[] = u"0123456789"
u"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
u"abcdefghijklmnopqrstuvwxyz";

const std::size_t charset_size = std::char_traits<char16_t>::length(charset);

std::mt19937_64 rng(42);
std::uniform_int_distribution<std::size_t> dist(0, charset_size - 1);

for (std::size_t i = 0; i < length - 1; ++i)
{
const auto index = dist(rng);
str[i] = charset[index];
}

str[length - 1] = u'\0';
}

inline void generate_random_string(char32_t* str, std::size_t length)
{
const char32_t charset[] = U"0123456789"
U"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
U"abcdefghijklmnopqrstuvwxyz";

const std::size_t charset_size = std::char_traits<char32_t>::length(charset);

std::mt19937_64 rng(42);
std::uniform_int_distribution<std::size_t> dist(0, charset_size - 1);

for (std::size_t i = 0; i < length - 1; ++i)
{
const auto index = dist(rng);
str[i] = charset[index];
}

str[length - 1] = u'\0';
}

inline void generate_random_string(wchar_t* str, std::size_t length)
{
const wchar_t charset[] = L"0123456789"
L"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
L"abcdefghijklmnopqrstuvwxyz";

const std::size_t charset_size = std::char_traits<wchar_t>::length(charset);

std::mt19937_64 rng(42);
std::uniform_int_distribution<std::size_t> dist(0, charset_size - 1);

for (std::size_t i = 0; i < length - 1; ++i)
{
const auto index = dist(rng);
str[i] = charset[index];
}

str[length - 1] = u'\0';
}

} // Namespace crypt
} // namespace boost

#endif // BOOST_CRYPT_TEST_GENERATE_RANDOM_STRINGS
Loading
Loading