From a3fe39312ab0b8c8f6146026f9e9c5f76b0078a2 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Wed, 25 Sep 2024 10:50:25 -0700 Subject: [PATCH 1/3] add rotr implementation --- include/boost/hash2/detail/rot.hpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/boost/hash2/detail/rot.hpp b/include/boost/hash2/detail/rot.hpp index a796a51..6d1614f 100644 --- a/include/boost/hash2/detail/rot.hpp +++ b/include/boost/hash2/detail/rot.hpp @@ -29,6 +29,11 @@ BOOST_FORCEINLINE std::uint64_t rotl( std::uint64_t v, int k ) return _rotl64( v, k ); } +BOOST_FORCEINLINE std::uint32_t rotr( std::uint32_t v, int k ) +{ + return _rotr( v, k ); +} + #else // k must not be 0 @@ -43,6 +48,12 @@ BOOST_FORCEINLINE std::uint64_t rotl( std::uint64_t v, int k ) return ( v << k ) + ( v >> ( 64 - k ) ); } +// k must not be 0 +BOOST_FORCEINLINE std::uint32_t rotr( std::uint32_t v, int k ) +{ + return ( v >> k ) | ( v << ( 32 - k ) ); +} + #endif } // namespace detail From 7ade44be8dba4322b1a87ac11d3286e50fae6522 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Wed, 25 Sep 2024 10:51:33 -0700 Subject: [PATCH 2/3] add prototype of sha-256 algo --- include/boost/hash2/sha2.hpp | 229 +++++++++++++++++++++++++++++++++++ test/Jamfile | 1 + test/sha2.cpp | 113 +++++++++++++++++ 3 files changed, 343 insertions(+) create mode 100644 include/boost/hash2/sha2.hpp create mode 100644 test/sha2.cpp diff --git a/include/boost/hash2/sha2.hpp b/include/boost/hash2/sha2.hpp new file mode 100644 index 0000000..7a3045d --- /dev/null +++ b/include/boost/hash2/sha2.hpp @@ -0,0 +1,229 @@ +#ifndef SHA2_HPP_INCLUDED +#define SHA2_HPP_INCLUDED + +// Copyright 2024 Peter Dimov. +// Copyright 2024 Christian Mazakas. +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt +// +// SHA2 message digest algorithm, https://csrc.nist.gov/pubs/fips/180-4/upd1/final, https://www.rfc-editor.org/rfc/rfc6234 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost +{ +namespace hash2 +{ + +class sha2_256 +{ +private: + + std::uint32_t state_[ 8 ]; + + static const int N = 64; + + unsigned char buffer_[ N ]; + std::size_t m_; // == n_ % N + + std::uint64_t n_; + +private: + + void init() + { + state_[ 0 ] = 0x6a09e667; + state_[ 1 ] = 0xbb67ae85; + state_[ 2 ] = 0x3c6ef372; + state_[ 3 ] = 0xa54ff53a; + state_[ 4 ] = 0x510e527f; + state_[ 5 ] = 0x9b05688c; + state_[ 6 ] = 0x1f83d9ab; + state_[ 7 ] = 0x5be0cd19; + } + + static std::uint32_t Sigma0( std::uint32_t x ) noexcept + { + return detail::rotr( x, 2 ) ^ detail::rotr( x, 13 ) ^ detail::rotr( x, 22 ); + } + + static std::uint32_t Sigma1( std::uint32_t x ) noexcept + { + return detail::rotr( x, 6 ) ^ detail::rotr( x, 11 ) ^ detail::rotr( x, 25 ); + } + + static std::uint32_t sigma0( std::uint32_t x ) noexcept + { + return detail::rotr( x, 7 ) ^ detail::rotr( x, 18 ) ^ ( x >> 3 ); + } + + static std::uint32_t sigma1( std::uint32_t x ) noexcept + { + return detail::rotr( x, 17 ) ^ detail::rotr( x, 19 ) ^ ( x >> 10 ); + } + + static std::uint32_t Ch( std::uint32_t x, std::uint32_t y, std::uint32_t z ) noexcept + { + return ( x & y ) ^ ( ~x & z ); + } + + static std::uint32_t Maj( std::uint32_t x, std::uint32_t y, std::uint32_t z ) noexcept + { + return ( x & y ) ^ ( x & z ) ^ ( y & z ); + } + + void transform( unsigned char const block[ 64 ] ) + { + constexpr static std::uint32_t const K[ 64 ] = + { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, + }; + + std::uint32_t W[ 64 ]; + + for( int t = 0; t < 16; ++t ) + { + W[ t ] = detail::read32be( block + t * 4 ); + } + + for( int t = 16; t < 64; ++t ) + { + W[ t ] = ( sigma1( W[ t - 2 ] ) + W[ t - 7] + sigma0( W[ t - 15 ] ) + W[ t - 16 ] ); + } + + std::uint32_t a = state_[ 0 ]; + std::uint32_t b = state_[ 1 ]; + std::uint32_t c = state_[ 2 ]; + std::uint32_t d = state_[ 3 ]; + std::uint32_t e = state_[ 4 ]; + std::uint32_t f = state_[ 5 ]; + std::uint32_t g = state_[ 6 ]; + std::uint32_t h = state_[ 7 ]; + + for( int t = 0; t < 64; ++t ) + { + std::uint32_t T1 = h + Sigma1( e ) + Ch( e, f, g ) + K[ t ] + W[ t ]; + std::uint32_t T2 = Sigma0( a ) + Maj( a, b, c ); + + h = g; + g = f; + f = e; + e = (d + T1); + d = c; + c = b; + b = a; + a = (T1 + T2); + } + + state_[0] += a; + state_[1] += b; + state_[2] += c; + state_[3] += d; + state_[4] += e; + state_[5] += f; + state_[6] += g; + state_[7] += h; + } + +public: + using result_type = std::array; + + sha2_256(): m_( 0 ), n_( 0 ) + { + init(); + } + + void update( void const * pv, std::size_t n ) + { + unsigned char const* p = static_cast( pv ); + + BOOST_ASSERT( m_ == n_ % N ); + + n_ += n; + + if( m_ > 0 ) + { + std::size_t k = N - m_; + + if( n < k ) + { + k = n; + } + + std::memcpy( buffer_ + m_, p, k ); + + p += k; + n -= k; + m_ += k; + + if( m_ < N ) return; + + BOOST_ASSERT( m_ == N ); + + transform( buffer_ ); + m_ = 0; + + std::memset( buffer_, 0, N ); + } + + BOOST_ASSERT( m_ == 0 ); + + while( n >= N ) + { + transform( p ); + + p += N; + n -= N; + } + + BOOST_ASSERT( n < N ); + + if( n > 0 ) + { + std::memcpy( buffer_, p, n ); + m_ = n; + } + + BOOST_ASSERT( m_ == n_ % N ); + } + + result_type result() + { + unsigned char bits[ 8 ]; + detail::write64be( bits, n_ * 8 ); + + std::size_t k = m_ < 56 ? 56 - m_ : 64 + 56 - m_; + unsigned char padding[ 64 ] = { 0x80 }; + + update( padding, k ); + update( bits, 8 ); + BOOST_ASSERT( m_ == 0 ); + + result_type digest; + for( int i = 0; i < 8; ++i ) { + detail::write32be( &digest[ i * 4 ], state_[ i ] ); + } + + return digest; + } +}; + +} // namespace boost +} // namespace hash2 + +#endif // #ifndef SHA2_HPP_INCLUDED diff --git a/test/Jamfile b/test/Jamfile index 4fce516..964cdc9 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -52,6 +52,7 @@ run xxhash.cpp ; run md5.cpp ; run hmac_md5.cpp ; run sha1.cpp ; +run sha2.cpp ; run hmac_sha1.cpp ; run ripemd.cpp ; diff --git a/test/sha2.cpp b/test/sha2.cpp new file mode 100644 index 0000000..e5d67c6 --- /dev/null +++ b/test/sha2.cpp @@ -0,0 +1,113 @@ +// Copyright 2024 Christian Mazakas. +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#define _CRT_SECURE_NO_WARNINGS + +#include +#include +#include +#include +#include + +template std::string to_string( std::array const & v ) +{ + std::string r; + + for( std::size_t i = 0; i < N; ++i ) + { + char buffer[ 4 ]; + std::snprintf( buffer, sizeof( buffer ), "%02x", v[ i ] ); + r += buffer; + } + + return r; +} + +template std::string digest( std::string const & s ) +{ + H h; + + h.update( s.data(), s.size() ); + + return to_string( h.result() ); +} + +template std::string digest( char (&buf)[N]) +{ + H h; + + h.update( buf, N ); + + return to_string( h.result() ); +} + +template std::string digest( std::vector const & v ) +{ + H h; + + h.update( v.data(), v.size() ); + + return to_string( h.result() ); +} + +using boost::hash2::sha2_256; + +int main() +{ + + // https://en.wikipedia.org/wiki/SHA-2#Test_vectors + + BOOST_TEST_EQ( digest( "" ), std::string( "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" ) ); + + // https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/SHA256.pdf + + BOOST_TEST_EQ( digest( "abc" ), std::string( "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" ) ); + BOOST_TEST_EQ( digest( "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" ), std::string( "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1" ) ); + + // use test vectors from here + // https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/SHA2_Additional.pdf + + BOOST_TEST_EQ( digest( "\xbd" ), std::string( "68325720aabd7c82f30f554b313d0570c95accbb7dc4b5aae11204c08ffe732b" ) ); + BOOST_TEST_EQ( digest( "\xc9\x8c\x8e\x55" ), std::string( "7abc22c0ae5af26ce93dbb94433a0e0b2e119d014f8e7f65bd56c61ccccd9504" ) ); + + { + char buf[ 55 ] = { 0 }; + BOOST_TEST_EQ( digest( buf ), std::string( "02779466cdec163811d078815c633f21901413081449002f24aa3e80f0b88ef7" ) ); + } + + { + char buf[ 56 ] = { 0 }; + BOOST_TEST_EQ( digest( buf ), std::string( "d4817aa5497628e7c77e6b606107042bbba3130888c5f47a375e6179be789fbb" ) ); + } + + { + char buf[ 64 ] = { 0 }; + BOOST_TEST_EQ( digest( buf ), std::string( "f5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b" ) ); + } + + { + char buf[ 1000 ] = { 0 }; + BOOST_TEST_EQ( digest( buf ), std::string( "541b3e9daa09b20bf85fa273e5cbd3e80185aa4ec298e765db87742b70138a53" ) ); + } + + { + char buf[ 1000 ] = {}; + for( auto& c : buf ) c = 'A'; + BOOST_TEST_EQ( digest( buf ), std::string( "c2e686823489ced2017f6059b8b239318b6364f6dcd835d0a519105a1eadd6e4" ) ); + } + + { + char buf[ 1005 ] = {}; + for( auto& c : buf ) c = 'U'; + BOOST_TEST_EQ( digest( buf ), std::string( "f4d62ddec0f3dd90ea1380fa16a5ff8dc4c54b21740650f24afc4120903552b0" ) ); + } + + { + std::vector buf(1000000, 0x00); + BOOST_TEST_EQ( digest( buf ), std::string( "d29751f2649b32ff572b5e0a9f541ea660a50f94ff0beedfb0b692b924cc8025" ) ); + } + + + return boost::report_errors(); +} From b594a3e9507513f48b15ded7dc097945c51d80d6 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Wed, 25 Sep 2024 13:27:58 -0700 Subject: [PATCH 3/3] style --- include/boost/hash2/sha2.hpp | 8 ++--- test/sha2.cpp | 68 +++++++++++++++++------------------- 2 files changed, 37 insertions(+), 39 deletions(-) diff --git a/include/boost/hash2/sha2.hpp b/include/boost/hash2/sha2.hpp index 7a3045d..e5b97db 100644 --- a/include/boost/hash2/sha2.hpp +++ b/include/boost/hash2/sha2.hpp @@ -1,5 +1,5 @@ -#ifndef SHA2_HPP_INCLUDED -#define SHA2_HPP_INCLUDED +#ifndef BOOST_HASH2_SHA2_HPP_INCLUDED +#define BOOST_HASH2_SHA2_HPP_INCLUDED // Copyright 2024 Peter Dimov. // Copyright 2024 Christian Mazakas. @@ -223,7 +223,7 @@ class sha2_256 } }; -} // namespace boost } // namespace hash2 +} // namespace boost -#endif // #ifndef SHA2_HPP_INCLUDED +#endif // #ifndef BOOST_HASH2_SHA2_HPP_INCLUDED diff --git a/test/sha2.cpp b/test/sha2.cpp index e5d67c6..665e958 100644 --- a/test/sha2.cpp +++ b/test/sha2.cpp @@ -12,50 +12,49 @@ template std::string to_string( std::array const & v ) { - std::string r; + std::string r; - for( std::size_t i = 0; i < N; ++i ) - { - char buffer[ 4 ]; - std::snprintf( buffer, sizeof( buffer ), "%02x", v[ i ] ); - r += buffer; - } + for( std::size_t i = 0; i < N; ++i ) + { + char buffer[ 4 ]; + std::snprintf( buffer, sizeof( buffer ), "%02x", v[ i ] ); + r += buffer; + } - return r; + return r; } template std::string digest( std::string const & s ) { - H h; + H h; - h.update( s.data(), s.size() ); + h.update( s.data(), s.size() ); - return to_string( h.result() ); + return to_string( h.result() ); } template std::string digest( char (&buf)[N]) { - H h; + H h; - h.update( buf, N ); + h.update( buf, N ); - return to_string( h.result() ); + return to_string( h.result() ); } template std::string digest( std::vector const & v ) { - H h; + H h; - h.update( v.data(), v.size() ); + h.update( v.data(), v.size() ); - return to_string( h.result() ); + return to_string( h.result() ); } using boost::hash2::sha2_256; int main() { - // https://en.wikipedia.org/wiki/SHA-2#Test_vectors BOOST_TEST_EQ( digest( "" ), std::string( "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" ) ); @@ -72,42 +71,41 @@ int main() BOOST_TEST_EQ( digest( "\xc9\x8c\x8e\x55" ), std::string( "7abc22c0ae5af26ce93dbb94433a0e0b2e119d014f8e7f65bd56c61ccccd9504" ) ); { - char buf[ 55 ] = { 0 }; - BOOST_TEST_EQ( digest( buf ), std::string( "02779466cdec163811d078815c633f21901413081449002f24aa3e80f0b88ef7" ) ); + char buf[ 55 ] = { 0 }; + BOOST_TEST_EQ( digest( buf ), std::string( "02779466cdec163811d078815c633f21901413081449002f24aa3e80f0b88ef7" ) ); } { - char buf[ 56 ] = { 0 }; - BOOST_TEST_EQ( digest( buf ), std::string( "d4817aa5497628e7c77e6b606107042bbba3130888c5f47a375e6179be789fbb" ) ); + char buf[ 56 ] = { 0 }; + BOOST_TEST_EQ( digest( buf ), std::string( "d4817aa5497628e7c77e6b606107042bbba3130888c5f47a375e6179be789fbb" ) ); } { - char buf[ 64 ] = { 0 }; - BOOST_TEST_EQ( digest( buf ), std::string( "f5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b" ) ); + char buf[ 64 ] = { 0 }; + BOOST_TEST_EQ( digest( buf ), std::string( "f5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b" ) ); } { - char buf[ 1000 ] = { 0 }; - BOOST_TEST_EQ( digest( buf ), std::string( "541b3e9daa09b20bf85fa273e5cbd3e80185aa4ec298e765db87742b70138a53" ) ); + char buf[ 1000 ] = { 0 }; + BOOST_TEST_EQ( digest( buf ), std::string( "541b3e9daa09b20bf85fa273e5cbd3e80185aa4ec298e765db87742b70138a53" ) ); } { - char buf[ 1000 ] = {}; - for( auto& c : buf ) c = 'A'; - BOOST_TEST_EQ( digest( buf ), std::string( "c2e686823489ced2017f6059b8b239318b6364f6dcd835d0a519105a1eadd6e4" ) ); + char buf[ 1000 ] = {}; + for( auto& c : buf ) c = 'A'; + BOOST_TEST_EQ( digest( buf ), std::string( "c2e686823489ced2017f6059b8b239318b6364f6dcd835d0a519105a1eadd6e4" ) ); } { - char buf[ 1005 ] = {}; - for( auto& c : buf ) c = 'U'; - BOOST_TEST_EQ( digest( buf ), std::string( "f4d62ddec0f3dd90ea1380fa16a5ff8dc4c54b21740650f24afc4120903552b0" ) ); + char buf[ 1005 ] = {}; + for( auto& c : buf ) c = 'U'; + BOOST_TEST_EQ( digest( buf ), std::string( "f4d62ddec0f3dd90ea1380fa16a5ff8dc4c54b21740650f24afc4120903552b0" ) ); } { - std::vector buf(1000000, 0x00); - BOOST_TEST_EQ( digest( buf ), std::string( "d29751f2649b32ff572b5e0a9f541ea660a50f94ff0beedfb0b692b924cc8025" ) ); + std::vector buf(1000000, 0x00); + BOOST_TEST_EQ( digest( buf ), std::string( "d29751f2649b32ff572b5e0a9f541ea660a50f94ff0beedfb0b692b924cc8025" ) ); } - return boost::report_errors(); }