diff --git a/CMakeLists.txt b/CMakeLists.txt index c31393602..0c7e30a9c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -140,6 +140,7 @@ set(kademlia_sources item get_peers get_item + ed25519 ) # -- ed25519 -- @@ -150,7 +151,6 @@ set(ed25519_sources key_exchange keypair sc - seed sign verify ) diff --git a/Jamfile b/Jamfile index 4bb4c884f..0629f3f2d 100644 --- a/Jamfile +++ b/Jamfile @@ -706,6 +706,7 @@ KADEMLIA_SOURCES = item get_item put_data + ed25519 ; ED25519_SOURCES = @@ -715,7 +716,6 @@ ED25519_SOURCES = key_exchange keypair sc - seed sign verify ; diff --git a/ed25519/src/add_scalar.cpp b/ed25519/src/add_scalar.cpp index c0e191a98..faa0089c5 100644 --- a/ed25519/src/add_scalar.cpp +++ b/ed25519/src/add_scalar.cpp @@ -2,9 +2,12 @@ #include "libtorrent/aux_/disable_warnings_push.hpp" #include "libtorrent/ed25519.hpp" +#include "libtorrent/hasher512.hpp" #include "ge.h" #include "sc.h" +namespace libtorrent +{ /* see http://crypto.stackexchange.com/a/6215/4697 */ void ed25519_add_scalar(unsigned char *public_key, unsigned char *private_key, const unsigned char *scalar) { @@ -28,6 +31,17 @@ void ed25519_add_scalar(unsigned char *public_key, unsigned char *private_key, c /* private key: a = n + t */ if (private_key) { sc_muladd(private_key, SC_1, n, private_key); + + // Fixed ed25519_add_scalar vulnerability. + // https://github.com/orlp/ed25519/commit/09ec167693edff9478b53d772487e94569cb58d0 + // https://github.com/orlp/ed25519/issues/3 + hasher512 hash; + hash.update({reinterpret_cast(private_key) + 32, 32}); + hash.update({reinterpret_cast(scalar), 32}); + sha512_hash hashbuf = hash.final(); + for (i = 0; i < 32; ++i) { + private_key[32 + i] = hashbuf[i]; + } } /* public key: A = nB + T */ @@ -57,3 +71,5 @@ void ed25519_add_scalar(unsigned char *public_key, unsigned char *private_key, c ge_p3_tobytes(public_key, &A); } } + +} diff --git a/ed25519/src/key_exchange.cpp b/ed25519/src/key_exchange.cpp index 1d728ed5a..26840f8d6 100644 --- a/ed25519/src/key_exchange.cpp +++ b/ed25519/src/key_exchange.cpp @@ -4,6 +4,9 @@ #include "libtorrent/ed25519.hpp" #include "fe.h" +namespace libtorrent +{ + void ed25519_key_exchange(unsigned char *shared_secret , const unsigned char *public_key, const unsigned char *private_key) { unsigned char e[32]; @@ -81,3 +84,5 @@ void ed25519_key_exchange(unsigned char *shared_secret fe_mul(x2, x2, z2); fe_tobytes(shared_secret, x2); } + +} diff --git a/ed25519/src/keypair.cpp b/ed25519/src/keypair.cpp index ac9149b88..2cd661908 100644 --- a/ed25519/src/keypair.cpp +++ b/ed25519/src/keypair.cpp @@ -5,7 +5,8 @@ #include "libtorrent/hasher512.hpp" #include "ge.h" -using namespace libtorrent; +namespace libtorrent +{ void ed25519_create_keypair(unsigned char *public_key, unsigned char *private_key, const unsigned char *seed) { ge_p3 A; @@ -19,3 +20,5 @@ void ed25519_create_keypair(unsigned char *public_key, unsigned char *private_ke ge_scalarmult_base(&A, private_key); ge_p3_tobytes(public_key, &A); } + +} diff --git a/ed25519/src/seed.cpp b/ed25519/src/seed.cpp deleted file mode 100644 index 7d03a37a0..000000000 --- a/ed25519/src/seed.cpp +++ /dev/null @@ -1,63 +0,0 @@ -// ignore warnings in this file -#include "libtorrent/aux_/disable_warnings_push.hpp" - -#include -#include -#include "libtorrent/config.hpp" -#include "libtorrent/ed25519.hpp" - -#ifndef ED25519_NO_SEED - -#if TORRENT_USE_CRYPTOGRAPHIC_BUFFER -#include -#include -using namespace Windows::Security::Cryptography; -using namespace Windows::Storage::Streams; -using namespace Microsoft::WRL; -#elif defined _WIN32 -#include -#include -#else -#include -#endif - -void ed25519_create_seed(unsigned char *seed) { -#if TORRENT_USE_CRYPTOGRAPHIC_BUFFER - IBuffer^ seedBuffer = CryptographicBuffer::GenerateRandom(32); - ComPtr bufferByteAccess; - reinterpret_cast(seedBuffer)->QueryInterface(IID_PPV_ARGS(&bufferByteAccess)); - bufferByteAccess->Buffer(&seed); -#elif defined _WIN32 - HCRYPTPROV prov; - - if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { - throw boost::system::system_error(boost::system::error_code(GetLastError() - , boost::system::system_category())); - } - - if (!CryptGenRandom(prov, 32, seed)) { - CryptReleaseContext(prov, 0); - throw boost::system::system_error(boost::system::error_code(GetLastError() - , boost::system::system_category())); - } - - CryptReleaseContext(prov, 0); -#else - FILE *f = fopen("/dev/urandom", "rb"); - - if (f == NULL) { - throw boost::system::system_error(boost::system::error_code(errno, boost::system::system_category())); - } - - int read = fread(seed, 1, 32, f); - if (read != 32) { - fclose(f); - throw boost::system::system_error(boost::system::error_code(errno, boost::system::system_category())); - } - - fclose(f); -#endif -} - -#endif - diff --git a/ed25519/src/sign.cpp b/ed25519/src/sign.cpp index d10a97a7e..e4c434ef7 100644 --- a/ed25519/src/sign.cpp +++ b/ed25519/src/sign.cpp @@ -6,7 +6,8 @@ #include "ge.h" #include "sc.h" -using namespace libtorrent; +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) { ge_p3 R; @@ -32,3 +33,5 @@ void ed25519_sign(unsigned char *signature, const unsigned char *message, size_t , private_key , reinterpret_cast(r.data())); } + +} diff --git a/ed25519/src/verify.cpp b/ed25519/src/verify.cpp index 15704be2c..b1ff1df66 100644 --- a/ed25519/src/verify.cpp +++ b/ed25519/src/verify.cpp @@ -6,7 +6,8 @@ #include "ge.h" #include "sc.h" -using namespace libtorrent; +namespace libtorrent +{ static int consttime_equal(const unsigned char *x, const unsigned char *y) { unsigned char r = 0; @@ -79,3 +80,5 @@ int ed25519_verify(const unsigned char *signature, const unsigned char *message, return 1; } + +} diff --git a/include/libtorrent/Makefile.am b/include/libtorrent/Makefile.am index a240098b4..43dcc45cf 100644 --- a/include/libtorrent/Makefile.am +++ b/include/libtorrent/Makefile.am @@ -197,6 +197,7 @@ nobase_include_HEADERS = \ kademlia/rpc_manager.hpp \ kademlia/traversal_algorithm.hpp \ kademlia/types.hpp \ + kademlia/ed25519.hpp \ kademlia/item.hpp \ kademlia/get_item.hpp \ kademlia/get_peers.hpp diff --git a/include/libtorrent/ed25519.hpp b/include/libtorrent/ed25519.hpp index 8a94b2471..350de92e2 100644 --- a/include/libtorrent/ed25519.hpp +++ b/include/libtorrent/ed25519.hpp @@ -4,6 +4,8 @@ #include "libtorrent/export.hpp" // for TORRENT_EXPORT #include // for size_t +namespace libtorrent +{ enum { ed25519_seed_size = 32, @@ -14,21 +16,12 @@ enum ed25519_shared_secret_size = 32 }; -extern "C" { - -#ifndef ED25519_NO_SEED -void TORRENT_EXPORT ed25519_create_seed(unsigned char *seed); -#endif - -// TODO: 3 wrap these into C++ calls with proper types (dht::signature, -// 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 *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); +void TORRENT_EXTRA_EXPORT ed25519_create_keypair(unsigned char *public_key, unsigned char *private_key, const unsigned char *seed); +void TORRENT_EXTRA_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_EXTRA_EXPORT ed25519_verify(const unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key); +void TORRENT_EXTRA_EXPORT ed25519_add_scalar(unsigned char *public_key, unsigned char *private_key, const unsigned char *scalar); +void TORRENT_EXTRA_EXPORT ed25519_key_exchange(unsigned char *shared_secret, const unsigned char *public_key, const unsigned char *private_key); } #endif // ED25519_HPP - diff --git a/include/libtorrent/kademlia/ed25519.hpp b/include/libtorrent/kademlia/ed25519.hpp new file mode 100644 index 000000000..1c96e1a0a --- /dev/null +++ b/include/libtorrent/kademlia/ed25519.hpp @@ -0,0 +1,102 @@ +/* + +Copyright (c) 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 LIBTORRENT_ED25519_HPP +#define LIBTORRENT_ED25519_HPP + +#include +#include +#include + +#include +#include + +namespace libtorrent { +namespace dht +{ + + // See documentation of internal random_bytes + TORRENT_EXPORT void ed25519_create_seed(std::array& seed); + + // Creates a new key pair from the given seed. + // + // It's important to clarify that the seed completely determines + // the key pair. Then it's enough to save the seed and the + // public key as the key-pair in a buffer of 64 bytes. The standard + // is (32 bytes seed, 32 bytes public key). + // + // This function does work with a given seed, giving you a pair of + // (64 bytes private key, 32 bytes public key). It's a trade-off between + // space and CPU, saving in one format or another. + // + // The smaller format is not weaker by any means, in fact, it is only + // the seed (32 bytes) that determines the point in the curve. + TORRENT_EXPORT void ed25519_create_keypair(public_key& pk + , secret_key& sk, std::array const& seed); + + // Creates a signature of the given message with the given key pair. + TORRENT_EXPORT void ed25519_sign(signature& sig, span msg + , public_key const& pk, secret_key const& sk); + + // Verifies the signature on the given message using ``pk`` + TORRENT_EXPORT bool ed25519_verify(signature const& sig + , span msg, public_key const& pk); + + // Adds a scalar to the given key pair where scalar is a 32 byte buffer + // (possibly generated with `ed25519_create_seed`), generating a new key pair. + // + // You can calculate the public key sum without knowing the private key and + // vice versa by passing in null for the key you don't know. This is useful + // when a third party (an authoritative server for example) needs to enforce + // randomness on a key pair while only knowing the public key of the other + // side. + // + // Warning: the last bit of the scalar is ignored - if comparing scalars make + // sure to clear it with `scalar[31] &= 127`. + // + // see http://crypto.stackexchange.com/a/6215/4697 + // see test_ed25519 for a practical example + TORRENT_EXPORT void ed25519_add_scalar(std::shared_ptr pk + , std::shared_ptr sk, std::array const& scalar); + + // Performs a key exchange on the given public key and private key, producing a + // shared secret. It is recommended to hash the shared secret before using it. + // + // This is useful when two parties want to share a secret but both only knows + // their respective public keys. + // see test_ed25519 for a practical example + TORRENT_EXPORT void ed25519_key_exchange(std::array& secret + , public_key const& pk, secret_key const& sk); + +}} + +#endif // LIBTORRENT_ED25519_HPP diff --git a/include/libtorrent/random.hpp b/include/libtorrent/random.hpp index 5bd2baa93..8fc352bbe 100644 --- a/include/libtorrent/random.hpp +++ b/include/libtorrent/random.hpp @@ -31,6 +31,7 @@ POSSIBILITY OF SUCH DAMAGE. */ #include "libtorrent/config.hpp" +#include "libtorrent/span.hpp" #include #include @@ -47,6 +48,17 @@ namespace libtorrent { std::shuffle(first, last, random_engine()); } + + // Fills the buffer with random bytes. + // + // This functions perform differently under different setups + // For Windows and all platforms when compiled with libcrypto, it + // generates cryptographically random bytes. + // If the above conditions are not true, then a standard + // std::independent_bits_engine + // generator is used. + // + TORRENT_EXTRA_EXPORT void random_bytes(span buffer); } TORRENT_EXTRA_EXPORT std::uint32_t random(std::uint32_t max); diff --git a/simulation/test_dht.cpp b/simulation/test_dht.cpp index 97a669289..4ff41e670 100644 --- a/simulation/test_dht.cpp +++ b/simulation/test_dht.cpp @@ -45,7 +45,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/socket_io.hpp" #include "setup_swarm.hpp" #include "setup_dht.hpp" -#include "libtorrent/ed25519.hpp" +#include "libtorrent/kademlia/ed25519.hpp" #include "libtorrent/bencode.hpp" #include "libtorrent/kademlia/item.hpp" #include @@ -314,9 +314,8 @@ TORRENT_TEST(dht_dual_stack_mutable_item) } if (ticks == 2) { - std::array seed; - ed25519_create_keypair((unsigned char*)pk.bytes.data() - , (unsigned char*)sk.bytes.data(), seed.data()); + std::array seed; + ed25519_create_keypair(pk, sk, seed); ses.dht_put_item(pk.bytes, [&](lt::entry& item, std::array& sig , std::uint64_t& seq, std::string const& salt) diff --git a/src/Makefile.am b/src/Makefile.am index 2cd225159..2bbbdc125 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -20,13 +20,13 @@ KADEMLIA_SOURCES = \ kademlia/get_peers.cpp \ kademlia/get_item.cpp \ kademlia/item.cpp \ + kademlia/ed25519.cpp \ ../ed25519/src/add_scalar.cpp \ ../ed25519/src/fe.cpp \ ../ed25519/src/ge.cpp \ ../ed25519/src/key_exchange.cpp \ ../ed25519/src/keypair.cpp \ ../ed25519/src/sc.cpp \ - ../ed25519/src/seed.cpp \ ../ed25519/src/sign.cpp \ ../ed25519/src/verify.cpp \ hasher512.cpp diff --git a/src/kademlia/ed25519.cpp b/src/kademlia/ed25519.cpp new file mode 100644 index 000000000..f8a3d9982 --- /dev/null +++ b/src/kademlia/ed25519.cpp @@ -0,0 +1,99 @@ +/* + +Copyright (c) 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 +#include +#include + +namespace libtorrent { +namespace dht +{ + + void ed25519_create_seed(std::array& seed) + { + aux::random_bytes(seed); + } + + void ed25519_create_keypair(public_key& pk + , secret_key& sk, std::array const& seed) + { + auto const pk_ptr = reinterpret_cast(pk.bytes.data()); + auto const sk_ptr = reinterpret_cast(sk.bytes.data()); + auto const seed_ptr = reinterpret_cast(seed.data()); + + libtorrent::ed25519_create_keypair(pk_ptr, sk_ptr, seed_ptr); + } + + void ed25519_sign(signature& sig, span msg + , public_key const& pk, secret_key const& sk) + { + auto const sig_ptr = reinterpret_cast(sig.bytes.data()); + auto const msg_ptr = reinterpret_cast(msg.data()); + auto const pk_ptr = reinterpret_cast(pk.bytes.data()); + auto const sk_ptr = reinterpret_cast(sk.bytes.data()); + + libtorrent::ed25519_sign(sig_ptr, msg_ptr, msg.size(), pk_ptr, sk_ptr); + } + + bool ed25519_verify(signature const& sig + , span msg, public_key const& pk) + { + auto const sig_ptr = reinterpret_cast(sig.bytes.data()); + auto const msg_ptr = reinterpret_cast(msg.data()); + auto const pk_ptr = reinterpret_cast(pk.bytes.data()); + + return libtorrent::ed25519_verify(sig_ptr, msg_ptr, msg.size(), pk_ptr) == 1; + } + + void ed25519_add_scalar(std::shared_ptr pk + , std::shared_ptr sk, std::array const& scalar) + { + auto const pk_ptr = pk + ? reinterpret_cast(pk->bytes.data()) : nullptr; + auto const sk_ptr = sk + ? reinterpret_cast(sk->bytes.data()) : nullptr; + auto const scalar_ptr = reinterpret_cast(scalar.data()); + + libtorrent::ed25519_add_scalar(pk_ptr, sk_ptr, scalar_ptr); + } + + void ed25519_key_exchange(std::array& secret + , public_key const& pk, secret_key const& sk) + { + auto const secret_ptr = reinterpret_cast(secret.data()); + auto const pk_ptr = reinterpret_cast(pk.bytes.data()); + auto const sk_ptr = reinterpret_cast(sk.bytes.data()); + + libtorrent::ed25519_key_exchange(secret_ptr, pk_ptr, sk_ptr); + } + +}} diff --git a/src/kademlia/item.cpp b/src/kademlia/item.cpp index 6e749a1e2..fc3d1eecb 100644 --- a/src/kademlia/item.cpp +++ b/src/kademlia/item.cpp @@ -34,7 +34,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include +#include #include // for snprintf #include // for PRId64 et.al. @@ -106,10 +106,7 @@ bool verify_mutable_item( char str[1200]; int len = canonical_string(v, seq, salt, str); - return ed25519_verify(reinterpret_cast(sig.bytes.data()) - , reinterpret_cast(str) - , len - , reinterpret_cast(pk.bytes.data())) == 1; + return ed25519_verify(sig, {str, size_t(len)}, pk); } // given the bencoded buffer ``v``, the salt (which is optional and may have @@ -129,12 +126,7 @@ void sign_mutable_item( char str[1200]; int const len = canonical_string(v, seq, salt, str); - ed25519_sign(reinterpret_cast(sig.bytes.data()) - , reinterpret_cast(str) - , len - , reinterpret_cast(pk.bytes.data()) - , reinterpret_cast(sk.bytes.data()) - ); + ed25519_sign(sig, {str, size_t(len)}, pk, sk); } item::item(public_key const& pk, span salt) diff --git a/src/random.cpp b/src/random.cpp index 01a8190c3..69f7e1c24 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -32,6 +32,19 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/config.hpp" #include "libtorrent/random.hpp" +#include "libtorrent/error_code.hpp" + +#if TORRENT_USE_CRYPTOAPI +#include +#include + +#elif defined TORRENT_USE_LIBCRYPTO +extern "C" { +#include +#include +} + +#endif namespace libtorrent { @@ -48,6 +61,51 @@ namespace libtorrent #endif return rng; } + + void random_bytes(span buffer) + { +#if TORRENT_USE_CRYPTOAPI + HCRYPTPROV prov; + + if (!CryptAcquireContext(&prov, NULL, NULL + , PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) + { +#ifndef BOOST_NO_EXCEPTIONS + throw system_error(error_code(GetLastError(), system_category())); +#else + std::terminate(); +#endif + } + + if (!CryptGenRandom(prov, int(buffer.size()) + , reinterpret_cast(buffer.data()))) + { + CryptReleaseContext(prov, 0); +#ifndef BOOST_NO_EXCEPTIONS + throw system_error(error_code(GetLastError(), system_category())); +#else + std::terminate(); +#endif + } + + CryptReleaseContext(prov, 0); +#elif defined TORRENT_USE_LIBCRYPTO + int r = RAND_bytes(reinterpret_cast(buffer.data()) + , int(buffer.size())); + if (r != 1) + { +#ifndef BOOST_NO_EXCEPTIONS + throw system_error(error_code(ERR_get_error(), system_category())); +#else + std::terminate(); +#endif + } +#else + std::uint32_t s = random(0xffffffff); + std::independent_bits_engine generator(s); + std::generate(buffer.begin(), buffer.end(), std::ref(generator)); +#endif + } } std::uint32_t random(std::uint32_t max) diff --git a/test/Jamfile b/test/Jamfile index 340348143..04769668b 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -145,7 +145,6 @@ test-suite libtorrent : test_dht_storage.cpp test_direct_dht.cpp test_hasher512.cpp - test_ed25519.cpp ] [ run test_string.cpp @@ -156,6 +155,7 @@ test-suite libtorrent : [ run test_bitfield.cpp ] [ run test_crc32.cpp ] [ run test_ffs.cpp ] + [ run test_ed25519.cpp ] [ run test_gzip.cpp ] [ run test_receive_buffer.cpp ] [ run test_alert_manager.cpp ] @@ -230,6 +230,7 @@ alias win-tests : test_gzip test_piece_picker test_ffs + test_ed25519 test_session_params ; @@ -240,6 +241,7 @@ alias arm-tests : test_bitfield test_crc32 test_ffs + test_ed25519 ; explicit arm-tests ; diff --git a/test/test_dht.cpp b/test/test_dht.cpp index b4e134523..3dcfc9b9e 100644 --- a/test/test_dht.cpp +++ b/test/test_dht.cpp @@ -42,7 +42,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/broadcast_socket.hpp" // for supports_ipv6 #include "libtorrent/performance_counters.hpp" // for counters #include "libtorrent/random.hpp" -#include "libtorrent/ed25519.hpp" +#include "libtorrent/kademlia/ed25519.hpp" #include "libtorrent/hex.hpp" // to_hex, from_hex #include "libtorrent/kademlia/node_id.hpp" @@ -1052,11 +1052,10 @@ void test_put(address(&rand_addr)()) seq = sequence_number(4); std::fprintf(stderr, "\nTEST GET/PUT%s \ngenerating ed25519 keys\n\n" , with_salt ? " with-salt" : " no-salt"); - unsigned char seed[32]; + std::array seed; ed25519_create_seed(seed); - ed25519_create_keypair((unsigned char*)pk.bytes.data() - , (unsigned char*)sk.bytes.data(), seed); + ed25519_create_keypair(pk, sk, seed); std::fprintf(stderr, "pub: %s priv: %s\n" , aux::to_hex(pk.bytes).c_str() , aux::to_hex(sk.bytes).c_str()); diff --git a/test/test_ed25519.cpp b/test/test_ed25519.cpp index 378787bec..d5a1de707 100644 --- a/test/test_ed25519.cpp +++ b/test/test_ed25519.cpp @@ -30,44 +30,39 @@ POSSIBILITY OF SUCH DAMAGE. */ +#include "test.hpp" + #ifndef TORRENT_DISABLE_DHT #include -#include "libtorrent/ed25519.hpp" +#include "libtorrent/kademlia/ed25519.hpp" #include "libtorrent/hex.hpp" -#include "test.hpp" - using namespace libtorrent; +using namespace libtorrent::dht; namespace { - void from_hex(std::string s, unsigned char* out) + void test_vector(std::string seed, std::string pub, std::string sig_hex, std::string message) { - aux::from_hex(s, reinterpret_cast(out)); - } + std::array s; + secret_key sk; + public_key pk; + signature sig; + std::vector msg(int(message.size()) / 2); - 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); + aux::from_hex(seed, s.data()); ed25519_create_keypair(pk, sk, s); - TEST_EQUAL(aux::to_hex({reinterpret_cast(pk), 32}), pub); + TEST_EQUAL(aux::to_hex(pk.bytes), pub); - from_hex(message, msg.data()); - ed25519_sign(sig, msg.data(), msg_size, pk, sk); + aux::from_hex(message, msg.data()); + ed25519_sign(sig, msg, pk, sk); - TEST_EQUAL(aux::to_hex({reinterpret_cast(sig), 64}), signature); + TEST_EQUAL(aux::to_hex(sig.bytes), sig_hex); - int r = ed25519_verify(sig, msg.data(), msg_size, pk); + bool r = ed25519_verify(sig, msg, pk); TEST_CHECK(r); } @@ -172,6 +167,136 @@ TORRENT_TEST(ed25519_test_vec1) , "f8b21962447b0a8f2e4279de411bea128e0be44b6915e6cda88341a68a0d8183" "57db938eac73e0af6d31206b3948f8c48a447308" ); + + // TST: 224 + test_vector( + "ae1d2c6b171be24c2e413d364dcda97fa476aaf9123d3366b0be03a142fe6e7d" + , "d437f57542c681dd543487408ec7a44bd42a5fd545ce2f4c8297d67bb0b3aa7b" + , "909008f3fcfff43988aee1314b15b1822caaa8dab120bd452af494e08335b44a" + "94c313c4b145eadd5166eaac034e29b7e6ac7941d5961fc49d260e1c4820b00e" + , "9e6c2fc76e30f17cd8b498845da44f22d55bec150c6130b411c6339d14b39969" + "ab1033be687569a991a06f70b2a8a6931a777b0e4be6723cd75e5aa7532813ef" + "50b3d37271640fa2fb287c0355257641ea935c851c0b6ac68be72c88dfc5856f" + "b53543fb377b0dbf64808afcc4274aa456855ad28f61267a419bc72166b9ca73" + "cd3bb79bf7dd259baa75911440974b68e8ba95a78cbbe1cb6ad807a33a1cce2f" + "406ff7bcbd058b44a311b38ab4d4e61416c4a74d883d6a6a794abd9cf1c03902" + "8bf1b20e3d4990aae86f32bf06cd8349a7a884cce0165e36a0640e987b9d51" + ); + + // TST: 225 + test_vector( + "0265a7944baccfebf417b87ae1e6df2ff2a544ffb58225a08e092be03f026097" + , "63d327615ea0139be0740b618aff1acfa818d4b0c2cfeaf0da93cdd5245fb5a9" + , "b6c445b7eddca5935c61708d44ea5906bd19cc54224eae3c8e46ce99f5cbbd34" + "1f26623938f5fe04070b1b02e71fbb7c78a90c0dda66cb143fab02e6a0bae306" + , "874ed712a2c41c26a2d9527c55233fde0a4ffb86af8e8a1dd0a820502c5a2693" + "2bf87ee0de72a8874ef2eebf83384d443f7a5f46a1233b4fb514a24699818248" + "94f325bf86aa0fe1217153d40f3556c43a8ea9269444e149fb70e9415ae0766c" + "565d93d1d6368f9a23a0ad76f9a09dbf79634aa97178677734d04ef1a5b3f87c" + "e1ee9fc5a9ac4e7a72c9d7d31ec89e28a845d2e1103c15d6410ce3c723b0cc22" + "09f698aa9fa288bbbecfd9e5f89cdcb09d3c215feb47a58b71ea70e2abead67f" + "1b08ea6f561fb93ef05232eedabfc1c7702ab039bc465cf57e207f1093fc8208" + ); } +TORRENT_TEST(create_seed) +{ + std::array s1; + std::array s2; + s1.fill(0); + s2.fill(0); + + TEST_CHECK(s1 == s2); + ed25519_create_seed(s1); + ed25519_create_seed(s2); + TEST_CHECK(s1 != s2); // what are the odds + + int n1 = 0; + int n2 = 0; + for (int i = 0; i < 32; i++) + { + if (s1[i] != 0) n1++; + if (s2[i] != 0) n2++; + } + TEST_CHECK(n1 > 0); + TEST_CHECK(n2 > 0); +} + +TORRENT_TEST(add_scalar) +{ + // client + std::array s1; + ed25519_create_seed(s1); + + public_key pk1; + secret_key sk1; + ed25519_create_keypair(pk1, sk1, s1); + + // client sends to server the public key + + // server generates another seed, it could be an scalar + // n = HMAC(k, pk1) and sends it back to the client + // see http://crypto.stackexchange.com/a/6215/4697 + std::array n; + ed25519_create_seed(n); + + // now the server knows that the client's public key + // must be (or assigns) pk1 + n + ed25519_add_scalar(std::make_shared(pk1) + , std::make_shared(), n); + + // server sends n to the client + + // the client, in order to properly sign messages, must + // adjust the private key + ed25519_add_scalar(std::make_shared() + , std::make_shared(sk1), n); + + // test sign and verification + std::string msg = "Hello world"; + signature sig; + ed25519_sign(sig, msg, pk1, sk1); + bool r = ed25519_verify(sig, msg, pk1); + TEST_CHECK(r); +} + +TORRENT_TEST(key_exchange) +{ + // user A + std::array s1; + ed25519_create_seed(s1); + + public_key pk1; + secret_key sk1; + ed25519_create_keypair(pk1, sk1, s1); + + // user A sends to user B the public key + + // user B + std::array s2; + ed25519_create_seed(s2); + + public_key pk2; + secret_key sk2; + ed25519_create_keypair(pk2, sk2, s2); + + // user B performs the key exchange + std::array secretB; + ed25519_key_exchange(secretB, pk1, sk2); + + // user B sends to user A the public key + + // user A performs the key exchange + std::array secretA; + ed25519_key_exchange(secretA, pk2, sk1); + + // now both users A and B must shared the same secret + TEST_EQUAL(aux::to_hex(secretA), aux::to_hex(secretB)); +} + +#else +TORRENT_TEST(empty) +{ + TEST_CHECK(true); +} #endif // TORRENT_DISABLE_DHT diff --git a/tools/dht_put.cpp b/tools/dht_put.cpp index 069286679..973e58259 100644 --- a/tools/dht_put.cpp +++ b/tools/dht_put.cpp @@ -36,7 +36,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/alert_types.hpp" #include "libtorrent/bencode.hpp" // for bencode() #include "libtorrent/kademlia/item.hpp" // for sign_mutable_item -#include "libtorrent/ed25519.hpp" +#include "libtorrent/kademlia/ed25519.hpp" #include "libtorrent/span.hpp" #include @@ -45,6 +45,7 @@ POSSIBILITY OF SUCH DAMAGE. #include using namespace libtorrent; +using namespace libtorrent::dht; using namespace std::placeholders; namespace lt = libtorrent; @@ -150,8 +151,8 @@ int dump_key(char *filename) return 1; } - unsigned char seed[32]; - int size = int(fread(seed, 1, 32, f)); + std::array seed; + int size = int(fread(seed.data(), 1, 32, f)); if (size != 32) { std::fprintf(stderr, "invalid key file.\n"); @@ -159,21 +160,20 @@ int dump_key(char *filename) } std::fclose(f); - std::array pk; - std::array sk; - ed25519_create_keypair((unsigned char*)pk.data() - , (unsigned char*)sk.data(), seed); + public_key pk; + secret_key sk; + ed25519_create_keypair(pk, sk, seed); std::printf("public key: %s\nprivate key: %s\n" - , to_hex(pk).c_str() - , to_hex(sk).c_str()); + , to_hex(pk.bytes).c_str() + , to_hex(sk.bytes).c_str()); return 0; } int generate_key(char* filename) { - unsigned char seed[32]; + std::array seed; ed25519_create_seed(seed); FILE* f = std::fopen(filename, "wb+"); @@ -184,7 +184,7 @@ int generate_key(char* filename) return 1; } - int size = int(std::fwrite(seed, 1, 32, f)); + int size = int(std::fwrite(seed.data(), 1, 32, f)); if (size != 32) { std::fprintf(stderr, "failed to write key file.\n"); @@ -347,24 +347,23 @@ int main(int argc, char* argv[]) return 1; } - unsigned char seed[32]; - fread(seed, 1, 32, f); + std::array seed; + fread(seed.data(), 1, 32, f); std::fclose(f); ++argv; --argc; if (argc < 1) usage(); - std::array public_key; - std::array private_key; - ed25519_create_keypair((unsigned char*)public_key.data() - , (unsigned char*)private_key.data(), seed); + public_key pk; + secret_key sk; + ed25519_create_keypair(pk, sk, seed); bootstrap(s); - s.dht_put_item(public_key, std::bind(&put_string, _1, _2, _3, _4 - , public_key, private_key, argv[0])); + s.dht_put_item(pk.bytes, std::bind(&put_string, _1, _2, _3, _4 + , pk.bytes, sk.bytes, argv[0])); - std::printf("MPUT publick key: %s\n", to_hex(public_key).c_str()); + std::printf("MPUT public key: %s\n", to_hex(pk.bytes).c_str()); alert* a = wait_for_alert(s, dht_put_alert::alert_type); dht_put_alert* pa = alert_cast(a);