From 17f20f72af65b77986ebf93732682e74563e95b7 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Mon, 28 Sep 2026 21:28:13 -0700 Subject: [PATCH 1/5] Require an IV before EVP ARIA-GCM encryption --- tests/api/test_evp_cipher.c | 35 +++++++++++++++++++++++++++++++++++ tests/api/test_evp_cipher.h | 2 ++ wolfcrypt/src/evp.c | 10 ++++++++++ 3 files changed, 47 insertions(+) diff --git a/tests/api/test_evp_cipher.c b/tests/api/test_evp_cipher.c index 8f0f0f816f1..da9265ed365 100644 --- a/tests/api/test_evp_cipher.c +++ b/tests/api/test_evp_cipher.c @@ -2151,6 +2151,41 @@ int test_wolfssl_EVP_chacha20_poly1305(void) return EXPECT_RESULT(); } +int test_evp_cipher_aria_gcm_iv_required(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && defined(HAVE_ARIA) && \ + !defined(HAVE_SELFTEST) && !defined(HAVE_FIPS) + EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); + byte key[ARIA_128_KEY_SIZE] = {0}; + byte iv[GCM_NONCE_MID_SZ] = {0}; + byte input[4] = {1, 2, 3, 4}; + byte output[WC_ARIA_GCM_GET_CIPHERTEXT_SIZE(sizeof(input))] = {0}; + int len = 0; + + ExpectNotNull(ctx); + if (ctx != NULL) { + ExpectIntEQ(EVP_EncryptInit_ex(ctx, EVP_aria_128_gcm(), NULL, + key, NULL), WOLFSSL_SUCCESS); + ExpectIntEQ(EVP_EncryptUpdate(ctx, output, &len, input, + sizeof(input)), WOLFSSL_SUCCESS); + ExpectIntEQ(EVP_EncryptFinal_ex(ctx, output, &len), + WOLFSSL_FAILURE); + ExpectIntLT(EVP_Cipher(ctx, output, input, sizeof(input)), 0); + + iv[0] = 1; + ExpectIntEQ(EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv), + WOLFSSL_SUCCESS); + ExpectIntEQ(EVP_EncryptUpdate(ctx, output, &len, input, + sizeof(input)), WOLFSSL_SUCCESS); + ExpectIntEQ(EVP_EncryptFinal_ex(ctx, output, &len), + WOLFSSL_SUCCESS); + EVP_CIPHER_CTX_free(ctx); + } +#endif + return EXPECT_RESULT(); +} + int test_wolfssl_EVP_aria_gcm(void) { int res = TEST_SKIPPED; diff --git a/tests/api/test_evp_cipher.h b/tests/api/test_evp_cipher.h index 3acc4a4d293..7b590c29093 100644 --- a/tests/api/test_evp_cipher.h +++ b/tests/api/test_evp_cipher.h @@ -53,6 +53,7 @@ int test_wolfssl_EVP_aes_ccm_zeroLen(void); int test_wolfssl_EVP_chacha20(void); int test_wolfssl_EVP_chacha20_poly1305(void); int test_wolfssl_EVP_aria_gcm(void); +int test_evp_cipher_aria_gcm_iv_required(void); int test_wolfssl_EVP_sm4_ecb(void); int test_wolfssl_EVP_sm4_cbc(void); int test_wolfssl_EVP_sm4_ctr(void); @@ -101,6 +102,7 @@ int test_evp_cipher_update_no_padding_buffered(void); TEST_DECL_GROUP("evp_cipher", test_wolfssl_EVP_chacha20), \ TEST_DECL_GROUP("evp_cipher", test_wolfssl_EVP_chacha20_poly1305), \ TEST_DECL_GROUP("evp_cipher", test_wolfssl_EVP_aria_gcm), \ + TEST_DECL_GROUP("evp_cipher", test_evp_cipher_aria_gcm_iv_required), \ TEST_DECL_GROUP("evp_cipher", test_wolfssl_EVP_sm4_ecb), \ TEST_DECL_GROUP("evp_cipher", test_wolfssl_EVP_sm4_cbc), \ TEST_DECL_GROUP("evp_cipher", test_wolfssl_EVP_sm4_ctr), \ diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index f60e4d59517..b09a91fef14 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -1480,6 +1480,14 @@ int wolfSSL_EVP_CipherFinal(WOLFSSL_EVP_CIPHER_CTX *ctx, unsigned char *out, case WC_ARIA_128_GCM_TYPE: case WC_ARIA_192_GCM_TYPE: case WC_ARIA_256_GCM_TYPE: + if (ctx->enc && ctx->cipher.aria.nonceSz == 0) { + XFREE(ctx->authBuffer, NULL, DYNAMIC_TYPE_OPENSSL); + ctx->authBuffer = NULL; + ctx->authBufferLen = 0; + *outl = 0; + ret = WOLFSSL_FAILURE; + break; + } if ((ctx->authBuffer && ctx->authBufferLen > 0) || (ctx->authBufferLen == 0)) { if (ctx->enc) @@ -9177,6 +9185,8 @@ void wolfSSL_EVP_init(void) case WC_ARIA_256_GCM_TYPE : WOLFSSL_MSG("ARIA GCM"); if (ctx->enc) { + if (ctx->cipher.aria.nonceSz == 0) + return WC_NO_ERR_TRACE(BAD_STATE_E); ret = wc_AriaEncrypt(&ctx->cipher.aria, dst, src, len, ctx->iv, ctx->ivSz, NULL, 0, ctx->authTag, ctx->authTagSz); From 02ee0681fbcdbc67e193c3ffedd0f729a7c5e134 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Mon, 28 Sep 2026 22:25:09 -0700 Subject: [PATCH 2/5] Require a fresh IV for each EVP ARIA-GCM message --- tests/api/test_evp_cipher.c | 53 +++++++++++++++++++++++++++++++++++++ tests/api/test_evp_cipher.h | 2 ++ wolfcrypt/src/evp.c | 14 ++++++++-- wolfssl/openssl/evp.h | 8 ++++-- 4 files changed, 73 insertions(+), 4 deletions(-) diff --git a/tests/api/test_evp_cipher.c b/tests/api/test_evp_cipher.c index da9265ed365..6b20f69678a 100644 --- a/tests/api/test_evp_cipher.c +++ b/tests/api/test_evp_cipher.c @@ -2186,6 +2186,59 @@ int test_evp_cipher_aria_gcm_iv_required(void) return EXPECT_RESULT(); } +int test_evp_cipher_aria_gcm_message_iv(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && defined(HAVE_ARIA) && \ + !defined(HAVE_SELFTEST) && !defined(HAVE_FIPS) + EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); + byte key[ARIA_128_KEY_SIZE] = {0}; + byte iv[GCM_NONCE_MID_SZ] = {0}; + byte input[4] = {1, 2, 3, 4}; + byte output[WC_ARIA_GCM_GET_CIPHERTEXT_SIZE(sizeof(input))] = {0}; + int len = 0; + + iv[sizeof(iv) - 1] = 1; + ExpectNotNull(ctx); + if (ctx != NULL) { + ExpectIntEQ(EVP_EncryptInit_ex(ctx, EVP_aria_128_gcm(), NULL, + key, iv), WOLFSSL_SUCCESS); + ExpectIntEQ(EVP_EncryptUpdate(ctx, output, &len, input, + sizeof(input)), WOLFSSL_SUCCESS); + ExpectIntEQ(EVP_EncryptFinal_ex(ctx, output, &len), + WOLFSSL_SUCCESS); + ExpectIntEQ(EVP_EncryptUpdate(ctx, output, &len, input, + sizeof(input)), WOLFSSL_SUCCESS); + ExpectIntEQ(EVP_EncryptFinal_ex(ctx, output, &len), + WOLFSSL_FAILURE); + ExpectIntEQ(EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, NULL), + WOLFSSL_SUCCESS); + ExpectIntEQ(EVP_EncryptUpdate(ctx, output, &len, input, + sizeof(input)), WOLFSSL_SUCCESS); + ExpectIntEQ(EVP_EncryptFinal_ex(ctx, output, &len), + WOLFSSL_FAILURE); + + iv[0]++; + ExpectIntEQ(EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv), + WOLFSSL_SUCCESS); + ExpectIntEQ(EVP_EncryptUpdate(ctx, output, &len, input, + sizeof(input)), WOLFSSL_SUCCESS); + ExpectIntEQ(EVP_EncryptFinal_ex(ctx, output, &len), + WOLFSSL_SUCCESS); + + iv[0]++; + ExpectIntEQ(EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv), + WOLFSSL_SUCCESS); + ExpectIntEQ(EVP_Cipher(ctx, output, input, sizeof(input)), + 0); + ExpectBufNE(output, input, sizeof(input)); + ExpectIntLT(EVP_Cipher(ctx, output, input, sizeof(input)), 0); + EVP_CIPHER_CTX_free(ctx); + } +#endif + return EXPECT_RESULT(); +} + int test_wolfssl_EVP_aria_gcm(void) { int res = TEST_SKIPPED; diff --git a/tests/api/test_evp_cipher.h b/tests/api/test_evp_cipher.h index 7b590c29093..82aaefad125 100644 --- a/tests/api/test_evp_cipher.h +++ b/tests/api/test_evp_cipher.h @@ -54,6 +54,7 @@ int test_wolfssl_EVP_chacha20(void); int test_wolfssl_EVP_chacha20_poly1305(void); int test_wolfssl_EVP_aria_gcm(void); int test_evp_cipher_aria_gcm_iv_required(void); +int test_evp_cipher_aria_gcm_message_iv(void); int test_wolfssl_EVP_sm4_ecb(void); int test_wolfssl_EVP_sm4_cbc(void); int test_wolfssl_EVP_sm4_ctr(void); @@ -103,6 +104,7 @@ int test_evp_cipher_update_no_padding_buffered(void); TEST_DECL_GROUP("evp_cipher", test_wolfssl_EVP_chacha20_poly1305), \ TEST_DECL_GROUP("evp_cipher", test_wolfssl_EVP_aria_gcm), \ TEST_DECL_GROUP("evp_cipher", test_evp_cipher_aria_gcm_iv_required), \ + TEST_DECL_GROUP("evp_cipher", test_evp_cipher_aria_gcm_message_iv), \ TEST_DECL_GROUP("evp_cipher", test_wolfssl_EVP_sm4_ecb), \ TEST_DECL_GROUP("evp_cipher", test_wolfssl_EVP_sm4_cbc), \ TEST_DECL_GROUP("evp_cipher", test_wolfssl_EVP_sm4_ctr), \ diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index b09a91fef14..8455639198f 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -1480,7 +1480,8 @@ int wolfSSL_EVP_CipherFinal(WOLFSSL_EVP_CIPHER_CTX *ctx, unsigned char *out, case WC_ARIA_128_GCM_TYPE: case WC_ARIA_192_GCM_TYPE: case WC_ARIA_256_GCM_TYPE: - if (ctx->enc && ctx->cipher.aria.nonceSz == 0) { + if (ctx->enc && (ctx->cipher.aria.nonceSz == 0 || + ctx->authIvUsed)) { XFREE(ctx->authBuffer, NULL, DYNAMIC_TYPE_OPENSSL); ctx->authBuffer = NULL; ctx->authBufferLen = 0; @@ -1502,6 +1503,8 @@ int wolfSSL_EVP_CipherFinal(WOLFSSL_EVP_CIPHER_CTX *ctx, unsigned char *out, ctx->authTag, ctx->authTagSz); if (ret == 0) { + if (ctx->enc) + ctx->authIvUsed = ctx->authIncIv ? 0 : 1; ret = WOLFSSL_SUCCESS; *outl = ctx->authBufferLen; } @@ -7643,6 +7646,9 @@ void wolfSSL_EVP_init(void) const byte* iv, int enc) { int ret = 0; +#ifdef HAVE_ARIA + int ivProvided = (iv != NULL); +#endif (void)key; (void)iv; (void)enc; @@ -8462,6 +8468,8 @@ void wolfSSL_EVP_init(void) != WOLFSSL_SUCCESS) { return WOLFSSL_FAILURE; } + if (ivProvided) + ctx->authIvUsed = 0; } #endif /* HAVE_AESGCM && ((!HAVE_FIPS && !HAVE_SELFTEST) || * HAVE_FIPS_VERSION >= 2 */ @@ -9185,11 +9193,13 @@ void wolfSSL_EVP_init(void) case WC_ARIA_256_GCM_TYPE : WOLFSSL_MSG("ARIA GCM"); if (ctx->enc) { - if (ctx->cipher.aria.nonceSz == 0) + if (ctx->cipher.aria.nonceSz == 0 || ctx->authIvUsed) return WC_NO_ERR_TRACE(BAD_STATE_E); ret = wc_AriaEncrypt(&ctx->cipher.aria, dst, src, len, ctx->iv, ctx->ivSz, NULL, 0, ctx->authTag, ctx->authTagSz); + if (ret == 0) + ctx->authIvUsed = 1; } else { ret = wc_AriaDecrypt(&ctx->cipher.aria, dst, src, len, diff --git a/wolfssl/openssl/evp.h b/wolfssl/openssl/evp.h index f55728b41df..c55ba2cf551 100644 --- a/wolfssl/openssl/evp.h +++ b/wolfssl/openssl/evp.h @@ -730,6 +730,8 @@ struct WOLFSSL_EVP_CIPHER_CTX { #if !defined(NO_AES) /* working iv pointer into cipher */ ALIGN16 unsigned char iv[WC_AES_BLOCK_SIZE]; +#elif defined(HAVE_ARIA) + ALIGN16 unsigned char iv[ARIA_BLOCK_SIZE]; #elif defined(WOLFSSL_SM4) ALIGN16 unsigned char iv[SM4_BLOCK_SIZE]; #elif defined(HAVE_CHACHA) && defined(HAVE_POLY1305) @@ -743,12 +745,13 @@ struct WOLFSSL_EVP_CIPHER_CTX { ALIGN16 byte lastBlock[WOLFSSL_EVP_BUF_SIZE]; int lastUsed; #if !defined(NO_AES) || !defined(NO_DES3) || defined(HAVE_AESGCM) || \ + defined(HAVE_ARIA) || \ defined (WOLFSSL_AES_XTS) || (defined(HAVE_CHACHA) || \ defined(HAVE_POLY1305) || defined(HAVE_AESCCM)) || \ defined(WOLFSSL_SM4_GCM) || defined(WOLFSSL_SM4_CCM) #define HAVE_WOLFSSL_EVP_CIPHER_CTX_IV int ivSz; -#if defined(HAVE_AESGCM) || defined(HAVE_AESCCM) || \ +#if defined(HAVE_AESGCM) || defined(HAVE_AESCCM) || defined(HAVE_ARIA) || \ defined(WOLFSSL_SM4_GCM) || defined(WOLFSSL_SM4_CCM) byte* authBuffer; int authBufferLen; @@ -770,10 +773,11 @@ struct WOLFSSL_EVP_CIPHER_CTX { #endif int authTagSz; #endif -#if defined(HAVE_AESGCM) || defined(HAVE_AESCCM) || \ +#if defined(HAVE_AESGCM) || defined(HAVE_AESCCM) || defined(HAVE_ARIA) || \ defined(WOLFSSL_SM4_GCM) || defined(WOLFSSL_SM4_CCM) WC_BITFIELD authIvGenEnable:1; WC_BITFIELD authIncIv:1; + WC_BITFIELD authIvUsed:1; #endif #endif }; From 36f06ce306f2660bf3399ec98f3f67d5b087e18f Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Tue, 29 Sep 2026 14:57:33 -0700 Subject: [PATCH 3/5] Require a caller IV for EVP ARIA GCM encryption --- tests/api/test_evp_cipher.c | 10 +++++++++- wolfcrypt/src/evp.c | 3 +++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/api/test_evp_cipher.c b/tests/api/test_evp_cipher.c index 6b20f69678a..e75232685aa 100644 --- a/tests/api/test_evp_cipher.c +++ b/tests/api/test_evp_cipher.c @@ -2166,7 +2166,15 @@ int test_evp_cipher_aria_gcm_iv_required(void) ExpectNotNull(ctx); if (ctx != NULL) { ExpectIntEQ(EVP_EncryptInit_ex(ctx, EVP_aria_128_gcm(), NULL, - key, NULL), WOLFSSL_SUCCESS); + NULL, NULL), WOLFSSL_SUCCESS); + ExpectIntEQ(EVP_EncryptUpdate(ctx, output, &len, input, + sizeof(input)), WOLFSSL_SUCCESS); + ExpectIntEQ(EVP_EncryptFinal_ex(ctx, output, &len), + WOLFSSL_FAILURE); + ExpectIntLT(EVP_Cipher(ctx, output, input, sizeof(input)), 0); + + ExpectIntEQ(EVP_EncryptInit_ex(ctx, NULL, NULL, key, NULL), + WOLFSSL_SUCCESS); ExpectIntEQ(EVP_EncryptUpdate(ctx, output, &len, input, sizeof(input)), WOLFSSL_SUCCESS); ExpectIntEQ(EVP_EncryptFinal_ex(ctx, output, &len), diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index 8455639198f..235f29e2be2 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -1533,6 +1533,7 @@ int wolfSSL_EVP_CipherFinal(WOLFSSL_EVP_CIPHER_CTX *ctx, unsigned char *out, else { /* Clear IV, since IV reuse is not recommended for AES GCM. */ XMEMSET(ctx->iv, 0, ARIA_BLOCK_SIZE); + ctx->authIvUsed = 1; } if (wolfSSL_StoreExternalIV(ctx) != WOLFSSL_SUCCESS) { ret = WOLFSSL_FAILURE; @@ -8470,6 +8471,8 @@ void wolfSSL_EVP_init(void) } if (ivProvided) ctx->authIvUsed = 0; + else if (type != NULL) + ctx->authIvUsed = 1; } #endif /* HAVE_AESGCM && ((!HAVE_FIPS && !HAVE_SELFTEST) || * HAVE_FIPS_VERSION >= 2 */ From 76f05333585dd0dfdd50d5fb736719d9ee9729bd Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Mon, 12 Oct 2026 13:14:39 -0700 Subject: [PATCH 4/5] Drop the redundant ARIA GCM IV used update in EVP final --- wolfcrypt/src/evp.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index 235f29e2be2..8c641c32b0e 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -1503,8 +1503,6 @@ int wolfSSL_EVP_CipherFinal(WOLFSSL_EVP_CIPHER_CTX *ctx, unsigned char *out, ctx->authTag, ctx->authTagSz); if (ret == 0) { - if (ctx->enc) - ctx->authIvUsed = ctx->authIncIv ? 0 : 1; ret = WOLFSSL_SUCCESS; *outl = ctx->authBufferLen; } @@ -1531,7 +1529,7 @@ int wolfSSL_EVP_CipherFinal(WOLFSSL_EVP_CIPHER_CTX *ctx, unsigned char *out, ctx->authIncIv = 0; } else { - /* Clear IV, since IV reuse is not recommended for AES GCM. */ + /* Clear IV since ARIA GCM must not reuse an IV. */ XMEMSET(ctx->iv, 0, ARIA_BLOCK_SIZE); ctx->authIvUsed = 1; } From d11376a46548efc919dfc0d79c9b451c234715e4 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Fri, 6 Nov 2026 13:30:58 -0800 Subject: [PATCH 5/5] Fix HAVE_ARIA endif comment in EVP cipher init --- wolfcrypt/src/evp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index 8c641c32b0e..55eb01c703f 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -8472,8 +8472,7 @@ void wolfSSL_EVP_init(void) else if (type != NULL) ctx->authIvUsed = 1; } - #endif /* HAVE_AESGCM && ((!HAVE_FIPS && !HAVE_SELFTEST) || - * HAVE_FIPS_VERSION >= 2 */ + #endif /* HAVE_ARIA */ #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)