better integration and API for ed25519 (#1037)

better integration and API for ed25519. using shared_ptr in ed25519_add_scalar
This commit is contained in:
Alden Torres 2016-08-29 20:28:42 -04:00 committed by Arvid Norberg
parent 118e30fd86
commit 32f5f8f257
21 changed files with 492 additions and 144 deletions

View File

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

View File

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

View File

@ -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<char const*>(private_key) + 32, 32});
hash.update({reinterpret_cast<char const*>(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);
}
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -1,63 +0,0 @@
// ignore warnings in this file
#include "libtorrent/aux_/disable_warnings_push.hpp"
#include <boost/system/error_code.hpp>
#include <boost/system/system_error.hpp>
#include "libtorrent/config.hpp"
#include "libtorrent/ed25519.hpp"
#ifndef ED25519_NO_SEED
#if TORRENT_USE_CRYPTOGRAPHIC_BUFFER
#include <robuffer.h>
#include <wrl/client.h>
using namespace Windows::Security::Cryptography;
using namespace Windows::Storage::Streams;
using namespace Microsoft::WRL;
#elif defined _WIN32
#include <windows.h>
#include <wincrypt.h>
#else
#include <stdio.h>
#endif
void ed25519_create_seed(unsigned char *seed) {
#if TORRENT_USE_CRYPTOGRAPHIC_BUFFER
IBuffer^ seedBuffer = CryptographicBuffer::GenerateRandom(32);
ComPtr<IBufferByteAccess> bufferByteAccess;
reinterpret_cast<IInspectable*>(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

View File

@ -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<unsigned char*>(r.data()));
}
}

View File

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

View File

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

View File

@ -4,6 +4,8 @@
#include "libtorrent/export.hpp" // for TORRENT_EXPORT
#include <stddef.h> // 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

View File

@ -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 <libtorrent/config.hpp>
#include <libtorrent/span.hpp>
#include <libtorrent/kademlia/types.hpp>
#include <array>
#include <memory>
namespace libtorrent {
namespace dht
{
// See documentation of internal random_bytes
TORRENT_EXPORT void ed25519_create_seed(std::array<char, 32>& 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<char, 32> const& seed);
// Creates a signature of the given message with the given key pair.
TORRENT_EXPORT void ed25519_sign(signature& sig, span<char const> 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<char const> 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<public_key> pk
, std::shared_ptr<secret_key> sk, std::array<char, 32> 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<char, 32>& secret
, public_key const& pk, secret_key const& sk);
}}
#endif // LIBTORRENT_ED25519_HPP

View File

@ -31,6 +31,7 @@ POSSIBILITY OF SUCH DAMAGE.
*/
#include "libtorrent/config.hpp"
#include "libtorrent/span.hpp"
#include <cstdint>
#include <random>
@ -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<std::mt19937, 8, std::uint8_t>
// generator is used.
//
TORRENT_EXTRA_EXPORT void random_bytes(span<char> buffer);
}
TORRENT_EXTRA_EXPORT std::uint32_t random(std::uint32_t max);

View File

