Skip to content

Commit

Permalink
Merge pull request #5 from cppalliance/wchar
Browse files Browse the repository at this point in the history
Add native interfaces to wider character types for MD5
  • Loading branch information
mborland authored Oct 15, 2024
2 parents d00484e + c02afaa commit 19737ff
Show file tree
Hide file tree
Showing 5 changed files with 335 additions and 35 deletions.
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

0 comments on commit 19737ff

Please sign in to comment.