mirror of
https://github.com/transmission/transmission.git
synced 2025-12-19 18:08:31 +00:00
Add basic support for v2 hashes in transmission-show (#3380)
* Add basic support for v2 hashes in transmission-show
* Add sha256 for more libraries
* Fix issue with sha256 digest length
* Add sha256 for polarssl
Note: Bumping miniumum PolarSSL version to 1.3 because of
sha2->sha256 name change.
* Add sha256 for CommonCrypto/ccrypto
* Add sha256 for cyassl
This commit is contained in:
@@ -124,7 +124,7 @@ set(GLIB_MINIMUM 2.50.1)
|
||||
set(GTK_MINIMUM 3.24.0)
|
||||
set(LIBAPPINDICATOR_MINIMUM 0.4.90)
|
||||
set(OPENSSL_MINIMUM 0.9.7)
|
||||
set(POLARSSL_MINIMUM 1.2)
|
||||
set(POLARSSL_MINIMUM 1.3)
|
||||
set(QT_MINIMUM 5.6)
|
||||
|
||||
if(WIN32)
|
||||
|
||||
@@ -179,6 +179,45 @@ std::optional<tr_sha1_digest_t> tr_sha1_final(tr_sha1_ctx_t raw_handle)
|
||||
****
|
||||
***/
|
||||
|
||||
tr_sha256_ctx_t tr_sha256_init(void)
|
||||
{
|
||||
auto* handle = new CC_SHA256_CTX();
|
||||
CC_SHA256_Init(handle);
|
||||
return handle;
|
||||
}
|
||||
|
||||
bool tr_sha256_update(tr_sha256_ctx_t handle, void const* data, size_t data_length)
|
||||
{
|
||||
TR_ASSERT(handle != nullptr);
|
||||
|
||||
if (data_length == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
TR_ASSERT(data != nullptr);
|
||||
|
||||
CC_SHA256_Update(static_cast<CC_SHA256_CTX*>(handle), data, data_length);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<tr_sha256_digest_t> tr_sha256_final(tr_sha256_ctx_t raw_handle)
|
||||
{
|
||||
TR_ASSERT(raw_handle != nullptr);
|
||||
auto* handle = static_cast<CC_SHA256_CTX*>(raw_handle);
|
||||
|
||||
auto digest = tr_sha256_digest_t{};
|
||||
auto* const digest_as_uchar = reinterpret_cast<unsigned char*>(std::data(digest));
|
||||
CC_SHA256_Final(digest_as_uchar, handle);
|
||||
|
||||
delete handle;
|
||||
return digest;
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include API_HEADER_CRYPT(error-crypt.h)
|
||||
#include API_HEADER_CRYPT(random.h)
|
||||
#include API_HEADER_CRYPT(sha.h)
|
||||
#include API_HEADER_CRYPT(sha256.h)
|
||||
#include API_HEADER(version.h)
|
||||
|
||||
#include <fmt/core.h>
|
||||
@@ -160,6 +161,51 @@ std::optional<tr_sha1_digest_t> tr_sha1_final(tr_sha1_ctx_t raw_handle)
|
||||
****
|
||||
***/
|
||||
|
||||
tr_sha256_ctx_t tr_sha256_init(void)
|
||||
{
|
||||
Sha256* handle = tr_new(Sha256, 1);
|
||||
|
||||
if (check_result(API(InitSha256)(handle)))
|
||||
{
|
||||
return handle;
|
||||
}
|
||||
|
||||
tr_free(handle);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool tr_sha256_update(tr_sha256_ctx_t raw_handle, void const* data, size_t data_length)
|
||||
{
|
||||
auto* handle = static_cast<Sha256*>(raw_handle);
|
||||
TR_ASSERT(handle != nullptr);
|
||||
|
||||
if (data_length == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
TR_ASSERT(data != nullptr);
|
||||
|
||||
return check_result(API(Sha256Update)(handle, static_cast<byte const*>(data), data_length));
|
||||
}
|
||||
|
||||
std::optional<tr_sha256_digest_t> tr_sha256_final(tr_sha256_ctx_t raw_handle)
|
||||
{
|
||||
auto* handle = static_cast<Sha256*>(raw_handle);
|
||||
TR_ASSERT(handle != nullptr);
|
||||
|
||||
auto digest = tr_sha256_digest_t{};
|
||||
auto* const digest_as_uchar = reinterpret_cast<unsigned char*>(std::data(digest));
|
||||
auto const ok = check_result(API(Sha256Final)(handle, digest_as_uchar));
|
||||
tr_free(handle);
|
||||
|
||||
return ok ? std::make_optional(digest) : std::nullopt;
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
||||
tr_dh_ctx_t tr_dh_new(
|
||||
uint8_t const* prime_num,
|
||||
size_t prime_num_length,
|
||||
|
||||
@@ -154,6 +154,54 @@ std::optional<tr_sha1_digest_t> tr_sha1_final(tr_sha1_ctx_t raw_handle)
|
||||
****
|
||||
***/
|
||||
|
||||
tr_sha256_ctx_t tr_sha256_init()
|
||||
{
|
||||
EVP_MD_CTX* handle = EVP_MD_CTX_create();
|
||||
|
||||
if (check_result(EVP_DigestInit_ex(handle, EVP_sha256(), nullptr)))
|
||||
{
|
||||
return handle;
|
||||
}
|
||||
|
||||
EVP_MD_CTX_destroy(handle);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool tr_sha256_update(tr_sha256_ctx_t raw_handle, void const* data, size_t data_length)
|
||||
{
|
||||
auto* const handle = static_cast<EVP_MD_CTX*>(raw_handle);
|
||||
|
||||
TR_ASSERT(handle != nullptr);
|
||||
|
||||
if (data_length == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
TR_ASSERT(data != nullptr);
|
||||
|
||||
return check_result(EVP_DigestUpdate(handle, data, data_length));
|
||||
}
|
||||
|
||||
std::optional<tr_sha256_digest_t> tr_sha256_final(tr_sha1_ctx_t raw_handle)
|
||||
{
|
||||
auto* handle = static_cast<EVP_MD_CTX*>(raw_handle);
|
||||
TR_ASSERT(handle != nullptr);
|
||||
|
||||
unsigned int hash_length = 0;
|
||||
auto digest = tr_sha256_digest_t{};
|
||||
auto* const digest_as_uchar = reinterpret_cast<unsigned char*>(std::data(digest));
|
||||
bool const ok = check_result(EVP_DigestFinal_ex(handle, digest_as_uchar, &hash_length));
|
||||
TR_ASSERT(!ok || hash_length == std::size(digest));
|
||||
|
||||
EVP_MD_CTX_destroy(handle);
|
||||
return ok ? std::make_optional(digest) : std::nullopt;
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < 0x0090802fL
|
||||
|
||||
static EVP_CIPHER_CTX* openssl_evp_cipher_context_new(void)
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include API_HEADER(dhm.h)
|
||||
#include API_HEADER(error.h)
|
||||
#include API_HEADER(sha1.h)
|
||||
#include API_HEADER(sha256.h)
|
||||
#include API_HEADER(version.h)
|
||||
|
||||
#include <fmt/core.h>
|
||||
@@ -40,6 +41,7 @@
|
||||
|
||||
using api_ctr_drbg_context = API(ctr_drbg_context);
|
||||
using api_sha1_context = API(sha1_context);
|
||||
using api_sha256_context = API(sha256_context);
|
||||
using api_dhm_context = API(dhm_context);
|
||||
|
||||
static void log_polarssl_error(int error_code, char const* file, int line)
|
||||
@@ -178,6 +180,54 @@ std::optional<tr_sha1_digest_t> tr_sha1_final(tr_sha1_ctx_t raw_handle)
|
||||
****
|
||||
***/
|
||||
|
||||
tr_sha256_ctx_t tr_sha256_init(void)
|
||||
{
|
||||
api_sha256_context* handle = tr_new0(api_sha256_context, 1);
|
||||
|
||||
#if API_VERSION_NUMBER >= 0x01030800
|
||||
API(sha256_init)(handle);
|
||||
#endif
|
||||
|
||||
API(sha256_starts)(handle, 0);
|
||||
return handle;
|
||||
}
|
||||
|
||||
bool tr_sha256_update(tr_sha256_ctx_t raw_handle, void const* data, size_t data_length)
|
||||
{
|
||||
auto* handle = static_cast<api_sha256_context*>(raw_handle);
|
||||
TR_ASSERT(handle != nullptr);
|
||||
|
||||
if (data_length == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
TR_ASSERT(data != nullptr);
|
||||
|
||||
API(sha256_update)(handle, static_cast<unsigned char const*>(data), data_length);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<tr_sha256_digest_t> tr_sha256_final(tr_sha256_ctx_t raw_handle)
|
||||
{
|
||||
auto* handle = static_cast<api_sha256_context*>(raw_handle);
|
||||
TR_ASSERT(handle != nullptr);
|
||||
|
||||
auto digest = tr_sha256_digest_t{};
|
||||
auto* const digest_as_uchar = reinterpret_cast<unsigned char*>(std::data(digest));
|
||||
API(sha256_finish)(handle, digest_as_uchar);
|
||||
#if API_VERSION_NUMBER >= 0x01030800
|
||||
API(sha256_free)(handle);
|
||||
#endif
|
||||
|
||||
tr_free(handle);
|
||||
return digest;
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
||||
tr_dh_ctx_t tr_dh_new(
|
||||
uint8_t const* prime_num,
|
||||
size_t prime_num_length,
|
||||
|
||||
@@ -205,6 +205,13 @@ std::string tr_sha1_to_string(tr_sha1_digest_t const& digest)
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string tr_sha256_to_string(tr_sha256_digest_t const& digest)
|
||||
{
|
||||
auto str = std::string(std::size(digest) * 2, '?');
|
||||
tr_binary_to_hex(std::data(digest), std::data(str), std::size(digest));
|
||||
return str;
|
||||
}
|
||||
|
||||
static void tr_hex_to_binary(char const* input, void* voutput, size_t byte_length)
|
||||
{
|
||||
static char constexpr Hex[] = "0123456789abcdef";
|
||||
@@ -235,3 +242,20 @@ std::optional<tr_sha1_digest_t> tr_sha1_from_string(std::string_view hex)
|
||||
tr_hex_to_binary(std::data(hex), std::data(digest), std::size(digest));
|
||||
return digest;
|
||||
}
|
||||
|
||||
std::optional<tr_sha256_digest_t> tr_sha256_from_string(std::string_view hex)
|
||||
{
|
||||
if (std::size(hex) != TR_SHA256_DIGEST_STRLEN)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!std::all_of(std::begin(hex), std::end(hex), [](unsigned char ch) { return isxdigit(ch); }))
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
auto digest = tr_sha256_digest_t{};
|
||||
tr_hex_to_binary(std::data(hex), std::data(digest), std::size(digest));
|
||||
return digest;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
|
||||
/** @brief Opaque SHA1 context type. */
|
||||
using tr_sha1_ctx_t = void*;
|
||||
/** @brief Opaque SHA256 context type. */
|
||||
using tr_sha256_ctx_t = void*;
|
||||
/** @brief Opaque DH context type. */
|
||||
using tr_dh_ctx_t = void*;
|
||||
/** @brief Opaque DH secret key type. */
|
||||
@@ -70,6 +72,44 @@ std::optional<tr_sha1_digest_t> tr_sha1(T... args)
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allocate and initialize new SHA256 hasher context.
|
||||
*/
|
||||
tr_sha256_ctx_t tr_sha256_init(void);
|
||||
|
||||
/**
|
||||
* @brief Update SHA256 hash.
|
||||
*/
|
||||
bool tr_sha256_update(tr_sha256_ctx_t handle, void const* data, size_t data_length);
|
||||
|
||||
/**
|
||||
* @brief Finalize and export SHA256 hash, free hasher context.
|
||||
*/
|
||||
std::optional<tr_sha256_digest_t> tr_sha256_final(tr_sha256_ctx_t handle);
|
||||
|
||||
/**
|
||||
* @brief generate a SHA256 hash from some memory
|
||||
*/
|
||||
template<typename... T>
|
||||
std::optional<tr_sha256_digest_t> tr_sha256(T... args)
|
||||
{
|
||||
auto ctx = tr_sha256_init();
|
||||
if (ctx == nullptr)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if ((tr_sha256_update(ctx, std::data(args), std::size(args)) && ...))
|
||||
{
|
||||
return tr_sha256_final(ctx);
|
||||
}
|
||||
|
||||
// one of the update() calls failed so we will return nullopt,
|
||||
// but we need to call final() first to ensure ctx is released
|
||||
tr_sha256_final(ctx);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allocate and initialize new Diffie-Hellman (DH) key exchange context.
|
||||
*/
|
||||
@@ -186,10 +226,20 @@ std::string tr_base64_decode(std::string_view input);
|
||||
std::string tr_sha1_to_string(tr_sha1_digest_t const&);
|
||||
|
||||
/**
|
||||
* @brief Generate a sha1 digest from a hex string.
|
||||
* @brief Generate a sha256 digest from a hex string.
|
||||
*/
|
||||
std::optional<tr_sha1_digest_t> tr_sha1_from_string(std::string_view hex);
|
||||
|
||||
/**
|
||||
* @brief Generate an ascii hex string for a sha256 digest.
|
||||
*/
|
||||
std::string tr_sha256_to_string(tr_sha256_digest_t const&);
|
||||
|
||||
/**
|
||||
* @brief Generate a sha256 digest from a hex string.
|
||||
*/
|
||||
std::optional<tr_sha256_digest_t> tr_sha256_from_string(std::string_view hex);
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif /* TR_CRYPTO_UTILS_H */
|
||||
|
||||
@@ -151,6 +151,19 @@ std::optional<tr_sha1_digest_t> parseHash(std::string_view sv)
|
||||
return {};
|
||||
}
|
||||
|
||||
std::optional<tr_sha256_digest_t> parseHash2(std::string_view sv)
|
||||
{
|
||||
// http://bittorrent.org/beps/bep_0009.html
|
||||
// Is the info-hash v2 hex encoded and tag removed, for a total of 64 characters.
|
||||
|
||||
if (auto const hash = tr_sha256_from_string(sv); hash)
|
||||
{
|
||||
return hash;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
/***
|
||||
@@ -237,12 +250,22 @@ bool tr_magnet_metainfo::parseMagnet(std::string_view magnet_link, tr_error** er
|
||||
}
|
||||
else if (static auto constexpr ValPrefix = "urn:btih:"sv; key == "xt"sv && tr_strvStartsWith(value, ValPrefix))
|
||||
{
|
||||
// v1 info-hash
|
||||
if (auto const hash = parseHash(value.substr(std::size(ValPrefix))); hash)
|
||||
{
|
||||
this->info_hash_ = *hash;
|
||||
got_hash = true;
|
||||
}
|
||||
}
|
||||
else if (static auto constexpr ValPrefix2 = "urn:btmh:1220"sv; key == "xt"sv && tr_strvStartsWith(value, ValPrefix2))
|
||||
{
|
||||
// v2 info-hash
|
||||
// The 1220 tag identifies the hash as sha256, removing tag before sending to parseHash2
|
||||
if (auto const hash = parseHash2(value.substr(std::size(ValPrefix2))); hash)
|
||||
{
|
||||
this->info_hash2_ = *hash;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
info_hash_str_ = tr_sha1_to_string(this->infoHash());
|
||||
|
||||
@@ -62,6 +62,11 @@ public:
|
||||
return info_hash_str_;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr std::string const& infoHash2String() const noexcept
|
||||
{
|
||||
return info_hash2_str_;
|
||||
}
|
||||
|
||||
void setName(std::string_view name)
|
||||
{
|
||||
name_ = name;
|
||||
@@ -73,6 +78,8 @@ protected:
|
||||
tr_announce_list announce_list_;
|
||||
std::vector<std::string> webseed_urls_;
|
||||
tr_sha1_digest_t info_hash_ = {};
|
||||
tr_sha256_digest_t info_hash2_ = {};
|
||||
std::string info_hash_str_;
|
||||
std::string info_hash2_str_;
|
||||
std::string name_;
|
||||
};
|
||||
|
||||
@@ -344,6 +344,7 @@ struct MetainfoHandler final : public transmission::benc::BasicHandler<MaxBencDe
|
||||
{
|
||||
// currently unused. TODO support for bittorrent v2
|
||||
// TODO https://github.com/transmission/transmission/issues/458
|
||||
tm_.is_v2_ = value == 2;
|
||||
}
|
||||
else if (
|
||||
pathIs(DurationKey) || //
|
||||
@@ -582,6 +583,7 @@ private:
|
||||
char const* const end = &context.raw().back() + 1;
|
||||
auto const info_dict_benc = std::string_view{ begin, size_t(end - begin) };
|
||||
auto const hash = tr_sha1(info_dict_benc);
|
||||
auto const hash2 = tr_sha256(info_dict_benc);
|
||||
if (!hash)
|
||||
{
|
||||
tr_error_set(context.error, EINVAL, "bad info_dict checksum");
|
||||
@@ -590,6 +592,8 @@ private:
|
||||
|
||||
tm_.info_hash_ = *hash;
|
||||
tm_.info_hash_str_ = tr_sha1_to_string(tm_.info_hash_);
|
||||
tm_.info_hash2_ = *hash2;
|
||||
tm_.info_hash2_str_ = tr_sha256_to_string(tm_.info_hash2_);
|
||||
tm_.info_dict_size_ = std::size(info_dict_benc);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -130,6 +130,18 @@ public:
|
||||
|
||||
[[nodiscard]] tr_sha1_digest_t const& pieceHash(tr_piece_index_t piece) const;
|
||||
|
||||
[[nodiscard]] bool hasV1Metadata() const
|
||||
{
|
||||
// need 'pieces' field and 'files' or 'length'
|
||||
// TODO check for 'files' or 'length'
|
||||
return pieces_.size() > 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool hasV2Metadata() const
|
||||
{
|
||||
return is_v2_;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr auto const& dateCreated() const noexcept
|
||||
{
|
||||
return date_created_;
|
||||
@@ -231,4 +243,5 @@ private:
|
||||
uint64_t pieces_offset_ = 0;
|
||||
|
||||
bool is_private_ = false;
|
||||
bool is_v2_ = false;
|
||||
};
|
||||
|
||||
@@ -103,3 +103,8 @@ auto inline constexpr TR_SHA1_DIGEST_LEN = size_t{ 20 };
|
||||
auto inline constexpr TR_SHA1_DIGEST_STRLEN = size_t{ 40 };
|
||||
using tr_sha1_digest_t = std::array<std::byte, TR_SHA1_DIGEST_LEN>;
|
||||
using tr_sha1_digest_string_t = std::array<char, TR_SHA1_DIGEST_STRLEN + 1>; // +1 for '\0'
|
||||
|
||||
auto inline constexpr TR_SHA256_DIGEST_LEN = size_t{ 32 };
|
||||
auto inline constexpr TR_SHA256_DIGEST_STRLEN = size_t{ 64 };
|
||||
using tr_sha256_digest_t = std::array<std::byte, TR_SHA256_DIGEST_LEN>;
|
||||
using tr_sha256_digest_string_t = std::array<char, TR_SHA256_DIGEST_STRLEN + 1>; // +1 for '\0'
|
||||
|
||||
@@ -58,6 +58,13 @@
|
||||
#define tr_base64_decode_impl tr_base64_decode_impl_
|
||||
#define tr_sha1_to_string tr_sha1_to_string_
|
||||
#define tr_sha1_from_string tr_sha1_from_string_
|
||||
#define tr_sha256 tr_sha256_
|
||||
#define tr_sha256_ctx_t tr_sha256_ctx_t_
|
||||
#define tr_sha256_final tr_sha256_final_
|
||||
#define tr_sha256_from_string tr_sha256_from_string_
|
||||
#define tr_sha256_init tr_sha256_init_
|
||||
#define tr_sha256_to_string tr_sha256_to_string_
|
||||
#define tr_sha256_update tr_sha256_update_
|
||||
|
||||
#undef TR_ENCRYPTION_H
|
||||
#undef TR_CRYPTO_UTILS_H
|
||||
@@ -116,6 +123,13 @@
|
||||
#undef tr_base64_decode_impl
|
||||
#undef tr_sha1_to_string
|
||||
#undef tr_sha1_from_string
|
||||
#undef tr_sha256
|
||||
#undef tr_sha256_ctx_t
|
||||
#undef tr_sha256_final
|
||||
#undef tr_sha256_from_string
|
||||
#undef tr_sha256_init
|
||||
#undef tr_sha256_to_string
|
||||
#undef tr_sha256_update
|
||||
|
||||
#else /* CRYPTO_REFERENCE_CHECK */
|
||||
|
||||
@@ -167,6 +181,13 @@
|
||||
#define tr_base64_decode_impl_ tr_base64_decode_impl
|
||||
#define tr_sha1_to_string_ tr_sha1_to_string
|
||||
#define tr_sha1_from_string_ tr_sha1_from_string
|
||||
#define tr_sha256_ tr_sha256
|
||||
#define tr_sha256_ctx_t_ tr_sha256_ctx_t
|
||||
#define tr_sha256_final_ tr_sha256_final
|
||||
#define tr_sha256_from_string_ tr_sha256_from_string
|
||||
#define tr_sha256_init_ tr_sha256_init
|
||||
#define tr_sha256_to_string_ tr_sha256_to_string
|
||||
#define tr_sha256_update_ tr_sha256_update
|
||||
|
||||
#endif /* CRYPTO_REFERENCE_CHECK */
|
||||
|
||||
|
||||
@@ -199,6 +199,30 @@ TEST(Crypto, sha1FromString)
|
||||
EXPECT_EQ(*lc, *uc);
|
||||
}
|
||||
|
||||
TEST(Crypto, sha256FromString)
|
||||
{
|
||||
// bad lengths
|
||||
EXPECT_FALSE(tr_sha256_from_string(""));
|
||||
EXPECT_FALSE(tr_sha256_from_string("a94a8fe5ccb19ba61c4c0873d391e987982fbbd"sv));
|
||||
EXPECT_FALSE(tr_sha256_from_string("a94a8fe5ccb19ba61c4c0873d391e987982fbbd33"sv));
|
||||
EXPECT_FALSE(tr_sha256_from_string("05d58dfd14ed21d33add137eb7a2c5d4ef5aaa4a945e654363d32b7c4bf5c92"sv));
|
||||
EXPECT_FALSE(tr_sha256_from_string("05d58dfd14ed21d33add137eb7a2c5d4ef5aaa4a945e654363d32b7c4bf5c9299"sv));
|
||||
// nonhex
|
||||
EXPECT_FALSE(tr_sha256_from_string("a94a8fe5ccb19ba61c4cz873d391e987982fbbd3aaaaaaaaaaaaaaaaaaaaaaa"sv));
|
||||
EXPECT_FALSE(tr_sha256_from_string("05 8dfd14ed21d33add137eb7a2c5d4ef5aaa4a945e654363d32b7c4bf5c92"sv));
|
||||
|
||||
// lowercase hex
|
||||
auto const baseline = "05d58dfd14ed21d33add137eb7a2c5d4ef5aaa4a945e654363d32b7c4bf5c929"sv;
|
||||
auto const lc = tr_sha256_from_string(baseline);
|
||||
EXPECT_TRUE(lc);
|
||||
EXPECT_EQ(baseline, tr_sha256_to_string(*lc));
|
||||
|
||||
// uppercase hex should yield the same result
|
||||
auto const uc = tr_sha256_from_string(tr_strupper(baseline));
|
||||
EXPECT_TRUE(uc);
|
||||
EXPECT_EQ(*lc, *uc);
|
||||
}
|
||||
|
||||
TEST(Crypto, random)
|
||||
{
|
||||
/* test that tr_rand_int() stays in-bounds */
|
||||
|
||||
@@ -11,6 +11,7 @@ function(AddShowTest name file_basename)
|
||||
endfunction()
|
||||
|
||||
AddShowTest(transmission-show-bittorrent-v2 bittorrent-v2-test)
|
||||
AddShowTest(transmission-show-bittorrent-v2-hybrid-test bittorrent-v2-hybrid-test)
|
||||
AddShowTest(transmission-show-inner-sanctum Inner_Sanctum_movie_archive)
|
||||
AddShowTest(transmission-show-thor Thor_and_the_Amazon_Women.avi)
|
||||
AddShowTest(transmission-show-ubuntu ubuntu-20.04.3-desktop-amd64.iso)
|
||||
|
||||
@@ -4,7 +4,7 @@ File: assets/Inner_Sanctum_movie_archive.torrent
|
||||
GENERAL
|
||||
|
||||
Name: Inner_Sanctum_movie
|
||||
Hash: f735d5be075bdb8832e29c96e80e53fdace6178b
|
||||
Hash v1: f735d5be075bdb8832e29c96e80e53fdace6178b
|
||||
Created by: ia_make_torrent
|
||||
Created on: Sat Oct 27 00:56:24 2018
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ File: assets/Thor_and_the_Amazon_Women.avi.torrent
|
||||
GENERAL
|
||||
|
||||
Name: Thor_and_the_Amazon_Women.avi
|
||||
Hash: 43fdd3e72588e9119c9c94c54332ee533cf80bd6
|
||||
Hash v1: 43fdd3e72588e9119c9c94c54332ee533cf80bd6
|
||||
Created by: Azureus/2.5.0.2
|
||||
Created on: Mon Jan 22 00:57:20 2007
|
||||
|
||||
|
||||
30
tests/utils/assets/bittorrent-v2-hybrid-test.show
Normal file
30
tests/utils/assets/bittorrent-v2-hybrid-test.show
Normal file
@@ -0,0 +1,30 @@
|
||||
Name: bittorrent-v1-v2-hybrid-test
|
||||
File: assets/bittorrent-v2-hybrid-test.torrent
|
||||
|
||||
GENERAL
|
||||
|
||||
Name: bittorrent-v1-v2-hybrid-test
|
||||
Hash v1: 631a31dd0a46257d5078c0dee4e66e26f73e42ac
|
||||
Hash v2: d8dd32ac93357c368556af3ac1d95c9d76bd0dff6fa9833ecdac3d53134efabb
|
||||
Created by: libtorrent
|
||||
Created on: Wed Jun 03 08:45:06 2020
|
||||
|
||||
Piece Count: 1709
|
||||
Piece Size: 512.0 KiB
|
||||
Total Size: 895.5 MB
|
||||
Privacy: Public torrent
|
||||
|
||||
TRACKERS
|
||||
|
||||
FILES
|
||||
|
||||
bittorrent-v1-v2-hybrid-test/Darkroom (Stellar, 1994, Amiga ECS) HQ.mp4 (6.54 MB)
|
||||
bittorrent-v1-v2-hybrid-test/Spaceballs-StateOfTheArt.avi (20.51 MB)
|
||||
bittorrent-v1-v2-hybrid-test/cncd_fairlight-ceasefire_(all_falls_down)-1080p.mp4 (342.2 MB)
|
||||
bittorrent-v1-v2-hybrid-test/eld-dust.mkv (61.64 MB)
|
||||
bittorrent-v1-v2-hybrid-test/fairlight_cncd-agenda_circling_forth-1080p30lq.mp4 (277.9 MB)
|
||||
bittorrent-v1-v2-hybrid-test/meet the deadline - Still _ Evoke 2014.mp4 (44.58 MB)
|
||||
bittorrent-v1-v2-hybrid-test/readme.txt (0.06 kB)
|
||||
bittorrent-v1-v2-hybrid-test/tbl-goa.avi (26.30 MB)
|
||||
bittorrent-v1-v2-hybrid-test/tbl-tint.mpg (115.9 MB)
|
||||
|
||||
BIN
tests/utils/assets/bittorrent-v2-hybrid-test.torrent
Normal file
BIN
tests/utils/assets/bittorrent-v2-hybrid-test.torrent
Normal file
Binary file not shown.
@@ -4,7 +4,7 @@ File: assets/bittorrent-v2-test.torrent
|
||||
GENERAL
|
||||
|
||||
Name: bittorrent-v2-test
|
||||
Hash: f987ab6bb50f831a861c3754ecd1b47dc2cf2e30
|
||||
Hash v2: caf1e1c30e81cb361b9ee167c4aa64228a7fa4fa9f6105232b28ad099f3a302e
|
||||
Created by: libtorrent
|
||||
Created on: Thu May 21 21:40:57 2020
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ File: assets/ubuntu-20.04.3-desktop-amd64.iso.torrent
|
||||
GENERAL
|
||||
|
||||
Name: ubuntu-20.04.3-desktop-amd64.iso
|
||||
Hash: b26c81363ac1a236765385a702aec107a49581b5
|
||||
Hash v1: b26c81363ac1a236765385a702aec107a49581b5
|
||||
Created by: mktorrent 1.1
|
||||
Created on: Thu Aug 26 09:42:51 2021
|
||||
|
||||
|
||||
@@ -193,7 +193,14 @@ void showInfo(app_opts const& opts, tr_torrent_metainfo const& metainfo)
|
||||
{
|
||||
printf("GENERAL\n\n");
|
||||
printf(" Name: %s\n", metainfo.name().c_str());
|
||||
printf(" Hash: %" TR_PRIsv "\n", TR_PRIsv_ARG(metainfo.infoHashString()));
|
||||
if (metainfo.hasV1Metadata())
|
||||
{
|
||||
printf(" Hash v1: %" TR_PRIsv "\n", TR_PRIsv_ARG(metainfo.infoHashString()));
|
||||
}
|
||||
if (metainfo.hasV2Metadata())
|
||||
{
|
||||
printf(" Hash v2: %" TR_PRIsv "\n", TR_PRIsv_ARG(metainfo.infoHash2String()));
|
||||
}
|
||||
printf(" Created by: %s\n", std::empty(metainfo.creator()) ? "Unknown" : metainfo.creator().c_str());
|
||||
printf(" Created on: %s\n\n", toString(metainfo.dateCreated()).c_str());
|
||||
|
||||
|
||||
Reference in New Issue
Block a user