Files
libtorrent/test/test_pe_crypto.cpp
2026-05-10 13:35:58 +02:00

170 lines
4.2 KiB
C++

/*
Copyright (c) 2007, Un Shyam
Copyright (c) 2007, 2011, 2013, 2015-2021, Arvid Norberg
Copyright (c) 2016, 2018, 2020-2021, Alden Torres
Copyright (c) 2018, Steven Siloti
All rights reserved.
You may use, distribute and modify this code under the terms of the BSD license,
see LICENSE file.
*/
#include <algorithm>
#include <iostream>
#include "libtorrent/hasher.hpp"
#include "libtorrent/aux_/pe_crypto.hpp"
#include "libtorrent/aux_/random.hpp"
#include "libtorrent/span.hpp"
#include "test.hpp"
#if !defined TORRENT_DISABLE_ENCRYPTION
namespace {
void test_enc_handler(lt::crypto_plugin& a, lt::crypto_plugin& b)
{
int const repcount = 128;
for (int rep = 0; rep < repcount; ++rep)
{
std::ptrdiff_t const buf_len = lt::aux::random(512 * 1024);
std::vector<char> buf(static_cast<std::size_t>(buf_len));
std::vector<char> cmp_buf(static_cast<std::size_t>(buf_len));
lt::aux::random_bytes(buf);
std::copy(buf.begin(), buf.end(), cmp_buf.begin());
using namespace lt::aux;
{
lt::span<char> iovec(buf.data(), buf_len);
auto const [next_barrier, iovec_out] = a.encrypt(iovec);
TEST_CHECK(buf != cmp_buf);
TEST_EQUAL(iovec_out.size(), 0);
TEST_EQUAL(next_barrier, int(buf_len));
}
{
lt::span<char> iovec(buf.data(), buf_len);
auto const [consume, produce, packet_size] = b.decrypt(iovec);
TEST_CHECK(buf == cmp_buf);
TEST_EQUAL(consume, 0);
TEST_EQUAL(produce, int(buf_len));
TEST_EQUAL(packet_size, 0);
}
{
lt::span<char> iovec(buf.data(), buf_len);
auto const [next_barrier, iovec_out] = b.encrypt(iovec);
TEST_EQUAL(iovec_out.size(), 0);
TEST_CHECK(buf != cmp_buf);
TEST_EQUAL(next_barrier, int(buf_len));
lt::span<char> iovec2(buf.data(), buf_len);
auto const [consume, produce, packet_size] = a.decrypt(iovec2);
TEST_CHECK(buf == cmp_buf);
TEST_EQUAL(consume, 0);
TEST_EQUAL(produce, int(buf_len));
TEST_EQUAL(packet_size, 0);
}
}
}
} // anonymous namespace
TORRENT_TEST(diffie_hellman)
{
using namespace lt;
const int repcount = 128;
for (int rep = 0; rep < repcount; ++rep)
{
aux::dh_key_exchange DH1, DH2;
TEST_CHECK(DH1.compute_secret(DH2.get_local_key()));
TEST_CHECK(DH2.compute_secret(DH1.get_local_key()));
TEST_EQUAL(DH1.get_secret(), DH2.get_secret());
if (!DH1.get_secret() != DH2.get_secret())
{
std::printf("DH1 local: ");
std::cout << DH1.get_local_key() << std::endl;
std::printf("DH2 local: ");
std::cout << DH2.get_local_key() << std::endl;
std::printf("DH1 shared_secret: ");
std::cout << DH1.get_secret() << std::endl;
std::printf("DH2 shared_secret: ");
std::cout << DH2.get_secret() << std::endl;
}
}
}
TORRENT_TEST(diffie_hellman_degenerate_key)
{
// MODP DH prime (BEP 8) used by dh_key_exchange. The generator is 2.
lt::aux::key_t const dh_prime(
"0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020"
"BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D"
"6D51C245E485B576625E7EC6F44C42E9A63A36210000000000090563");
// public keys outside [2, p-2] are degenerate and must be rejected.
// Otherwise an attacker can fix the shared secret to a small set of
// known values, defeating the encryption.
{
lt::aux::dh_key_exchange dh;
TEST_CHECK(!dh.compute_secret(lt::aux::key_t(0)));
}
{
lt::aux::dh_key_exchange dh;
TEST_CHECK(!dh.compute_secret(lt::aux::key_t(1)));
}
{
lt::aux::dh_key_exchange dh;
TEST_CHECK(!dh.compute_secret(dh_prime - 1));
}
{
lt::aux::dh_key_exchange dh;
TEST_CHECK(!dh.compute_secret(dh_prime));
}
// boundary values inside the valid range must be accepted.
{
lt::aux::dh_key_exchange dh;
TEST_CHECK(dh.compute_secret(lt::aux::key_t(2)));
}
{
lt::aux::dh_key_exchange dh;
TEST_CHECK(dh.compute_secret(dh_prime - 2));
}
}
TORRENT_TEST(rc4)
{
using namespace lt;
sha1_hash test1_key = hasher("test1_key",8).final();
sha1_hash test2_key = hasher("test2_key",8).final();
std::printf("testing RC4 handler\n");
aux::rc4_handler rc41;
rc41.set_incoming_key(test2_key);
rc41.set_outgoing_key(test1_key);
aux::rc4_handler rc42;
rc42.set_incoming_key(test1_key);
rc42.set_outgoing_key(test2_key);
test_enc_handler(rc41, rc42);
}
#else
TORRENT_TEST(disabled)
{
std::printf("PE test not run because it's disabled\n");
}
#endif