2013-12-27 05:28:25 +01:00
|
|
|
/*
|
|
|
|
|
|
|
|
Copyright (c) 2013, Steven Siloti
|
|
|
|
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/hasher.hpp>
|
|
|
|
#include <libtorrent/kademlia/item.hpp>
|
|
|
|
#include <libtorrent/bencode.hpp>
|
2014-07-19 09:12:20 +02:00
|
|
|
#include <libtorrent/ed25519.hpp>
|
2013-12-27 05:28:25 +01:00
|
|
|
|
2016-05-17 15:24:06 +02:00
|
|
|
#include <cstdio> // for snprintf
|
|
|
|
#include <cinttypes> // for PRId64 et.al.
|
|
|
|
|
2013-12-31 09:37:42 +01:00
|
|
|
#ifdef TORRENT_DEBUG
|
2015-03-12 06:20:12 +01:00
|
|
|
#include "libtorrent/bdecode.hpp"
|
2013-12-31 09:37:42 +01:00
|
|
|
#endif
|
|
|
|
|
2013-12-27 05:28:25 +01:00
|
|
|
namespace libtorrent { namespace dht
|
|
|
|
{
|
|
|
|
|
|
|
|
namespace
|
|
|
|
{
|
2014-01-03 05:18:46 +01:00
|
|
|
enum { canonical_length = 1200 };
|
2016-06-18 20:01:38 +02:00
|
|
|
int canonical_string(std::pair<char const*, int> v, std::uint64_t seq
|
2014-01-03 05:18:46 +01:00
|
|
|
, std::pair<char const*, int> salt, char out[canonical_length])
|
2013-12-27 05:28:25 +01:00
|
|
|
{
|
2013-12-31 09:37:42 +01:00
|
|
|
// v must be valid bencoding!
|
|
|
|
#ifdef TORRENT_DEBUG
|
2015-03-12 06:20:12 +01:00
|
|
|
bdecode_node e;
|
2013-12-31 09:37:42 +01:00
|
|
|
error_code ec;
|
2015-03-12 06:20:12 +01:00
|
|
|
TORRENT_ASSERT(bdecode(v.first, v.first + v.second, e, ec) == 0);
|
2013-12-31 09:37:42 +01:00
|
|
|
#endif
|
2014-01-03 05:18:46 +01:00
|
|
|
char* ptr = out;
|
|
|
|
|
|
|
|
int left = canonical_length - (ptr - out);
|
|
|
|
if (salt.second > 0)
|
|
|
|
{
|
2016-05-17 15:24:06 +02:00
|
|
|
ptr += std::snprintf(ptr, left, "4:salt%d:", salt.second);
|
2014-01-03 05:18:46 +01:00
|
|
|
left = canonical_length - (ptr - out);
|
|
|
|
memcpy(ptr, salt.first, (std::min)(salt.second, left));
|
|
|
|
ptr += (std::min)(salt.second, left);
|
|
|
|
left = canonical_length - (ptr - out);
|
|
|
|
}
|
2016-05-17 15:24:06 +02:00
|
|
|
ptr += std::snprintf(ptr, canonical_length - (ptr - out)
|
2014-01-03 05:18:46 +01:00
|
|
|
, "3:seqi%" PRId64 "e1:v", seq);
|
|
|
|
left = canonical_length - (ptr - out);
|
|
|
|
memcpy(ptr, v.first, (std::min)(v.second, left));
|
|
|
|
ptr += (std::min)(v.second, left);
|
|
|
|
TORRENT_ASSERT((ptr - out) <= canonical_length);
|
|
|
|
return ptr - out;
|
2013-12-27 05:28:25 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-03 00:35:35 +01:00
|
|
|
// calculate the target hash for an immutable item.
|
|
|
|
sha1_hash item_target_id(std::pair<char const*, int> v)
|
|
|
|
{
|
|
|
|
hasher h;
|
|
|
|
h.update(v.first, v.second);
|
|
|
|
return h.final();
|
|
|
|
}
|
|
|
|
|
|
|
|
// calculate the target hash for a mutable item.
|
|
|
|
sha1_hash item_target_id(std::pair<char const*, int> salt
|
2014-01-03 05:18:46 +01:00
|
|
|
, char const* pk)
|
|
|
|
{
|
|
|
|
hasher h;
|
2014-03-03 00:35:35 +01:00
|
|
|
h.update(pk, item_pk_len);
|
|
|
|
if (salt.second > 0) h.update(salt.first, salt.second);
|
2014-01-03 05:18:46 +01:00
|
|
|
return h.final();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool verify_mutable_item(
|
2015-08-07 06:30:29 +02:00
|
|
|
std::pair<char const*, int> v
|
|
|
|
, std::pair<char const*, int> salt
|
2016-06-18 20:01:38 +02:00
|
|
|
, std::uint64_t seq
|
2015-08-07 06:30:29 +02:00
|
|
|
, char const* pk
|
|
|
|
, char const* sig)
|
2013-12-27 05:28:25 +01:00
|
|
|
{
|
|
|
|
char str[canonical_length];
|
2014-01-03 05:18:46 +01:00
|
|
|
int len = canonical_string(v, seq, salt, str);
|
2013-12-27 05:28:25 +01:00
|
|
|
|
2015-08-07 06:30:29 +02:00
|
|
|
return ed25519_verify(reinterpret_cast<unsigned char const*>(sig)
|
|
|
|
, reinterpret_cast<unsigned char const*>(str)
|
|
|
|
, len
|
|
|
|
, reinterpret_cast<unsigned char const*>(pk)) == 1;
|
2013-12-27 05:28:25 +01:00
|
|
|
}
|
|
|
|
|
2014-02-24 01:31:13 +01:00
|
|
|
// given the bencoded buffer ``v``, the salt (which is optional and may have
|
|
|
|
// a length of zero to be omitted), sequence number ``seq``, public key (32
|
|
|
|
// bytes ed25519 key) ``pk`` and a secret/private key ``sk`` (64 bytes ed25519
|
|
|
|
// key) a signature ``sig`` is produced. The ``sig`` pointer must point to
|
|
|
|
// at least 64 bytes of available space. This space is where the signature is
|
|
|
|
// written.
|
2014-01-03 05:18:46 +01:00
|
|
|
void sign_mutable_item(
|
2015-08-07 06:30:29 +02:00
|
|
|
std::pair<char const*, int> v
|
|
|
|
, std::pair<char const*, int> salt
|
2016-06-18 20:01:38 +02:00
|
|
|
, std::uint64_t seq
|
2015-08-07 06:30:29 +02:00
|
|
|
, char const* pk
|
|
|
|
, char const* sk
|
|
|
|
, char* sig)
|
2013-12-27 05:28:25 +01:00
|
|
|
{
|
|
|
|
char str[canonical_length];
|
2014-01-03 05:18:46 +01:00
|
|
|
int len = canonical_string(v, seq, salt, str);
|
2013-12-27 05:28:25 +01:00
|
|
|
|
2015-08-07 06:30:29 +02:00
|
|
|
ed25519_sign(reinterpret_cast<unsigned char*>(sig)
|
|
|
|
, reinterpret_cast<unsigned char const*>(str)
|
|
|
|
, len
|
|
|
|
, reinterpret_cast<unsigned char const*>(pk)
|
|
|
|
, reinterpret_cast<unsigned char const*>(sk)
|
2013-12-27 05:28:25 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2014-03-03 00:35:35 +01:00
|
|
|
item::item(char const* pk, std::string const& salt)
|
2014-03-23 02:41:00 +01:00
|
|
|
: m_salt(salt)
|
2014-03-03 00:35:35 +01:00
|
|
|
, m_seq(0)
|
2014-03-23 02:41:00 +01:00
|
|
|
, m_mutable(true)
|
2014-03-03 00:35:35 +01:00
|
|
|
{
|
|
|
|
memcpy(m_pk.data(), pk, item_pk_len);
|
|
|
|
}
|
|
|
|
|
2014-01-03 05:18:46 +01:00
|
|
|
item::item(entry const& v
|
|
|
|
, std::pair<char const*, int> salt
|
2016-06-18 20:01:38 +02:00
|
|
|
, std::uint64_t seq, char const* pk, char const* sk)
|
2013-12-27 05:28:25 +01:00
|
|
|
{
|
2014-01-03 05:18:46 +01:00
|
|
|
assign(v, salt, seq, pk, sk);
|
2013-12-27 05:28:25 +01:00
|
|
|
}
|
|
|
|
|
2014-01-03 05:18:46 +01:00
|
|
|
void item::assign(entry const& v, std::pair<char const*, int> salt
|
2016-06-18 20:01:38 +02:00
|
|
|
, std::uint64_t seq, char const* pk, char const* sk)
|
2013-12-27 05:28:25 +01:00
|
|
|
{
|
|
|
|
m_value = v;
|
|
|
|
if (pk && sk)
|
|
|
|
{
|
|
|
|
char buffer[1000];
|
|
|
|
int bsize = bencode(buffer, v);
|
|
|
|
TORRENT_ASSERT(bsize <= 1000);
|
2014-01-03 05:18:46 +01:00
|
|
|
sign_mutable_item(std::make_pair(buffer, bsize)
|
2016-05-01 05:10:47 +02:00
|
|
|
, salt, seq, pk, sk, m_sig.data());
|
2014-05-12 09:28:34 +02:00
|
|
|
m_salt.assign(salt.first, salt.second);
|
2016-05-01 05:10:47 +02:00
|
|
|
memcpy(m_pk.data(), pk, item_pk_len);
|
2013-12-27 05:28:25 +01:00
|
|
|
m_seq = seq;
|
|
|
|
m_mutable = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
m_mutable = false;
|
|
|
|
}
|
|
|
|
|
2015-03-12 06:20:12 +01:00
|
|
|
bool item::assign(bdecode_node const& v
|
2014-01-03 05:18:46 +01:00
|
|
|
, std::pair<char const*, int> salt
|
2016-06-18 20:01:38 +02:00
|
|
|
, std::uint64_t seq, char const* pk, char const* sig)
|
2013-12-27 05:28:25 +01:00
|
|
|
{
|
2015-03-12 06:20:12 +01:00
|
|
|
TORRENT_ASSERT(v.data_section().second <= 1000);
|
2013-12-27 05:28:25 +01:00
|
|
|
if (pk && sig)
|
|
|
|
{
|
2015-03-12 06:20:12 +01:00
|
|
|
if (!verify_mutable_item(v.data_section(), salt, seq, pk, sig))
|
2013-12-27 05:28:25 +01:00
|
|
|
return false;
|
2016-05-01 05:10:47 +02:00
|
|
|
memcpy(m_pk.data(), pk, item_pk_len);
|
|
|
|
memcpy(m_sig.data(), sig, item_sig_len);
|
2014-01-03 05:18:46 +01:00
|
|
|
if (salt.second > 0)
|
|
|
|
m_salt.assign(salt.first, salt.second);
|
2014-02-24 01:31:13 +01:00
|
|
|
else
|
|
|
|
m_salt.clear();
|
2013-12-27 05:28:25 +01:00
|
|
|
m_seq = seq;
|
|
|
|
m_mutable = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
m_mutable = false;
|
|
|
|
|
2015-03-12 06:20:12 +01:00
|
|
|
m_value = v;
|
2013-12-27 05:28:25 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-06-18 20:01:38 +02:00
|
|
|
void item::assign(entry const& v, std::string salt, std::uint64_t seq
|
2014-02-24 01:31:13 +01:00
|
|
|
, char const* pk, char const* sig)
|
|
|
|
{
|
2015-10-22 05:26:41 +02:00
|
|
|
#if TORRENT_USE_ASSERTS
|
|
|
|
TORRENT_ASSERT(pk && sig);
|
|
|
|
char buffer[1000];
|
|
|
|
int bsize = bencode(buffer, v);
|
|
|
|
TORRENT_ASSERT(bsize <= 1000);
|
|
|
|
TORRENT_ASSERT(verify_mutable_item(
|
|
|
|
std::make_pair(buffer, bsize)
|
|
|
|
, std::make_pair(salt.data(), int(salt.size()))
|
|
|
|
, seq, pk, sig));
|
|
|
|
#endif
|
|
|
|
|
2016-05-01 05:10:47 +02:00
|
|
|
memcpy(m_pk.data(), pk, item_pk_len);
|
|
|
|
memcpy(m_sig.data(), sig, item_sig_len);
|
2014-02-24 01:31:13 +01:00
|
|
|
m_salt = salt;
|
|
|
|
m_seq = seq;
|
|
|
|
m_mutable = true;
|
|
|
|
m_value = v;
|
|
|
|
}
|
|
|
|
|
2013-12-27 05:28:25 +01:00
|
|
|
} } // namespace libtorrent::dht
|