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