Skip to content

Commit c070c59

Browse files
authored
Merge pull request #153 from haydenroche5/aes_ctr_bug
Fix bug with AES-CTR initialization.
2 parents 4067767 + d66e0a0 commit c070c59

File tree

4 files changed

+90
-6
lines changed

4 files changed

+90
-6
lines changed

src/we_aes_ctr.c

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ typedef struct we_AesCtr
3434
{
3535
/** The wolfSSL AES data object. */
3636
Aes aes;
37-
/** Flag to indicate whether wolfSSL AES object initialized. */
38-
unsigned int init:1;
37+
/** Flag to indicate whether IV has been set. */
38+
unsigned int ivSet:1;
3939
} we_AesCtr;
4040

4141

@@ -54,6 +54,7 @@ static int we_aes_ctr_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
5454
int ret = 1;
5555
int rc;
5656
we_AesCtr *aes;
57+
const unsigned char *tmpIv;
5758

5859
WOLFENGINE_ENTER(WE_LOG_CIPHER, "we_aes_ctr_init");
5960

@@ -75,13 +76,20 @@ static int we_aes_ctr_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
7576
}
7677

7778
if (ret == 1) {
78-
/* Must have initialized wolfSSL AES object when here. */
79-
aes->init = 1;
80-
8179
if (key != NULL) {
80+
if (iv == NULL && aes->ivSet) {
81+
/* If the IV was set on a previous call, we don't want to pass
82+
* NULL for the IV to wc_AesSetKey, as that will result in the
83+
* IV being set to 0s. */
84+
tmpIv = (unsigned char *)&aes->aes.reg;
85+
}
86+
else {
87+
tmpIv = iv;
88+
}
89+
8290
/* No decryption for CTR. */
8391
rc = wc_AesSetKey(&aes->aes, key, EVP_CIPHER_CTX_key_length(ctx),
84-
iv, AES_ENCRYPTION);
92+
tmpIv, AES_ENCRYPTION);
8593
if (rc != 0) {
8694
WOLFENGINE_ERROR_FUNC(WE_LOG_CIPHER, "wc_AesSetKey", rc);
8795
ret = 0;
@@ -93,6 +101,9 @@ static int we_aes_ctr_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
93101
WOLFENGINE_ERROR_FUNC(WE_LOG_CIPHER, "wc_AesSetIV", rc);
94102
ret = 0;
95103
}
104+
else {
105+
aes->ivSet = 1;
106+
}
96107
}
97108
}
98109

test/test_cipher.c

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,5 +514,75 @@ int test_aes256_ctr_stream(ENGINE *e, void *data)
514514
return err;
515515
}
516516

517+
/* OpenSSL allows the user to call EVP_CipherInit with NULL key or IV. In the
518+
* past, setting the IV first (with key NULL) with wolfEngine and then setting
519+
* the key (with IV NULL) would result in the IV getting set to 0s on the call
520+
* to set the key. This was discovered in testing with OpenSSH. This is a
521+
* regression test to ensure we preserve the IV in this scenario. */
522+
int test_aes_ctr_iv_init_regression(ENGINE *e, void *data)
523+
{
524+
int err = 0;
525+
unsigned char iv[AES_BLOCK_SIZE];
526+
unsigned char key[16];
527+
EVP_CIPHER_CTX* encCtx = NULL;
528+
EVP_CIPHER_CTX* decCtx = NULL;
529+
const unsigned char plainText[] = "Lorem ipsum dolor sit amet";
530+
unsigned char encText[sizeof(plainText)];
531+
unsigned char decText[sizeof(plainText)];
532+
533+
(void)data;
534+
535+
/* Generate a random IV and key. */
536+
err = RAND_bytes(iv, AES_BLOCK_SIZE) != 1;
537+
if (err == 0) {
538+
err = RAND_bytes(key, 16) != 1;
539+
}
540+
541+
/* Create encryption context. Use OpenSSL for encryption. */
542+
if (err == 0) {
543+
err = (encCtx = EVP_CIPHER_CTX_new()) == NULL;
544+
}
545+
if (err == 0) {
546+
err = EVP_CipherInit_ex(encCtx, EVP_aes_128_ctr(), NULL, NULL, iv, 1)
547+
!= 1;
548+
}
549+
if (err == 0) {
550+
err = EVP_CipherInit_ex(encCtx, NULL, NULL, key, NULL, -1) != 1;
551+
}
552+
553+
/* Create decryption context. Use wolfEngine for decryption. */
554+
if (err == 0) {
555+
err = (decCtx = EVP_CIPHER_CTX_new()) == NULL;
556+
}
557+
if (err == 0) {
558+
err = EVP_CipherInit_ex(decCtx, EVP_aes_128_ctr(), e, NULL, iv, 0) != 1;
559+
}
560+
if (err == 0) {
561+
err = EVP_CipherInit_ex(decCtx, NULL, e, key, NULL, -1) != 1;
562+
}
563+
564+
/* Encrypt. */
565+
if (err == 0) {
566+
err = EVP_Cipher(encCtx, encText, plainText, sizeof(plainText)) < 0;
567+
}
568+
569+
/* Decrypt. */
570+
if (err == 0) {
571+
err = EVP_Cipher(decCtx, decText, encText, sizeof(plainText)) < 0;
572+
}
573+
574+
/* Ensure decrypted and plaintext match. */
575+
if (err == 0) {
576+
err = memcmp(decText, plainText, sizeof(plainText)) != 0;
577+
}
578+
579+
if (encCtx != NULL)
580+
EVP_CIPHER_CTX_free(encCtx);
581+
if (decCtx != NULL)
582+
EVP_CIPHER_CTX_free(decCtx);
583+
584+
return err;
585+
}
586+
517587
#endif /* WE_HAVE_AESCTR */
518588

test/unit.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ TEST_CASE test_case[] = {
116116
TEST_DECL(test_aes128_ctr_stream, NULL),
117117
TEST_DECL(test_aes192_ctr_stream, NULL),
118118
TEST_DECL(test_aes256_ctr_stream, NULL),
119+
TEST_DECL(test_aes_ctr_iv_init_regression, NULL),
119120
#endif
120121
#ifdef WE_HAVE_AESGCM
121122
TEST_DECL(test_aes128_gcm, NULL),

test/unit.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,8 @@ int test_aes128_ctr_stream(ENGINE *e, void *data);
154154
int test_aes192_ctr_stream(ENGINE *e, void *data);
155155
int test_aes256_ctr_stream(ENGINE *e, void *data);
156156

157+
int test_aes_ctr_iv_init_regression(ENGINE *, void *);
158+
157159
#endif
158160

159161
#ifdef WE_HAVE_AESGCM

0 commit comments

Comments
 (0)