📄 crypto.c
字号:
crypto_digest_assign(crypto_digest_env_t *into,
const crypto_digest_env_t *from)
{
tor_assert(into);
tor_assert(from);
memcpy(into,from,sizeof(crypto_digest_env_t));
}
/** Compute the HMAC-SHA-1 of the <b>msg_len</b> bytes in <b>msg</b>, using
* the <b>key</b> of length <b>key_len</b>. Store the DIGEST_LEN-byte result
* in <b>hmac_out</b>.
*/
void
crypto_hmac_sha1(char *hmac_out,
const char *key, size_t key_len,
const char *msg, size_t msg_len)
{
tor_assert(key_len < INT_MAX);
tor_assert(msg_len < INT_MAX);
HMAC(EVP_sha1(), key, (int)key_len, (unsigned char*)msg, (int)msg_len,
(unsigned char*)hmac_out, NULL);
}
/* DH */
/** Shared P parameter for our DH key exchanged. */
static BIGNUM *dh_param_p = NULL;
/** Shared G parameter for our DH key exchanges. */
static BIGNUM *dh_param_g = NULL;
/** Initialize dh_param_p and dh_param_g if they are not already
* set. */
static void
init_dh_param(void)
{
BIGNUM *p, *g;
int r;
if (dh_param_p && dh_param_g)
return;
p = BN_new();
g = BN_new();
tor_assert(p);
tor_assert(g);
/* This is from rfc2409, section 6.2. It's a safe prime, and
supposedly it equals:
2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 }.
*/
r = BN_hex2bn(&p,
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08"
"8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B"
"302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9"
"A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6"
"49286651ECE65381FFFFFFFFFFFFFFFF");
tor_assert(r);
r = BN_set_word(g, 2);
tor_assert(r);
dh_param_p = p;
dh_param_g = g;
}
#define DH_PRIVATE_KEY_BITS 320
/** Allocate and return a new DH object for a key exchange.
*/
crypto_dh_env_t *
crypto_dh_new(void)
{
crypto_dh_env_t *res = NULL;
if (!dh_param_p)
init_dh_param();
res = tor_malloc_zero(sizeof(crypto_dh_env_t));
if (!(res->dh = DH_new()))
goto err;
if (!(res->dh->p = BN_dup(dh_param_p)))
goto err;
if (!(res->dh->g = BN_dup(dh_param_g)))
goto err;
res->dh->length = DH_PRIVATE_KEY_BITS;
return res;
err:
crypto_log_errors(LOG_WARN, "creating DH object");
if (res && res->dh) DH_free(res->dh); /* frees p and g too */
if (res) tor_free(res);
return NULL;
}
/** Return the length of the DH key in <b>dh</b>, in bytes.
*/
int
crypto_dh_get_bytes(crypto_dh_env_t *dh)
{
tor_assert(dh);
return DH_size(dh->dh);
}
/** Generate \<x,g^x\> for our part of the key exchange. Return 0 on
* success, -1 on failure.
*/
int
crypto_dh_generate_public(crypto_dh_env_t *dh)
{
again:
if (!DH_generate_key(dh->dh)) {
crypto_log_errors(LOG_WARN, "generating DH key");
return -1;
}
if (tor_check_dh_key(dh->dh->pub_key)<0) {
log_warn(LD_CRYPTO, "Weird! Our own DH key was invalid. I guess once-in-"
"the-universe chances really do happen. Trying again.");
/* Free and clear the keys, so openssl will actually try again. */
BN_free(dh->dh->pub_key);
BN_free(dh->dh->priv_key);
dh->dh->pub_key = dh->dh->priv_key = NULL;
goto again;
}
return 0;
}
/** Generate g^x as necessary, and write the g^x for the key exchange
* as a <b>pubkey_len</b>-byte value into <b>pubkey</b>. Return 0 on
* success, -1 on failure. <b>pubkey_len</b> must be \>= DH_BYTES.
*/
int
crypto_dh_get_public(crypto_dh_env_t *dh, char *pubkey, size_t pubkey_len)
{
int bytes;
tor_assert(dh);
if (!dh->dh->pub_key) {
if (crypto_dh_generate_public(dh)<0)
return -1;
}
tor_assert(dh->dh->pub_key);
bytes = BN_num_bytes(dh->dh->pub_key);
tor_assert(bytes >= 0);
if (pubkey_len < (size_t)bytes) {
log_warn(LD_CRYPTO,
"Weird! pubkey_len (%d) was smaller than DH_BYTES (%d)",
(int) pubkey_len, bytes);
return -1;
}
memset(pubkey, 0, pubkey_len);
BN_bn2bin(dh->dh->pub_key, (unsigned char*)(pubkey+(pubkey_len-bytes)));
return 0;
}
/** Check for bad diffie-hellman public keys (g^x). Return 0 if the key is
* okay (in the subgroup [2,p-2]), or -1 if it's bad.
* See http://www.cl.cam.ac.uk/ftp/users/rja14/psandqs.ps.gz for some tips.
*/
static int
tor_check_dh_key(BIGNUM *bn)
{
BIGNUM *x;
char *s;
tor_assert(bn);
x = BN_new();
tor_assert(x);
if (!dh_param_p)
init_dh_param();
BN_set_word(x, 1);
if (BN_cmp(bn,x)<=0) {
log_warn(LD_CRYPTO, "DH key must be at least 2.");
goto err;
}
BN_copy(x,dh_param_p);
BN_sub_word(x, 1);
if (BN_cmp(bn,x)>=0) {
log_warn(LD_CRYPTO, "DH key must be at most p-2.");
goto err;
}
BN_free(x);
return 0;
err:
BN_free(x);
s = BN_bn2hex(bn);
log_warn(LD_CRYPTO, "Rejecting insecure DH key [%s]", s);
OPENSSL_free(s);
return -1;
}
#undef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
/** Given a DH key exchange object, and our peer's value of g^y (as a
* <b>pubkey_len</b>-byte value in <b>pubkey</b>) generate
* <b>secret_bytes_out</b> bytes of shared key material and write them
* to <b>secret_out</b>. Return the number of bytes generated on success,
* or -1 on failure.
*
* (We generate key material by computing
* SHA1( g^xy || "\x00" ) || SHA1( g^xy || "\x01" ) || ...
* where || is concatenation.)
*/
ssize_t
crypto_dh_compute_secret(crypto_dh_env_t *dh,
const char *pubkey, size_t pubkey_len,
char *secret_out, size_t secret_bytes_out)
{
char *secret_tmp = NULL;
BIGNUM *pubkey_bn = NULL;
size_t secret_len=0;
int result=0;
tor_assert(dh);
tor_assert(secret_bytes_out/DIGEST_LEN <= 255);
tor_assert(pubkey_len < INT_MAX);
if (!(pubkey_bn = BN_bin2bn((const unsigned char*)pubkey,
(int)pubkey_len, NULL)))
goto error;
if (tor_check_dh_key(pubkey_bn)<0) {
/* Check for invalid public keys. */
log_warn(LD_CRYPTO,"Rejected invalid g^x");
goto error;
}
secret_tmp = tor_malloc(crypto_dh_get_bytes(dh));
result = DH_compute_key((unsigned char*)secret_tmp, pubkey_bn, dh->dh);
if (result < 0) {
log_warn(LD_CRYPTO,"DH_compute_key() failed.");
goto error;
}
secret_len = result;
/* sometimes secret_len might be less than 128, e.g., 127. that's ok. -RD */
/* Actually, http://www.faqs.org/rfcs/rfc2631.html says:
* Leading zeros MUST be preserved, so that ZZ occupies as many
* octets as p. For instance, if p is 1024 bits, ZZ should be 128
* bytes long.
* XXX021 What are the security implications here? -NM
*/
if (crypto_expand_key_material(secret_tmp, secret_len,
secret_out, secret_bytes_out)<0)
goto error;
secret_len = secret_bytes_out;
goto done;
error:
result = -1;
done:
crypto_log_errors(LOG_WARN, "completing DH handshake");
if (pubkey_bn)
BN_free(pubkey_bn);
tor_free(secret_tmp);
if (result < 0)
return result;
else
return secret_len;
}
/** Given <b>key_in_len</b> bytes of negotiated randomness in <b>key_in</b>
* ("K"), expand it into <b>key_out_len</b> bytes of negotiated key material in
* <b>key_out</b> by taking the first <b>key_out_len</b> bytes of
* H(K | [00]) | H(K | [01]) | ....
*
* Return 0 on success, -1 on failure.
*/
int
crypto_expand_key_material(const char *key_in, size_t key_in_len,
char *key_out, size_t key_out_len)
{
int i;
char *cp, *tmp = tor_malloc(key_in_len+1);
char digest[DIGEST_LEN];
/* If we try to get more than this amount of key data, we'll repeat blocks.*/
tor_assert(key_out_len <= DIGEST_LEN*256);
memcpy(tmp, key_in, key_in_len);
for (cp = key_out, i=0; cp < key_out+key_out_len;
++i, cp += DIGEST_LEN) {
tmp[key_in_len] = i;
if (crypto_digest(digest, tmp, key_in_len+1))
goto err;
memcpy(cp, digest, MIN(DIGEST_LEN, key_out_len-(cp-key_out)));
}
memset(tmp, 0, key_in_len+1);
tor_free(tmp);
memset(digest, 0, sizeof(digest));
return 0;
err:
memset(tmp, 0, key_in_len+1);
tor_free(tmp);
memset(digest, 0, sizeof(digest));
return -1;
}
/** Free a DH key exchange object.
*/
void
crypto_dh_free(crypto_dh_env_t *dh)
{
tor_assert(dh);
tor_assert(dh->dh);
DH_free(dh->dh);
tor_free(dh);
}
/* random numbers */
/* This is how much entropy OpenSSL likes to add right now, so maybe it will
* work for us too. */
#define ADD_ENTROPY 32
/* Use RAND_poll if openssl is 0.9.6 release or later. (The "f" means
"release".) */
#define HAVE_RAND_POLL (OPENSSL_VERSION_NUMBER >= 0x0090600fl)
/* Versions of openssl prior to 0.9.7k and 0.9.8c had a bug where RAND_poll
* would allocate an fd_set on the stack, open a new file, and try to FD_SET
* that fd without checking whether it fit in the fd_set. Thus, if the
* system has not just been started up, it is unsafe to call */
#define RAND_POLL_IS_SAFE \
((OPENSSL_VERSION_NUMBER >= 0x009070afl && \
OPENSSL_VERSION_NUMBER <= 0x00907fffl) || \
(OPENSSL_VERSION_NUMBER >= 0x0090803fl))
/* We could actually get away with calling RAND_poll */
#define USE_RAND_POLL (HAVE_RAND_POLL && RAND_POLL_IS_SAFE)
/** Seed OpenSSL's random number generator with bytes from the operating
* system. <b>startup</b> should be true iff we have just started Tor and
* have not yet allocated a bunch of fds. Return 0 on success, -1 on failure.
*/
int
crypto_seed_rng(int startup)
{
char buf[ADD_ENTROPY];
int rand_poll_status = 0;
/* local variables */
#ifdef MS_WINDOWS
static int provider_set = 0;
static HCRYPTPROV provider;
#else
static const char *filenames[] = {
"/dev/srandom", "/dev/urandom", "/dev/random", NULL
};
int fd, i;
size_t n;
#endif
#if HAVE_RAND_POLL
/* OpenSSL 0.9.6 adds a RAND_poll function that knows about more kinds of
* entropy than we do. We'll try calling that, *and* calling our own entropy
* functions. If one succeeds, we'll accept the RNG as seeded. */
if (startup || RAND_POLL_IS_SAFE) {
rand_poll_status = RAND_poll();
if (rand_poll_status == 0)
log_warn(LD_CRYPTO, "RAND_poll() failed.");
}
#endif
#ifdef MS_WINDOWS
if (!provider_set) {
if (!CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT)) {
if ((unsigned long)GetLastError() != (unsigned long)NTE_BAD_KEYSET) {
log_warn(LD_CRYPTO, "Can't get CryptoAPI provider [1]");
return rand_poll_status ? 0 : -1;
}
}
provider_set = 1;
}
if (!CryptGenRandom(provider, sizeof(buf), buf)) {
log_warn(LD_CRYPTO, "Can't get entropy from CryptoAPI.");
return rand_poll_status ? 0 : -1;
}
RAND_seed(buf, sizeof(buf));
memset(buf, 0, sizeof(buf));
return 0;
#else
for (i = 0; filenames[i]; ++i) {
fd = open(filenames[i], O_RDONLY, 0);
if (fd<0) continue;
log_info(LD_CRYPTO, "Seeding RNG from \"%s\"", filenames[i]);
n = read_all(fd, buf, sizeof(buf), 0);
close(fd);
if (n != sizeof(buf)) {
log_warn(LD_CRYPTO,
"Error reading from entropy source (read only %lu bytes).",
(unsigned long)n);
return -1;
}
RAND_seed(buf, (int)sizeof(buf));
memset(buf, 0, sizeof(buf));
return 0;
}
log_warn(LD_CRYPTO, "Cannot seed RNG -- no entropy source found.");
return rand_poll_status ? 0 : -1;
#endif
}
/** Write <b>n</b> bytes of strong random data to <b>to</b>. Return 0 on
* success, -1 on failure.
*/
int
crypto_rand(char *to, size_t n)
{
int r;
tor_assert(n < INT_MAX);
tor_assert(to);
r = RAND_bytes((unsigned char*)to, (int)n);
if (r == 0)
crypto_log_errors(LOG_WARN, "generating random data");
return (r == 1) ? 0 : -1;
}
/** Return a pseudorandom integer, chosen uniformly from the values
* between 0 and <b>max</b>-1. */
int
crypto_rand_int(unsigned int max)
{
unsigned int val;
unsigned int cutoff;
tor_assert(max < UINT_MAX);
tor_assert(max > 0); /* don't div by 0 */
/* We ignore any values that are >= 'cutoff,' to avoid biasing the
* distribution with clipping at the upper end of unsigned int's
* range.
*/
cutoff = UINT_MAX - (UINT_MAX%max);
while (1) {
crypto_rand((char*)&val, sizeof(val));
if (val < cutoff)
return val % max;
}
}
/** Return a pseudorandom 64-bit integer, chosen uniformly from the values
* between 0 and <b>max</b>-1. */
uint64_t
crypto_rand_uint64(uint64_t max)
{
uint64_t val;
uint64_t cutoff;
tor_assert(max < UINT64_MAX);
tor_assert(max > 0); /* don't div by 0 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -