From 2a5f63c9a61be7582620c4b5da202bb3fd7e4138 Mon Sep 17 00:00:00 2001 From: Pauli Date: Mon, 24 Jun 2019 17:54:47 +1000 Subject: [PATCH] Allow AES XTS decryption using duplicate keys. This feature is enabled by default outside of FIPS builds which ban such actions completely. Encryption is always disallowed and will generate an error. Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/9112) (cherry picked from commit 2c840201e57e27fa9f1b26a970270a91813e32fe) --- crypto/err/openssl.txt | 4 ++ crypto/evp/e_aes.c | 72 ++++++++++++++++++++++- crypto/evp/evp_err.c | 8 ++- include/openssl/evperr.h | 6 +- test/recipes/30-test_evp_data/evpciph.txt | 21 +++++++ 5 files changed, 107 insertions(+), 4 deletions(-) diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index bf440f33b6..bb6b932fe0 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -714,11 +714,14 @@ ENGINE_F_INT_ENGINE_CONFIGURE:188:int_engine_configure ENGINE_F_INT_ENGINE_MODULE_INIT:187:int_engine_module_init ENGINE_F_OSSL_HMAC_INIT:200:ossl_hmac_init EVP_F_AESNI_INIT_KEY:165:aesni_init_key +EVP_F_AESNI_XTS_INIT_KEY:207:aesni_xts_init_key EVP_F_AES_GCM_CTRL:196:aes_gcm_ctrl EVP_F_AES_INIT_KEY:133:aes_init_key EVP_F_AES_OCB_CIPHER:169:aes_ocb_cipher EVP_F_AES_T4_INIT_KEY:178:aes_t4_init_key +EVP_F_AES_T4_XTS_INIT_KEY:208:aes_t4_xts_init_key EVP_F_AES_WRAP_CIPHER:170:aes_wrap_cipher +EVP_F_AES_XTS_INIT_KEY:209:aes_xts_init_key EVP_F_ALG_MODULE_INIT:177:alg_module_init EVP_F_ARIA_CCM_INIT_KEY:175:aria_ccm_init_key EVP_F_ARIA_GCM_CTRL:197:aria_gcm_ctrl @@ -2289,6 +2292,7 @@ EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM:118:unsupported private key algorithm EVP_R_UNSUPPORTED_SALT_TYPE:126:unsupported salt type EVP_R_WRAP_MODE_NOT_ALLOWED:170:wrap mode not allowed EVP_R_WRONG_FINAL_BLOCK_LENGTH:109:wrong final block length +EVP_R_XTS_DUPLICATED_KEYS:183:xts duplicated keys KDF_R_INVALID_DIGEST:100:invalid digest KDF_R_MISSING_ITERATION_COUNT:109:missing iteration count KDF_R_MISSING_KEY:104:missing key diff --git a/crypto/evp/e_aes.c b/crypto/evp/e_aes.c index 68322e1982..e60d736b9c 100644 --- a/crypto/evp/e_aes.c +++ b/crypto/evp/e_aes.c @@ -59,6 +59,12 @@ typedef struct { const unsigned char iv[16]); } EVP_AES_XTS_CTX; +#ifdef FIPS_MODE +static const int allow_insecure_decrypt = 0; +#else +static const int allow_insecure_decrypt = 1; +#endif + typedef struct { union { double align; @@ -383,10 +389,27 @@ static int aesni_xts_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, const unsigned char *iv, int enc) { EVP_AES_XTS_CTX *xctx = EVP_C_DATA(EVP_AES_XTS_CTX,ctx); + if (!iv && !key) return 1; if (key) { + /* The key is two half length keys in reality */ + const int bytes = EVP_CIPHER_CTX_key_length(ctx) / 2; + const int bits = bytes * 8; + + /* + * Verify that the two keys are different. + * + * This addresses Rogaway's vulnerability. + * See comment in aes_xts_init_key() below. + */ + if ((!allow_insecure_decrypt || enc) + && CRYPTO_memcmp(key, key + bytes, bytes) == 0) { + EVPerr(EVP_F_AESNI_XTS_INIT_KEY, EVP_R_XTS_DUPLICATED_KEYS); + return 0; + } + /* key_len is two AES keys */ if (enc) { aesni_set_encrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 4, @@ -787,11 +810,27 @@ static int aes_t4_xts_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, const unsigned char *iv, int enc) { EVP_AES_XTS_CTX *xctx = EVP_C_DATA(EVP_AES_XTS_CTX,ctx); + if (!iv && !key) return 1; if (key) { - int bits = EVP_CIPHER_CTX_key_length(ctx) * 4; + /* The key is two half length keys in reality */ + const int bytes = EVP_CIPHER_CTX_key_length(ctx) / 2; + const int bits = bytes * 8; + + /* + * Verify that the two keys are different. + * + * This addresses Rogaway's vulnerability. + * See comment in aes_xts_init_key() below. + */ + if ((!allow_insecure_decrypt || enc) + && CRYPTO_memcmp(key, key + bytes, bytes) == 0) { + EVPerr(EVP_F_AES_T4_XTS_INIT_KEY, EVP_R_XTS_DUPLICATED_KEYS); + return 0; + } + xctx->stream = NULL; /* key_len is two AES keys */ if (enc) { @@ -3284,10 +3323,12 @@ BLOCK_CIPHER_custom(NID_aes, 128, 1, 12, gcm, GCM, static int aes_xts_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr) { - EVP_AES_XTS_CTX *xctx = EVP_C_DATA(EVP_AES_XTS_CTX,c); + EVP_AES_XTS_CTX *xctx = EVP_C_DATA(EVP_AES_XTS_CTX, c); + if (type == EVP_CTRL_COPY) { EVP_CIPHER_CTX *out = ptr; EVP_AES_XTS_CTX *xctx_out = EVP_C_DATA(EVP_AES_XTS_CTX,out); + if (xctx->xts.key1) { if (xctx->xts.key1 != &xctx->ks1) return 0; @@ -3311,11 +3352,38 @@ static int aes_xts_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, const unsigned char *iv, int enc) { EVP_AES_XTS_CTX *xctx = EVP_C_DATA(EVP_AES_XTS_CTX,ctx); + if (!iv && !key) return 1; if (key) do { + /* The key is two half length keys in reality */ + const int bytes = EVP_CIPHER_CTX_key_length(ctx) / 2; + const int bits = bytes * 8; + + /* + * Verify that the two keys are different. + * + * This addresses the vulnerability described in Rogaway's + * September 2004 paper: + * + * "Efficient Instantiations of Tweakable Blockciphers and + * Refinements to Modes OCB and PMAC". + * (http://web.cs.ucdavis.edu/~rogaway/papers/offsets.pdf) + * + * FIPS 140-2 IG A.9 XTS-AES Key Generation Requirements states + * that: + * "The check for Key_1 != Key_2 shall be done at any place + * BEFORE using the keys in the XTS-AES algorithm to process + * data with them." + */ + if ((!allow_insecure_decrypt || enc) + && CRYPTO_memcmp(key, key + bytes, bytes) == 0) { + EVPerr(EVP_F_AES_XTS_INIT_KEY, EVP_R_XTS_DUPLICATED_KEYS); + return 0; + } + #ifdef AES_XTS_ASM xctx->stream = enc ? AES_xts_encrypt : AES_xts_decrypt; #else diff --git a/crypto/evp/evp_err.c b/crypto/evp/evp_err.c index 60df27cbc2..40ed0d902f 100644 --- a/crypto/evp/evp_err.c +++ b/crypto/evp/evp_err.c @@ -1,6 +1,6 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the OpenSSL license (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -15,11 +15,15 @@ static const ERR_STRING_DATA EVP_str_functs[] = { {ERR_PACK(ERR_LIB_EVP, EVP_F_AESNI_INIT_KEY, 0), "aesni_init_key"}, + {ERR_PACK(ERR_LIB_EVP, EVP_F_AESNI_XTS_INIT_KEY, 0), "aesni_xts_init_key"}, {ERR_PACK(ERR_LIB_EVP, EVP_F_AES_GCM_CTRL, 0), "aes_gcm_ctrl"}, {ERR_PACK(ERR_LIB_EVP, EVP_F_AES_INIT_KEY, 0), "aes_init_key"}, {ERR_PACK(ERR_LIB_EVP, EVP_F_AES_OCB_CIPHER, 0), "aes_ocb_cipher"}, {ERR_PACK(ERR_LIB_EVP, EVP_F_AES_T4_INIT_KEY, 0), "aes_t4_init_key"}, + {ERR_PACK(ERR_LIB_EVP, EVP_F_AES_T4_XTS_INIT_KEY, 0), + "aes_t4_xts_init_key"}, {ERR_PACK(ERR_LIB_EVP, EVP_F_AES_WRAP_CIPHER, 0), "aes_wrap_cipher"}, + {ERR_PACK(ERR_LIB_EVP, EVP_F_AES_XTS_INIT_KEY, 0), "aes_xts_init_key"}, {ERR_PACK(ERR_LIB_EVP, EVP_F_ALG_MODULE_INIT, 0), "alg_module_init"}, {ERR_PACK(ERR_LIB_EVP, EVP_F_ARIA_CCM_INIT_KEY, 0), "aria_ccm_init_key"}, {ERR_PACK(ERR_LIB_EVP, EVP_F_ARIA_GCM_CTRL, 0), "aria_gcm_ctrl"}, @@ -266,6 +270,8 @@ static const ERR_STRING_DATA EVP_str_reasons[] = { "wrap mode not allowed"}, {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_WRONG_FINAL_BLOCK_LENGTH), "wrong final block length"}, + {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_XTS_DUPLICATED_KEYS), + "xts duplicated keys"}, {0, NULL} }; diff --git a/include/openssl/evperr.h b/include/openssl/evperr.h index 84f03eb3c4..0a5b7e24f3 100644 --- a/include/openssl/evperr.h +++ b/include/openssl/evperr.h @@ -1,6 +1,6 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the OpenSSL license (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -20,11 +20,14 @@ int ERR_load_EVP_strings(void); * EVP function codes. */ # define EVP_F_AESNI_INIT_KEY 165 +# define EVP_F_AESNI_XTS_INIT_KEY 207 # define EVP_F_AES_GCM_CTRL 196 # define EVP_F_AES_INIT_KEY 133 # define EVP_F_AES_OCB_CIPHER 169 # define EVP_F_AES_T4_INIT_KEY 178 +# define EVP_F_AES_T4_XTS_INIT_KEY 208 # define EVP_F_AES_WRAP_CIPHER 170 +# define EVP_F_AES_XTS_INIT_KEY 209 # define EVP_F_ALG_MODULE_INIT 177 # define EVP_F_ARIA_CCM_INIT_KEY 175 # define EVP_F_ARIA_GCM_CTRL 197 @@ -190,5 +193,6 @@ int ERR_load_EVP_strings(void); # define EVP_R_UNSUPPORTED_SALT_TYPE 126 # define EVP_R_WRAP_MODE_NOT_ALLOWED 170 # define EVP_R_WRONG_FINAL_BLOCK_LENGTH 109 +# define EVP_R_XTS_DUPLICATED_KEYS 183 #endif diff --git a/test/recipes/30-test_evp_data/evpciph.txt b/test/recipes/30-test_evp_data/evpciph.txt index 68eddca7b7..634b63346c 100644 --- a/test/recipes/30-test_evp_data/evpciph.txt +++ b/test/recipes/30-test_evp_data/evpciph.txt @@ -1190,7 +1190,28 @@ Result = CIPHERFINAL_ERROR Title = AES XTS test vectors from IEEE Std 1619-2007 +# Using the same key twice for encryption is always banned. Cipher = aes-128-xts +Operation = ENCRYPT +Key = 0000000000000000000000000000000000000000000000000000000000000000 +IV = 00000000000000000000000000000000 +Plaintext = 0000000000000000000000000000000000000000000000000000000000000000 +Ciphertext = 917cf69ebd68b2ec9b9fe9a3eadda692cd43d2f59598ed858c02c2652fbf922e + +# Using the same key twice for decryption is banned in FIPS mode. +#Cipher = aes-128-xts +#FIPS = YES +#Operation = DECRYPT +#Key = 0000000000000000000000000000000000000000000000000000000000000000 +#IV = 00000000000000000000000000000000 +#Plaintext = 0000000000000000000000000000000000000000000000000000000000000000 +#Ciphertext = 917cf69ebd68b2ec9b9fe9a3eadda692cd43d2f59598ed858c02c2652fbf922e +#Result = KEY_SET_ERROR + +# Using the same key twice for decryption is allowed outside of FIPS mode. +Cipher = aes-128-xts +#FIPS = NO +Operation = DECRYPT Key = 0000000000000000000000000000000000000000000000000000000000000000 IV = 00000000000000000000000000000000 Plaintext = 0000000000000000000000000000000000000000000000000000000000000000 -- 2.25.1