diff options
Diffstat (limited to 'src/common/aes.c')
-rw-r--r-- | src/common/aes.c | 141 |
1 files changed, 98 insertions, 43 deletions
diff --git a/src/common/aes.c b/src/common/aes.c index 5791e66765..f6288e81e6 100644 --- a/src/common/aes.c +++ b/src/common/aes.c @@ -18,10 +18,10 @@ #include <openssl/evp.h> #include <openssl/engine.h> #include "crypto.h" -#if OPENSSL_VERSION_NUMBER >= OPENSSL_V(1,0,0,'a') +#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,0) /* See comments about which counter mode implementation to use below. */ #include <openssl/modes.h> -#define USE_OPENSSL_CTR +#define CAN_USE_OPENSSL_CTR #endif #include "compat.h" #include "aes.h" @@ -62,7 +62,7 @@ struct aes_cnt_cipher { AES_KEY aes; } key; -#if !defined(WORDS_BIGENDIAN) && !defined(USE_OPENSSL_CTR) +#if !defined(WORDS_BIGENDIAN) #define USING_COUNTER_VARS /** These four values, together, implement a 128-bit counter, with * counter0 as the low-order word and counter3 as the high-order word. */ @@ -84,11 +84,7 @@ struct aes_cnt_cipher { /** The encrypted value of ctr_buf. */ uint8_t buf[16]; /** Our current stream position within buf. */ -#ifdef USE_OPENSSL_CTR unsigned int pos; -#else - uint8_t pos; -#endif /** True iff we're using the evp implementation of this cipher. */ uint8_t using_evp; @@ -98,6 +94,11 @@ struct aes_cnt_cipher { * we're testing it or because we have hardware acceleration configured */ static int should_use_EVP = 0; +#ifdef CAN_USE_OPENSSL_CTR +/**DOCDOC*/ +static int should_use_openssl_CTR = 0; +#endif + /** 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. */ @@ -128,7 +129,50 @@ evaluate_evp_for_aes(int force_val) return 0; } -#ifndef USE_OPENSSL_CTR +/**DOCDOC*/ +int +evaluate_ctr_for_aes(void) +{ +#ifdef CAN_USE_OPENSSL_CTR + /* Result of encrypting an all-zero block with an all-zero 128-bit AES key. + * This should be the same as encrypting an all-zero block with an all-zero + * 128-bit AES key in counter mode, starting at position 0 of the stream. + */ + static const unsigned char encrypt_zero[] = + "\x66\xe9\x4b\xd4\xef\x8a\x2c\x3b\x88\x4c\xfa\x59\xca\x34\x2b\x2e"; + unsigned char zero[16]; + unsigned char output[16]; + unsigned char ivec[16]; + unsigned char ivec_tmp[16]; + unsigned int pos, i; + AES_KEY key; + memset(zero, 0, sizeof(zero)); + memset(ivec, 0, sizeof(ivec)); + AES_set_encrypt_key(zero, 128, &key); + + pos = 0; + /* Encrypting a block one byte at a time should make the error manifest + * itself for known bogus openssl versions. */ + for (i=0; i<16; ++i) + AES_ctr128_encrypt(&zero[i], &output[i], 1, &key, ivec, ivec_tmp, &pos); + + if (memcmp(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_notice(LD_CRYPTO, "This OpenSSL has a good implementation of counter " + "mode; using it."); + should_use_openssl_CTR = 1; + } +#else + log_notice(LD_CRYPTO, "This version of OpenSSL has a slow implementation of " + "counter mode; not using it."); +#endif + return 0; +} + #if !defined(USING_COUNTER_VARS) #define COUNTER(c, n) ((c)->ctr_buf.buf32[3-(n)]) #else @@ -157,7 +201,6 @@ _aes_fill_buf(aes_cnt_cipher_t *cipher) AES_encrypt(cipher->ctr_buf.buf, cipher->buf, &cipher->key.aes); } } -#endif /** * Return a newly allocated counter-mode AES128 cipher implementation. @@ -203,11 +246,12 @@ aes_set_key(aes_cnt_cipher_t *cipher, const char *key, int key_bits) cipher->pos = 0; -#ifdef USE_OPENSSL_CTR - memset(cipher->buf, 0, sizeof(cipher->buf)); -#else - _aes_fill_buf(cipher); +#ifdef CAN_USE_OPENSSL_CTR + if (should_use_openssl_CTR) + memset(cipher->buf, 0, sizeof(cipher->buf)); + else #endif + _aes_fill_buf(cipher); } /** Release storage held by <b>cipher</b> @@ -232,7 +276,7 @@ aes_free_cipher(aes_cnt_cipher_t *cipher) #define UPDATE_CTR_BUF(c, n) #endif -#ifdef USE_OPENSSL_CTR +#ifdef CAN_USE_OPENSSL_CTR /* Helper function to use EVP with openssl's counter-mode wrapper. */ static void evp_block128_fn(const uint8_t in[16], uint8_t out[16], @@ -252,29 +296,34 @@ void aes_crypt(aes_cnt_cipher_t *cipher, const char *input, size_t len, char *output) { -#ifdef 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); +#ifdef CAN_USE_OPENSSL_CTR + 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 + else +#endif + { int c = cipher->pos; if (PREDICT_UNLIKELY(!len)) return; @@ -297,7 +346,7 @@ aes_crypt(aes_cnt_cipher_t *cipher, const char *input, size_t len, UPDATE_CTR_BUF(cipher, 0); _aes_fill_buf(cipher); } -#endif + } } /** Encrypt <b>len</b> bytes from <b>input</b>, storing the results in place. @@ -307,9 +356,14 @@ 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) { -#ifdef USE_OPENSSL_CTR - aes_crypt(cipher, data, len, data); -#else +#ifdef CAN_USE_OPENSSL_CTR + if (should_use_openssl_CTR) { + aes_crypt(cipher, data, len, data); + return; + } + else +#endif + { int c = cipher->pos; if (PREDICT_UNLIKELY(!len)) return; @@ -332,7 +386,7 @@ aes_crypt_inplace(aes_cnt_cipher_t *cipher, char *data, size_t len) UPDATE_CTR_BUF(cipher, 0); _aes_fill_buf(cipher); } -#endif + } } /** Reset the 128-bit counter of <b>cipher</b> to the 16-bit big-endian value @@ -349,8 +403,9 @@ aes_set_iv(aes_cnt_cipher_t *cipher, const char *iv) cipher->pos = 0; memcpy(cipher->ctr_buf.buf, iv, 16); -#ifndef USE_OPENSSL_CTR - _aes_fill_buf(cipher); +#ifdef CAN_USE_OPENSSL_CTR + if (!should_use_openssl_CTR) #endif + _aes_fill_buf(cipher); } |