📄 crypto.c
字号:
/* We ignore any values that are >= 'cutoff,' to avoid biasing the
* distribution with clipping at the upper end of unsigned int's
* range.
*/
cutoff = UINT64_MAX - (UINT64_MAX%max);
while (1) {
crypto_rand((char*)&val, sizeof(val));
if (val < cutoff)
return val % max;
}
}
/** Generate and return a new random hostname starting with <b>prefix</b>,
* ending with <b>suffix</b>, and containing no less than
* <b>min_rand_len</b> and no more than <b>max_rand_len</b> random base32
* characters between. */
char *
crypto_random_hostname(int min_rand_len, int max_rand_len, const char *prefix,
const char *suffix)
{
char *result, *rand_bytes;
int randlen, rand_bytes_len;
size_t resultlen, prefixlen;
tor_assert(max_rand_len >= min_rand_len);
randlen = min_rand_len + crypto_rand_int(max_rand_len - min_rand_len + 1);
prefixlen = strlen(prefix);
resultlen = prefixlen + strlen(suffix) + randlen + 16;
rand_bytes_len = ((randlen*5)+7)/8;
if (rand_bytes_len % 5)
rand_bytes_len += 5 - (rand_bytes_len%5);
rand_bytes = tor_malloc(rand_bytes_len);
crypto_rand(rand_bytes, rand_bytes_len);
result = tor_malloc(resultlen);
memcpy(result, prefix, prefixlen);
base32_encode(result+prefixlen, resultlen-prefixlen,
rand_bytes, rand_bytes_len);
tor_free(rand_bytes);
strlcpy(result+prefixlen+randlen, suffix, resultlen-(prefixlen+randlen));
return result;
}
/** Return a randomly chosen element of <b>sl</b>; or NULL if <b>sl</b>
* is empty. */
void *
smartlist_choose(const smartlist_t *sl)
{
int len = smartlist_len(sl);
if (len)
return smartlist_get(sl,crypto_rand_int(len));
return NULL; /* no elements to choose from */
}
/** Scramble the elements of <b>sl</b> into a random order. */
void
smartlist_shuffle(smartlist_t *sl)
{
int i;
/* From the end of the list to the front, choose at random from the
positions we haven't looked at yet, and swap that position into the
current position. Remember to give "no swap" the same probability as
any other swap. */
for (i = smartlist_len(sl)-1; i > 0; --i) {
int j = crypto_rand_int(i+1);
smartlist_swap(sl, i, j);
}
}
/** Base-64 encode <b>srclen</b> bytes of data from <b>src</b>. Write
* the result into <b>dest</b>, if it will fit within <b>destlen</b>
* bytes. Return the number of bytes written on success; -1 if
* destlen is too short, or other failure.
*/
int
base64_encode(char *dest, size_t destlen, const char *src, size_t srclen)
{
/* FFFF we might want to rewrite this along the lines of base64_decode, if
* it ever shows up in the profile. */
EVP_ENCODE_CTX ctx;
int len, ret;
tor_assert(srclen < INT_MAX);
/* 48 bytes of input -> 64 bytes of output plus newline.
Plus one more byte, in case I'm wrong.
*/
if (destlen < ((srclen/48)+1)*66)
return -1;
if (destlen > SIZE_T_CEILING)
return -1;
EVP_EncodeInit(&ctx);
EVP_EncodeUpdate(&ctx, (unsigned char*)dest, &len,
(unsigned char*)src, (int)srclen);
EVP_EncodeFinal(&ctx, (unsigned char*)(dest+len), &ret);
ret += len;
return ret;
}
#define X 255
#define SP 64
#define PAD 65
/** Internal table mapping byte values to what they represent in base64.
* Numbers 0..63 are 6-bit integers. SPs are spaces, and should be
* skipped. Xs are invalid and must not appear in base64. PAD indicates
* end-of-string. */
static const uint8_t base64_decode_table[256] = {
X, X, X, X, X, X, X, X, X, SP, SP, SP, X, SP, X, X, /* */
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
SP, X, X, X, X, X, X, X, X, X, X, 62, X, X, X, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, X, X, X, PAD, X, X,
X, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, X, X, X, X, X,
X, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, X, X, X, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
};
/** Base-64 decode <b>srclen</b> bytes of data from <b>src</b>. Write
* the result into <b>dest</b>, if it will fit within <b>destlen</b>
* bytes. Return the number of bytes written on success; -1 if
* destlen is too short, or other failure.
*
* NOTE 1: destlen is checked conservatively, as though srclen contained no
* spaces or padding.
*
* NOTE 2: This implementation does not check for the correct number of
* padding "=" characters at the end of the string, and does not check
* for internal padding characters.
*/
int
base64_decode(char *dest, size_t destlen, const char *src, size_t srclen)
{
#ifdef USE_OPENSSL_BASE64
EVP_ENCODE_CTX ctx;
int len, ret;
/* 64 bytes of input -> *up to* 48 bytes of output.
Plus one more byte, in case I'm wrong.
*/
if (destlen < ((srclen/64)+1)*49)
return -1;
if (destlen > SIZE_T_CEILING)
return -1;
EVP_DecodeInit(&ctx);
EVP_DecodeUpdate(&ctx, (unsigned char*)dest, &len,
(unsigned char*)src, srclen);
EVP_DecodeFinal(&ctx, (unsigned char*)dest, &ret);
ret += len;
return ret;
#else
const char *eos = src+srclen;
uint32_t n=0;
int n_idx=0;
char *dest_orig = dest;
/* Max number of bits == srclen*6.
* Number of bytes required to hold all bits == (srclen*6)/8.
* Yes, we want to round down: anything that hangs over the end of a
* byte is padding. */
if (destlen < (srclen*3)/4)
return -1;
if (destlen > SIZE_T_CEILING)
return -1;
/* Iterate over all the bytes in src. Each one will add 0 or 6 bits to the
* value we're decoding. Accumulate bits in <b>n</b>, and whenever we have
* 24 bits, batch them into 3 bytes and flush those bytes to dest.
*/
for ( ; src < eos; ++src) {
unsigned char c = (unsigned char) *src;
uint8_t v = base64_decode_table[c];
switch (v) {
case X:
/* This character isn't allowed in base64. */
return -1;
case SP:
/* This character is whitespace, and has no effect. */
continue;
case PAD:
/* We've hit an = character: the data is over. */
goto end_of_loop;
default:
/* We have an actual 6-bit value. Append it to the bits in n. */
n = (n<<6) | v;
if ((++n_idx) == 4) {
/* We've accumulated 24 bits in n. Flush them. */
*dest++ = (n>>16);
*dest++ = (n>>8) & 0xff;
*dest++ = (n) & 0xff;
n_idx = 0;
n = 0;
}
}
}
end_of_loop:
/* If we have leftover bits, we need to cope. */
switch (n_idx) {
case 0:
default:
/* No leftover bits. We win. */
break;
case 1:
/* 6 leftover bits. That's invalid; we can't form a byte out of that. */
return -1;
case 2:
/* 12 leftover bits: The last 4 are padding and the first 8 are data. */
*dest++ = n >> 4;
break;
case 3:
/* 18 leftover bits: The last 2 are padding and the first 16 are data. */
*dest++ = n >> 10;
*dest++ = n >> 2;
}
tor_assert((dest-dest_orig) <= (ssize_t)destlen);
tor_assert((dest-dest_orig) <= INT_MAX);
return (int)(dest-dest_orig);
#endif
}
#undef X
#undef SP
#undef NIL
/** Base-64 encode DIGEST_LINE bytes from <b>digest</b>, remove the trailing =
* and newline characters, and store the nul-terminated result in the first
* BASE64_DIGEST_LEN+1 bytes of <b>d64</b>. */
int
digest_to_base64(char *d64, const char *digest)
{
char buf[256];
base64_encode(buf, sizeof(buf), digest, DIGEST_LEN);
buf[BASE64_DIGEST_LEN] = '\0';
memcpy(d64, buf, BASE64_DIGEST_LEN+1);
return 0;
}
/** Given a base-64 encoded, nul-terminated digest in <b>d64</b> (without
* trailing newline or = characters), decode it and store the result in the
* first DIGEST_LEN bytes at <b>digest</b>. */
int
digest_from_base64(char *digest, const char *d64)
{
#ifdef USE_OPENSSL_BASE64
char buf_in[BASE64_DIGEST_LEN+3];
char buf[256];
if (strlen(d64) != BASE64_DIGEST_LEN)
return -1;
memcpy(buf_in, d64, BASE64_DIGEST_LEN);
memcpy(buf_in+BASE64_DIGEST_LEN, "=\n\0", 3);
if (base64_decode(buf, sizeof(buf), buf_in, strlen(buf_in)) != DIGEST_LEN)
return -1;
memcpy(digest, buf, DIGEST_LEN);
return 0;
#else
if (base64_decode(digest, DIGEST_LEN, d64, strlen(d64)) == DIGEST_LEN)
return 0;
else
return -1;
#endif
}
/** Implements base32 encoding as in rfc3548. Limitation: Requires
* that srclen*8 is a multiple of 5.
*/
void
base32_encode(char *dest, size_t destlen, const char *src, size_t srclen)
{
unsigned int i, bit, v, u;
size_t nbits = srclen * 8;
tor_assert((nbits%5) == 0); /* We need an even multiple of 5 bits. */
tor_assert((nbits/5)+1 <= destlen); /* We need enough space. */
tor_assert(destlen < SIZE_T_CEILING);
for (i=0,bit=0; bit < nbits; ++i, bit+=5) {
/* set v to the 16-bit value starting at src[bits/8], 0-padded. */
v = ((uint8_t)src[bit/8]) << 8;
if (bit+5<nbits) v += (uint8_t)src[(bit/8)+1];
/* set u to the 5-bit value at the bit'th bit of src. */
u = (v >> (11-(bit%8))) & 0x1F;
dest[i] = BASE32_CHARS[u];
}
dest[i] = '\0';
}
/** Implements base32 decoding as in rfc3548. Limitation: Requires
* that srclen*5 is a multiple of 8. Returns 0 if successful, -1 otherwise.
*/
int
base32_decode(char *dest, size_t destlen, const char *src, size_t srclen)
{
/* XXXX we might want to rewrite this along the lines of base64_decode, if
* it ever shows up in the profile. */
unsigned int i, j, bit;
size_t nbits;
char *tmp;
nbits = srclen * 5;
tor_assert((nbits%8) == 0); /* We need an even multiple of 8 bits. */
tor_assert((nbits/8) <= destlen); /* We need enough space. */
tor_assert(destlen < SIZE_T_CEILING);
/* Convert base32 encoded chars to the 5-bit values that they represent. */
tmp = tor_malloc_zero(srclen);
for (j = 0; j < srclen; ++j) {
if (src[j] > 0x60 && src[j] < 0x7B) tmp[j] = src[j] - 0x61;
else if (src[j] > 0x31 && src[j] < 0x38) tmp[j] = src[j] - 0x18;
else if (src[j] > 0x40 && src[j] < 0x5B) tmp[j] = src[j] - 0x41;
else {
log_warn(LD_BUG, "illegal character in base32 encoded string");
tor_free(tmp);
return -1;
}
}
/* Assemble result byte-wise by applying five possible cases. */
for (i = 0, bit = 0; bit < nbits; ++i, bit += 8) {
switch (bit % 40) {
case 0:
dest[i] = (((uint8_t)tmp[(bit/5)]) << 3) +
(((uint8_t)tmp[(bit/5)+1]) >> 2);
break;
case 8:
dest[i] = (((uint8_t)tmp[(bit/5)]) << 6) +
(((uint8_t)tmp[(bit/5)+1]) << 1) +
(((uint8_t)tmp[(bit/5)+2]) >> 4);
break;
case 16:
dest[i] = (((uint8_t)tmp[(bit/5)]) << 4) +
(((uint8_t)tmp[(bit/5)+1]) >> 1);
break;
case 24:
dest[i] = (((uint8_t)tmp[(bit/5)]) << 7) +
(((uint8_t)tmp[(bit/5)+1]) << 2) +
(((uint8_t)tmp[(bit/5)+2]) >> 3);
break;
case 32:
dest[i] = (((uint8_t)tmp[(bit/5)]) << 5) +
((uint8_t)tmp[(bit/5)+1]);
break;
}
}
memset(tmp, 0, srclen);
tor_free(tmp);
tmp = NULL;
return 0;
}
/** Implement RFC2440-style iterated-salted S2K conversion: convert the
* <b>secret_len</b>-byte <b>secret</b> into a <b>key_out_len</b> byte
* <b>key_out</b>. As in RFC2440, the first 8 bytes of s2k_specifier
* are a salt; the 9th byte describes how much iteration to do.
* Does not support <b>key_out_len</b> > DIGEST_LEN.
*/
void
secret_to_key(char *key_out, size_t key_out_len, const char *secret,
size_t secret_len, const char *s2k_specifier)
{
crypto_digest_env_t *d;
uint8_t c;
size_t count, tmplen;
char *tmp;
tor_assert(key_out_len < SIZE_T_CEILING);
#define EXPBIAS 6
c = s2k_specifier[8];
count = ((uint32_t)16 + (c & 15)) << ((c >> 4) + EXPBIAS);
#undef EXPBIAS
tor_assert(key_out_len <= DIGEST_LEN);
d = crypto_new_digest_env();
tmplen = 8+secret_len;
tmp = tor_malloc(tmplen);
memcpy(tmp,s2k_specifier,8);
memcpy(tmp+8,secret,secret_len);
secret_len += 8;
while (count) {
if (count >= secret_len) {
crypto_digest_add_bytes(d, tmp, secret_len);
count -= secret_len;
} else {
crypto_digest_add_bytes(d, tmp, count);
count = 0;
}
}
crypto_digest_get_digest(d, key_out, key_out_len);
memset(tmp, 0, tmplen);
tor_free(tmp);
crypto_free_digest_env(d);
}
#ifdef TOR_IS_MULTITHREADED
/** Helper: openssl uses this callback to manipulate mutexes. */
static void
_openssl_locking_cb(int mode, int n, const char *file, int line)
{
(void)file;
(void)line;
if (!_openssl_mutexes)
/* This is not a really good fix for the
* "release-freed-lock-from-separate-thread-on-shutdown" problem, but
* it can't hurt. */
return;
if (mode & CRYPTO_LOCK)
tor_mutex_acquire(_openssl_mutexes[n]);
else
tor_mutex_release(_openssl_mutexes[n]);
}
/** Helper: Construct mutexes, and set callbacks to help OpenSSL handle being
* multithreaded. */
static int
setup_openssl_threading(void)
{
int i;
int n = CRYPTO_num_locks();
_n_openssl_mutexes = n;
_openssl_mutexes = tor_malloc(n*sizeof(tor_mutex_t *));
for (i=0; i < n; ++i)
_openssl_mutexes[i] = tor_mutex_new();
CRYPTO_set_locking_callback(_openssl_locking_cb);
CRYPTO_set_id_callback(tor_get_thread_id);
return 0;
}
#else
static int
setup_openssl_threading(void)
{
return 0;
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -