From 44d9f456f81a799a32ef67d4ed49e707cd0b879a Mon Sep 17 00:00:00 2001 From: Alden Torres Date: Thu, 25 Aug 2016 19:07:16 -0400 Subject: [PATCH] adding support for a more configurable sha512 hasher (#1028) adding support for a more configurable sha512 hasher, digest32 template, using hasher512. --- CMakeLists.txt | 9 +- Jamfile | 15 +- Makefile.am | 3 +- configure.ac | 1 + docs/gen_reference_doc.py | 1 + ed25519/src/keypair.cpp | 6 +- ed25519/src/sha512.h | 22 --- ed25519/src/sign.cpp | 36 ++--- ed25519/src/verify.cpp | 21 +-- include/libtorrent/Makefile.am | 2 + include/libtorrent/ed25519.hpp | 2 +- include/libtorrent/extensions.hpp | 2 +- include/libtorrent/hasher.hpp | 13 +- include/libtorrent/hasher512.hpp | 124 ++++++++++++++ include/libtorrent/sha1.hpp | 12 +- include/libtorrent/sha1_hash.hpp | 121 ++++++++------ include/libtorrent/sha512.hpp | 23 +++ include/libtorrent/torrent_handle.hpp | 2 +- src/Makefile.am | 15 +- src/hasher.cpp | 8 +- src/hasher512.cpp | 224 ++++++++++++++++++++++++++ src/sha1.cpp | 10 +- src/sha1_hash.cpp | 62 +++---- {ed25519/src => src}/sha512.cpp | 64 ++++---- test/Jamfile | 2 + test/Makefile.am | 2 + test/test_ed25519.cpp | 177 ++++++++++++++++++++ test/test_hasher.cpp | 47 +++++- test/test_hasher512.cpp | 91 +++++++++++ 29 files changed, 914 insertions(+), 203 deletions(-) delete mode 100644 ed25519/src/sha512.h create mode 100644 include/libtorrent/hasher512.hpp create mode 100644 include/libtorrent/sha512.hpp create mode 100644 src/hasher512.cpp rename {ed25519/src => src}/sha512.cpp (91%) create mode 100644 test/test_ed25519.cpp create mode 100644 test/test_hasher512.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d5123c64a..c31393602 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -151,7 +151,6 @@ set(ed25519_sources keypair sc seed - sha512 sign verify ) @@ -215,7 +214,9 @@ if (encryption) include_directories(${OPENSSL_INCLUDE_DIR}) else() add_definitions(-DTORRENT_DISABLE_ENCRYPTION) - list(APPEND sources sha1) + if (NOT WIN32 AND NOT APPLE) + list(APPEND sources sha1) + endif() endif (encryption) if (NOT logging) @@ -233,6 +234,10 @@ if (dht) foreach(s ${ed25519_sources}) list(APPEND sources2 ed25519/src/${s}) endforeach(s) + list(APPEND sources2 src/hasher512) + if (NOT encryption AND NOT WIN32 AND NOT APPLE) + list(APPEND sources2 src/sha512) + endif() else() add_definitions(-DTORRENT_DISABLE_DHT) endif() diff --git a/Jamfile b/Jamfile index 9fdf3b396..9a41550b7 100644 --- a/Jamfile +++ b/Jamfile @@ -341,15 +341,21 @@ rule building ( properties * ) result += src/pe_crypto.cpp ; } - if built-in in $(properties) + if built-in in $(properties) + && ! windows in $(properties) + && ! darwin in $(properties) { result += src/sha1.cpp ; + if on in $(properties) + { + result += src/sha512.cpp ; + } } if ( darwin in $(properties) || gcc in $(properties) - || clang in $(propertoes) - || clang-darwin in $(propertoes) ) + || clang in $(properties) + || clang-darwin in $(properties) ) && shared in $(properties) # on GCC, enabling debugging in libstdc++ # breaks the ABI and its ability to appear @@ -652,7 +658,6 @@ SOURCES = tracker_manager http_tracker_connection udp_tracker_connection - sha1 timestamp_history udp_socket upnp @@ -714,7 +719,6 @@ ED25519_SOURCES = keypair sc seed - sha512 sign verify ; @@ -766,6 +770,7 @@ lib torrent on:src/kademlia/$(KADEMLIA_SOURCES).cpp on:ed25519/src/$(ED25519_SOURCES).cpp + on:src/hasher512.cpp debug:on debug:on diff --git a/Makefile.am b/Makefile.am index b5b424dbc..1bcfd7758 100644 --- a/Makefile.am +++ b/Makefile.am @@ -111,8 +111,7 @@ ED25519_SOURCE = \ ed25519/src/fixedint.h \ ed25519/src/ge.h \ ed25519/src/precomp_data.h \ - ed25519/src/sc.h \ - ed25519/src/sha512.h + ed25519/src/sc.h EXTRA_DIST = \ Jamfile \ diff --git a/configure.ac b/configure.ac index b113f86d2..a1b4cf8a6 100644 --- a/configure.ac +++ b/configure.ac @@ -385,6 +385,7 @@ AS_CASE(["$ARG_ENABLE_ENCRYPTION"], AX_CHECK_OPENSSL([ AC_DEFINE([TORRENT_USE_OPENSSL],[1],[Define to use OpenSSL support.]) + AC_DEFINE([TORRENT_USE_LIBCRYPTO],[1],[Define to use libcrypto from OpenSSL.]) COMPILETIME_OPTIONS="$COMPILETIME_OPTIONS -DTORRENT_USE_OPENSSL -DTORRENT_USE_LIBCRYPTO " ], [ AC_MSG_ERROR([OpenSSL library not found. Try using --with-openssl=DIR or disabling encryption at all.]) diff --git a/docs/gen_reference_doc.py b/docs/gen_reference_doc.py index 6802ea1d8..66288854f 100644 --- a/docs/gen_reference_doc.py +++ b/docs/gen_reference_doc.py @@ -94,6 +94,7 @@ category_mapping = { 'bitfield.hpp': 'Utility', 'sha1_hash.hpp': 'Utility', 'hasher.hpp': 'Utility', + 'hasher512.hpp': 'Utility', 'identify_client.hpp': 'Utility', 'ip_filter.hpp': 'Filter', 'session_settings.hpp': 'Settings', diff --git a/ed25519/src/keypair.cpp b/ed25519/src/keypair.cpp index 90d8dbc3b..ac9149b88 100644 --- a/ed25519/src/keypair.cpp +++ b/ed25519/src/keypair.cpp @@ -2,14 +2,16 @@ #include "libtorrent/aux_/disable_warnings_push.hpp" #include "libtorrent/ed25519.hpp" -#include "sha512.h" +#include "libtorrent/hasher512.hpp" #include "ge.h" +using namespace libtorrent; void ed25519_create_keypair(unsigned char *public_key, unsigned char *private_key, const unsigned char *seed) { ge_p3 A; - sha512(seed, 32, private_key); + hasher512 hash({reinterpret_cast(seed), 32}); + std::memcpy(private_key, hash.final().data(), 64); private_key[0] &= 248; private_key[31] &= 63; private_key[31] |= 64; diff --git a/ed25519/src/sha512.h b/ed25519/src/sha512.h deleted file mode 100644 index 7f93a3264..000000000 --- a/ed25519/src/sha512.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef SHA512_H -#define SHA512_H - -#include - -#include "fixedint.h" - -/* state */ -typedef struct sha512_context_ { - u64 length, state[8]; - size_t curlen; - unsigned char buf[128]; -} sha512_context; - - -int sha512_init(sha512_context * md); -int sha512_final(sha512_context * md, unsigned char *out); -int sha512_update(sha512_context * md, const unsigned char *in, size_t inlen); -int sha512(const unsigned char *message, size_t message_len, unsigned char *out); - -#endif - diff --git a/ed25519/src/sign.cpp b/ed25519/src/sign.cpp index cf4b20d2a..d10a97a7e 100644 --- a/ed25519/src/sign.cpp +++ b/ed25519/src/sign.cpp @@ -2,33 +2,33 @@ #include "libtorrent/aux_/disable_warnings_push.hpp" #include "libtorrent/ed25519.hpp" -#include "sha512.h" +#include "libtorrent/hasher512.hpp" #include "ge.h" #include "sc.h" +using namespace libtorrent; void ed25519_sign(unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key, const unsigned char *private_key) { - sha512_context hash; - unsigned char hram[64]; - unsigned char r[64]; ge_p3 R; + hasher512 hash; + hash.update({reinterpret_cast(private_key) + 32, 32}); + hash.update({reinterpret_cast(message), message_len}); + sha512_hash r = hash.final(); - sha512_init(&hash); - sha512_update(&hash, private_key + 32, 32); - sha512_update(&hash, message, message_len); - sha512_final(&hash, r); - - sc_reduce(r); - ge_scalarmult_base(&R, r); + sc_reduce(reinterpret_cast(r.data())); + ge_scalarmult_base(&R, reinterpret_cast(r.data())); ge_p3_tobytes(signature, &R); - sha512_init(&hash); - sha512_update(&hash, signature, 32); - sha512_update(&hash, public_key, 32); - sha512_update(&hash, message, message_len); - sha512_final(&hash, hram); + hash.reset(); + hash.update({reinterpret_cast(signature), 32}); + hash.update({reinterpret_cast(public_key), 32}); + hash.update({reinterpret_cast(message), message_len}); + sha512_hash hram = hash.final(); - sc_reduce(hram); - sc_muladd(signature + 32, hram, private_key, r); + sc_reduce(reinterpret_cast(hram.data())); + sc_muladd(signature + 32 + , reinterpret_cast(hram.data()) + , private_key + , reinterpret_cast(r.data())); } diff --git a/ed25519/src/verify.cpp b/ed25519/src/verify.cpp index b5d81b8e5..15704be2c 100644 --- a/ed25519/src/verify.cpp +++ b/ed25519/src/verify.cpp @@ -2,10 +2,12 @@ #include "libtorrent/aux_/disable_warnings_push.hpp" #include "libtorrent/ed25519.hpp" -#include "sha512.h" +#include "libtorrent/hasher512.hpp" #include "ge.h" #include "sc.h" +using namespace libtorrent; + static int consttime_equal(const unsigned char *x, const unsigned char *y) { unsigned char r = 0; @@ -48,9 +50,7 @@ static int consttime_equal(const unsigned char *x, const unsigned char *y) { } int ed25519_verify(const unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key) { - unsigned char h[64]; unsigned char checker[32]; - sha512_context hash; ge_p3 A; ge_p2 R; @@ -62,14 +62,15 @@ int ed25519_verify(const unsigned char *signature, const unsigned char *message, return 0; } - sha512_init(&hash); - sha512_update(&hash, signature, 32); - sha512_update(&hash, public_key, 32); - sha512_update(&hash, message, message_len); - sha512_final(&hash, h); + hasher512 hash; + hash.update({reinterpret_cast(signature), 32}); + hash.update({reinterpret_cast(public_key), 32}); + hash.update({reinterpret_cast(message), message_len}); + sha512_hash h = hash.final(); - sc_reduce(h); - ge_double_scalarmult_vartime(&R, h, &A, signature + 32); + sc_reduce(reinterpret_cast(h.data())); + ge_double_scalarmult_vartime(&R, reinterpret_cast(h.data()) + , &A, signature + 32); ge_tobytes(checker, &R); if (!consttime_equal(checker, signature)) { diff --git a/include/libtorrent/Makefile.am b/include/libtorrent/Makefile.am index 0f7a1f132..a240098b4 100644 --- a/include/libtorrent/Makefile.am +++ b/include/libtorrent/Makefile.am @@ -54,6 +54,7 @@ nobase_include_HEADERS = \ fingerprint.hpp \ gzip.hpp \ hasher.hpp \ + hasher512.hpp \ hex.hpp \ heterogeneous_queue.hpp \ http_connection.hpp \ @@ -112,6 +113,7 @@ nobase_include_HEADERS = \ session_status.hpp \ settings_pack.hpp \ sha1.hpp \ + sha512.hpp \ sha1_hash.hpp \ sliding_average.hpp \ socket.hpp \ diff --git a/include/libtorrent/ed25519.hpp b/include/libtorrent/ed25519.hpp index 3a85fb74a..8a94b2471 100644 --- a/include/libtorrent/ed25519.hpp +++ b/include/libtorrent/ed25519.hpp @@ -24,7 +24,7 @@ void TORRENT_EXPORT ed25519_create_seed(unsigned char *seed); // public_key and secret_key) void TORRENT_EXPORT ed25519_create_keypair(unsigned char *public_key, unsigned char *private_key, const unsigned char *seed); void TORRENT_EXPORT ed25519_sign(unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key, const unsigned char *private_key); -int TORRENT_EXPORT ed25519_verify(const unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *private_key); +int TORRENT_EXPORT ed25519_verify(const unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key); void TORRENT_EXPORT ed25519_add_scalar(unsigned char *public_key, unsigned char *private_key, const unsigned char *scalar); void TORRENT_EXPORT ed25519_key_exchange(unsigned char *shared_secret, const unsigned char *public_key, const unsigned char *private_key); diff --git a/include/libtorrent/extensions.hpp b/include/libtorrent/extensions.hpp index 33c6d1ddf..b8fa70f04 100644 --- a/include/libtorrent/extensions.hpp +++ b/include/libtorrent/extensions.hpp @@ -161,6 +161,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/config.hpp" #include "libtorrent/span.hpp" +#include "libtorrent/sha1_hash.hpp" #include "libtorrent/string_view.hpp" #include "libtorrent/socket.hpp" @@ -175,7 +176,6 @@ namespace libtorrent struct torrent_plugin; struct add_torrent_params; struct torrent_handle; - class sha1_hash; struct session_handle; struct peer_connection_handle; diff --git a/include/libtorrent/hasher.hpp b/include/libtorrent/hasher.hpp index d901618f3..08a502968 100644 --- a/include/libtorrent/hasher.hpp +++ b/include/libtorrent/hasher.hpp @@ -34,9 +34,7 @@ POSSIBILITY OF SUCH DAMAGE. #define TORRENT_HASHER_HPP_INCLUDED #include "libtorrent/config.hpp" -#include "libtorrent/peer_id.hpp" -#include "libtorrent/config.hpp" -#include "libtorrent/assert.hpp" +#include "libtorrent/sha1_hash.hpp" #include "libtorrent/span.hpp" #include @@ -48,7 +46,8 @@ POSSIBILITY OF SUCH DAMAGE. #include #elif TORRENT_USE_CRYPTOAPI -#include +#include +#include #elif defined TORRENT_USE_LIBCRYPTO @@ -76,7 +75,8 @@ namespace libtorrent // If you want to reuse the hasher object once you have created a hash, you have to // call ``reset()`` to reinitialize it. // - // The sha1-algorithm used was implemented by Steve Reid and released as public domain. + // The built-in software version of sha1-algorithm was implemented + // by Steve Reid and released as public domain. // For more info, see ``src/sha1.cpp``. class TORRENT_EXPORT hasher { @@ -116,11 +116,10 @@ namespace libtorrent #elif defined TORRENT_USE_LIBCRYPTO SHA_CTX m_context; #else - sha_ctx m_context; + sha1_ctx m_context; #endif }; } #endif // TORRENT_HASHER_HPP_INCLUDED - diff --git a/include/libtorrent/hasher512.hpp b/include/libtorrent/hasher512.hpp new file mode 100644 index 000000000..62fb9fda8 --- /dev/null +++ b/include/libtorrent/hasher512.hpp @@ -0,0 +1,124 @@ +/* + +Copyright (c) 2003-2016, Arvid Norberg, Alden Torres +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef TORRENT_HASHER512_HPP_INCLUDED +#define TORRENT_HASHER512_HPP_INCLUDED + +#include "libtorrent/config.hpp" +#include "libtorrent/sha1_hash.hpp" +#include "libtorrent/span.hpp" + +#include + +#ifdef TORRENT_USE_LIBGCRYPT +#include + +#elif TORRENT_USE_COMMONCRYPTO +#include + +#elif TORRENT_USE_CRYPTOAPI +#include +#include + +#elif defined TORRENT_USE_LIBCRYPTO + +extern "C" { +#include +} + +#else +#include "libtorrent/sha512.hpp" +#endif + +namespace libtorrent +{ + using sha512_hash = digest32<512>; + + // this is a SHA-512 hash class. + // + // You use it by first instantiating it, then call ``update()`` to feed it + // with data. i.e. you don't have to keep the entire buffer of which you want to + // create the hash in memory. You can feed the hasher parts of it at a time. When + // You have fed the hasher with all the data, you call ``final()`` and it + // will return the sha1-hash of the data. + // + // The constructor that takes a ``char const*`` and an integer will construct the + // sha1 context and feed it the data passed in. + // + // If you want to reuse the hasher object once you have created a hash, you have to + // call ``reset()`` to reinitialize it. + // + // The built-in software version of the sha512-algorithm is from LibTomCrypt + // For more info, see ``src/sha512.cpp``. + class TORRENT_EXPORT hasher512 + { + public: + + hasher512(); + + // this is the same as default constructing followed by a call to + // ``update(data)``. + explicit hasher512(span data); + hasher512(hasher512 const&); + hasher512& operator=(hasher512 const&); + + // append the following bytes to what is being hashed + hasher512& update(span data); + + // store the SHA-512 digest of the buffers previously passed to + // update() and the hasher constructor. + sha512_hash final(); + + // restore the hasher state to be as if the hasher has just been + // default constructed. + void reset(); + + ~hasher512(); + + private: + +#ifdef TORRENT_USE_LIBGCRYPT + gcry_md_hd_t m_context; +#elif TORRENT_USE_COMMONCRYPTO + CC_SHA512_CTX m_context; +#elif TORRENT_USE_CRYPTOAPI + HCRYPTHASH m_context; +#elif defined TORRENT_USE_LIBCRYPTO + SHA512_CTX m_context; +#else + sha512_ctx m_context; +#endif + }; + +} + +#endif // TORRENT_HASHER512_HPP_INCLUDED diff --git a/include/libtorrent/sha1.hpp b/include/libtorrent/sha1.hpp index ed7f22047..74b74ba5d 100644 --- a/include/libtorrent/sha1.hpp +++ b/include/libtorrent/sha1.hpp @@ -19,7 +19,7 @@ changelog at the end of sha1.cpp namespace libtorrent { - struct TORRENT_EXTRA_EXPORT sha_ctx + struct sha1_ctx { std::uint32_t state[5]; std::uint32_t count[2]; @@ -27,12 +27,10 @@ namespace libtorrent }; // we don't want these to clash with openssl's libcrypto - TORRENT_EXTRA_EXPORT void SHA1_init(sha_ctx* context); - TORRENT_EXTRA_EXPORT void SHA1_update(sha_ctx* context - , std::uint8_t const* data - , std::uint32_t len); - TORRENT_EXTRA_EXPORT void SHA1_final(std::uint8_t* digest, sha_ctx* context); + TORRENT_EXTRA_EXPORT void SHA1_init(sha1_ctx* context); + TORRENT_EXTRA_EXPORT void SHA1_update(sha1_ctx* context + , std::uint8_t const* data, std::uint32_t len); + TORRENT_EXTRA_EXPORT void SHA1_final(std::uint8_t* digest, sha1_ctx* context); } #endif - diff --git a/include/libtorrent/sha1_hash.hpp b/include/libtorrent/sha1_hash.hpp index c24bda0fb..502d66174 100644 --- a/include/libtorrent/sha1_hash.hpp +++ b/include/libtorrent/sha1_hash.hpp @@ -49,66 +49,79 @@ POSSIBILITY OF SUCH DAMAGE. namespace libtorrent { + // TODO: find a better place for these functions + namespace aux + { + TORRENT_EXTRA_EXPORT void bits_shift_left(span number, int n); + TORRENT_EXTRA_EXPORT void bits_shift_right(span number, int n); + } - // This type holds a SHA-1 digest or any other kind of 20 byte + // This type holds an N digest or any other kind of N bits // sequence. It implements a number of convenience functions, such // as bit operations, comparison operators etc. // - // In libtorrent it is primarily used to hold info-hashes, piece-hashes, - // peer IDs, node IDs etc. - class TORRENT_EXPORT sha1_hash + // This data structure is 32 bits aligned, like it's the case for + // each SHA-N specification. + template + class digest32 { - enum { number_size = 5 }; + static_assert(N % 32 == 0, "N must be a multiple of 32"); + enum { number_size = N / 32 }; public: // the size of the hash in bytes - static constexpr size_t size() { return number_size * sizeof(std::uint32_t); } + static constexpr size_t size() { return N / 8; } - // constructs an all-zero sha1-hash - sha1_hash() { clear(); } + // constructs an all-zero digest + digest32() { clear(); } - // returns an all-F sha1-hash. i.e. the maximum value - // representable by a 160 bit number (20 bytes). This is + digest32(digest32 const&) = default; + digest32(digest32&&) = default; + digest32& operator=(digest32 const&) = default; + digest32& operator=(digest32&&) = default; + + // returns an all-F digest. i.e. the maximum value + // representable by an N bit number (N/8 bytes). This is // a static member function. - static sha1_hash max() + static digest32 max() { - sha1_hash ret; + digest32 ret; std::memset(ret.m_number, 0xff, size()); return ret; } - // returns an all-zero sha1-hash. i.e. the minimum value - // representable by a 160 bit number (20 bytes). This is + // returns an all-zero digest. i.e. the minimum value + // representable by an N bit number (N/8 bytes). This is // a static member function. - static sha1_hash min() + static digest32 min() { - sha1_hash ret; + digest32 ret; // all bits are already 0 return ret; } - // copies 20 bytes from the pointer provided, into the sha1-hash. - // The passed in string MUST be at least 20 bytes. 0-terminators + // copies N/8 bytes from the pointer provided, into the digest. + // The passed in string MUST be at least N/8 bytes. 0-terminators // are ignored, ``s`` is treated like a raw memory buffer. - explicit sha1_hash(char const* s) + explicit digest32(char const* s) { if (s == nullptr) clear(); else std::memcpy(m_number, s, size()); } #ifndef TORRENT_NO_DEPRECATE TORRENT_DEPRECATED - explicit sha1_hash(std::string const& s) + explicit digest32(std::string const& s) { assign(s.data()); } #endif - explicit sha1_hash(span s) + explicit digest32(span s) { assign(s); } void assign(span s) { - TORRENT_ASSERT(s.size() >= 20); + TORRENT_ASSERT(s.size() >= N / 8); size_t const sl = s.size() < size() ? s.size() : size(); std::memcpy(m_number, s.data(), sl); } @@ -117,10 +130,10 @@ namespace libtorrent char const* data() const { return reinterpret_cast(&m_number[0]); } char* data() { return reinterpret_cast(&m_number[0]); } - // set the sha1-hash to all zeroes. + // set the digest to all zeroes. void clear() { std::memset(m_number, 0, size()); } - // return true if the sha1-hash is all zero. + // return true if the digest is all zero. bool is_all_zeros() const { for (int i = 0; i < number_size; ++i) @@ -129,21 +142,29 @@ namespace libtorrent } // shift left ``n`` bits. - sha1_hash& operator<<=(int n); + digest32& operator<<=(int n) + { + aux::bits_shift_left({m_number, number_size}, n); + return *this; + } // shift right ``n`` bits. - sha1_hash& operator>>=(int n); + digest32& operator>>=(int n) + { + aux::bits_shift_right({m_number, number_size}, n); + return *this; + } // standard comparison operators - bool operator==(sha1_hash const& n) const + bool operator==(digest32 const& n) const { return std::equal(n.m_number, n.m_number + number_size, m_number); } - bool operator!=(sha1_hash const& n) const + bool operator!=(digest32 const& n) const { return !std::equal(n.m_number, n.m_number + number_size, m_number); } - bool operator<(sha1_hash const& n) const + bool operator<(digest32 const& n) const { for (int i = 0; i < number_size; ++i) { @@ -160,49 +181,49 @@ namespace libtorrent return aux::count_leading_zeros({m_number, number_size}); } - // returns a bit-wise negated copy of the sha1-hash - sha1_hash operator~() const + // returns a bit-wise negated copy of the digest + digest32 operator~() const { - sha1_hash ret; + digest32 ret; for (int i = 0; i < number_size; ++i) ret.m_number[i] = ~m_number[i]; return ret; } - // returns the bit-wise XOR of the two sha1-hashes. - sha1_hash operator^(sha1_hash const& n) const + // returns the bit-wise XOR of the two digests. + digest32 operator^(digest32 const& n) const { - sha1_hash ret = *this; + digest32 ret = *this; ret ^= n; return ret; } - // in-place bit-wise XOR with the passed in sha1_hash. - sha1_hash& operator^=(sha1_hash const& n) + // in-place bit-wise XOR with the passed in digest. + digest32& operator^=(digest32 const& n) { for (int i = 0; i < number_size; ++i) m_number[i] ^= n.m_number[i]; return *this; } - // returns the bit-wise AND of the two sha1-hashes. - sha1_hash operator&(sha1_hash const& n) const + // returns the bit-wise AND of the two digests. + digest32 operator&(digest32 const& n) const { - sha1_hash ret = *this; + digest32 ret = *this; ret &= n; return ret; } - // in-place bit-wise AND of the passed in sha1_hash - sha1_hash& operator&=(sha1_hash const& n) + // in-place bit-wise AND of the passed in digest + digest32& operator&=(digest32 const& n) { for (int i = 0; i < number_size; ++i) m_number[i] &= n.m_number[i]; return *this; } - // in-place bit-wise OR of the two sha1-hash. - sha1_hash& operator|=(sha1_hash const& n) + // in-place bit-wise OR of the two digests. + digest32& operator|=(digest32 const& n) { for (int i = 0; i < number_size; ++i) m_number[i] |= n.m_number[i]; @@ -235,8 +256,8 @@ namespace libtorrent iterator end() { return reinterpret_cast(m_number) + size(); } - // return a copy of the 20 bytes representing the sha1-hash as a std::string. - // It's still a binary string with 20 binary characters. + // return a copy of the N/8 bytes representing the digest as a std::string. + // It's still a binary string with N/8 binary characters. std::string to_string() const { return std::string(reinterpret_cast(&m_number[0]), size()); @@ -248,6 +269,14 @@ namespace libtorrent }; + // This type holds a SHA-1 digest or any other kind of 20 byte + // sequence. It implements a number of convenience functions, such + // as bit operations, comparison operators etc. + // + // In libtorrent it is primarily used to hold info-hashes, piece-hashes, + // peer IDs, node IDs etc. + using sha1_hash = digest32<160>; + // this is here to support usage of sha1_hash in boost unordered containers typedef sha1_hash peer_id; inline std::size_t hash_value(sha1_hash const& b) diff --git a/include/libtorrent/sha512.hpp b/include/libtorrent/sha512.hpp new file mode 100644 index 000000000..b2449d833 --- /dev/null +++ b/include/libtorrent/sha512.hpp @@ -0,0 +1,23 @@ +#ifndef TORRENT_SHA512_HPP_INCLUDED +#define TORRENT_SHA512_HPP_INCLUDED + +#include "libtorrent/config.hpp" +#include + +namespace libtorrent +{ + + struct sha512_ctx + { + std::uint64_t length, state[8]; + size_t curlen; + std::uint8_t buf[128]; + }; + + TORRENT_EXTRA_EXPORT int SHA512_init(sha512_ctx* context); + TORRENT_EXTRA_EXPORT int SHA512_update(sha512_ctx* context + , std::uint8_t const* data, std::uint32_t len); + TORRENT_EXTRA_EXPORT int SHA512_final(std::uint8_t* digest, sha512_ctx* context); +} + +#endif diff --git a/include/libtorrent/torrent_handle.hpp b/include/libtorrent/torrent_handle.hpp index bb623d63a..a465d9d2e 100644 --- a/include/libtorrent/torrent_handle.hpp +++ b/include/libtorrent/torrent_handle.hpp @@ -52,6 +52,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/address.hpp" #include "libtorrent/socket.hpp" // tcp::endpoint #include "libtorrent/span.hpp" +#include "libtorrent/sha1_hash.hpp" namespace libtorrent { @@ -69,7 +70,6 @@ namespace libtorrent struct peer_list_entry; struct torrent_status; struct torrent_handle; - class sha1_hash; struct storage_interface; class torrent; diff --git a/src/Makefile.am b/src/Makefile.am index d34a498b7..2cd225159 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -27,9 +27,15 @@ KADEMLIA_SOURCES = \ ../ed25519/src/keypair.cpp \ ../ed25519/src/sc.cpp \ ../ed25519/src/seed.cpp \ - ../ed25519/src/sha512.cpp \ ../ed25519/src/sign.cpp \ - ../ed25519/src/verify.cpp + ../ed25519/src/verify.cpp \ + hasher512.cpp +endif + +if ! WITH_OPENSSL +BUILTIN_CRYPTO_SOURCES = \ + sha1.cpp \ + sha512.cpp endif libtorrent_rasterbar_la_SOURCES = \ @@ -113,7 +119,6 @@ libtorrent_rasterbar_la_SOURCES = \ session_settings.cpp \ proxy_settings.cpp \ settings_pack.cpp \ - sha1.cpp \ sha1_hash.cpp \ smart_ban.cpp \ socket_io.cpp \ @@ -147,7 +152,9 @@ libtorrent_rasterbar_la_SOURCES = \ file_progress.cpp \ ffs.cpp \ \ - $(KADEMLIA_SOURCES) + $(KADEMLIA_SOURCES) \ + \ + $(BUILTIN_CRYPTO_SOURCES) libtorrent_rasterbar_la_LDFLAGS = -version-info $(INTERFACE_VERSION_INFO) libtorrent_rasterbar_la_LIBADD = @OPENSSL_LIBS@ diff --git a/src/hasher.cpp b/src/hasher.cpp index 2f6a24cc3..594149937 100644 --- a/src/hasher.cpp +++ b/src/hasher.cpp @@ -32,6 +32,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/hasher.hpp" #include "libtorrent/error_code.hpp" +#include "libtorrent/assert.hpp" #if TORRENT_USE_CRYPTOAPI namespace @@ -179,7 +180,7 @@ namespace libtorrent gcry_md_final(m_context); digest.assign((char const*)gcry_md_read(m_context, 0)); #elif TORRENT_USE_COMMONCRYPTO - CC_SHA1_Final(digest.begin(), &m_context); + CC_SHA1_Final(reinterpret_cast(digest.data()), &m_context); #elif TORRENT_USE_CRYPTOAPI DWORD size = DWORD(digest.size()); @@ -194,9 +195,9 @@ namespace libtorrent } TORRENT_ASSERT(size == digest.size()); #elif defined TORRENT_USE_LIBCRYPTO - SHA1_Final(digest.begin(), &m_context); + SHA1_Final(reinterpret_cast(digest.data()), &m_context); #else - SHA1_final(digest.begin(), &m_context); + SHA1_final(reinterpret_cast(digest.data()), &m_context); #endif return digest; } @@ -233,4 +234,3 @@ namespace libtorrent #endif } } - diff --git a/src/hasher512.cpp b/src/hasher512.cpp new file mode 100644 index 000000000..d0f4aca43 --- /dev/null +++ b/src/hasher512.cpp @@ -0,0 +1,224 @@ +/* + +Copyright (c) 2003-2016, Arvid Norberg, Alden Torres +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include "libtorrent/hasher512.hpp" +#include "libtorrent/error_code.hpp" +#include "libtorrent/assert.hpp" + +#if TORRENT_USE_CRYPTOAPI +namespace +{ + HCRYPTPROV make_crypt_provider() + { + using namespace libtorrent; + + HCRYPTPROV ret; + if (CryptAcquireContext(&ret, nullptr, nullptr, PROV_RSA_AES + , CRYPT_VERIFYCONTEXT) == false) + { +#ifndef BOOST_NO_EXCEPTIONS + throw system_error(error_code(GetLastError(), system_category())); +#else + std::terminate(); +#endif + } + return ret; + } + + HCRYPTPROV get_crypt_provider() + { + static HCRYPTPROV prov = make_crypt_provider(); + return prov; + } +} +#endif + +namespace libtorrent +{ + hasher512::hasher512() + { +#ifdef TORRENT_USE_LIBGCRYPT + gcry_md_open(&m_context, GCRY_MD_SHA512, 0); +#elif TORRENT_USE_COMMONCRYPTO + CC_SHA512_Init(&m_context); +#elif TORRENT_USE_CRYPTOAPI + if (CryptCreateHash(get_crypt_provider(), CALG_SHA_512, 0, 0, &m_context) == false) + { +#ifndef BOOST_NO_EXCEPTIONS + throw system_error(error_code(GetLastError(), system_category())); +#else + std::terminate(); +#endif + } +#elif defined TORRENT_USE_LIBCRYPTO + SHA512_Init(&m_context); +#else + SHA512_init(&m_context); +#endif + } + + hasher512::hasher512(span data) + : hasher512() + { + update(data); + } + +#ifdef TORRENT_USE_LIBGCRYPT + hasher512::hasher512(hasher512 const& h) + { + gcry_md_copy(&m_context, h.m_context); + } + + hasher512& hasher512::operator=(hasher512 const& h) + { + if (this == &h) return; + gcry_md_close(m_context); + gcry_md_copy(&m_context, h.m_context); + return *this; + } +#elif TORRENT_USE_CRYPTOAPI + hasher512::hasher512(hasher512 const& h) + { + if (CryptDuplicateHash(h.m_context, 0, 0, &m_context) == false) + { +#ifndef BOOST_NO_EXCEPTIONS + throw system_error(error_code(GetLastError(), system_category())); +#else + std::terminate(); +#endif + } + } + + hasher512& hasher512::operator=(hasher512 const& h) + { + if (this == &h) return *this; + CryptDestroyHash(m_context); + if (CryptDuplicateHash(h.m_context, 0, 0, &m_context) == false) + { +#ifndef BOOST_NO_EXCEPTIONS + throw system_error(error_code(GetLastError(), system_category())); +#else + std::terminate(); +#endif + } + return *this; + } +#else + hasher512::hasher512(hasher512 const&) = default; + hasher512& hasher512::operator=(hasher512 const&) = default; +#endif + + hasher512& hasher512::update(span data) + { + TORRENT_ASSERT(!data.empty()); +#ifdef TORRENT_USE_LIBGCRYPT + gcry_md_write(m_context, data.data(), data.size()); +#elif TORRENT_USE_COMMONCRYPTO + CC_SHA512_Update(&m_context, reinterpret_cast(data.data()), data.size()); +#elif TORRENT_USE_CRYPTOAPI + if (CryptHashData(m_context, reinterpret_cast(data.data()), int(data.size()), 0) == false) + { +#ifndef BOOST_NO_EXCEPTIONS + throw system_error(error_code(GetLastError(), system_category())); +#else + std::terminate(); +#endif + } +#elif defined TORRENT_USE_LIBCRYPTO + SHA512_Update(&m_context, reinterpret_cast(data.data()), data.size()); +#else + SHA512_update(&m_context, reinterpret_cast(data.data()), data.size()); +#endif + return *this; + } + + sha512_hash hasher512::final() + { + sha512_hash digest; +#ifdef TORRENT_USE_LIBGCRYPT + gcry_md_final(m_context); + digest.assign((char const*)gcry_md_read(m_context, 0)); +#elif TORRENT_USE_COMMONCRYPTO + CC_SHA512_Final(reinterpret_cast(digest.data()), &m_context); +#elif TORRENT_USE_CRYPTOAPI + + DWORD size = DWORD(digest.size()); + if (CryptGetHashParam(m_context, HP_HASHVAL + , reinterpret_cast(digest.data()), &size, 0) == false) + { +#ifndef BOOST_NO_EXCEPTIONS + throw system_error(error_code(GetLastError(), system_category())); +#else + std::terminate(); +#endif + } + TORRENT_ASSERT(size == digest.size()); +#elif defined TORRENT_USE_LIBCRYPTO + SHA512_Final(reinterpret_cast(digest.data()), &m_context); +#else + SHA512_final(reinterpret_cast(digest.data()), &m_context); +#endif + return digest; + } + + void hasher512::reset() + { +#ifdef TORRENT_USE_LIBGCRYPT + gcry_md_reset(m_context); +#elif TORRENT_USE_COMMONCRYPTO + CC_SHA512_Init(&m_context); +#elif TORRENT_USE_CRYPTOAPI + CryptDestroyHash(m_context); + if (CryptCreateHash(get_crypt_provider(), CALG_SHA_512, 0, 0, &m_context) == false) + { +#ifndef BOOST_NO_EXCEPTIONS + throw system_error(error_code(GetLastError(), system_category())); +#else + std::terminate(); +#endif + } +#elif defined TORRENT_USE_LIBCRYPTO + SHA512_Init(&m_context); +#else + SHA512_init(&m_context); +#endif + } + + hasher512::~hasher512() + { +#if TORRENT_USE_CRYPTOAPI + CryptDestroyHash(m_context); +#elif defined TORRENT_USE_LIBGCRYPT + gcry_md_close(m_context); +#endif + } +} diff --git a/src/sha1.cpp b/src/sha1.cpp index 41aa62515..7d158bf86 100644 --- a/src/sha1.cpp +++ b/src/sha1.cpp @@ -120,7 +120,7 @@ namespace } #ifdef VERBOSE - void SHAPrintContext(sha_ctx *context, char *msg) + void SHAPrintContext(sha1_ctx *context, char *msg) { using namespace std; std::printf("%s (%d,%d) %x %x %x %x %x\n" @@ -135,7 +135,7 @@ namespace #endif template - void internal_update(sha_ctx* context, u8 const* data, u32 len) + void internal_update(sha1_ctx* context, u8 const* data, u32 len) { using namespace std; u32 i, j; // JHB @@ -177,7 +177,7 @@ namespace // SHA1Init - Initialize new context -void SHA1_init(sha_ctx* context) +void SHA1_init(sha1_ctx* context) { // SHA1 initialization constants context->state[0] = 0x67452301; @@ -191,7 +191,7 @@ void SHA1_init(sha_ctx* context) // Run your data through this. -void SHA1_update(sha_ctx* context, u8 const* data, u32 len) +void SHA1_update(sha1_ctx* context, u8 const* data, u32 len) { // GCC standard defines for endianness // test with: cpp -dM /dev/null @@ -212,7 +212,7 @@ void SHA1_update(sha_ctx* context, u8 const* data, u32 len) // Add padding and return the message digest. -void SHA1_final(u8* digest, sha_ctx* context) +void SHA1_final(u8* digest, sha1_ctx* context) { u8 finalcount[8]; diff --git a/src/sha1_hash.cpp b/src/sha1_hash.cpp index b5fb48b2b..be8a85d93 100644 --- a/src/sha1_hash.cpp +++ b/src/sha1_hash.cpp @@ -62,21 +62,24 @@ namespace libtorrent #endif // TORRENT_USE_IOSTREAM - sha1_hash& sha1_hash::operator<<=(int n) +namespace aux +{ + void bits_shift_left(span number, int n) { TORRENT_ASSERT(n >= 0); - const int num_words = n / 32; + int const num_words = n / 32; + int const number_size = int(number.size()); if (num_words >= number_size) { - std::memset(m_number, 0, size()); - return *this; + std::memset(number.data(), 0, number_size * 4); + return; } if (num_words > 0) { - std::memmove(m_number, m_number + num_words + std::memmove(number.data(), number.data() + num_words , (number_size - num_words) * sizeof(std::uint32_t)); - std::memset(m_number + (number_size - num_words) + std::memset(number.data() + (number_size - num_words) , 0, num_words * sizeof(std::uint32_t)); n -= num_words * 32; } @@ -86,34 +89,34 @@ namespace libtorrent // byte order, so they have to be byteswapped before // applying the shift operations, and then byteswapped // back again. - m_number[0] = aux::network_to_host(m_number[0]); + number[0] = aux::network_to_host(number[0]); for (int i = 0; i < number_size - 1; ++i) { - m_number[i] <<= n; - m_number[i + 1] = aux::network_to_host(m_number[i + 1]); - m_number[i] |= m_number[i + 1] >> (32 - n); - m_number[i] = aux::host_to_network(m_number[i]); + number[i] <<= n; + number[i + 1] = aux::network_to_host(number[i + 1]); + number[i] |= number[i + 1] >> (32 - n); + number[i] = aux::host_to_network(number[i]); } - m_number[number_size - 1] <<= n; - m_number[number_size - 1] = aux::host_to_network(m_number[number_size - 1]); + number[number_size - 1] <<= n; + number[number_size - 1] = aux::host_to_network(number[number_size - 1]); } - return *this; } - sha1_hash& sha1_hash::operator>>=(int n) + void bits_shift_right(span number, int n) { TORRENT_ASSERT(n >= 0); - const int num_words = n / 32; + int const num_words = n / 32; + int const number_size = int(number.size()); if (num_words >= number_size) { - std::memset(m_number, 0, size()); - return *this; + std::memset(number.data(), 0, number_size * 4); + return; } if (num_words > 0) { - std::memmove(m_number + num_words - , m_number, (number_size - num_words) * sizeof(std::uint32_t)); - std::memset(m_number, 0, num_words * sizeof(std::uint32_t)); + std::memmove(number.data() + num_words + , number.data(), (number_size - num_words) * sizeof(std::uint32_t)); + std::memset(number.data(), 0, num_words * sizeof(std::uint32_t)); n -= num_words * 32; } if (n > 0) @@ -122,19 +125,18 @@ namespace libtorrent // byte order, so they have to be byteswapped before // applying the shift operations, and then byteswapped // back again. - m_number[number_size - 1] = aux::network_to_host(m_number[number_size - 1]); + number[number_size - 1] = aux::network_to_host(number[number_size - 1]); for (int i = number_size - 1; i > 0; --i) { - m_number[i] >>= n; - m_number[i - 1] = aux::network_to_host(m_number[i - 1]); - m_number[i] |= (m_number[i - 1] << (32 - n)) & 0xffffffff; - m_number[i] = aux::host_to_network(m_number[i]); + number[i] >>= n; + number[i - 1] = aux::network_to_host(number[i - 1]); + number[i] |= (number[i - 1] << (32 - n)) & 0xffffffff; + number[i] = aux::host_to_network(number[i]); } - m_number[0] >>= n; - m_number[0] = aux::host_to_network(m_number[0]); + number[0] >>= n; + number[0] = aux::host_to_network(number[0]); } - return *this; } - +} } diff --git a/ed25519/src/sha512.cpp b/src/sha512.cpp similarity index 91% rename from ed25519/src/sha512.cpp rename to src/sha512.cpp index f0d37c9fe..a77792ff3 100644 --- a/ed25519/src/sha512.cpp +++ b/src/sha512.cpp @@ -1,3 +1,8 @@ +#include +#include + +#include "libtorrent/sha512.hpp" + // ignore warnings in this file #include "libtorrent/aux_/disable_warnings_push.hpp" @@ -12,13 +17,17 @@ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org */ -#include "fixedint.h" -#include "sha512.h" +using u64 = std::uint64_t; +using i64 = std::int64_t; +using i32 = std::int32_t; #ifndef UINT64_C #define UINT64_C(x) x ## LL #endif +namespace libtorrent +{ + /* the K array */ static const u64 K[80] = { UINT64_C(0x428a2f98d728ae22), UINT64_C(0x7137449123ef65cd), @@ -95,7 +104,7 @@ static const u64 K[80] = { #endif /* compress 1024-bits */ -static int sha512_compress(sha512_context *md, unsigned char *buf) +static int sha512_compress(sha512_ctx *md, unsigned char *buf) { u64 S[8], W[80], t0, t1; int i; @@ -151,7 +160,7 @@ static int sha512_compress(sha512_context *md, unsigned char *buf) @param md The hash state you wish to initialize @return 0 if successful */ -int sha512_init(sha512_context * md) { +int SHA512_init(sha512_ctx* md) { if (md == NULL) return 1; md->curlen = 0; @@ -175,7 +184,7 @@ int sha512_init(sha512_context * md) { @param inlen The length of the data (octets) @return 0 if successful */ -int sha512_update (sha512_context * md, const unsigned char *in, size_t inlen) +int SHA512_update(sha512_ctx* md, std::uint8_t const* in, std::uint32_t inlen) { size_t n; size_t i; @@ -222,28 +231,28 @@ int sha512_update (sha512_context * md, const unsigned char *in, size_t inlen) @param out [out] The destination of the hash (64 bytes) @return 0 if successful */ - int sha512_final(sha512_context * md, unsigned char *out) - { +int SHA512_final(std::uint8_t* out, sha512_ctx* md) +{ int i; if (md == NULL) return 1; if (out == NULL) return 1; if (md->curlen >= sizeof(md->buf)) { - return 1; - } + return 1; + } /* increase the length of the message */ - md->length += md->curlen * UINT64_C(8); + md->length += md->curlen * UINT64_C(8); /* append the '1' bit */ - md->buf[md->curlen++] = (unsigned char)0x80; + md->buf[md->curlen++] = (unsigned char)0x80; /* if the length is currently above 112 bytes we append zeros * then compress. Then we can fall back to padding zeros and length * encoding like normal. */ - if (md->curlen > 112) { + if (md->curlen > 112) { while (md->curlen < 128) { md->buf[md->curlen++] = (unsigned char)0; } @@ -255,31 +264,20 @@ int sha512_update (sha512_context * md, const unsigned char *in, size_t inlen) * note: that from 112 to 120 is the 64 MSB of the length. We assume that you won't hash * > 2^64 bits of data... :-) */ -while (md->curlen < 120) { - md->buf[md->curlen++] = (unsigned char)0; -} + while (md->curlen < 120) { + md->buf[md->curlen++] = (unsigned char)0; + } /* store length */ -STORE64H(md->length, md->buf+120); -sha512_compress(md, md->buf); + STORE64H(md->length, md->buf+120); + sha512_compress(md, md->buf); /* copy output */ -for (i = 0; i < 8; i++) { - STORE64H(md->state[i], out+(8*i)); -} + for (i = 0; i < 8; i++) { + STORE64H(md->state[i], out+(8*i)); + } -return 0; -} - -int sha512(const unsigned char *message, size_t message_len, unsigned char *out) -{ - sha512_context ctx; - int ret; - ret = sha512_init(&ctx); - if (ret) return ret; - ret = sha512_update(&ctx, message, message_len); - if (ret) return ret; - ret = sha512_final(&ctx, out); - if (ret) return ret; return 0; } + +} // libtorrent namespace diff --git a/test/Jamfile b/test/Jamfile index a5149fa22..340348143 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -144,6 +144,8 @@ test-suite libtorrent : [ run test_dht.cpp test_dht_storage.cpp test_direct_dht.cpp + test_hasher512.cpp + test_ed25519.cpp ] [ run test_string.cpp diff --git a/test/Makefile.am b/test/Makefile.am index f8b5ef2fb..a97ee5a79 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -180,6 +180,8 @@ test_primitives_SOURCES = \ test_xml.cpp \ test_ip_filter.cpp \ test_hasher.cpp \ + test_hasher512.cpp \ + test_ed25519.cpp \ test_dht_storage.cpp \ test_dht.cpp \ test_block_cache.cpp \ diff --git a/test/test_ed25519.cpp b/test/test_ed25519.cpp new file mode 100644 index 000000000..378787bec --- /dev/null +++ b/test/test_ed25519.cpp @@ -0,0 +1,177 @@ +/* + +Copyright (c) 2016, Alden Torres +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef TORRENT_DISABLE_DHT + +#include + +#include "libtorrent/ed25519.hpp" +#include "libtorrent/hex.hpp" + +#include "test.hpp" + +using namespace libtorrent; + +namespace +{ + void from_hex(std::string s, unsigned char* out) + { + aux::from_hex(s, reinterpret_cast(out)); + } + + void test_vector(std::string seed, std::string pub, std::string signature, std::string message) + { + unsigned char s[32]; + unsigned char sk[64]; + unsigned char pk[32]; + unsigned char sig[64]; + int msg_size = int(message.size()) / 2; + std::vector msg(msg_size); + + from_hex(seed, s); + ed25519_create_keypair(pk, sk, s); + + TEST_EQUAL(aux::to_hex({reinterpret_cast(pk), 32}), pub); + + from_hex(message, msg.data()); + ed25519_sign(sig, msg.data(), msg_size, pk, sk); + + TEST_EQUAL(aux::to_hex({reinterpret_cast(sig), 64}), signature); + + int r = ed25519_verify(sig, msg.data(), msg_size, pk); + + TEST_CHECK(r); + } +} + +// https://git.gnupg.org/cgi-bin/gitweb.cgi?p=libgcrypt.git;a=blob;f=tests/t-ed25519.inp;hb=HEAD +TORRENT_TEST(ed25519_test_vec1) +{ + // TST: 2 + test_vector( + "4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb" + , "3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c" + , "92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da" + "085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00" + , "72" + ); + + // TST: 3 + test_vector( + "c5aa8df43f9f837bedb7442f31dcb7b166d38535076f094b85ce3a2e0b4458f7" + , "fc51cd8e6218a1a38da47ed00230f0580816ed13ba3303ac5deb911548908025" + , "6291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac" + "18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40a" + , "af82" + ); + + // TST: 4 + test_vector( + "0d4a05b07352a5436e180356da0ae6efa0345ff7fb1572575772e8005ed978e9" + , "e61a185bcef2613a6c7cb79763ce945d3b245d76114dd440bcf5f2dc1aa57057" + , "d9868d52c2bebce5f3fa5a79891970f309cb6591e3e1702a70276fa97c24b3a8" + "e58606c38c9758529da50ee31b8219cba45271c689afa60b0ea26c99db19b00c" + , "cbc77b" + ); + + // TST: 47 + test_vector( + "89f0d68299ba0a5a83f248ae0c169f8e3849a9b47bd4549884305c9912b46603" + , "aba3e795aab2012acceadd7b3bd9daeeed6ff5258bdcd7c93699c2a3836e3832" + , "2c691fa8d487ce20d5d2fa41559116e0bbf4397cf5240e152556183541d66cf7" + "53582401a4388d390339dbef4d384743caa346f55f8daba68ba7b9131a8a6e0b" + , "4f1846dd7ad50e545d4cfbffbb1dc2ff145dc123754d08af4e44ecc0bc8c9141" + "1388bc7653e2d893d1eac2107d05" + ); + + // TST: 48 + test_vector( + "0a3c1844e2db070fb24e3c95cb1cc6714ef84e2ccd2b9dd2f1460ebf7ecf13b1" + , "72e409937e0610eb5c20b326dc6ea1bbbc0406701c5cd67d1fbde09192b07c01" + , "87f7fdf46095201e877a588fe3e5aaf476bd63138d8a878b89d6ac60631b3458" + "b9d41a3c61a588e1db8d29a5968981b018776c588780922f5aa732ba6379dd05" + , "4c8274d0ed1f74e2c86c08d955bde55b2d54327e82062a1f71f70d536fdc8722" + "cdead7d22aaead2bfaa1ad00b82957" + ); + + // TST: 49 + test_vector( + "c8d7a8818b98dfdb20839c871cb5c48e9e9470ca3ad35ba2613a5d3199c8ab23" + , "90d2efbba4d43e6b2b992ca16083dbcfa2b322383907b0ee75f3e95845d3c47f" + , "fa2e994421aef1d5856674813d05cbd2cf84ef5eb424af6ecd0dc6fdbdc2fe60" + "5fe985883312ecf34f59bfb2f1c9149e5b9cc9ecda05b2731130f3ed28ddae0b" + , "783e33c3acbdbb36e819f544a7781d83fc283d3309f5d3d12c8dcd6b0b3d0e89" + "e38cfd3b4d0885661ca547fb9764abff" + ); + + // TST: 50 + test_vector( + "b482703612d0c586f76cfcb21cfd2103c957251504a8c0ac4c86c9c6f3e429ff" + , "fd711dc7dd3b1dfb9df9704be3e6b26f587fe7dd7ba456a91ba43fe51aec09ad" + , "58832bdeb26feafc31b46277cf3fb5d7a17dfb7ccd9b1f58ecbe6feb97966682" + "8f239ba4d75219260ecac0acf40f0e5e2590f4caa16bbbcd8a155d347967a607" + , "29d77acfd99c7a0070a88feb6247a2bce9984fe3e6fbf19d4045042a21ab26cb" + "d771e184a9a75f316b648c6920db92b87b" + ); + + // TST: 51 + test_vector( + "84e50dd9a0f197e3893c38dbd91fafc344c1776d3a400e2f0f0ee7aa829eb8a2" + , "2c50f870ee48b36b0ac2f8a5f336fb090b113050dbcc25e078200a6e16153eea" + , "69e6a4491a63837316e86a5f4ba7cd0d731ecc58f1d0a264c67c89befdd8d382" + "9d8de13b33cc0bf513931715c7809657e2bfb960e5c764c971d733746093e500" + , "f3992cde6493e671f1e129ddca8038b0abdb77bb9035f9f8be54bd5d68c1aeff" + "724ff47d29344391dc536166b8671cbbf123" + ); + + // TST: 52 + test_vector( + "b322d46577a2a991a4d1698287832a39c487ef776b4bff037a05c7f1812bdeec" + , "eb2bcadfd3eec2986baff32b98e7c4dbf03ff95d8ad5ff9aa9506e5472ff845f" + , "c7b55137317ca21e33489ff6a9bfab97c855dc6f85684a70a9125a261b56d5e6" + "f149c5774d734f2d8debfc77b721896a8267c23768e9badb910eef83ec258802" + , "19f1bf5dcf1750c611f1c4a2865200504d82298edd72671f62a7b1471ac3d4a3" + "0f7de9e5da4108c52a4ce70a3e114a52a3b3c5" + ); + + // TST: 53 + test_vector( + "960cab5034b9838d098d2dcbf4364bec16d388f6376d73a6273b70f82bbc98c0" + , "5e3c19f2415acf729f829a4ebd5c40e1a6bc9fbca95703a9376087ed0937e51a" + , "27d4c3a1811ef9d4360b3bdd133c2ccc30d02c2f248215776cb07ee4177f9b13" + "fc42dd70a6c2fed8f225c7663c7f182e7ee8eccff20dc7b0e1d5834ec5b1ea01" + , "f8b21962447b0a8f2e4279de411bea128e0be44b6915e6cda88341a68a0d8183" + "57db938eac73e0af6d31206b3948f8c48a447308" + ); +} + +#endif // TORRENT_DISABLE_DHT diff --git a/test/test_hasher.cpp b/test/test_hasher.cpp index beca7d3a1..30ace89b8 100644 --- a/test/test_hasher.cpp +++ b/test/test_hasher.cpp @@ -31,12 +31,14 @@ POSSIBILITY OF SUCH DAMAGE. */ #include "libtorrent/hasher.hpp" -#include "libtorrent/hex.hpp" // from_hex +#include "libtorrent/hex.hpp" #include "test.hpp" using namespace libtorrent; +namespace +{ // test vectors from RFC 3174 // http://www.faqs.org/rfcs/rfc3174.html @@ -58,11 +60,19 @@ char const* result_array[4] = "DEA356A2CDDD90C7A7ECEDC5EBB563934F460452" }; +void test_vector(std::string s, std::string output, int const n = 1) +{ + hasher h; + for (int i = 0; i < n; i++) + h.update(s); + std::string digest = h.final().to_string(); + TEST_EQUAL(aux::to_hex(digest), output); +} + +} TORRENT_TEST(hasher) { - using namespace libtorrent; - for (int test = 0; test < 4; ++test) { hasher h; @@ -75,3 +85,34 @@ TORRENT_TEST(hasher) } } +// http://www.di-mgt.com.au/sha_testvectors.html +TORRENT_TEST(hasher_test_vec1) +{ + test_vector( + "abc" + , "a9993e364706816aba3e25717850c26c9cd0d89d" + ); + + test_vector( + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + , "84983e441c3bd26ebaae4aa1f95129e5e54670f1" + ); + + test_vector( + "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhi" + "jklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" + , "a49b2446a02c645bf419f995b67091253a04a259" + ); + + test_vector( + "a" + , "34aa973cd4c4daa4f61eeb2bdbad27316534016f" + , 1000000 + ); + + test_vector( + "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno" + , "7789f0c9ef7bfc40d93311143dfbe69e2017f592" + , 16777216 + ); +} diff --git a/test/test_hasher512.cpp b/test/test_hasher512.cpp new file mode 100644 index 000000000..d0b82801a --- /dev/null +++ b/test/test_hasher512.cpp @@ -0,0 +1,91 @@ +/* + +Copyright (c) 2016, Alden Torres +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef TORRENT_DISABLE_DHT + +#include "libtorrent/hasher512.hpp" +#include "libtorrent/hex.hpp" + +#include "test.hpp" + +using namespace libtorrent; + +namespace +{ + void test_vector(std::string s, std::string output, int const n = 1) + { + hasher512 h; + for (int i = 0; i < n; i++) + h.update(s); + std::string digest = h.final().to_string(); + TEST_EQUAL(aux::to_hex(digest), output); + } +} + +// http://www.di-mgt.com.au/sha_testvectors.html +TORRENT_TEST(hasher512_test_vec1) +{ + test_vector( + "abc" + , "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a" + "2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f" + ); + + test_vector( + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + , "204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c335" + "96fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445" + ); + + test_vector( + "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhi" + "jklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" + , "8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018" + "501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909" + ); + + test_vector( + "a" + , "e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973eb" + "de0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b" + , 1000000 + ); + + test_vector( + "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno" + , "b47c933421ea2db149ad6e10fce6c7f93d0752380180ffd7f4629a712134831d" + "77be6091b819ed352c2967a2e2d4fa5050723c9630691f1a05a7281dbe6c1086" + , 16777216 + ); +} + +#endif // TORRENT_DISABLE_DHT