adding support for a more configurable sha512 hasher (#1028)

adding support for a more configurable sha512 hasher, digest32 template, using hasher512.
This commit is contained in:
Alden Torres 2016-08-25 19:07:16 -04:00 committed by Arvid Norberg
parent 73d6ba6ae3
commit 44d9f456f8
29 changed files with 914 additions and 203 deletions

View File

@ -151,7 +151,6 @@ set(ed25519_sources
keypair keypair
sc sc
seed seed
sha512
sign sign
verify verify
) )
@ -215,7 +214,9 @@ if (encryption)
include_directories(${OPENSSL_INCLUDE_DIR}) include_directories(${OPENSSL_INCLUDE_DIR})
else() else()
add_definitions(-DTORRENT_DISABLE_ENCRYPTION) add_definitions(-DTORRENT_DISABLE_ENCRYPTION)
list(APPEND sources sha1) if (NOT WIN32 AND NOT APPLE)
list(APPEND sources sha1)
endif()
endif (encryption) endif (encryption)
if (NOT logging) if (NOT logging)
@ -233,6 +234,10 @@ if (dht)
foreach(s ${ed25519_sources}) foreach(s ${ed25519_sources})
list(APPEND sources2 ed25519/src/${s}) list(APPEND sources2 ed25519/src/${s})
endforeach(s) endforeach(s)
list(APPEND sources2 src/hasher512)
if (NOT encryption AND NOT WIN32 AND NOT APPLE)
list(APPEND sources2 src/sha512)
endif()
else() else()
add_definitions(-DTORRENT_DISABLE_DHT) add_definitions(-DTORRENT_DISABLE_DHT)
endif() endif()

15
Jamfile
View File

@ -341,15 +341,21 @@ rule building ( properties * )
result += <source>src/pe_crypto.cpp ; result += <source>src/pe_crypto.cpp ;
} }
if <crypo>built-in in $(properties) if <crypto>built-in in $(properties)
&& ! <target-os>windows in $(properties)
&& ! <target-os>darwin in $(properties)
{ {
result += <source>src/sha1.cpp ; result += <source>src/sha1.cpp ;
if <dht>on in $(properties)
{
result += <source>src/sha512.cpp ;
}
} }
if ( <toolset>darwin in $(properties) if ( <toolset>darwin in $(properties)
|| <toolset>gcc in $(properties) || <toolset>gcc in $(properties)
|| <toolset>clang in $(propertoes) || <toolset>clang in $(properties)
|| <toolset>clang-darwin in $(propertoes) ) || <toolset>clang-darwin in $(properties) )
&& <link>shared in $(properties) && <link>shared in $(properties)
# on GCC, enabling debugging in libstdc++ # on GCC, enabling debugging in libstdc++
# breaks the ABI and its ability to appear # breaks the ABI and its ability to appear
@ -652,7 +658,6 @@ SOURCES =
tracker_manager tracker_manager
http_tracker_connection http_tracker_connection
udp_tracker_connection udp_tracker_connection
sha1
timestamp_history timestamp_history
udp_socket udp_socket
upnp upnp
@ -714,7 +719,6 @@ ED25519_SOURCES =
keypair keypair
sc sc
seed seed
sha512
sign sign
verify verify
; ;
@ -766,6 +770,7 @@ lib torrent
<dht>on:<source>src/kademlia/$(KADEMLIA_SOURCES).cpp <dht>on:<source>src/kademlia/$(KADEMLIA_SOURCES).cpp
<dht>on:<source>ed25519/src/$(ED25519_SOURCES).cpp <dht>on:<source>ed25519/src/$(ED25519_SOURCES).cpp
<dht>on:<source>src/hasher512.cpp
<variant>debug:<asserts>on <variant>debug:<asserts>on
<variant>debug:<invariant-checks>on <variant>debug:<invariant-checks>on

View File

@ -111,8 +111,7 @@ ED25519_SOURCE = \
ed25519/src/fixedint.h \ ed25519/src/fixedint.h \
ed25519/src/ge.h \ ed25519/src/ge.h \
ed25519/src/precomp_data.h \ ed25519/src/precomp_data.h \
ed25519/src/sc.h \ ed25519/src/sc.h
ed25519/src/sha512.h
EXTRA_DIST = \ EXTRA_DIST = \
Jamfile \ Jamfile \

View File

