/* 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 #include #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 buf(static_cast(buf_len)); std::vector cmp_buf(static_cast(buf_len)); lt::aux::random_bytes(buf); std::copy(buf.begin(), buf.end(), cmp_buf.begin()); using namespace lt::aux; { lt::span 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 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 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 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