2014-12-04 11:27:38 +00:00
|
|
|
/*
|
|
|
|
* This file Copyright (C) 2007-2014 Mnemosyne LLC
|
|
|
|
*
|
|
|
|
* It may be used under the GNU GPL versions 2 or 3
|
|
|
|
* or any future license endorsed by Mnemosyne LLC.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2021-10-17 20:17:18 +00:00
|
|
|
#include <cstdarg>
|
|
|
|
#include <cstring> /* memcpy(), memmove(), memset(), strcmp(), strlen() */
|
2021-11-11 19:03:33 +00:00
|
|
|
#include <random> /* random_device, mt19937, uniform_int_distribution*/
|
2014-12-04 11:27:38 +00:00
|
|
|
|
2021-09-12 03:47:29 +00:00
|
|
|
#include <arc4.h>
|
2021-09-12 17:41:49 +00:00
|
|
|
|
|
|
|
extern "C"
|
|
|
|
{
|
2015-01-01 21:16:36 +00:00
|
|
|
#include <b64/cdecode.h>
|
|
|
|
#include <b64/cencode.h>
|
2021-09-12 17:41:49 +00:00
|
|
|
}
|
2015-01-01 21:16:36 +00:00
|
|
|
|
2014-12-04 11:27:38 +00:00
|
|
|
#include "transmission.h"
|
|
|
|
#include "crypto-utils.h"
|
2017-06-08 07:24:12 +00:00
|
|
|
#include "tr-assert.h"
|
2014-12-04 11:27:38 +00:00
|
|
|
#include "utils.h"
|
|
|
|
|
|
|
|
/***
|
|
|
|
****
|
|
|
|
***/
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
void tr_dh_align_key(uint8_t* key_buffer, size_t key_size, size_t buffer_size)
|
#4400, #5462: Move DH helpers to crypto-utils
On a way to factoring out OpenSSL support to a standalone file to ease
addition of other crypto libraries support in the future, move helpers
providing DH key exchange to crypto-utils.{c,h}. OpenSSL-related
functionality (DH context management) is moved to crypto-utils-openssl.c.
Since we know in advance that DH secret key management code will be the
same for most of backends, implement common functionality in separate
crypto-utils-fallback.c.
Add new tr_dh_ctx_t and tr_dh_secret_t types and functions to be
implemented by crypto backends:
* tr_dh_new - allocate DH context,
* tr_dh_free - free the context,
* tr_dh_make_key - generate private/public keypair,
* tr_dh_agree - perform DH key exchange and generate secret key,
* tr_dh_secret_derive - calculate secret key hash,
* tr_dh_secret_free - free the secret key,
* tr_dh_align_key - align some DH key in the buffer allocated for it.
Make DH secret key not accessible in plain form outside the crypto
backend. This allows for implementations where the key is managed by
the underlying library and is not even exposed to our backend.
2014-12-04 19:18:08 +00:00
|
|
|
{
|
2017-06-08 07:24:12 +00:00
|
|
|
TR_ASSERT(key_size <= buffer_size);
|
#4400, #5462: Move DH helpers to crypto-utils
On a way to factoring out OpenSSL support to a standalone file to ease
addition of other crypto libraries support in the future, move helpers
providing DH key exchange to crypto-utils.{c,h}. OpenSSL-related
functionality (DH context management) is moved to crypto-utils-openssl.c.
Since we know in advance that DH secret key management code will be the
same for most of backends, implement common functionality in separate
crypto-utils-fallback.c.
Add new tr_dh_ctx_t and tr_dh_secret_t types and functions to be
implemented by crypto backends:
* tr_dh_new - allocate DH context,
* tr_dh_free - free the context,
* tr_dh_make_key - generate private/public keypair,
* tr_dh_agree - perform DH key exchange and generate secret key,
* tr_dh_secret_derive - calculate secret key hash,
* tr_dh_secret_free - free the secret key,
* tr_dh_align_key - align some DH key in the buffer allocated for it.
Make DH secret key not accessible in plain form outside the crypto
backend. This allows for implementations where the key is managed by
the underlying library and is not even exposed to our backend.
2014-12-04 19:18:08 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
/* DH can generate key sizes that are smaller than the size of
|
|
|
|
key buffer with exponentially decreasing probability, in which case
|
|
|
|
the msb's of key buffer need to be zeroed appropriately. */
|
|
|
|
if (key_size < buffer_size)
|
#4400, #5462: Move DH helpers to crypto-utils
On a way to factoring out OpenSSL support to a standalone file to ease
addition of other crypto libraries support in the future, move helpers
providing DH key exchange to crypto-utils.{c,h}. OpenSSL-related
functionality (DH context management) is moved to crypto-utils-openssl.c.
Since we know in advance that DH secret key management code will be the
same for most of backends, implement common functionality in separate
crypto-utils-fallback.c.
Add new tr_dh_ctx_t and tr_dh_secret_t types and functions to be
implemented by crypto backends:
* tr_dh_new - allocate DH context,
* tr_dh_free - free the context,
* tr_dh_make_key - generate private/public keypair,
* tr_dh_agree - perform DH key exchange and generate secret key,
* tr_dh_secret_derive - calculate secret key hash,
* tr_dh_secret_free - free the secret key,
* tr_dh_align_key - align some DH key in the buffer allocated for it.
Make DH secret key not accessible in plain form outside the crypto
backend. This allows for implementations where the key is managed by
the underlying library and is not even exposed to our backend.
2014-12-04 19:18:08 +00:00
|
|
|
{
|
2017-04-20 16:02:19 +00:00
|
|
|
size_t const offset = buffer_size - key_size;
|
2017-04-19 12:04:45 +00:00
|
|
|
memmove(key_buffer + offset, key_buffer, key_size);
|
|
|
|
memset(key_buffer, 0, offset);
|
#4400, #5462: Move DH helpers to crypto-utils
On a way to factoring out OpenSSL support to a standalone file to ease
addition of other crypto libraries support in the future, move helpers
providing DH key exchange to crypto-utils.{c,h}. OpenSSL-related
functionality (DH context management) is moved to crypto-utils-openssl.c.
Since we know in advance that DH secret key management code will be the
same for most of backends, implement common functionality in separate
crypto-utils-fallback.c.
Add new tr_dh_ctx_t and tr_dh_secret_t types and functions to be
implemented by crypto backends:
* tr_dh_new - allocate DH context,
* tr_dh_free - free the context,
* tr_dh_make_key - generate private/public keypair,
* tr_dh_agree - perform DH key exchange and generate secret key,
* tr_dh_secret_derive - calculate secret key hash,
* tr_dh_secret_free - free the secret key,
* tr_dh_align_key - align some DH key in the buffer allocated for it.
Make DH secret key not accessible in plain form outside the crypto
backend. This allows for implementations where the key is managed by
the underlying library and is not even exposed to our backend.
2014-12-04 19:18:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
|
|
****
|
|
|
|
***/
|
|
|
|
|
2017-04-20 16:02:19 +00:00
|
|
|
bool tr_sha1(uint8_t* hash, void const* data1, int data1_length, ...)
|
2014-12-04 12:13:59 +00:00
|
|
|
{
|
2021-10-27 00:16:56 +00:00
|
|
|
tr_sha1_ctx_t sha = tr_sha1_init();
|
|
|
|
if (sha == nullptr)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2014-12-04 12:13:59 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
if (tr_sha1_update(sha, data1, data1_length))
|
2014-12-04 12:13:59 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
va_list vl;
|
|
|
|
va_start(vl, data1_length);
|
|
|
|
|
2021-10-27 00:16:56 +00:00
|
|
|
void const* data = nullptr;
|
2021-09-15 00:18:09 +00:00
|
|
|
while ((data = va_arg(vl, void const*)) != nullptr)
|
2014-12-04 12:13:59 +00:00
|
|
|
{
|
2017-04-20 16:02:19 +00:00
|
|
|
int const data_length = va_arg(vl, int);
|
2017-06-08 07:24:12 +00:00
|
|
|
TR_ASSERT(data_length >= 0);
|
2017-04-19 12:04:45 +00:00
|
|
|
|
|
|
|
if (!tr_sha1_update(sha, data, data_length))
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2014-12-04 12:13:59 +00:00
|
|
|
}
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
va_end(vl);
|
|
|
|
|
|
|
|
/* did we reach the end of argument list? */
|
2021-09-15 00:18:09 +00:00
|
|
|
if (data == nullptr)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
|
|
|
return tr_sha1_final(sha, hash);
|
|
|
|
}
|
2014-12-04 12:13:59 +00:00
|
|
|
}
|
|
|
|
|
2021-09-15 00:18:09 +00:00
|
|
|
tr_sha1_final(sha, nullptr);
|
2017-04-19 12:04:45 +00:00
|
|
|
return false;
|
2014-12-04 12:13:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
|
|
****
|
|
|
|
***/
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
int tr_rand_int(int upper_bound)
|
2014-12-04 11:27:38 +00:00
|
|
|
{
|
2017-06-08 07:24:12 +00:00
|
|
|
TR_ASSERT(upper_bound > 0);
|
2014-12-04 11:27:38 +00:00
|
|
|
|
2021-10-27 00:16:56 +00:00
|
|
|
unsigned int noise = 0;
|
2020-05-12 01:34:03 +00:00
|
|
|
if (tr_rand_buffer(&noise, sizeof(noise)))
|
2014-12-04 11:27:38 +00:00
|
|
|
{
|
2020-05-12 01:34:03 +00:00
|
|
|
return noise % upper_bound;
|
2014-12-04 11:27:38 +00:00
|
|
|
}
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
/* fall back to a weaker implementation... */
|
|
|
|
return tr_rand_int_weak(upper_bound);
|
2014-12-04 11:27:38 +00:00
|
|
|
}
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
int tr_rand_int_weak(int upper_bound)
|
2014-12-04 11:27:38 +00:00
|
|
|
{
|
2017-06-08 07:24:12 +00:00
|
|
|
TR_ASSERT(upper_bound > 0);
|
2014-12-04 11:27:38 +00:00
|
|
|
|
2021-11-11 19:03:33 +00:00
|
|
|
thread_local auto random_engine = std::mt19937{ std::random_device{}() };
|
|
|
|
using distribution_type = std::uniform_int_distribution<>;
|
|
|
|
thread_local distribution_type distribution;
|
2017-06-13 02:24:09 +00:00
|
|
|
|
2021-11-11 19:03:33 +00:00
|
|
|
// Upper bound is inclusive in std::uniform_int_distribution.
|
|
|
|
return distribution(random_engine, distribution_type::param_type{ 0, upper_bound - 1 });
|
2014-12-04 11:27:38 +00:00
|
|
|
}
|
2014-12-04 19:58:34 +00:00
|
|
|
|
|
|
|
/***
|
|
|
|
****
|
|
|
|
***/
|
|
|
|
|
2021-11-14 02:03:01 +00:00
|
|
|
std::string tr_ssha1(std::string_view plain_text)
|
2014-12-04 20:45:18 +00:00
|
|
|
{
|
2021-10-21 00:39:05 +00:00
|
|
|
auto constexpr SaltvalLen = int{ 8 };
|
|
|
|
auto constexpr SalterLen = int{ 64 };
|
2017-04-19 12:04:45 +00:00
|
|
|
|
2017-04-20 16:02:19 +00:00
|
|
|
static char const* salter =
|
2017-04-19 12:04:45 +00:00
|
|
|
"0123456789"
|
|
|
|
"abcdefghijklmnopqrstuvwxyz"
|
|
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
|
|
"./";
|
|
|
|
|
2021-10-21 00:39:05 +00:00
|
|
|
unsigned char salt[SaltvalLen];
|
2017-04-19 12:04:45 +00:00
|
|
|
uint8_t sha[SHA_DIGEST_LENGTH];
|
2021-10-21 00:39:05 +00:00
|
|
|
char buf[2 * SHA_DIGEST_LENGTH + SaltvalLen + 2];
|
2017-04-19 12:04:45 +00:00
|
|
|
|
2021-10-21 00:39:05 +00:00
|
|
|
tr_rand_buffer(salt, SaltvalLen);
|
2017-04-19 12:04:45 +00:00
|
|
|
|
2021-10-14 15:36:49 +00:00
|
|
|
for (auto& ch : salt)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2021-10-21 00:39:05 +00:00
|
|
|
ch = salter[ch % SalterLen];
|
2017-04-19 12:04:45 +00:00
|
|
|
}
|
|
|
|
|
2021-11-14 02:03:01 +00:00
|
|
|
tr_sha1(sha, std::data(plain_text), std::size(plain_text), salt, SaltvalLen, nullptr);
|
2017-04-19 12:04:45 +00:00
|
|
|
tr_sha1_to_hex(&buf[1], sha);
|
2021-10-21 00:39:05 +00:00
|
|
|
memcpy(&buf[1 + 2 * SHA_DIGEST_LENGTH], &salt, SaltvalLen);
|
|
|
|
buf[1 + 2 * SHA_DIGEST_LENGTH + SaltvalLen] = '\0';
|
2017-04-19 12:04:45 +00:00
|
|
|
buf[0] = '{'; /* signal that this is a hash. this makes saving/restoring easier */
|
|
|
|
|
2021-11-14 02:03:01 +00:00
|
|
|
return std::string{ buf };
|
2014-12-04 20:45:18 +00:00
|
|
|
}
|
|
|
|
|
2021-11-14 02:03:01 +00:00
|
|
|
bool tr_ssha1_matches(std::string_view ssha1, std::string_view plain_text)
|
2014-12-04 20:45:18 +00:00
|
|
|
{
|
2017-04-20 16:02:19 +00:00
|
|
|
size_t const brace_len = 1;
|
|
|
|
size_t const brace_and_hash_len = brace_len + 2 * SHA_DIGEST_LENGTH;
|
2017-01-09 11:15:07 +00:00
|
|
|
|
2021-11-14 02:03:01 +00:00
|
|
|
size_t const source_len = std::size(ssha1);
|
2017-04-19 12:04:45 +00:00
|
|
|
|
|
|
|
if (source_len < brace_and_hash_len || ssha1[0] != '{')
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2014-12-04 20:45:18 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
/* extract the salt */
|
2021-11-14 02:03:01 +00:00
|
|
|
char const* const salt = std::data(ssha1) + brace_and_hash_len;
|
2017-04-20 16:02:19 +00:00
|
|
|
size_t const salt_len = source_len - brace_and_hash_len;
|
2014-12-04 20:45:18 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
uint8_t buf[SHA_DIGEST_LENGTH * 2 + 1];
|
2014-12-04 20:45:18 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
/* hash pass + salt */
|
2021-11-14 02:03:01 +00:00
|
|
|
tr_sha1(buf, std::data(plain_text), std::size(plain_text), salt, (int)salt_len, nullptr);
|
2017-04-19 12:04:45 +00:00
|
|
|
tr_sha1_to_hex((char*)buf, buf);
|
2014-12-04 20:45:18 +00:00
|
|
|
|
2021-11-14 02:03:01 +00:00
|
|
|
return strncmp(std::data(ssha1) + brace_len, (char const*)buf, SHA_DIGEST_LENGTH * 2) == 0;
|
2014-12-04 20:45:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
|
|
****
|
|
|
|
***/
|
|
|
|
|
2017-04-20 16:02:19 +00:00
|
|
|
void* tr_base64_encode(void const* input, size_t input_length, size_t* output_length)
|
2014-12-04 19:58:34 +00:00
|
|
|
{
|
2021-10-27 00:16:56 +00:00
|
|
|
char* ret = nullptr;
|
2014-12-04 19:58:34 +00:00
|
|
|
|
2021-09-15 00:18:09 +00:00
|
|
|
if (input != nullptr)
|
2014-12-04 19:58:34 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
if (input_length != 0)
|
2014-12-04 19:58:34 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
size_t ret_length = 4 * ((input_length + 2) / 3);
|
|
|
|
base64_encodestate state;
|
2015-01-01 21:16:36 +00:00
|
|
|
|
2015-01-03 21:35:20 +00:00
|
|
|
#ifdef USE_SYSTEM_B64
|
2017-04-19 12:04:45 +00:00
|
|
|
/* Additional space is needed for newlines if we're using unpatched libb64 */
|
|
|
|
ret_length += ret_length / 72 + 1;
|
2015-01-03 21:35:20 +00:00
|
|
|
#endif
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
ret = tr_new(char, ret_length + 8);
|
2015-01-01 21:16:36 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
base64_init_encodestate(&state);
|
2021-09-12 17:41:49 +00:00
|
|
|
ret_length = base64_encode_block(static_cast<char const*>(input), input_length, ret, &state);
|
2017-04-19 12:04:45 +00:00
|
|
|
ret_length += base64_encode_blockend(ret + ret_length, &state);
|
2015-01-01 21:16:36 +00:00
|
|
|
|
2021-09-15 00:18:09 +00:00
|
|
|
if (output_length != nullptr)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
|
|
|
*output_length = ret_length;
|
|
|
|
}
|
2015-01-01 21:16:36 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
ret[ret_length] = '\0';
|
2015-01-01 21:16:36 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
return ret;
|
|
|
|
}
|
2021-10-14 19:26:38 +00:00
|
|
|
|
|
|
|
ret = tr_strdup("");
|
2014-12-04 19:58:34 +00:00
|
|
|
}
|
|
|
|
|
2021-09-15 00:18:09 +00:00
|
|
|
if (output_length != nullptr)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
|
|
|
*output_length = 0;
|
|
|
|
}
|
2014-12-04 19:58:34 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
return ret;
|
2014-12-04 19:58:34 +00:00
|
|
|
}
|
|
|
|
|
2017-04-20 16:02:19 +00:00
|
|
|
void* tr_base64_encode_str(char const* input, size_t* output_length)
|
2014-12-04 19:58:34 +00:00
|
|
|
{
|
2021-09-15 00:18:09 +00:00
|
|
|
return tr_base64_encode(input, input == nullptr ? 0 : strlen(input), output_length);
|
2014-12-04 19:58:34 +00:00
|
|
|
}
|
|
|
|
|
2017-04-20 16:02:19 +00:00
|
|
|
void* tr_base64_decode(void const* input, size_t input_length, size_t* output_length)
|
2014-12-04 19:58:34 +00:00
|
|
|
{
|
2021-10-27 00:16:56 +00:00
|
|
|
char* ret = nullptr;
|
2014-12-04 19:58:34 +00:00
|
|
|
|
2021-09-15 00:18:09 +00:00
|
|
|
if (input != nullptr)
|
2014-12-04 19:58:34 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
if (input_length != 0)
|
2014-12-04 19:58:34 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
size_t ret_length = input_length / 4 * 3;
|
|
|
|
base64_decodestate state;
|
2015-01-01 21:16:36 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
ret = tr_new(char, ret_length + 8);
|
2015-01-01 21:16:36 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
base64_init_decodestate(&state);
|
2021-09-12 17:41:49 +00:00
|
|
|
ret_length = base64_decode_block(static_cast<char const*>(input), input_length, ret, &state);
|
2015-01-01 21:16:36 +00:00
|
|
|
|
2021-09-15 00:18:09 +00:00
|
|
|
if (output_length != nullptr)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
|
|
|
*output_length = ret_length;
|
|
|
|
}
|
2015-01-01 21:16:36 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
ret[ret_length] = '\0';
|
2015-01-01 21:16:36 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
return ret;
|
|
|
|
}
|
2021-10-14 19:26:38 +00:00
|
|
|
|
|
|
|
ret = tr_strdup("");
|
2014-12-04 19:58:34 +00:00
|
|
|
}
|
|
|
|
|
2021-09-15 00:18:09 +00:00
|
|
|
if (output_length != nullptr)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
|
|
|
*output_length = 0;
|
|
|
|
}
|
2014-12-04 19:58:34 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
return ret;
|
2014-12-04 19:58:34 +00:00
|
|
|
}
|
|
|
|
|
2017-04-20 16:02:19 +00:00
|
|
|
void* tr_base64_decode_str(char const* input, size_t* output_length)
|
2014-12-04 19:58:34 +00:00
|
|
|
{
|
2021-09-15 00:18:09 +00:00
|
|
|
return tr_base64_decode(input, input == nullptr ? 0 : strlen(input), output_length);
|
2014-12-04 19:58:34 +00:00
|
|
|
}
|
2021-11-10 00:13:47 +00:00
|
|
|
|
2021-11-15 03:54:48 +00:00
|
|
|
std::string tr_base64_decode_str(std::string_view input)
|
|
|
|
{
|
|
|
|
auto len = size_t{};
|
|
|
|
auto* buf = tr_base64_decode(std::data(input), std::size(input), &len);
|
|
|
|
auto str = std::string{ reinterpret_cast<char const*>(buf), len };
|
|
|
|
tr_free(buf);
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2021-11-10 00:13:47 +00:00
|
|
|
/***
|
|
|
|
****
|
|
|
|
***/
|
|
|
|
|
|
|
|
static void tr_binary_to_hex(void const* vinput, void* voutput, size_t byte_length)
|
|
|
|
{
|
|
|
|
static char const hex[] = "0123456789abcdef";
|
|
|
|
|
|
|
|
auto const* input = static_cast<uint8_t const*>(vinput);
|
|
|
|
auto* output = static_cast<char*>(voutput);
|
|
|
|
|
|
|
|
/* go from back to front to allow for in-place conversion */
|
|
|
|
input += byte_length;
|
|
|
|
output += byte_length * 2;
|
|
|
|
|
|
|
|
*output = '\0';
|
|
|
|
|
|
|
|
while (byte_length-- > 0)
|
|
|
|
{
|
|
|
|
unsigned int const val = *(--input);
|
|
|
|
*(--output) = hex[val & 0xf];
|
|
|
|
*(--output) = hex[val >> 4];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void tr_sha1_to_hex(void* hex, void const* sha1)
|
|
|
|
{
|
|
|
|
tr_binary_to_hex(sha1, hex, SHA_DIGEST_LENGTH);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void tr_hex_to_binary(void const* vinput, void* voutput, size_t byte_length)
|
|
|
|
{
|
|
|
|
static char const hex[] = "0123456789abcdef";
|
|
|
|
|
|
|
|
auto const* input = static_cast<uint8_t const*>(vinput);
|
|
|
|
auto* output = static_cast<uint8_t*>(voutput);
|
|
|
|
|
|
|
|
for (size_t i = 0; i < byte_length; ++i)
|
|
|
|
{
|
|
|
|
int const hi = strchr(hex, tolower(*input++)) - hex;
|
|
|
|
int const lo = strchr(hex, tolower(*input++)) - hex;
|
|
|
|
*output++ = (uint8_t)((hi << 4) | lo);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void tr_hex_to_sha1(void* sha1, void const* hex)
|
|
|
|
{
|
|
|
|
tr_hex_to_binary(hex, sha1, SHA_DIGEST_LENGTH);
|
|
|
|
}
|