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 [email protected]
Automated List Manager [email protected]