Hi, I've noticed an inconsistency between the behavior of AES_CTR in FIPS and non-FIPS modes. I am using openssl-1.0.1c and openssl-fips-2.0.
The following code demonstrates the issue: 1 #include <stdio.h> 2 #include <string.h> 3 #include "openssl/evp.h" 4 5 #define MSG_SIZE 14 6 const unsigned char *key = (unsigned char *)"1234567890123456"; 7 const unsigned char *iv = (unsigned char *)"0101010101010101"; 8 9 int main(void) { 10 11 unsigned char in_1[MSG_SIZE]; 12 unsigned char in_2[MSG_SIZE]; 13 unsigned char out_1[MSG_SIZE]; 14 unsigned char out_2[MSG_SIZE]; 15 int out_len_1, out_len_2; 16 17 EVP_CIPHER_CTX ctx_1, ctx_2; 18 19 memset ( in_1, 0, MSG_SIZE ); 20 memset ( in_2, 0, MSG_SIZE ); 21 22 EVP_CIPHER_CTX_init( &ctx_1 ); 23 EVP_EncryptInit( &ctx_1, EVP_aes_128_ctr(), key, iv ); 24 EVP_EncryptUpdate( &ctx_1, out_1, &out_len_1, in_1, MSG_SIZE ); 25 EVP_EncryptInit( &ctx_1, NULL, NULL, iv ); 26 EVP_EncryptUpdate( &ctx_1, out_1, &out_len_1, in_1, MSG_SIZE ); 27 28 FIPS_mode_set(1); /* Enable FIPS mode */ 29 30 EVP_CIPHER_CTX_init( &ctx_2 ); 31 EVP_EncryptInit( &ctx_2, EVP_aes_128_ctr(), key, iv ); 32 EVP_EncryptUpdate( &ctx_2, out_2, &out_len_2, in_2, MSG_SIZE ); 33 EVP_EncryptInit( &ctx_2, NULL, NULL, iv ); 34 EVP_EncryptUpdate( &ctx_2, out_2, &out_len_2, in_2, MSG_SIZE ); 35 36 if ( memcmp( out_1, out_2, MSG_SIZE ) == 0 ) { 37 printf("Buffers are equal.\n\n"); 38 } else { 39 printf("Buffers are not equal.\n\n"); 40 } 41 42 return 0; 43 } The reason for the difference outputs is that there is a difference in the EVP_EncryptInit code (lines 25 and 33) for the 2 modes. In the non-FIPS mode, line 25 will reset the ctx_1->num to zero. This is done in EVP_CipherInit_ex(), line 240: 239 case EVP_CIPH_CTR_MODE: 240 ctx->num = 0; 241 /* Don't reuse IV for CTR mode */ 242 if(iv) 243 memcpy(ctx->iv, iv, EVP_CIPHER_CTX_iv_length(ctx)); 244 break; 245 However, in FIPS mode, the equivalent line does not reset ctx_2->num. This is from FIPS_cipherinit(), lines 210-215: 210 case EVP_CIPH_CTR_MODE: 211 /* Don't reuse IV for CTR mode */ 212 if(iv) 213 memcpy(ctx->iv, iv, M_EVP_CIPHER_CTX_iv_length(ctx)); 214 break; 215 I can make my program work if I change line 33 from: EVP_EncryptInit( &ctx_2, NULL, NULL, iv ); to: EVP_EncryptInit( &ctx_2, EVP_aes_128_ctr(), key, iv ); This explicitly specifies the cipher and key again. From the docs, it appears that I should be able to set them to NULL and have it work, if they don't need to be updated, and that is how it works in the non-FIPS mode. Questions: ======== 1) Should I need to explicitly specifies the cipher and key again in EVP_EncryptInit(), if I am only updating the IV? (i.e. should I be able to put NULL for key and cipher). 2) Is there purposely a difference in behavior between the FIPS and non-FIPS versions, or is this a bug? My understanding was that they *should* work interchangeably. Thanks, AJ ______________________________________________________________________ OpenSSL Project http://www.openssl.org User Support Mailing List openssl-users@openssl.org Automated List Manager majord...@openssl.org