From d67c18f6c3bb4799f15276a8f4d0c1e649fd1d95 Mon Sep 17 00:00:00 2001 From: Peter Conrad Date: Wed, 29 Jul 2015 23:22:34 +0200 Subject: [PATCH] Fixed shift in hashes + more tests --- CMakeLists.txt | 1 + src/crypto/_digest_common.cpp | 33 +++++++++++++++ src/crypto/_digest_common.hpp | 7 +++ src/crypto/ripemd160.cpp | 7 +-- src/crypto/sha1.cpp | 7 +-- src/crypto/sha224.cpp | 9 ++-- src/crypto/sha256.cpp | 9 ++-- src/crypto/sha512.cpp | 7 +-- tests/crypto/sha_tests.cpp | 80 +++++++++++++++++++++++++++++++++-- 9 files changed, 129 insertions(+), 31 deletions(-) create mode 100644 src/crypto/_digest_common.cpp create mode 100644 src/crypto/_digest_common.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a95eff3..d95a2dd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -189,6 +189,7 @@ set( fc_sources src/log/file_appender.cpp src/log/gelf_appender.cpp src/log/logger_config.cpp + src/crypto/_digest_common.cpp src/crypto/openssl.cpp src/crypto/aes.cpp src/crypto/crc.cpp diff --git a/src/crypto/_digest_common.cpp b/src/crypto/_digest_common.cpp new file mode 100644 index 0000000..eeb1bc7 --- /dev/null +++ b/src/crypto/_digest_common.cpp @@ -0,0 +1,33 @@ +#include +#include +#include "_digest_common.hpp" + +namespace fc { namespace detail { + static void shift_l( const uint32_t* in, uint32_t* out, std::size_t n, int i) { + if (i < n) { + memcpy( out, in + i, 4*(n-i) ); + } else { + i = n; + } + memset( out + (n-i), 0, 4 * i ); + } + + void shift_l( const char* in, char* out, std::size_t n, int i) { + FC_ASSERT( (n & 3) == 0 ); // all hashes are a multiple of 32 bit + n >>= 2; + const uint32_t* in32 = (uint32_t*) in; + uint32_t* out32 = (uint32_t*) out; + + if (i >= 32) { + shift_l( in32, out32, n, i >> 5 ); + i &= 0x1f; + in32 = out32; + } + + std::size_t p; + for( p = 0; p < n-1; ++p ) + out32[p] = boost::endian::native_to_big(boost::endian::big_to_native(in32[p]) << i + | (boost::endian::big_to_native(in32[p+1])>>(32-i))); + out32[p] = boost::endian::native_to_big(boost::endian::big_to_native(in32[p]) << i); + } +}} diff --git a/src/crypto/_digest_common.hpp b/src/crypto/_digest_common.hpp new file mode 100644 index 0000000..a95b76d --- /dev/null +++ b/src/crypto/_digest_common.hpp @@ -0,0 +1,7 @@ +#pragma once + +/* Common stuff for cryptographic hashes + */ +namespace fc { namespace detail { + void shift_l( const char* in, char* out, std::size_t n, int i); +}} diff --git a/src/crypto/ripemd160.cpp b/src/crypto/ripemd160.cpp index ed3671a..e336b39 100644 --- a/src/crypto/ripemd160.cpp +++ b/src/crypto/ripemd160.cpp @@ -8,6 +8,7 @@ #include #include #include +#include "_digest_common.hpp" namespace fc { @@ -69,11 +70,7 @@ void ripemd160::encoder::reset() { ripemd160 operator << ( const ripemd160& h1, uint32_t i ) { ripemd160 result; - uint8_t* r = (uint8_t*)result._hash; - uint8_t* s = (uint8_t*)h1._hash; - for( uint32_t p = 0; p < sizeof(h1._hash)-1; ++p ) - r[p] = s[p] << i | (s[p+1]>>(8-i)); - r[19] = s[19] << i; + fc::detail::shift_l( h1.data(), result.data(), result.data_size(), i ); return result; } ripemd160 operator ^ ( const ripemd160& h1, const ripemd160& h2 ) { diff --git a/src/crypto/sha1.cpp b/src/crypto/sha1.cpp index 479d1ed..88107db 100644 --- a/src/crypto/sha1.cpp +++ b/src/crypto/sha1.cpp @@ -5,6 +5,7 @@ #include #include #include +#include "_digest_common.hpp" namespace fc { @@ -54,11 +55,7 @@ void sha1::encoder::reset() { sha1 operator << ( const sha1& h1, uint32_t i ) { sha1 result; - uint8_t* r = (uint8_t*)result._hash; - uint8_t* s = (uint8_t*)h1._hash; - for( uint32_t p = 0; p < sizeof(h1._hash)-1; ++p ) - r[p] = s[p] << i | (s[p+1]>>(8-i)); - r[19] = s[19] << i; + fc::detail::shift_l( h1.data(), result.data(), result.data_size(), i ); return result; } sha1 operator ^ ( const sha1& h1, const sha1& h2 ) { diff --git a/src/crypto/sha224.cpp b/src/crypto/sha224.cpp index d55802c..83f1a6a 100644 --- a/src/crypto/sha224.cpp +++ b/src/crypto/sha224.cpp @@ -4,7 +4,8 @@ #include #include #include - +#include "_digest_common.hpp" + namespace fc { sha224::sha224() { memset( _hash, 0, sizeof(_hash) ); } @@ -52,11 +53,7 @@ namespace fc { sha224 operator << ( const sha224& h1, uint32_t i ) { sha224 result; - uint8_t* r = (uint8_t*)&result;//result._hash; - uint8_t* s = (uint8_t*)&h1;//h1._hash; - for( uint32_t p = 0; p < sizeof(sha224)-1; ++p ) - r[p] = s[p] << i | (s[p+1]>>(8-i)); - r[sizeof(sha224)-1] = s[sizeof(sha224)-1] << i; + fc::detail::shift_l( h1.data(), result.data(), result.data_size(), i ); return result; } sha224 operator ^ ( const sha224& h1, const sha224& h2 ) { diff --git a/src/crypto/sha256.cpp b/src/crypto/sha256.cpp index ae1d6af..1af5822 100644 --- a/src/crypto/sha256.cpp +++ b/src/crypto/sha256.cpp @@ -5,7 +5,8 @@ #include #include #include - +#include "_digest_common.hpp" + namespace fc { sha256::sha256() { memset( _hash, 0, sizeof(_hash) ); } @@ -64,11 +65,7 @@ namespace fc { sha256 operator << ( const sha256& h1, uint32_t i ) { sha256 result; - uint8_t* r = (uint8_t*)result._hash; - uint8_t* s = (uint8_t*)h1._hash; - for( uint32_t p = 0; p < sizeof(h1._hash)-1; ++p ) - r[p] = s[p] << i | (s[p+1]>>(8-i)); - r[31] = s[31] << i; + fc::detail::shift_l( h1.data(), result.data(), result.data_size(), i ); return result; } sha256 operator ^ ( const sha256& h1, const sha256& h2 ) { diff --git a/src/crypto/sha512.cpp b/src/crypto/sha512.cpp index d177fe3..0baa03e 100644 --- a/src/crypto/sha512.cpp +++ b/src/crypto/sha512.cpp @@ -4,6 +4,7 @@ #include #include #include +#include "_digest_common.hpp" namespace fc { @@ -52,11 +53,7 @@ namespace fc { sha512 operator << ( const sha512& h1, uint32_t i ) { sha512 result; - uint8_t* r = (uint8_t*)result._hash; - uint8_t* s = (uint8_t*)h1._hash; - for( uint32_t p = 0; p < sizeof(h1._hash)-1; ++p ) - r[p] = s[p] << i | (s[p+1]>>(8-i)); - r[63] = s[63] << i; + fc::detail::shift_l( h1.data(), result.data(), result.data_size(), i ); return result; } sha512 operator ^ ( const sha512& h1, const sha512& h2 ) { diff --git a/tests/crypto/sha_tests.cpp b/tests/crypto/sha_tests.cpp index 005f659..056bf61 100644 --- a/tests/crypto/sha_tests.cpp +++ b/tests/crypto/sha_tests.cpp @@ -1,5 +1,7 @@ #include +#include +#include #include #include #include @@ -14,6 +16,7 @@ static const std::string TEST2(""); static const std::string TEST3("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"); static const std::string TEST4("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"); static char TEST5[1000001]; +static const std::string TEST6("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno"); static void init_5() { memset( TEST5, 'a', sizeof(TEST5) - 1 ); @@ -30,16 +33,65 @@ void test( const char* to_hash, const std::string& expected ) { template void test( const std::string& to_hash, const std::string& expected ) { + H hash = H::hash( to_hash ); + BOOST_CHECK_EQUAL( expected, (std::string) hash ); test( to_hash.c_str(), expected ); } -template void test( const std::string& test, const std::string& expected ); -template void test( const std::string& test, const std::string& expected ); -template void test( const std::string& test, const std::string& expected ); -template void test( const std::string& test, const std::string& expected ); +template +void test_big( const std::string& expected ) { + typename H::encoder enc; + for (char c : TEST6) { enc.put(c); } + for (int i = 0; i < 16777215; i++) { + enc.write( TEST6.c_str(), TEST6.size() ); + } + H hash = enc.result(); + BOOST_CHECK_EQUAL( expected, (std::string) hash ); + + enc.reset(); + enc.write( TEST1.c_str(), TEST1.size() ); + hash = enc.result(); + BOOST_CHECK( hash >= H::hash( TEST1 ) ); + test( TEST1, (std::string) hash ); + + hash = hash ^ hash; + hash.data()[hash.data_size() - 1] = 1; + for (int i = hash.data_size() * 8 - 1; i > 0; i--) { + H other = hash << i; + BOOST_CHECK( other != hash ); + BOOST_CHECK( other > hash ); + BOOST_CHECK( hash < other ); + } + + H hash2( expected ); + fc::variant v; + to_variant( hash2, v ); + from_variant( v, hash ); + BOOST_CHECK( hash == hash2 ); + + H hash3( expected.substr(15) + "000000000000000" ); + BOOST_CHECK( hash3 == hash2 << 60 ); +} + +template void test_big( const std::string& expected ); +template void test_big( const std::string& expected ); +template void test_big( const std::string& expected ); +template void test_big( const std::string& expected ); +template void test_big( const std::string& expected ); BOOST_AUTO_TEST_SUITE(fc_crypto) +BOOST_AUTO_TEST_CASE(ripemd160_test) +{ + init_5(); + test( TEST1, "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc" ); + test( TEST2, "9c1185a5c5e9fc54612808977ee8f548b2258d31" ); + test( TEST3, "12a053384a9c0c88e405a06c27dcf49ada62eb2b" ); +// test( TEST4, "" ); + test( TEST5, "52783243c1697bdbe16d37f97f68f08325dc1528" ); + test_big( "29b6df855772aa9a95442bf83b282b495f9f6541" ); +} + BOOST_AUTO_TEST_CASE(sha1_test) { init_5(); @@ -48,6 +100,7 @@ BOOST_AUTO_TEST_CASE(sha1_test) test( TEST3, "84983e441c3bd26ebaae4aa1f95129e5e54670f1" ); test( TEST4, "a49b2446a02c645bf419f995b67091253a04a259" ); test( TEST5, "34aa973cd4c4daa4f61eeb2bdbad27316534016f" ); + test_big( "7789f0c9ef7bfc40d93311143dfbe69e2017f592" ); } BOOST_AUTO_TEST_CASE(sha224_test) @@ -58,6 +111,7 @@ BOOST_AUTO_TEST_CASE(sha224_test) test( TEST3, "75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525" ); test( TEST4, "c97ca9a559850ce97a04a96def6d99a9e0e0e2ab14e6b8df265fc0b3" ); test( TEST5, "20794655980c91d8bbb4c1ea97618a4bf03f42581948b2ee4ee7ad67" ); + test_big( "b5989713ca4fe47a009f8621980b34e6d63ed3063b2a0a2c867d8a85" ); } BOOST_AUTO_TEST_CASE(sha256_test) @@ -68,6 +122,22 @@ BOOST_AUTO_TEST_CASE(sha256_test) test( TEST3, "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1" ); test( TEST4, "cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1" ); test( TEST5, "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0" ); + test_big( "50e72a0e26442fe2552dc3938ac58658228c0cbfb1d2ca872ae435266fcd055e" ); + + std::vector test_object; + test_object.push_back( 42 ); + fc::sha256 digest = fc::digest( test_object ); + BOOST_CHECK( digest == fc::sha256::hash( test_object ) ); + fc::sha256 other( digest.data(), digest.data_size() ); + BOOST_CHECK( digest == other ); + fc::sha512 yet_another = fc::sha512::hash( TEST1 ); + try { + fc::sha256 fourth( yet_another.data(), yet_another.data_size() ); + BOOST_FAIL( "Expected exception!" ); + } catch ( fc::exception& expected ) {} + + fc::sha256 fourth( "445C7A8007A93D8733188288BB320A8FE2DEBD2AE1B47F0F50BC10BAE845C094" ); + BOOST_CHECK_EQUAL( "d61967f63c7dd183914a4ae452c9f6ad5d462ce3d277798075b107615c1a8a30", (std::string) fc::sha256::hash(fourth) ); } BOOST_AUTO_TEST_CASE(sha512_test) @@ -83,6 +153,8 @@ BOOST_AUTO_TEST_CASE(sha512_test) "501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909" ); test( TEST5, "e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973eb" "de0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b" ); + test_big( "b47c933421ea2db149ad6e10fce6c7f93d0752380180ffd7f4629a712134831d" + "77be6091b819ed352c2967a2e2d4fa5050723c9630691f1a05a7281dbe6c1086" ); } BOOST_AUTO_TEST_SUITE_END()