@ -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 <boost/bind.hpp>
@ -314,9 +314,8 @@ TORRENT_TEST(dht_dual_stack_mutable_item)
}
if (ticks == 2)
{
std::array<unsigned char, ed25519_seed_size> seed;
ed25519_create_keypair((unsigned char*)pk.bytes.data()
, (unsigned char*)sk.bytes.data(), seed.data());
std::array<char, 32> seed;
ed25519_create_keypair(pk, sk, seed);
ses.dht_put_item(pk.bytes, [&](lt::entry& item, std::array<char, 64>& sig
, std::uint64_t& seq, std::string const& salt)

View File

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

99
src/kademlia/ed25519.cpp Normal file
View File

@ -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 <libtorrent/kademlia/ed25519.hpp>
#include <libtorrent/random.hpp>
#include <libtorrent/ed25519.hpp>
namespace libtorrent {
namespace dht
{
void ed25519_create_seed(std::array<char, 32>& seed)
{
aux::random_bytes(seed);
}
void ed25519_create_keypair(public_key& pk
, secret_key& sk, std::array<char, 32> const& seed)
{
auto const pk_ptr = reinterpret_cast<unsigned char*>(pk.bytes.data());
auto const sk_ptr = reinterpret_cast<unsigned char*>(sk.bytes.data());
auto const seed_ptr = reinterpret_cast<unsigned char const*>(seed.data());
libtorrent::ed25519_create_keypair(pk_ptr, sk_ptr, seed_ptr);
}
void ed25519_sign(signature& sig, span<char const> msg
, public_key const& pk, secret_key const& sk)
{
auto const sig_ptr = reinterpret_cast<unsigned char*>(sig.bytes.data());
auto const msg_ptr = reinterpret_cast<unsigned char const*>(msg.data());
auto const pk_ptr = reinterpret_cast<unsigned char const*>(pk.bytes.data());
auto const sk_ptr = reinterpret_cast<unsigned char const*>(sk.bytes.data());
libtorrent::ed25519_sign(sig_ptr, msg_ptr, msg.size(), pk_ptr, sk_ptr);
}
bool ed25519_verify(signature const& sig
, span<char const> msg, public_key const& pk)
{
auto const sig_ptr = reinterpret_cast<unsigned char const*>(sig.bytes.data());
auto const msg_ptr = reinterpret_cast<unsigned char const*>(msg.data());
auto const pk_ptr = reinterpret_cast<unsigned char const*>(pk.bytes.data());
return libtorrent::ed25519_verify(sig_ptr, msg_ptr, msg.size(), pk_ptr) == 1;
}
void ed25519_add_scalar(std::shared_ptr<public_key> pk
, std::shared_ptr<secret_key> sk, std::array<char, 32> const& scalar)
{
auto const pk_ptr = pk
? reinterpret_cast<unsigned char*>(pk->bytes.data()) : nullptr;
auto const sk_ptr = sk
? reinterpret_cast<unsigned char*>(sk->bytes.data()) : nullptr;
auto const scalar_ptr = reinterpret_cast<unsigned char const*>(scalar.data());
libtorrent::ed25519_add_scalar(pk_ptr, sk_ptr, scalar_ptr);
}
void ed25519_key_exchange(std::array<char, 32>& secret
, public_key const& pk, secret_key const& sk)
{
auto const secret_ptr = reinterpret_cast<unsigned char*>(secret.data());
auto const pk_ptr = reinterpret_cast<unsigned char const*>(pk.bytes.data());
auto const sk_ptr = reinterpret_cast<unsigned char const*>(sk.bytes.data());
libtorrent::ed25519_key_exchange(secret_ptr, pk_ptr, sk_ptr);
}
}}

View File

@ -34,7 +34,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include <libtorrent/kademlia/item.hpp>
#include <libtorrent/bencode.hpp>
#include <libtorrent/span.hpp>
#include <libtorrent/ed25519.hpp>
#include <libtorrent/kademlia/ed25519.hpp>
#include <cstdio> // for snprintf
#include <cinttypes> // 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<unsigned char const*>(sig.bytes.data())
, reinterpret_cast<unsigned char const*>(str)
, len
, reinterpret_cast<unsigned char const*>(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<unsigned char*>(sig.bytes.data())
, reinterpret_cast<unsigned char const*>(str)
, len
, reinterpret_cast<unsigned char const*>(pk.bytes.data())
, reinterpret_cast<unsigned char const*>(sk.bytes.data())
);
ed25519_sign(sig, {str, size_t(len)}, pk, sk);
}
item::item(public_key const& pk, span<char const> salt)

View File

@ -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 <windows.h>
#include <wincrypt.h>
#elif defined TORRENT_USE_LIBCRYPTO
extern "C" {
#include <openssl/rand.h>
#include <openssl/err.h>
}
#endif
namespace libtorrent
{
@ -48,6 +61,51 @@ namespace libtorrent
#endif
return rng;
}
void random_bytes(span<char> 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<BYTE*>(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<unsigned char*>(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<std::mt19937, 8, std::uint8_t> generator(s);
std::generate(buffer.begin(), buffer.end(), std::ref(generator));
#endif
}
}
std::uint32_t random(std::uint32_t max)

View File

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

View File

@ -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<char, 32> 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());

View File

@ -30,44 +30,39 @@ POSSIBILITY OF SUCH DAMAGE.
*/
#include "test.hpp"
#ifndef TORRENT_DISABLE_DHT
#include <memory>
#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<char*>(out));
}
std::array<char, 32> s;
secret_key sk;
public_key pk;
signature sig;
std::vector<char> 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<unsigned char> 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<char const*>(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<char const*>(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<char, 32> s1;
std::array<char, 32> 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<char, 32> 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<char, 32> 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<public_key>(pk1)
, std::make_shared<secret_key>(), 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<public_key>()
, std::make_shared<secret_key>(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<char, 32> 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<char, 32> 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<char, 32> secretB;
ed25519_key_exchange(secretB, pk1, sk2);
// user B sends to user A the public key
// user A performs the key exchange
std::array<char, 32> 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

View File

@ -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 <functional>
@ -45,6 +45,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include <cstdlib>
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<char, 32> 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<char, 32> pk;
std::array<char, 64> 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<char, 32> 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<char, 32> seed;
fread(seed.data(), 1, 32, f);
std::fclose(f);
++argv;
--argc;
if (argc < 1) usage();
std::array<char, 32> public_key;
std::array<char, 64> 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<dht_put_alert>(a);