diff --git a/include/boost/hash2/sha2.hpp b/include/boost/hash2/sha2.hpp index e5b97db..b014ee9 100644 --- a/include/boost/hash2/sha2.hpp +++ b/include/boost/hash2/sha2.hpp @@ -12,9 +12,7 @@ #include #include #include -#include #include -#include #include #include @@ -23,10 +21,11 @@ namespace boost namespace hash2 { -class sha2_256 +namespace detail { -private: +struct sha2_256_base +{ std::uint32_t state_[ 8 ]; static const int N = 64; @@ -36,18 +35,8 @@ class sha2_256 std::uint64_t n_; -private: - - void init() + sha2_256_base(): m_( 0 ), n_( 0 ) { - 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 @@ -140,14 +129,6 @@ class sha2_256 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 ); @@ -201,6 +182,35 @@ class sha2_256 BOOST_ASSERT( m_ == n_ % N ); } +}; + +} // namespace detail + +class sha2_256 : detail::sha2_256_base +{ +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; + } + +public: + using result_type = std::array; + + sha2_256() + { + init(); + } + + using detail::sha2_256_base::update; result_type result() { @@ -223,6 +233,53 @@ class sha2_256 } }; +class sha2_224 : detail::sha2_256_base +{ +private: + + void init() + { + state_[ 0 ] = 0xc1059ed8; + state_[ 1 ] = 0x367cd507; + state_[ 2 ] = 0x3070dd17; + state_[ 3 ] = 0xf70e5939; + state_[ 4 ] = 0xffc00b31; + state_[ 5 ] = 0x68581511; + state_[ 6 ] = 0x64f98fa7; + state_[ 7 ] = 0xbefa4fa4; + } + +public: + using result_type = std::array; + + sha2_224() + { + init(); + } + + using detail::sha2_256_base::update; + + 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 < 7; ++i ) { + detail::write32be( &digest[ i * 4 ], state_[ i ] ); + } + + return digest; + } +}; + } // namespace hash2 } // namespace boost diff --git a/test/sha2.cpp b/test/sha2.cpp index 665e958..cc5134f 100644 --- a/test/sha2.cpp +++ b/test/sha2.cpp @@ -52,8 +52,10 @@ template std::string digest( std::vector const & v ) } using boost::hash2::sha2_256; +using boost::hash2::sha2_224; -int main() +static +void sha_256() { // https://en.wikipedia.org/wiki/SHA-2#Test_vectors @@ -106,6 +108,55 @@ int main() std::vector buf(1000000, 0x00); BOOST_TEST_EQ( digest( buf ), std::string( "d29751f2649b32ff572b5e0a9f541ea660a50f94ff0beedfb0b692b924cc8025" ) ); } +} + +static +void sha_224() +{ + // https://en.wikipedia.org/wiki/SHA-2#Test_vectors + + BOOST_TEST_EQ( digest( "" ), std::string( "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f" ) ); + + // https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/SHA224.pdf + BOOST_TEST_EQ( digest( "abc" ), std::string( "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7" ) ); + BOOST_TEST_EQ( digest( "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" ), std::string( "75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525" ) ); + + // https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/SHA2_Additional.pdf + BOOST_TEST_EQ( digest( "\xff" ), std::string( "e33f9d75e6ae1369dbabf81b96b4591ae46bba30b591a6b6c62542b5" ) ); + BOOST_TEST_EQ( digest( "\xe5\xe0\x99\x24" ), std::string( "fd19e74690d291467ce59f077df311638f1c3a46e510d0e49a67062d" ) ); + + { + char buf[ 56 ] = { 0 }; + BOOST_TEST_EQ( digest( buf ), std::string( "5c3e25b69d0ea26f260cfae87e23759e1eca9d1ecc9fbf3c62266804" ) ); + } + + { + char buf[ 1000 ] = {}; + for( auto& c : buf ) c = 'Q'; + BOOST_TEST_EQ( digest( buf ), std::string( "3706197f66890a41779dc8791670522e136fafa24874685715bd0a8a" ) ); + } + { + char buf[ 1000 ] = {}; + for( auto& c : buf ) c = 'A'; + BOOST_TEST_EQ( digest( buf ), std::string( "a8d0c66b5c6fdfd836eb3c6d04d32dfe66c3b1f168b488bf4c9c66ce" ) ); + } + + { + char buf[ 1005 ] = {}; + for( auto& c : buf ) c = '\x99'; + BOOST_TEST_EQ( digest( buf ), std::string( "cb00ecd03788bf6c0908401e0eb053ac61f35e7e20a2cfd7bd96d640" ) ); + } + + { + std::vector buf(1000000, 0x00); + BOOST_TEST_EQ( digest( buf ), std::string( "3a5d74b68f14f3a4b2be9289b8d370672d0b3d2f53bc303c59032df3" ) ); + } +} + +int main() +{ + sha_256(); + sha_224(); return boost::report_errors(); }