refactor: tr_ssha1(), tr_ssha1_matches() (#2148)
* refactor: make tr_ssha1 and tr_ssha1_matches string_view-friendly
This commit is contained in:
parent
7ff6756ac5
commit
99aeaa0eaf
|
@ -118,10 +118,8 @@ int tr_rand_int_weak(int upper_bound)
|
|||
****
|
||||
***/
|
||||
|
||||
char* tr_ssha1(char const* plain_text)
|
||||
std::string tr_ssha1(std::string_view plain_text)
|
||||
{
|
||||
TR_ASSERT(plain_text != nullptr);
|
||||
|
||||
auto constexpr SaltvalLen = int{ 8 };
|
||||
auto constexpr SalterLen = int{ 64 };
|
||||
|
||||
|
@ -142,24 +140,21 @@ char* tr_ssha1(char const* plain_text)
|
|||
ch = salter[ch % SalterLen];
|
||||
}
|
||||
|
||||
tr_sha1(sha, plain_text, (int)strlen(plain_text), salt, SaltvalLen, nullptr);
|
||||
tr_sha1(sha, std::data(plain_text), std::size(plain_text), salt, SaltvalLen, nullptr);
|
||||
tr_sha1_to_hex(&buf[1], sha);
|
||||
memcpy(&buf[1 + 2 * SHA_DIGEST_LENGTH], &salt, SaltvalLen);
|
||||
buf[1 + 2 * SHA_DIGEST_LENGTH + SaltvalLen] = '\0';
|
||||
buf[0] = '{'; /* signal that this is a hash. this makes saving/restoring easier */
|
||||
|
||||
return tr_strdup(buf);
|
||||
return std::string{ buf };
|
||||
}
|
||||
|
||||
bool tr_ssha1_matches(char const* ssha1, char const* plain_text)
|
||||
bool tr_ssha1_matches(std::string_view ssha1, std::string_view plain_text)
|
||||
{
|
||||
TR_ASSERT(ssha1 != nullptr);
|
||||
TR_ASSERT(plain_text != nullptr);
|
||||
|
||||
size_t const brace_len = 1;
|
||||
size_t const brace_and_hash_len = brace_len + 2 * SHA_DIGEST_LENGTH;
|
||||
|
||||
size_t const source_len = strlen(ssha1);
|
||||
size_t const source_len = std::size(ssha1);
|
||||
|
||||
if (source_len < brace_and_hash_len || ssha1[0] != '{')
|
||||
{
|
||||
|
@ -167,16 +162,16 @@ bool tr_ssha1_matches(char const* ssha1, char const* plain_text)
|
|||
}
|
||||
|
||||
/* extract the salt */
|
||||
char const* const salt = ssha1 + brace_and_hash_len;
|
||||
char const* const salt = std::data(ssha1) + brace_and_hash_len;
|
||||
size_t const salt_len = source_len - brace_and_hash_len;
|
||||
|
||||
uint8_t buf[SHA_DIGEST_LENGTH * 2 + 1];
|
||||
|
||||
/* hash pass + salt */
|
||||
tr_sha1(buf, plain_text, (int)strlen(plain_text), salt, (int)salt_len, nullptr);
|
||||
tr_sha1(buf, std::data(plain_text), std::size(plain_text), salt, (int)salt_len, nullptr);
|
||||
tr_sha1_to_hex((char*)buf, buf);
|
||||
|
||||
return strncmp(ssha1 + brace_len, (char const*)buf, SHA_DIGEST_LENGTH * 2) == 0;
|
||||
return strncmp(std::data(ssha1) + brace_len, (char const*)buf, SHA_DIGEST_LENGTH * 2) == 0;
|
||||
}
|
||||
|
||||
/***
|
||||
|
|
|
@ -9,9 +9,11 @@
|
|||
#ifndef TR_CRYPTO_UTILS_H
|
||||
#define TR_CRYPTO_UTILS_H
|
||||
|
||||
#include <cinttypes>
|
||||
#include <cstddef>
|
||||
#include <optional>
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include "transmission.h" /* SHA_DIGEST_LENGTH */
|
||||
#include "tr-macros.h"
|
||||
|
@ -143,12 +145,12 @@ bool tr_rand_buffer(void* buffer, size_t length);
|
|||
/**
|
||||
* @brief Generate a SSHA password from its plaintext source.
|
||||
*/
|
||||
char* tr_ssha1(char const* plain_text) TR_GNUC_MALLOC;
|
||||
std::string tr_ssha1(std::string_view plain_text);
|
||||
|
||||
/**
|
||||
* @brief Validate a test password against the a ssha1 password.
|
||||
*/
|
||||
bool tr_ssha1_matches(char const* ssha1, char const* plain_text);
|
||||
bool tr_ssha1_matches(std::string_view ssha1, std::string_view plain_text);
|
||||
|
||||
/**
|
||||
* @brief Translate a block of bytes into base64.
|
||||
|
|
|
@ -64,7 +64,7 @@ struct tr_rpc_server
|
|||
int start_retry_counter;
|
||||
tr_session* session;
|
||||
char* username;
|
||||
char* password;
|
||||
std::string password;
|
||||
std::string whitelistStr;
|
||||
std::list<std::string> whitelist;
|
||||
std::list<std::string> hostWhitelist;
|
||||
|
@ -1012,23 +1012,21 @@ char const* tr_rpcGetUsername(tr_rpc_server const* server)
|
|||
|
||||
void tr_rpcSetPassword(tr_rpc_server* server, char const* password)
|
||||
{
|
||||
tr_free(server->password);
|
||||
|
||||
if (*password != '{')
|
||||
{
|
||||
server->password = tr_ssha1(password);
|
||||
}
|
||||
else
|
||||
{
|
||||
server->password = strdup(password);
|
||||
server->password = password;
|
||||
}
|
||||
|
||||
dbgmsg("setting our Password to [%s]", server->password);
|
||||
dbgmsg("setting our Password to [%s]", server->password.c_str());
|
||||
}
|
||||
|
||||
char const* tr_rpcGetPassword(tr_rpc_server const* server)
|
||||
{
|
||||
return server->password != nullptr ? server->password : "";
|
||||
return server->password.c_str();
|
||||
}
|
||||
|
||||
void tr_rpcSetPasswordEnabled(tr_rpc_server* server, bool isEnabled)
|
||||
|
@ -1088,7 +1086,6 @@ static void closeServer(void* vserver)
|
|||
|
||||
tr_free(server->url);
|
||||
tr_free(server->username);
|
||||
tr_free(server->password);
|
||||
delete server;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
#include <string>
|
||||
#include <unordered_set>
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
TEST(Crypto, torrentHash)
|
||||
{
|
||||
auto a = tr_crypto{};
|
||||
|
@ -124,43 +126,41 @@ TEST(Crypto, ssha1)
|
|||
{
|
||||
struct LocalTest
|
||||
{
|
||||
char const* const plain_text;
|
||||
char const* const ssha1;
|
||||
std::string_view plain_text;
|
||||
std::string_view ssha1;
|
||||
};
|
||||
|
||||
auto const tests = std::array<LocalTest, 2>{
|
||||
LocalTest{ "test", "{15ad0621b259a84d24dcd4e75b09004e98a3627bAMbyRHJy" },
|
||||
{ "QNY)(*#$B)!_X$B !_B#($^!)*&$%CV!#)&$C!@$(P*)", "{10e2d7acbb104d970514a147cd16d51dfa40fb3c0OSwJtOL" },
|
||||
};
|
||||
auto constexpr Tests = std::array<LocalTest, 2>{ {
|
||||
{ "test"sv, "{15ad0621b259a84d24dcd4e75b09004e98a3627bAMbyRHJy"sv },
|
||||
{ "QNY)(*#$B)!_X$B !_B#($^!)*&$%CV!#)&$C!@$(P*)"sv, "{10e2d7acbb104d970514a147cd16d51dfa40fb3c0OSwJtOL"sv },
|
||||
} };
|
||||
|
||||
auto constexpr HashCount = size_t{ 4 * 1024 };
|
||||
|
||||
for (auto const& test : tests)
|
||||
for (auto const& [plain_text, ssha1] : Tests)
|
||||
{
|
||||
std::unordered_set<std::string> hashes;
|
||||
auto hashes = std::unordered_set<std::string>{};
|
||||
hashes.reserve(HashCount);
|
||||
|
||||
char* const phrase = tr_strdup(test.plain_text);
|
||||
EXPECT_TRUE(tr_ssha1_matches(test.ssha1, phrase));
|
||||
EXPECT_TRUE(tr_ssha1_matches_(test.ssha1, phrase));
|
||||
EXPECT_TRUE(tr_ssha1_matches(ssha1, plain_text));
|
||||
EXPECT_TRUE(tr_ssha1_matches_(ssha1, plain_text));
|
||||
|
||||
for (size_t j = 0; j < HashCount; ++j)
|
||||
{
|
||||
char* hash = (j % 2 == 0) ? tr_ssha1(phrase) : tr_ssha1_(phrase);
|
||||
EXPECT_NE(nullptr, hash);
|
||||
auto const hash = (j % 2 == 0) ? tr_ssha1(plain_text) : tr_ssha1_(plain_text);
|
||||
|
||||
// phrase matches each of generated hashes
|
||||
EXPECT_TRUE(tr_ssha1_matches(hash, phrase));
|
||||
EXPECT_TRUE(tr_ssha1_matches_(hash, phrase));
|
||||
EXPECT_TRUE(tr_ssha1_matches(hash, plain_text));
|
||||
EXPECT_TRUE(tr_ssha1_matches_(hash, plain_text));
|
||||
|
||||
hashes.insert(hash);
|
||||
tr_free(hash);
|
||||
}
|
||||
|
||||
// confirm all hashes are different
|
||||
EXPECT_EQ(HashCount, hashes.size());
|
||||
|
||||
/* exchange two first chars */
|
||||
auto phrase = std::string{ plain_text };
|
||||
phrase[0] ^= phrase[1];
|
||||
phrase[1] ^= phrase[0];
|
||||
phrase[0] ^= phrase[1];
|
||||
|
@ -168,11 +168,9 @@ TEST(Crypto, ssha1)
|
|||
for (auto const& hash : hashes)
|
||||
{
|
||||
/* changed phrase doesn't match the hashes */
|
||||
EXPECT_FALSE(tr_ssha1_matches(hash.c_str(), phrase));
|
||||
EXPECT_FALSE(tr_ssha1_matches_(hash.c_str(), phrase));
|
||||
EXPECT_FALSE(tr_ssha1_matches(hash, phrase));
|
||||
EXPECT_FALSE(tr_ssha1_matches_(hash, phrase));
|
||||
}
|
||||
|
||||
tr_free(phrase);
|
||||
}
|
||||
|
||||
/* should work with different salt lengths as well */
|
||||
|
|
Loading…
Reference in New Issue