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

Reply via email to