@ -385,6 +385,7 @@ AS_CASE(["$ARG_ENABLE_ENCRYPTION"],
AX_CHECK_OPENSSL([ AX_CHECK_OPENSSL([
AC_DEFINE([TORRENT_USE_OPENSSL],[1],[Define to use OpenSSL support.]) 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 " 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.]) AC_MSG_ERROR([OpenSSL library not found. Try using --with-openssl=DIR or disabling encryption at all.])

View File

@ -94,6 +94,7 @@ category_mapping = {
'bitfield.hpp': 'Utility', 'bitfield.hpp': 'Utility',
'sha1_hash.hpp': 'Utility', 'sha1_hash.hpp': 'Utility',
'hasher.hpp': 'Utility', 'hasher.hpp': 'Utility',
'hasher512.hpp': 'Utility',
'identify_client.hpp': 'Utility', 'identify_client.hpp': 'Utility',
'ip_filter.hpp': 'Filter', 'ip_filter.hpp': 'Filter',
'session_settings.hpp': 'Settings', 'session_settings.hpp': 'Settings',

View File

@ -2,14 +2,16 @@
#include "libtorrent/aux_/disable_warnings_push.hpp" #include "libtorrent/aux_/disable_warnings_push.hpp"
#include "libtorrent/ed25519.hpp" #include "libtorrent/ed25519.hpp"
#include "sha512.h" #include "libtorrent/hasher512.hpp"
#include "ge.h" #include "ge.h"
using namespace libtorrent;
void ed25519_create_keypair(unsigned char *public_key, unsigned char *private_key, const unsigned char *seed) { void ed25519_create_keypair(unsigned char *public_key, unsigned char *private_key, const unsigned char *seed) {
ge_p3 A; ge_p3 A;
sha512(seed, 32, private_key); hasher512 hash({reinterpret_cast<char const*>(seed), 32});
std::memcpy(private_key, hash.final().data(), 64);
private_key[0] &= 248; private_key[0] &= 248;
private_key[31] &= 63; private_key[31] &= 63;
private_key[31] |= 64; private_key[31] |= 64;

View File

@ -1,22 +0,0 @@
#ifndef SHA512_H
#define SHA512_H
#include <stddef.h>
#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

View File

@ -2,33 +2,33 @@
#include "libtorrent/aux_/disable_warnings_push.hpp" #include "libtorrent/aux_/disable_warnings_push.hpp"
#include "libtorrent/ed25519.hpp" #include "libtorrent/ed25519.hpp"
#include "sha512.h" #include "libtorrent/hasher512.hpp"
#include "ge.h" #include "ge.h"
#include "sc.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) { 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; ge_p3 R;
hasher512 hash;
hash.update({reinterpret_cast<char const*>(private_key) + 32, 32});
hash.update({reinterpret_cast<char const*>(message), message_len});
sha512_hash r = hash.final();
sha512_init(&hash); sc_reduce(reinterpret_cast<unsigned char*>(r.data()));
sha512_update(&hash, private_key + 32, 32); ge_scalarmult_base(&R, reinterpret_cast<unsigned char*>(r.data()));
sha512_update(&hash, message, message_len);
sha512_final(&hash, r);
sc_reduce(r);
ge_scalarmult_base(&R, r);
ge_p3_tobytes(signature, &R); ge_p3_tobytes(signature, &R);
sha512_init(&hash); hash.reset();
sha512_update(&hash, signature, 32); hash.update({reinterpret_cast<char const*>(signature), 32});
sha512_update(&hash, public_key, 32); hash.update({reinterpret_cast<char const*>(public_key), 32});
sha512_update(&hash, message, message_len); hash.update({reinterpret_cast<char const*>(message), message_len});
sha512_final(&hash, hram); sha512_hash hram = hash.final();
sc_reduce(hram); sc_reduce(reinterpret_cast<unsigned char*>(hram.data()));
sc_muladd(signature + 32, hram, private_key, r); sc_muladd(signature + 32
, reinterpret_cast<unsigned char*>(hram.data())
, private_key
, reinterpret_cast<unsigned char*>(r.data()));
} }

View File

@ -2,10 +2,12 @@
#include "libtorrent/aux_/disable_warnings_push.hpp" #include "libtorrent/aux_/disable_warnings_push.hpp"
#include "libtorrent/ed25519.hpp" #include "libtorrent/ed25519.hpp"
#include "sha512.h" #include "libtorrent/hasher512.hpp"
#include "ge.h" #include "ge.h"
#include "sc.h" #include "sc.h"
using namespace libtorrent;
static int consttime_equal(const unsigned char *x, const unsigned char *y) { static int consttime_equal(const unsigned char *x, const unsigned char *y) {
unsigned char r = 0; 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) { 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]; unsigned char checker[32];
sha512_context hash;
ge_p3 A; ge_p3 A;
ge_p2 R; ge_p2 R;
@ -62,14 +62,15 @@ int ed25519_verify(const unsigned char *signature, const unsigned char *message,
return 0; return 0;
} }
sha512_init(&hash); hasher512 hash;
sha512_update(&hash, signature, 32); hash.update({reinterpret_cast<char const*>(signature), 32});
sha512_update(&hash, public_key, 32); hash.update({reinterpret_cast<char const*>(public_key), 32});
sha512_update(&hash, message, message_len); hash.update({reinterpret_cast<char const*>(message), message_len});
sha512_final(&hash, h); sha512_hash h = hash.final();
sc_reduce(h); sc_reduce(reinterpret_cast<unsigned char*>(h.data()));
ge_double_scalarmult_vartime(&R, h, &A, signature + 32); ge_double_scalarmult_vartime(&R, reinterpret_cast<unsigned char*>(h.data())
, &A, signature + 32);
ge_tobytes(checker, &R); ge_tobytes(checker, &R);
if (!consttime_equal(checker, signature)) { if (!consttime_equal(checker, signature)) {

View File

@ -54,6 +54,7 @@ nobase_include_HEADERS = \
fingerprint.hpp \ fingerprint.hpp \
gzip.hpp \ gzip.hpp \
hasher.hpp \ hasher.hpp \
hasher512.hpp \
hex.hpp \ hex.hpp \
heterogeneous_queue.hpp \ heterogeneous_queue.hpp \
http_connection.hpp \ http_connection.hpp \
@ -112,6 +113,7 @@ nobase_include_HEADERS = \
session_status.hpp \ session_status.hpp \
settings_pack.hpp \ settings_pack.hpp \
sha1.hpp \ sha1.hpp \
sha512.hpp \
sha1_hash.hpp \ sha1_hash.hpp \
sliding_average.hpp \ sliding_average.hpp \
socket.hpp \ socket.hpp \

View File

@ -24,7 +24,7 @@ void TORRENT_EXPORT ed25519_create_seed(unsigned char *seed);
// public_key and secret_key) // 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_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); 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_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); void TORRENT_EXPORT ed25519_key_exchange(unsigned char *shared_secret, const unsigned char *public_key, const unsigned char *private_key);

View File

@ -161,6 +161,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/config.hpp" #include "libtorrent/config.hpp"
#include "libtorrent/span.hpp" #include "libtorrent/span.hpp"
#include "libtorrent/sha1_hash.hpp"
#include "libtorrent/string_view.hpp" #include "libtorrent/string_view.hpp"
#include "libtorrent/socket.hpp" #include "libtorrent/socket.hpp"
@ -175,7 +176,6 @@ namespace libtorrent
struct torrent_plugin; struct torrent_plugin;
struct add_torrent_params; struct add_torrent_params;
struct torrent_handle; struct torrent_handle;
class sha1_hash;
struct session_handle; struct session_handle;
struct peer_connection_handle; struct peer_connection_handle;

View File

@ -34,9 +34,7 @@ POSSIBILITY OF SUCH DAMAGE.
#define TORRENT_HASHER_HPP_INCLUDED #define TORRENT_HASHER_HPP_INCLUDED
#include "libtorrent/config.hpp" #include "libtorrent/config.hpp"
#include "libtorrent/peer_id.hpp" #include "libtorrent/sha1_hash.hpp"
#include "libtorrent/config.hpp"
#include "libtorrent/assert.hpp"
#include "libtorrent/span.hpp" #include "libtorrent/span.hpp"
#include <cstdint> #include <cstdint>
@ -48,7 +46,8 @@ POSSIBILITY OF SUCH DAMAGE.
#include <CommonCrypto/CommonDigest.h> #include <CommonCrypto/CommonDigest.h>
#elif TORRENT_USE_CRYPTOAPI #elif TORRENT_USE_CRYPTOAPI
#include <Wincrypt.h> #include <windows.h>
#include <wincrypt.h>
#elif defined TORRENT_USE_LIBCRYPTO #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 // If you want to reuse the hasher object once you have created a hash, you have to
// call ``reset()`` to reinitialize it. // 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``. // For more info, see ``src/sha1.cpp``.
class TORRENT_EXPORT hasher class TORRENT_EXPORT hasher
{ {
@ -116,11 +116,10 @@ namespace libtorrent
#elif defined TORRENT_USE_LIBCRYPTO #elif defined TORRENT_USE_LIBCRYPTO
SHA_CTX m_context; SHA_CTX m_context;
#else #else
sha_ctx m_context; sha1_ctx m_context;
#endif #endif
}; };
} }
#endif // TORRENT_HASHER_HPP_INCLUDED #endif // TORRENT_HASHER_HPP_INCLUDED

View File

@ -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 <cstdint>
#ifdef TORRENT_USE_LIBGCRYPT
#include <gcrypt.h>
#elif TORRENT_USE_COMMONCRYPTO
#include <CommonCrypto/CommonDigest.h>
#elif TORRENT_USE_CRYPTOAPI
#include <windows.h>
#include <wincrypt.h>
#elif defined TORRENT_USE_LIBCRYPTO
extern "C" {
#include <openssl/sha.h>
}
#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<char const> data);
hasher512(hasher512 const&);
hasher512& operator=(hasher512 const&);
// append the following bytes to what is being hashed
hasher512& update(span<char const> 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

View File

@ -19,7 +19,7 @@ changelog at the end of sha1.cpp
namespace libtorrent namespace libtorrent
{ {
struct TORRENT_EXTRA_EXPORT sha_ctx struct sha1_ctx
{ {
std::uint32_t state[5]; std::uint32_t state[5];
std::uint32_t count[2]; std::uint32_t count[2];
@ -27,12 +27,10 @@ namespace libtorrent
}; };
// we don't want these to clash with openssl's libcrypto // 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_init(sha1_ctx* context);
TORRENT_EXTRA_EXPORT void SHA1_update(sha_ctx* context TORRENT_EXTRA_EXPORT void SHA1_update(sha1_ctx* context
, std::uint8_t const* data , std::uint8_t const* data, std::uint32_t len);
, std::uint32_t len); TORRENT_EXTRA_EXPORT void SHA1_final(std::uint8_t* digest, sha1_ctx* context);
TORRENT_EXTRA_EXPORT void SHA1_final(std::uint8_t* digest, sha_ctx* context);
} }
#endif #endif

View File

@ -49,66 +49,79 @@ POSSIBILITY OF SUCH DAMAGE.
namespace libtorrent namespace libtorrent
{ {
// TODO: find a better place for these functions
namespace aux
{
TORRENT_EXTRA_EXPORT void bits_shift_left(span<std::uint32_t> number, int n);
TORRENT_EXTRA_EXPORT void bits_shift_right(span<std::uint32_t> 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 // sequence. It implements a number of convenience functions, such
// as bit operations, comparison operators etc. // as bit operations, comparison operators etc.
// //
// In libtorrent it is primarily used to hold info-hashes, piece-hashes, // This data structure is 32 bits aligned, like it's the case for
// peer IDs, node IDs etc. // each SHA-N specification.
class TORRENT_EXPORT sha1_hash template <int N>
class digest32
{ {
enum { number_size = 5 }; static_assert(N % 32 == 0, "N must be a multiple of 32");
enum { number_size = N / 32 };
public: public:
// the size of the hash in bytes // 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 // constructs an all-zero digest
sha1_hash() { clear(); } digest32() { clear(); }
// returns an all-F sha1-hash. i.e. the maximum value digest32(digest32 const&) = default;
// representable by a 160 bit number (20 bytes). This is 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. // a static member function.
static sha1_hash max() static digest32 max()
{ {
sha1_hash ret; digest32 ret;
std::memset(ret.m_number, 0xff, size()); std::memset(ret.m_number, 0xff, size());
return ret; return ret;
} }
// returns an all-zero sha1-hash. i.e. the minimum value // returns an all-zero digest. i.e. the minimum value
// representable by a 160 bit number (20 bytes). This is // representable by an N bit number (N/8 bytes). This is
// a static member function. // a static member function.
static sha1_hash min() static digest32 min()
{ {
sha1_hash ret; digest32 ret;
// all bits are already 0 // all bits are already 0
return ret; return ret;
} }
// copies 20 bytes from the pointer provided, into the sha1-hash. // copies N/8 bytes from the pointer provided, into the digest.
// The passed in string MUST be at least 20 bytes. 0-terminators // The passed in string MUST be at least N/8 bytes. 0-terminators
// are ignored, ``s`` is treated like a raw memory buffer. // 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(); if (s == nullptr) clear();
else std::memcpy(m_number, s, size()); else std::memcpy(m_number, s, size());
} }
#ifndef TORRENT_NO_DEPRECATE #ifndef TORRENT_NO_DEPRECATE
TORRENT_DEPRECATED TORRENT_DEPRECATED
explicit sha1_hash(std::string const& s) explicit digest32(std::string const& s)
{ {
assign(s.data()); assign(s.data());
} }
#endif #endif
explicit sha1_hash(span<char const> s) explicit digest32(span<char const> s)
{ {
assign(s); assign(s);
} }
void assign(span<char const> s) void assign(span<char const> s)
{ {
TORRENT_ASSERT(s.size() >= 20); TORRENT_ASSERT(s.size() >= N / 8);
size_t const sl = s.size() < size() ? s.size() : size(); size_t const sl = s.size() < size() ? s.size() : size();
std::memcpy(m_number, s.data(), sl); std::memcpy(m_number, s.data(), sl);
} }
@ -117,10 +130,10 @@ namespace libtorrent
char const* data() const { return reinterpret_cast<char const*>(&m_number[0]); } char const* data() const { return reinterpret_cast<char const*>(&m_number[0]); }
char* data() { return reinterpret_cast<char*>(&m_number[0]); } char* data() { return reinterpret_cast<char*>(&m_number[0]); }
// set the sha1-hash to all zeroes. // set the digest to all zeroes.
void clear() { std::memset(m_number, 0, size()); } 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 bool is_all_zeros() const
{ {
for (int i = 0; i < number_size; ++i) for (int i = 0; i < number_size; ++i)
@ -129,21 +142,29 @@ namespace libtorrent
} }
// shift left ``n`` bits. // 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. // 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 // 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); 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); 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) for (int i = 0; i < number_size; ++i)
{ {
@ -160,49 +181,49 @@ namespace libtorrent
return aux::count_leading_zeros({m_number, number_size}); return aux::count_leading_zeros({m_number, number_size});
} }
// returns a bit-wise negated copy of the sha1-hash // returns a bit-wise negated copy of the digest
sha1_hash operator~() const digest32 operator~() const
{ {
sha1_hash ret; digest32 ret;
for (int i = 0; i < number_size; ++i) for (int i = 0; i < number_size; ++i)
ret.m_number[i] = ~m_number[i]; ret.m_number[i] = ~m_number[i];
return ret; return ret;
} }
// returns the bit-wise XOR of the two sha1-hashes. // returns the bit-wise XOR of the two digests.
sha1_hash operator^(sha1_hash const& n) const digest32 operator^(digest32 const& n) const
{ {
sha1_hash ret = *this; digest32 ret = *this;
ret ^= n; ret ^= n;
return ret; return ret;
} }
// in-place bit-wise XOR with the passed in sha1_hash. // in-place bit-wise XOR with the passed in digest.
sha1_hash& operator^=(sha1_hash const& n) digest32& operator^=(digest32 const& n)
{ {
for (int i = 0; i < number_size; ++i) for (int i = 0; i < number_size; ++i)
m_number[i] ^= n.m_number[i]; m_number[i] ^= n.m_number[i];
return *this; return *this;
} }
// returns the bit-wise AND of the two sha1-hashes. // returns the bit-wise AND of the two digests.
sha1_hash operator&(sha1_hash const& n) const digest32 operator&(digest32 const& n) const
{ {
sha1_hash ret = *this; digest32 ret = *this;
ret &= n; ret &= n;
return ret; return ret;
} }
// in-place bit-wise AND of the passed in sha1_hash // in-place bit-wise AND of the passed in digest
sha1_hash& operator&=(sha1_hash const& n) digest32& operator&=(digest32 const& n)
{ {
for (int i = 0; i < number_size; ++i) for (int i = 0; i < number_size; ++i)
m_number[i] &= n.m_number[i]; m_number[i] &= n.m_number[i];
return *this; return *this;
} }
// in-place bit-wise OR of the two sha1-hash. // in-place bit-wise OR of the two digests.
sha1_hash& operator|=(sha1_hash const& n) digest32& operator|=(digest32 const& n)
{ {
for (int i = 0; i < number_size; ++i) for (int i = 0; i < number_size; ++i)
m_number[i] |= n.m_number[i]; m_number[i] |= n.m_number[i];
@ -235,8 +256,8 @@ namespace libtorrent
iterator end() iterator end()
{ return reinterpret_cast<std::uint8_t*>(m_number) + size(); } { return reinterpret_cast<std::uint8_t*>(m_number) + size(); }
// return a copy of the 20 bytes representing the sha1-hash as a std::string. // return a copy of the N/8 bytes representing the digest as a std::string.
// It's still a binary string with 20 binary characters. // It's still a binary string with N/8 binary characters.
std::string to_string() const std::string to_string() const
{ {
return std::string(reinterpret_cast<char const*>(&m_number[0]), size()); return std::string(reinterpret_cast<char const*>(&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 // this is here to support usage of sha1_hash in boost unordered containers
typedef sha1_hash peer_id; typedef sha1_hash peer_id;
inline std::size_t hash_value(sha1_hash const& b) inline std::size_t hash_value(sha1_hash const& b)

View File

@ -0,0 +1,23 @@
#ifndef TORRENT_SHA512_HPP_INCLUDED
#define TORRENT_SHA512_HPP_INCLUDED
#include "libtorrent/config.hpp"
#include <cstdint>
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

View File

@ -52,6 +52,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/address.hpp" #include "libtorrent/address.hpp"
#include "libtorrent/socket.hpp" // tcp::endpoint #include "libtorrent/socket.hpp" // tcp::endpoint
#include "libtorrent/span.hpp" #include "libtorrent/span.hpp"
#include "libtorrent/sha1_hash.hpp"
namespace libtorrent namespace libtorrent
{ {
@ -69,7 +70,6 @@ namespace libtorrent
struct peer_list_entry; struct peer_list_entry;
struct torrent_status; struct torrent_status;
struct torrent_handle; struct torrent_handle;
class sha1_hash;
struct storage_interface; struct storage_interface;
class torrent; class torrent;

View File

@ -27,9 +27,15 @@ KADEMLIA_SOURCES = \
../ed25519/src/keypair.cpp \ ../ed25519/src/keypair.cpp \
../ed25519/src/sc.cpp \ ../ed25519/src/sc.cpp \
../ed25519/src/seed.cpp \ ../ed25519/src/seed.cpp \
../ed25519/src/sha512.cpp \
../ed25519/src/sign.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 endif
libtorrent_rasterbar_la_SOURCES = \ libtorrent_rasterbar_la_SOURCES = \
@ -113,7 +119,6 @@ libtorrent_rasterbar_la_SOURCES = \
session_settings.cpp \ session_settings.cpp \
proxy_settings.cpp \ proxy_settings.cpp \
settings_pack.cpp \ settings_pack.cpp \
sha1.cpp \
sha1_hash.cpp \ sha1_hash.cpp \
smart_ban.cpp \ smart_ban.cpp \
socket_io.cpp \ socket_io.cpp \
@ -147,7 +152,9 @@ libtorrent_rasterbar_la_SOURCES = \
file_progress.cpp \ file_progress.cpp \
ffs.cpp \ ffs.cpp \
\ \
$(KADEMLIA_SOURCES) $(KADEMLIA_SOURCES) \
\
$(BUILTIN_CRYPTO_SOURCES)
libtorrent_rasterbar_la_LDFLAGS = -version-info $(INTERFACE_VERSION_INFO) libtorrent_rasterbar_la_LDFLAGS = -version-info $(INTERFACE_VERSION_INFO)
libtorrent_rasterbar_la_LIBADD = @OPENSSL_LIBS@ libtorrent_rasterbar_la_LIBADD = @OPENSSL_LIBS@

View File

@ -32,6 +32,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/hasher.hpp" #include "libtorrent/hasher.hpp"
#include "libtorrent/error_code.hpp" #include "libtorrent/error_code.hpp"
#include "libtorrent/assert.hpp"
#if TORRENT_USE_CRYPTOAPI #if TORRENT_USE_CRYPTOAPI
namespace namespace
@ -179,7 +180,7 @@ namespace libtorrent
gcry_md_final(m_context); gcry_md_final(m_context);
digest.assign((char const*)gcry_md_read(m_context, 0)); digest.assign((char const*)gcry_md_read(m_context, 0));
#elif TORRENT_USE_COMMONCRYPTO #elif TORRENT_USE_COMMONCRYPTO
CC_SHA1_Final(digest.begin(), &m_context); CC_SHA1_Final(reinterpret_cast<unsigned char*>(digest.data()), &m_context);
#elif TORRENT_USE_CRYPTOAPI #elif TORRENT_USE_CRYPTOAPI
DWORD size = DWORD(digest.size()); DWORD size = DWORD(digest.size());
@ -194,9 +195,9 @@ namespace libtorrent
} }
TORRENT_ASSERT(size == digest.size()); TORRENT_ASSERT(size == digest.size());
#elif defined TORRENT_USE_LIBCRYPTO #elif defined TORRENT_USE_LIBCRYPTO
SHA1_Final(digest.begin(), &m_context); SHA1_Final(reinterpret_cast<unsigned char*>(digest.data()), &m_context);
#else #else
SHA1_final(digest.begin(), &m_context); SHA1_final(reinterpret_cast<unsigned char*>(digest.data()), &m_context);
#endif #endif
return digest; return digest;
} }
@ -233,4 +234,3 @@ namespace libtorrent
#endif #endif
} }
} }

224
src/hasher512.cpp Normal file
View File

@ -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<char const> 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<char const> 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<unsigned char const*>(data.data()), data.size());
#elif TORRENT_USE_CRYPTOAPI
if (CryptHashData(m_context, reinterpret_cast<BYTE const*>(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<unsigned char const*>(data.data()), data.size());
#else
SHA512_update(&m_context, reinterpret_cast<unsigned char const*>(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<unsigned char*>(digest.data()), &m_context);
#elif TORRENT_USE_CRYPTOAPI
DWORD size = DWORD(digest.size());
if (CryptGetHashParam(m_context, HP_HASHVAL
, reinterpret_cast<BYTE*>(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<unsigned char*>(digest.data()), &m_context);
#else
SHA512_final(reinterpret_cast<unsigned char*>(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
}
}

View File

@ -120,7 +120,7 @@ namespace
} }
#ifdef VERBOSE #ifdef VERBOSE
void SHAPrintContext(sha_ctx *context, char *msg) void SHAPrintContext(sha1_ctx *context, char *msg)
{ {
using namespace std; using namespace std;
std::printf("%s (%d,%d) %x %x %x %x %x\n" std::printf("%s (%d,%d) %x %x %x %x %x\n"
@ -135,7 +135,7 @@ namespace
#endif #endif
template <class BlkFun> template <class BlkFun>
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; using namespace std;
u32 i, j; // JHB u32 i, j; // JHB
@ -177,7 +177,7 @@ namespace
// SHA1Init - Initialize new context // SHA1Init - Initialize new context
void SHA1_init(sha_ctx* context) void SHA1_init(sha1_ctx* context)
{ {
// SHA1 initialization constants // SHA1 initialization constants
context->state[0] = 0x67452301; context->state[0] = 0x67452301;
@ -191,7 +191,7 @@ void SHA1_init(sha_ctx* context)
// Run your data through this. // 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 // GCC standard defines for endianness
// test with: cpp -dM /dev/null // 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. // 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]; u8 finalcount[8];

View File

@ -62,21 +62,24 @@ namespace libtorrent
#endif // TORRENT_USE_IOSTREAM #endif // TORRENT_USE_IOSTREAM
sha1_hash& sha1_hash::operator<<=(int n) namespace aux
{
void bits_shift_left(span<std::uint32_t> number, int n)
{ {
TORRENT_ASSERT(n >= 0); 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) if (num_words >= number_size)
{ {
std::memset(m_number, 0, size()); std::memset(number.data(), 0, number_size * 4);
return *this; return;
} }
if (num_words > 0) 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)); , (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)); , 0, num_words * sizeof(std::uint32_t));
n -= num_words * 32; n -= num_words * 32;
} }
@ -86,34 +89,34 @@ namespace libtorrent
// byte order, so they have to be byteswapped before // byte order, so they have to be byteswapped before
// applying the shift operations, and then byteswapped // applying the shift operations, and then byteswapped
// back again. // 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) for (int i = 0; i < number_size - 1; ++i)
{ {
m_number[i] <<= n; number[i] <<= n;
m_number[i + 1] = aux::network_to_host(m_number[i + 1]); number[i + 1] = aux::network_to_host(number[i + 1]);
m_number[i] |= m_number[i + 1] >> (32 - n); number[i] |= number[i + 1] >> (32 - n);
m_number[i] = aux::host_to_network(m_number[i]); number[i] = aux::host_to_network(number[i]);
} }
m_number[number_size - 1] <<= n; number[number_size - 1] <<= n;
m_number[number_size - 1] = aux::host_to_network(m_number[number_size - 1]); 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<std::uint32_t> number, int n)
{ {
TORRENT_ASSERT(n >= 0); 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) if (num_words >= number_size)
{ {
std::memset(m_number, 0, size()); std::memset(number.data(), 0, number_size * 4);
return *this; return;
} }
if (num_words > 0) if (num_words > 0)
{ {
std::memmove(m_number + num_words std::memmove(number.data() + num_words
, m_number, (number_size - num_words) * sizeof(std::uint32_t)); , number.data(), (number_size - num_words) * sizeof(std::uint32_t));
std::memset(m_number, 0, num_words * sizeof(std::uint32_t)); std::memset(number.data(), 0, num_words * sizeof(std::uint32_t));
n -= num_words * 32; n -= num_words * 32;
} }
if (n > 0) if (n > 0)
@ -122,19 +125,18 @@ namespace libtorrent
// byte order, so they have to be byteswapped before // byte order, so they have to be byteswapped before
// applying the shift operations, and then byteswapped // applying the shift operations, and then byteswapped
// back again. // 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) for (int i = number_size - 1; i > 0; --i)
{ {
m_number[i] >>= n; number[i] >>= n;
m_number[i - 1] = aux::network_to_host(m_number[i - 1]); number[i - 1] = aux::network_to_host(number[i - 1]);
m_number[i] |= (m_number[i - 1] << (32 - n)) & 0xffffffff; number[i] |= (number[i - 1] << (32 - n)) & 0xffffffff;
m_number[i] = aux::host_to_network(m_number[i]); number[i] = aux::host_to_network(number[i]);
} }
m_number[0] >>= n; number[0] >>= n;
m_number[0] = aux::host_to_network(m_number[0]); number[0] = aux::host_to_network(number[0]);
} }
return *this;
} }
}
} }

View File

@ -1,3 +1,8 @@
#include <cstdio>
#include <cstring>
#include "libtorrent/sha512.hpp"
// ignore warnings in this file // ignore warnings in this file
#include "libtorrent/aux_/disable_warnings_push.hpp" #include "libtorrent/aux_/disable_warnings_push.hpp"
@ -12,13 +17,17 @@
* Tom St Denis, tomstdenis@gmail.com, http://libtom.org * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
*/ */
#include "fixedint.h" using u64 = std::uint64_t;
#include "sha512.h" using i64 = std::int64_t;
using i32 = std::int32_t;
#ifndef UINT64_C #ifndef UINT64_C
#define UINT64_C(x) x ## LL #define UINT64_C(x) x ## LL
#endif #endif
namespace libtorrent
{
/* the K array */ /* the K array */
static const u64 K[80] = { static const u64 K[80] = {
UINT64_C(0x428a2f98d728ae22), UINT64_C(0x7137449123ef65cd), UINT64_C(0x428a2f98d728ae22), UINT64_C(0x7137449123ef65cd),
@ -95,7 +104,7 @@ static const u64 K[80] = {
#endif #endif
/* compress 1024-bits */ /* 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; u64 S[8], W[80], t0, t1;
int i; 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 @param md The hash state you wish to initialize
@return 0 if successful @return 0 if successful
*/ */
int sha512_init(sha512_context * md) { int SHA512_init(sha512_ctx* md) {
if (md == NULL) return 1; if (md == NULL) return 1;
md->curlen = 0; md->curlen = 0;
@ -175,7 +184,7 @@ int sha512_init(sha512_context * md) {
@param inlen The length of the data (octets) @param inlen The length of the data (octets)
@return 0 if successful @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 n;
size_t i; 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) @param out [out] The destination of the hash (64 bytes)
@return 0 if successful @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; int i;
if (md == NULL) return 1; if (md == NULL) return 1;
if (out == NULL) return 1; if (out == NULL) return 1;
if (md->curlen >= sizeof(md->buf)) { if (md->curlen >= sizeof(md->buf)) {
return 1; return 1;
} }
/* increase the length of the message */ /* increase the length of the message */
md->length += md->curlen * UINT64_C(8); md->length += md->curlen * UINT64_C(8);
/* append the '1' bit */ /* 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 /* if the length is currently above 112 bytes we append zeros
* then compress. Then we can fall back to padding zeros and length * then compress. Then we can fall back to padding zeros and length
* encoding like normal. * encoding like normal.
*/ */
if (md->curlen > 112) { if (md->curlen > 112) {
while (md->curlen < 128) { while (md->curlen < 128) {
md->buf[md->curlen++] = (unsigned char)0; 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 * 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... :-) * > 2^64 bits of data... :-)
*/ */
while (md->curlen < 120) { while (md->curlen < 120) {
md->buf[md->curlen++] = (unsigned char)0; md->buf[md->curlen++] = (unsigned char)0;
} }
/* store length */ /* store length */
STORE64H(md->length, md->buf+120); STORE64H(md->length, md->buf+120);
sha512_compress(md, md->buf); sha512_compress(md, md->buf);
/* copy output */ /* copy output */
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
STORE64H(md->state[i], out+(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; return 0;
} }
} // libtorrent namespace

View File

@ -144,6 +144,8 @@ test-suite libtorrent :
[ run test_dht.cpp [ run test_dht.cpp
test_dht_storage.cpp test_dht_storage.cpp
test_direct_dht.cpp test_direct_dht.cpp
test_hasher512.cpp
test_ed25519.cpp
] ]
[ run test_string.cpp [ run test_string.cpp

View File

@ -180,6 +180,8 @@ test_primitives_SOURCES = \
test_xml.cpp \ test_xml.cpp \
test_ip_filter.cpp \ test_ip_filter.cpp \
test_hasher.cpp \ test_hasher.cpp \
test_hasher512.cpp \
test_ed25519.cpp \
test_dht_storage.cpp \ test_dht_storage.cpp \
test_dht.cpp \ test_dht.cpp \
test_block_cache.cpp \ test_block_cache.cpp \

177
test/test_ed25519.cpp Normal file
View File

@ -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 <memory>
#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<char*>(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<unsigned char> msg(msg_size);
from_hex(seed, s);
ed25519_create_keypair(pk, sk, s);
TEST_EQUAL(aux::to_hex({reinterpret_cast<char const*>(pk), 32}), pub);
from_hex(message, msg.data());
ed25519_sign(sig, msg.data(), msg_size, pk, sk);
TEST_EQUAL(aux::to_hex({reinterpret_cast<char const*>(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

View File

@ -31,12 +31,14 @@ POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "libtorrent/hasher.hpp" #include "libtorrent/hasher.hpp"
#include "libtorrent/hex.hpp" // from_hex #include "libtorrent/hex.hpp"
#include "test.hpp" #include "test.hpp"
using namespace libtorrent; using namespace libtorrent;
namespace
{
// test vectors from RFC 3174 // test vectors from RFC 3174
// http://www.faqs.org/rfcs/rfc3174.html // http://www.faqs.org/rfcs/rfc3174.html
@ -58,11 +60,19 @@ char const* result_array[4] =
"DEA356A2CDDD90C7A7ECEDC5EBB563934F460452" "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) TORRENT_TEST(hasher)
{ {
using namespace libtorrent;
for (int test = 0; test < 4; ++test) for (int test = 0; test < 4; ++test)
{ {
hasher h; 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
);
}

91
test/test_hasher512.cpp Normal file
View File

@ -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