1 /*
2 
3 Copyright (c) 2013, Steven Siloti
4 All rights reserved.
5 
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
8 are met:
9 
10     * Redistributions of source code must retain the above copyright
11       notice, this list of conditions and the following disclaimer.
12     * Redistributions in binary form must reproduce the above copyright
13       notice, this list of conditions and the following disclaimer in
14       the documentation and/or other materials provided with the distribution.
15     * Neither the name of the author nor the names of its
16       contributors may be used to endorse or promote products derived
17       from this software without specific prior written permission.
18 
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 POSSIBILITY OF SUCH DAMAGE.
30 
31 */
32 
33 #include <libtorrent/hasher.hpp>
34 #include <libtorrent/kademlia/item.hpp>
35 #include <libtorrent/bencode.hpp>
36 #include <libtorrent/kademlia/ed25519.hpp>
37 #include <libtorrent/aux_/numeric_cast.hpp>
38 
39 #include <cstdio> // for snprintf
40 #include <cinttypes> // for PRId64 et.al.
41 #include <algorithm> // for copy
42 
43 #if TORRENT_USE_ASSERTS
44 #include "libtorrent/bdecode.hpp"
45 #endif
46 
47 namespace libtorrent { namespace dht {
48 
49 namespace {
50 
canonical_string(span<char const> v,sequence_number const seq,span<char const> salt,span<char> out)51 	int canonical_string(span<char const> v
52 		, sequence_number const seq
53 		, span<char const> salt
54 		, span<char> out)
55 	{
56 		// v must be valid bencoding!
57 #if TORRENT_USE_ASSERTS
58 		bdecode_node e;
59 		error_code ec;
60 		TORRENT_ASSERT(bdecode(v.data(), v.data() + v.size(), e, ec) == 0);
61 #endif
62 		char* ptr = out.data();
63 
64 		auto left = out.size() - (ptr - out.data());
65 		if (!salt.empty())
66 		{
67 			ptr += std::snprintf(ptr, static_cast<std::size_t>(left), "4:salt%d:", int(salt.size()));
68 			left = out.size() - (ptr - out.data());
69 			std::copy(salt.begin(), salt.begin() + std::min(salt.size(), left), ptr);
70 			ptr += std::min(salt.size(), left);
71 			left = out.size() - (ptr - out.data());
72 		}
73 		ptr += std::snprintf(ptr, static_cast<std::size_t>(left), "3:seqi%" PRId64 "e1:v", seq.value);
74 		left = out.size() - (ptr - out.data());
75 		std::copy(v.begin(), v.begin() + std::min(v.size(), left), ptr);
76 		ptr += std::min(v.size(), left);
77 		TORRENT_ASSERT((ptr - out.data()) <= int(out.size()));
78 		return int(ptr - out.data());
79 	}
80 }
81 
82 // calculate the target hash for an immutable item.
item_target_id(span<char const> v)83 sha1_hash item_target_id(span<char const> v)
84 {
85 	return hasher(v).final();
86 }
87 
88 // calculate the target hash for a mutable item.
item_target_id(span<char const> salt,public_key const & pk)89 sha1_hash item_target_id(span<char const> salt
90 	, public_key const& pk)
91 {
92 	hasher h(pk.bytes);
93 	if (!salt.empty()) h.update(salt);
94 	return h.final();
95 }
96 
verify_mutable_item(span<char const> v,span<char const> salt,sequence_number const seq,public_key const & pk,signature const & sig)97 bool verify_mutable_item(
98 	span<char const> v
99 	, span<char const> salt
100 	, sequence_number const seq
101 	, public_key const& pk
102 	, signature const& sig)
103 {
104 	char str[1200];
105 	int len = canonical_string(v, seq, salt, str);
106 
107 	return ed25519_verify(sig, {str, len}, pk);
108 }
109 
110 // given the bencoded buffer ``v``, the salt (which is optional and may have
111 // a length of zero to be omitted), sequence number ``seq``, public key (32
112 // bytes ed25519 key) ``pk`` and a secret/private key ``sk`` (64 bytes ed25519
113 // key) a signature ``sig`` is produced. The ``sig`` pointer must point to
114 // at least 64 bytes of available space. This space is where the signature is
115 // written.
sign_mutable_item(span<char const> v,span<char const> salt,sequence_number const seq,public_key const & pk,secret_key const & sk)116 signature sign_mutable_item(
117 	span<char const> v
118 	, span<char const> salt
119 	, sequence_number const seq
120 	, public_key const& pk
121 	, secret_key const& sk)
122 {
123 	char str[1200];
124 	int const len = canonical_string(v, seq, salt, str);
125 
126 	return ed25519_sign({str, len}, pk, sk);
127 }
128 
item(public_key const & pk,span<char const> salt)129 item::item(public_key const& pk, span<char const> salt)
130 	: m_salt(salt.data(), static_cast<std::size_t>(salt.size()))
131 	, m_pk(pk)
132 	, m_seq(0)
133 	, m_mutable(true)
134 {}
135 
item(entry v)136 item::item(entry v)
137 	: m_value(std::move(v))
138 	, m_seq(0)
139 	, m_mutable(false)
140 {}
141 
item(bdecode_node const & v)142 item::item(bdecode_node const& v)
143 	: m_seq(0)
144 	, m_mutable(false)
145 {
146 	// TODO: implement ctor for entry from bdecode_node?
147 	m_value = v;
148 }
149 
item(entry v,span<char const> salt,sequence_number const seq,public_key const & pk,secret_key const & sk)150 item::item(entry v, span<char const> salt
151 	, sequence_number const seq, public_key const& pk, secret_key const& sk)
152 {
153 	assign(std::move(v), salt, seq, pk, sk);
154 }
155 
assign(entry v)156 void item::assign(entry v)
157 {
158 	m_mutable = false;
159 	m_value = std::move(v);
160 }
161 
assign(entry v,span<char const> salt,sequence_number const seq,public_key const & pk,secret_key const & sk)162 void item::assign(entry v, span<char const> salt
163 	, sequence_number const seq, public_key const& pk, secret_key const& sk)
164 {
165 	std::array<char, 1000> buffer;
166 	int const bsize = bencode(buffer.begin(), v);
167 	TORRENT_ASSERT(bsize <= 1000);
168 	m_sig = sign_mutable_item(span<char const>(buffer).first(bsize)
169 		, salt, seq, pk, sk);
170 	m_salt.assign(salt.data(), static_cast<std::size_t>(salt.size()));
171 	m_pk = pk;
172 	m_seq = seq;
173 	m_mutable = true;
174 	m_value = std::move(v);
175 }
176 
assign(bdecode_node const & v)177 void item::assign(bdecode_node const& v)
178 {
179 	m_mutable = false;
180 	m_value = v;
181 }
182 
assign(bdecode_node const & v,span<char const> salt,sequence_number const seq,public_key const & pk,signature const & sig)183 bool item::assign(bdecode_node const& v, span<char const> salt
184 	, sequence_number const seq, public_key const& pk, signature const& sig)
185 {
186 	TORRENT_ASSERT(v.data_section().size() <= 1000);
187 	if (!verify_mutable_item(v.data_section(), salt, seq, pk, sig))
188 		return false;
189 	m_pk = pk;
190 	m_sig = sig;
191 	if (!salt.empty())
192 		m_salt.assign(salt.data(), static_cast<std::size_t>(salt.size()));
193 	else
194 		m_salt.clear();
195 	m_seq = seq;
196 	m_mutable = true;
197 
198 	m_value = v;
199 	return true;
200 }
201 
assign(entry v,span<char const> salt,sequence_number const seq,public_key const & pk,signature const & sig)202 void item::assign(entry v, span<char const> salt
203 	, sequence_number const seq
204 	, public_key const& pk, signature const& sig)
205 {
206 
207 	m_pk = pk;
208 	m_sig = sig;
209 	m_salt.assign(salt.data(), static_cast<std::size_t>(salt.size()));
210 	m_seq = seq;
211 	m_mutable = true;
212 	m_value = std::move(v);
213 }
214 
215 } } // namespace libtorrent::dht
216