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.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2014-12-04 12:13:59 +00:00
|
|
|
#include <stdarg.h>
|
2017-04-21 07:40:57 +00:00
|
|
|
#include <stdlib.h> /* abs(), srand(), rand() */
|
|
|
|
#include <string.h> /* memcpy(), memmove(), memset(), strcmp(), strlen() */
|
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
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
tr_sha1_ctx_t sha;
|
2014-12-04 12:13:59 +00:00
|
|
|
|
2021-09-15 00:18:09 +00:00
|
|
|
if ((sha = tr_sha1_init()) == 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;
|
2017-04-20 16:02:19 +00:00
|
|
|
void const* data;
|
2014-12-04 12:13:59 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
va_start(vl, data1_length);
|
|
|
|
|
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
|
|
|
|
2020-05-12 01:34:03 +00:00
|
|
|
unsigned int noise;
|
2017-06-13 02:24:09 +00:00
|
|
|
|
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
|
|
|
|
2017-06-13 02:24:09 +00:00
|
|
|
static bool init = false;
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
if (!init)
|
2014-12-04 11:27:38 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
srand(tr_time_msec());
|
|
|
|
init = true;
|
2014-12-04 11:27:38 +00:00
|
|
|
}
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
return rand() % upper_bound;
|
2014-12-04 11:27:38 +00:00
|
|
|
}
|
2014-12-04 19:58:34 +00:00
|
|
|
|
|
|
|
/***
|
|
|
|
****
|
|
|
|
***/
|
|
|
|
|
2017-04-20 16:02:19 +00:00
|
|
|
char* tr_ssha1(char const* plain_text)
|
2014-12-04 20:45:18 +00:00
|
|
|
{
|
2021-09-15 00:18:09 +00:00
|
|
|
TR_ASSERT(plain_text != nullptr);
|
2017-06-13 02:24:09 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
enum
|
|
|
|
{
|
|
|
|
saltval_len = 8,
|
|
|
|
salter_len = 64
|
|
|
|
};
|
|
|
|
|
2017-04-20 16:02:19 +00:00
|
|
|
static char const* salter =
|
2017-04-19 12:04:45 +00:00
|
|
|
"0123456789"
|
|
|
|
"abcdefghijklmnopqrstuvwxyz"
|
|
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
|
|
"./";
|
|
|
|
|
|
|
|
unsigned char salt[saltval_len];
|
|
|
|
uint8_t sha[SHA_DIGEST_LENGTH];
|
|
|
|
char buf[2 * SHA_DIGEST_LENGTH + saltval_len + 2];
|
|
|
|
|
|
|
|
tr_rand_buffer(salt, saltval_len);
|
|
|
|
|
2021-10-14 15:36:49 +00:00
|
|
|
for (auto& ch : salt)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2021-10-14 15:36:49 +00:00
|
|
|
ch = salter[ch % salter_len];
|
2017-04-19 12:04:45 +00:00
|
|
|
}
|
|
|
|
|
2021-09-15 00:18:09 +00:00
|
|
|
tr_sha1(sha, plain_text, (int)strlen(plain_text), salt, saltval_len, nullptr);
|
2017-04-19 12:04:45 +00:00
|
|
|
tr_sha1_to_hex(&buf[1], sha);
|
|
|
|
memcpy(&buf[1 + 2 * SHA_DIGEST_LENGTH], &salt, saltval_len);
|
|
|
|
buf[1 + 2 * SHA_DIGEST_LENGTH + saltval_len] = '\0';
|
|
|
|
buf[0] = '{'; /* signal that this is a hash. this makes saving/restoring easier */
|
|
|
|
|
|
|
|
return tr_strdup(buf);
|
2014-12-04 20:45:18 +00:00
|
|
|
}
|
|
|
|
|
2017-04-20 16:02:19 +00:00
|
|
|
bool tr_ssha1_matches(char const* ssha1, char const* plain_text)
|
2014-12-04 20:45:18 +00:00
|
|
|
{
|
2021-09-15 00:18:09 +00:00
|
|
|
TR_ASSERT(ssha1 != nullptr);
|
|
|
|
TR_ASSERT(plain_text != nullptr);
|
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
|
|
|
|
2017-04-20 16:02:19 +00:00
|
|
|
size_t const source_len = strlen(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 */
|
2017-04-20 16:02:19 +00:00
|
|
|
char const* const salt = ssha1 + brace_and_hash_len;
|
|
|
|
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-09-15 00:18:09 +00:00
|
|
|
tr_sha1(buf, plain_text, (int)strlen(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
|
|
|
|
2017-04-20 16:02:19 +00:00
|
|
|
return strncmp(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
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
char* ret;
|
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
|
|
|
}
|
2017-04-19 12:04:45 +00:00
|
|
|
else
|
2014-12-04 19:58:34 +00:00
|
|
|
{
|
2021-09-15 00:18:09 +00:00
|
|
|
ret = nullptr;
|
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
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
char* ret;
|
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
|
|
|
}
|
2017-04-19 12:04:45 +00:00
|
|
|
else
|
2014-12-04 19:58:34 +00:00
|
|
|
{
|
2021-09-15 00:18:09 +00:00
|
|
|
ret = nullptr;
|
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
|
|
|
}
|