diff options
Diffstat (limited to 'src/common/aes.c')
-rw-r--r-- | src/common/aes.c | 207 |
1 files changed, 58 insertions, 149 deletions
diff --git a/src/common/aes.c b/src/common/aes.c index 5f2c3f2f03..15970a73f0 100644 --- a/src/common/aes.c +++ b/src/common/aes.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001, Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2015, The Tor Project, Inc. */ + * Copyright (c) 2007-2016, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -23,6 +23,19 @@ #error "We require OpenSSL >= 1.0.0" #endif +#ifdef __GNUC__ +#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) +#endif + +#if __GNUC__ && GCC_VERSION >= 402 +#if GCC_VERSION >= 406 +#pragma GCC diagnostic push +#endif +/* Some versions of OpenSSL declare SSL_get_selected_srtp_profile twice in + * srtp.h. Suppress the GCC warning so we can build with -Wredundant-decl. */ +#pragma GCC diagnostic ignored "-Wredundant-decls" +#endif + #include <assert.h> #include <stdlib.h> #include <string.h> @@ -30,6 +43,15 @@ #include <openssl/evp.h> #include <openssl/engine.h> #include <openssl/modes.h> + +#if __GNUC__ && GCC_VERSION >= 402 +#if GCC_VERSION >= 406 +#pragma GCC diagnostic pop +#else +#pragma GCC diagnostic warning "-Wredundant-decls" +#endif +#endif + #include "compat.h" #include "aes.h" #include "util.h" @@ -81,47 +103,34 @@ #ifdef USE_EVP_AES_CTR -struct aes_cnt_cipher { - EVP_CIPHER_CTX evp; -}; +/* We don't actually define the struct here. */ aes_cnt_cipher_t * aes_new_cipher(const char *key, const char *iv) { - aes_cnt_cipher_t *cipher; - cipher = tor_malloc_zero(sizeof(aes_cnt_cipher_t)); - EVP_EncryptInit(&cipher->evp, EVP_aes_128_ctr(), + EVP_CIPHER_CTX *cipher = EVP_CIPHER_CTX_new(); + EVP_EncryptInit(cipher, EVP_aes_128_ctr(), (const unsigned char*)key, (const unsigned char *)iv); - return cipher; + return (aes_cnt_cipher_t *) cipher; } void -aes_cipher_free(aes_cnt_cipher_t *cipher) +aes_cipher_free(aes_cnt_cipher_t *cipher_) { - if (!cipher) + if (!cipher_) return; - EVP_CIPHER_CTX_cleanup(&cipher->evp); - memwipe(cipher, 0, sizeof(aes_cnt_cipher_t)); - tor_free(cipher); -} -void -aes_crypt(aes_cnt_cipher_t *cipher, const char *input, size_t len, - char *output) -{ - int outl; - - tor_assert(len < INT_MAX); - - EVP_EncryptUpdate(&cipher->evp, (unsigned char*)output, - &outl, (const unsigned char *)input, (int)len); + EVP_CIPHER_CTX *cipher = (EVP_CIPHER_CTX *) cipher_; + EVP_CIPHER_CTX_cleanup(cipher); + EVP_CIPHER_CTX_free(cipher); } void -aes_crypt_inplace(aes_cnt_cipher_t *cipher, char *data, size_t len) +aes_crypt_inplace(aes_cnt_cipher_t *cipher_, char *data, size_t len) { int outl; + EVP_CIPHER_CTX *cipher = (EVP_CIPHER_CTX *) cipher_; tor_assert(len < INT_MAX); - EVP_EncryptUpdate(&cipher->evp, (unsigned char*)data, + EVP_EncryptUpdate(cipher, (unsigned char*)data, &outl, (unsigned char*)data, (int)len); } int @@ -182,10 +191,6 @@ struct aes_cnt_cipher { * we're testing it or because we have hardware acceleration configured */ static int should_use_EVP = 0; -/** True iff we have tested the counter-mode implementation and found that it - * doesn't have the counter-mode bug from OpenSSL 1.0.0. */ -static int should_use_openssl_CTR = 0; - /** Check whether we should use the EVP interface for AES. If <b>force_val</b> * is nonnegative, we use use EVP iff it is true. Otherwise, we use EVP * if there is an engine enabled for aes-ecb. */ @@ -250,13 +255,9 @@ evaluate_ctr_for_aes(void) if (fast_memneq(output, encrypt_zero, 16)) { /* Counter mode is buggy */ - log_notice(LD_CRYPTO, "This OpenSSL has a buggy version of counter mode; " - "not using it."); - } else { - /* Counter mode is okay */ - log_info(LD_CRYPTO, "This OpenSSL has a good implementation of counter " - "mode; using it."); - should_use_openssl_CTR = 1; + log_err(LD_CRYPTO, "This OpenSSL has a buggy version of counter mode; " + "quitting tor."); + exit(1); } return 0; } @@ -267,29 +268,6 @@ evaluate_ctr_for_aes(void) #define COUNTER(c, n) ((c)->counter ## n) #endif -/** - * Helper function: set <b>cipher</b>'s internal buffer to the encrypted - * value of the current counter. - */ -static INLINE void -aes_fill_buf_(aes_cnt_cipher_t *cipher) -{ - /* We don't currently use OpenSSL's counter mode implementation because: - * 1) some versions have known bugs - * 2) its attitude towards IVs is not our own - * 3) changing the counter position was not trivial, last time I looked. - * None of these issues are insurmountable in principle. - */ - - if (cipher->using_evp) { - int outl=16, inl=16; - EVP_EncryptUpdate(&cipher->key.evp, cipher->buf, &outl, - cipher->ctr_buf.buf, inl); - } else { - AES_encrypt(cipher->ctr_buf.buf, cipher->buf, &cipher->key.aes); - } -} - static void aes_set_key(aes_cnt_cipher_t *cipher, const char *key, int key_bits); static void aes_set_iv(aes_cnt_cipher_t *cipher, const char *iv); @@ -342,10 +320,7 @@ aes_set_key(aes_cnt_cipher_t *cipher, const char *key, int key_bits) cipher->pos = 0; - if (should_use_openssl_CTR) - memset(cipher->buf, 0, sizeof(cipher->buf)); - else - aes_fill_buf_(cipher); + memset(cipher->buf, 0, sizeof(cipher->buf)); } /** Release storage held by <b>cipher</b> @@ -381,63 +356,6 @@ evp_block128_fn(const uint8_t in[16], EVP_EncryptUpdate(ctx, out, &outl, in, inl); } -/** Encrypt <b>len</b> bytes from <b>input</b>, storing the result in - * <b>output</b>. Uses the key in <b>cipher</b>, and advances the counter - * by <b>len</b> bytes as it encrypts. - */ -void -aes_crypt(aes_cnt_cipher_t *cipher, const char *input, size_t len, - char *output) -{ - if (should_use_openssl_CTR) { - if (cipher->using_evp) { - /* In openssl 1.0.0, there's an if'd out EVP_aes_128_ctr in evp.h. If - * it weren't disabled, it might be better just to use that. - */ - CRYPTO_ctr128_encrypt((const unsigned char *)input, - (unsigned char *)output, - len, - &cipher->key.evp, - cipher->ctr_buf.buf, - cipher->buf, - &cipher->pos, - evp_block128_fn); - } else { - AES_ctr128_encrypt((const unsigned char *)input, - (unsigned char *)output, - len, - &cipher->key.aes, - cipher->ctr_buf.buf, - cipher->buf, - &cipher->pos); - } - return; - } else { - int c = cipher->pos; - if (PREDICT_UNLIKELY(!len)) return; - - while (1) { - do { - if (len-- == 0) { cipher->pos = c; return; } - *(output++) = *(input++) ^ cipher->buf[c]; - } while (++c != 16); - cipher->pos = c = 0; - if (PREDICT_UNLIKELY(! ++COUNTER(cipher, 0))) { - if (PREDICT_UNLIKELY(! ++COUNTER(cipher, 1))) { - if (PREDICT_UNLIKELY(! ++COUNTER(cipher, 2))) { - ++COUNTER(cipher, 3); - UPDATE_CTR_BUF(cipher, 3); - } - UPDATE_CTR_BUF(cipher, 2); - } - UPDATE_CTR_BUF(cipher, 1); - } - UPDATE_CTR_BUF(cipher, 0); - aes_fill_buf_(cipher); - } - } -} - /** Encrypt <b>len</b> bytes from <b>input</b>, storing the results in place. * Uses the key in <b>cipher</b>, and advances the counter by <b>len</b> bytes * as it encrypts. @@ -445,32 +363,26 @@ aes_crypt(aes_cnt_cipher_t *cipher, const char *input, size_t len, void aes_crypt_inplace(aes_cnt_cipher_t *cipher, char *data, size_t len) { - if (should_use_openssl_CTR) { - aes_crypt(cipher, data, len, data); - return; + if (cipher->using_evp) { + /* In openssl 1.0.0, there's an if'd out EVP_aes_128_ctr in evp.h. If + * it weren't disabled, it might be better just to use that. + */ + CRYPTO_ctr128_encrypt((const unsigned char *)data, + (unsigned char *)data, + len, + &cipher->key.evp, + cipher->ctr_buf.buf, + cipher->buf, + &cipher->pos, + evp_block128_fn); } else { - int c = cipher->pos; - if (PREDICT_UNLIKELY(!len)) return; - - while (1) { - do { - if (len-- == 0) { cipher->pos = c; return; } - *(data++) ^= cipher->buf[c]; - } while (++c != 16); - cipher->pos = c = 0; - if (PREDICT_UNLIKELY(! ++COUNTER(cipher, 0))) { - if (PREDICT_UNLIKELY(! ++COUNTER(cipher, 1))) { - if (PREDICT_UNLIKELY(! ++COUNTER(cipher, 2))) { - ++COUNTER(cipher, 3); - UPDATE_CTR_BUF(cipher, 3); - } - UPDATE_CTR_BUF(cipher, 2); - } - UPDATE_CTR_BUF(cipher, 1); - } - UPDATE_CTR_BUF(cipher, 0); - aes_fill_buf_(cipher); - } + AES_ctr128_encrypt((const unsigned char *)data, + (unsigned char *)data, + len, + &cipher->key.aes, + cipher->ctr_buf.buf, + cipher->buf, + &cipher->pos); } } @@ -487,9 +399,6 @@ aes_set_iv(aes_cnt_cipher_t *cipher, const char *iv) #endif cipher->pos = 0; memcpy(cipher->ctr_buf.buf, iv, 16); - - if (!should_use_openssl_CTR) - aes_fill_buf_(cipher); } #endif |