tor/src/lib/crypt_ops/crypto.c

262 lines
7.0 KiB
C
Raw Normal View History

/* Copyright (c) 2001, Matej Pfajfar.
2006-02-09 06:46:49 +01:00
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
2018-06-20 14:13:28 +02:00
* Copyright (c) 2007-2018, The Tor Project, Inc. */
/* See LICENSE for licensing information */
2004-05-10 05:53:24 +02:00
/**
* \file crypto.c
* \brief Wrapper functions to present a consistent interface to
* public-key and symmetric cryptography operations from OpenSSL and
* other places.
2004-05-10 05:53:24 +02:00
**/
#include "orconfig.h"
#ifdef _WIN32
#include <winsock2.h>
#include <windows.h>
#include <wincrypt.h>
2009-05-27 23:55:51 +02:00
/* Windows defines this; so does OpenSSL 0.9.8h and later. We don't actually
* use either definition. */
#undef OCSP_RESPONSE
#endif /* defined(_WIN32) */
#define CRYPTO_PRIVATE
2018-06-21 18:47:11 +02:00
#include "lib/crypt_ops/compat_openssl.h"
#include "lib/crypt_ops/crypto.h"
#include "lib/crypt_ops/crypto_curve25519.h"
#include "lib/crypt_ops/crypto_digest.h"
#include "lib/crypt_ops/crypto_dh.h"
#include "lib/crypt_ops/crypto_ed25519.h"
#include "lib/crypt_ops/crypto_format.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_rsa.h"
#include "lib/crypt_ops/crypto_util.h"
DISABLE_GCC_WARNING(redundant-decls)
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/bn.h>
#include <openssl/dh.h>
#include <openssl/conf.h>
#include <openssl/hmac.h>
#include <openssl/ssl.h>
ENABLE_GCC_WARNING(redundant-decls)
#if __GNUC__ && GCC_VERSION >= 402
#if GCC_VERSION >= 406
#pragma GCC diagnostic pop
#else
#pragma GCC diagnostic warning "-Wredundant-decls"
#endif
#endif /* __GNUC__ && GCC_VERSION >= 402 */
#ifdef HAVE_CTYPE_H
#include <ctype.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "lib/log/log.h"
#include "lib/log/util_bug.h"
2018-06-21 18:20:52 +02:00
#include "lib/cc/torint.h"
2018-06-21 18:47:11 +02:00
#include "lib/crypt_ops/aes.h"
#include "lib/encoding/binascii.h"
#include "keccak-tiny/keccak-tiny.h"
2018-06-21 22:52:58 +02:00
#include "siphash.h"
#include <string.h>
/** Allocate and return a new symmetric cipher using the provided key and iv.
* The key is <b>bits</b> bits long; the IV is CIPHER_IV_LEN bytes. Both
* must be provided. Key length must be 128, 192, or 256 */
crypto_cipher_t *
crypto_cipher_new_with_iv_and_bits(const uint8_t *key,
const uint8_t *iv,
int bits)
{
tor_assert(key);
tor_assert(iv);
return aes_new_cipher((const uint8_t*)key, (const uint8_t*)iv, bits);
}
/** Allocate and return a new symmetric cipher using the provided key and iv.
* The key is CIPHER_KEY_LEN bytes; the IV is CIPHER_IV_LEN bytes. Both
* must be provided.
*/
crypto_cipher_t *
crypto_cipher_new_with_iv(const char *key, const char *iv)
{
return crypto_cipher_new_with_iv_and_bits((uint8_t*)key, (uint8_t*)iv,
128);
}
/** Return a new crypto_cipher_t with the provided <b>key</b> and an IV of all
* zero bytes and key length <b>bits</b>. Key length must be 128, 192, or
* 256. */
crypto_cipher_t *
crypto_cipher_new_with_bits(const char *key, int bits)
{
char zeroiv[CIPHER_IV_LEN];
memset(zeroiv, 0, sizeof(zeroiv));
return crypto_cipher_new_with_iv_and_bits((uint8_t*)key, (uint8_t*)zeroiv,
bits);
}
/** Return a new crypto_cipher_t with the provided <b>key</b> (of
* CIPHER_KEY_LEN bytes) and an IV of all zero bytes. */
crypto_cipher_t *
crypto_cipher_new(const char *key)
{
return crypto_cipher_new_with_bits(key, 128);
}
2004-05-10 05:53:24 +02:00
/** Free a symmetric cipher.
*/
void
crypto_cipher_free_(crypto_cipher_t *env)
{
if (!env)
return;
aes_cipher_free(env);
}
/** Copy <b>in</b> to the <b>outlen</b>-byte buffer <b>out</b>, adding spaces
* every four characters. */
void
crypto_add_spaces_to_fp(char *out, size_t outlen, const char *in)
{
int n = 0;
char *end = out+outlen;
tor_assert(outlen < SIZE_T_CEILING);
while (*in && out<end) {
*out++ = *in++;
if (++n == 4 && *in && out<end) {
n = 0;
*out++ = ' ';
}
}
tor_assert(out<end);
*out = '\0';
}
/* symmetric crypto */
2004-05-10 05:53:24 +02:00
/** Encrypt <b>fromlen</b> bytes from <b>from</b> using the cipher
* <b>env</b>; on success, store the result to <b>to</b> and return 0.
* Does not check for failure.
*/
int
crypto_cipher_encrypt(crypto_cipher_t *env, char *to,
const char *from, size_t fromlen)
{
tor_assert(env);
tor_assert(env);
tor_assert(from);
tor_assert(fromlen);
tor_assert(to);
tor_assert(fromlen < SIZE_T_CEILING);
memcpy(to, from, fromlen);
aes_crypt_inplace(env, to, fromlen);
return 0;
}
2004-05-10 05:53:24 +02:00
/** Decrypt <b>fromlen</b> bytes from <b>from</b> using the cipher
* <b>env</b>; on success, store the result to <b>to</b> and return 0.
* Does not check for failure.
*/
int
crypto_cipher_decrypt(crypto_cipher_t *env, char *to,
const char *from, size_t fromlen)
{
tor_assert(env);
tor_assert(from);
tor_assert(to);
tor_assert(fromlen < SIZE_T_CEILING);
memcpy(to, from, fromlen);
aes_crypt_inplace(env, to, fromlen);
return 0;
}
/** Encrypt <b>len</b> bytes on <b>from</b> using the cipher in <b>env</b>;
* on success. Does not check for failure.
*/
void
crypto_cipher_crypt_inplace(crypto_cipher_t *env, char *buf, size_t len)
{
tor_assert(len < SIZE_T_CEILING);
aes_crypt_inplace(env, buf, len);
}
/** Encrypt <b>fromlen</b> bytes (at least 1) from <b>from</b> with the key in
* <b>key</b> to the buffer in <b>to</b> of length
* <b>tolen</b>. <b>tolen</b> must be at least <b>fromlen</b> plus
* CIPHER_IV_LEN bytes for the initialization vector. On success, return the
* number of bytes written, on failure, return -1.
*/
int
crypto_cipher_encrypt_with_iv(const char *key,
char *to, size_t tolen,
const char *from, size_t fromlen)
{
crypto_cipher_t *cipher;
tor_assert(from);
tor_assert(to);
tor_assert(fromlen < INT_MAX);
if (fromlen < 1)
return -1;
if (tolen < fromlen + CIPHER_IV_LEN)
return -1;
char iv[CIPHER_IV_LEN];
crypto_rand(iv, sizeof(iv));
cipher = crypto_cipher_new_with_iv(key, iv);
memcpy(to, iv, CIPHER_IV_LEN);
crypto_cipher_encrypt(cipher, to+CIPHER_IV_LEN, from, fromlen);
crypto_cipher_free(cipher);
memwipe(iv, 0, sizeof(iv));
return (int)(fromlen + CIPHER_IV_LEN);
}
/** Decrypt <b>fromlen</b> bytes (at least 1+CIPHER_IV_LEN) from <b>from</b>
* with the key in <b>key</b> to the buffer in <b>to</b> of length
* <b>tolen</b>. <b>tolen</b> must be at least <b>fromlen</b> minus
* CIPHER_IV_LEN bytes for the initialization vector. On success, return the
* number of bytes written, on failure, return -1.
*/
int
crypto_cipher_decrypt_with_iv(const char *key,
char *to, size_t tolen,
const char *from, size_t fromlen)
{
crypto_cipher_t *cipher;
tor_assert(key);
tor_assert(from);
tor_assert(to);
tor_assert(fromlen < INT_MAX);
if (fromlen <= CIPHER_IV_LEN)
return -1;
if (tolen < fromlen - CIPHER_IV_LEN)
return -1;
cipher = crypto_cipher_new_with_iv(key, from);
crypto_cipher_encrypt(cipher, to, from+CIPHER_IV_LEN, fromlen-CIPHER_IV_LEN);
crypto_cipher_free(cipher);
return (int)(fromlen - CIPHER_IV_LEN);
}