From c655fa0e3048c1a4465202e8d502fff29cb773e4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 2 Jun 2026 09:54:46 +0000 Subject: [PATCH 01/12] Initial plan From dd90fd1981f4a44f7fea6ee697cb6a9f1ad6dbe9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 2 Jun 2026 10:08:36 +0000 Subject: [PATCH 02/12] Fix Android ChaCha20Poly1305 tag mismatch exception Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com> --- .../Interop.Cipher.cs | 26 +++++++ .../Cryptography/ChaCha20Poly1305.Android.cs | 15 +++- .../pal_cipher.c | 73 +++++++++++++++---- .../pal_cipher.h | 1 + 4 files changed, 100 insertions(+), 15 deletions(-) diff --git a/src/libraries/Common/src/Interop/Android/System.Security.Cryptography.Native.Android/Interop.Cipher.cs b/src/libraries/Common/src/Interop/Android/System.Security.Cryptography.Native.Android/Interop.Cipher.cs index dc9fa576936491..94cf895f4396ce 100644 --- a/src/libraries/Common/src/Interop/Android/System.Security.Cryptography.Native.Android/Interop.Cipher.cs +++ b/src/libraries/Common/src/Interop/Android/System.Security.Cryptography.Native.Android/Interop.Cipher.cs @@ -101,6 +101,32 @@ ref MemoryMarshal.GetReference(input), input.Length); } + [LibraryImport(Libraries.AndroidCryptoNative, EntryPoint = "AndroidCryptoNative_AeadCipherUpdate")] + [return: MarshalAs(UnmanagedType.Bool)] + private static partial bool EvpAeadCipherUpdate( + SafeEvpCipherCtxHandle ctx, + ref byte @out, + out int outl, + ref byte @in, + int inl, + [MarshalAs(UnmanagedType.Bool)] out bool authTagMismatch); + + internal static bool EvpAeadCipherUpdate( + SafeEvpCipherCtxHandle ctx, + Span output, + out int bytesWritten, + ReadOnlySpan input, + out bool authTagMismatch) + { + return EvpAeadCipherUpdate( + ctx, + ref MemoryMarshal.GetReference(output), + out bytesWritten, + ref MemoryMarshal.GetReference(input), + input.Length, + out authTagMismatch); + } + [LibraryImport(Libraries.AndroidCryptoNative, EntryPoint = "AndroidCryptoNative_CipherUpdateAAD")] [return: MarshalAs(UnmanagedType.Bool)] private static partial bool CipherUpdateAAD( diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/ChaCha20Poly1305.Android.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/ChaCha20Poly1305.Android.cs index a62b54dbf12fd4..b668c95a2d5b10 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/ChaCha20Poly1305.Android.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/ChaCha20Poly1305.Android.cs @@ -127,9 +127,20 @@ private void DecryptCore( throw new CryptographicException(); } - if (!Interop.Crypto.EvpCipherUpdate(_ctxHandle, plaintext.Slice(plaintextBytesWritten), out int bytesWritten, tag)) + if (!Interop.Crypto.EvpAeadCipherUpdate( + _ctxHandle, + plaintext.Slice(plaintextBytesWritten), + out int bytesWritten, + tag, + out bool authTagMismatch)) { CryptographicOperations.ZeroMemory(plaintext); + + if (authTagMismatch) + { + throw new AuthenticationTagMismatchException(); + } + throw new CryptographicException(); } @@ -139,7 +150,7 @@ private void DecryptCore( _ctxHandle, plaintext.Slice(plaintextBytesWritten), out bytesWritten, - out bool authTagMismatch)) + out authTagMismatch)) { CryptographicOperations.ZeroMemory(plaintext); diff --git a/src/native/libs/System.Security.Cryptography.Native.Android/pal_cipher.c b/src/native/libs/System.Security.Cryptography.Native.Android/pal_cipher.c index a775b0f7552888..ee37ab58dad789 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Android/pal_cipher.c +++ b/src/native/libs/System.Security.Cryptography.Native.Android/pal_cipher.c @@ -76,6 +76,29 @@ ARGS_NON_NULL_ALL static jobject GetAlgorithmName(JNIEnv* env, CipherInfo* type) return make_java_string(env, type->name); } +ARGS_NON_NULL_ALL static int32_t CheckJNIExceptionsForAuthTagMismatch(JNIEnv* env, int32_t* authTagMismatch) +{ + jthrowable ex = NULL; + + if (TryGetJNIException(env, &ex, false)) + { + if (ex == NULL) + { + return FAIL; + } + + if ((*env)->IsInstanceOf(env, ex, g_AEADBadTagExceptionClass)) + { + *authTagMismatch = 1; + } + + (*env)->DeleteLocalRef(env, ex); + return FAIL; + } + + return SUCCESS; +} + int32_t AndroidCryptoNative_CipherIsSupported(CipherInfo* type) { abort_if_invalid_pointer_argument (type); @@ -276,6 +299,42 @@ int32_t AndroidCryptoNative_CipherUpdate(CipherCtx* ctx, uint8_t* outm, int32_t* return CheckJNIExceptions(env) ? FAIL : SUCCESS; } +int32_t AndroidCryptoNative_AeadCipherUpdate( + CipherCtx* ctx, uint8_t* outm, int32_t* outl, uint8_t* in, int32_t inl, int32_t* authTagMismatch) +{ + if (!ctx) + return FAIL; + + abort_if_invalid_pointer_argument(authTagMismatch); + + *authTagMismatch = 0; + + if (!outl && !in) + // it means caller wants us to record "inl" but we don't need it. + return SUCCESS; + + abort_if_invalid_pointer_argument(outl); + abort_if_invalid_pointer_argument(in); + + JNIEnv* env = GetJNIEnv(); + jbyteArray inDataBytes = make_java_byte_array(env, inl); + (*env)->SetByteArrayRegion(env, inDataBytes, 0, inl, (jbyte*)in); + + *outl = 0; + jbyteArray outDataBytes = (jbyteArray)(*env)->CallObjectMethod(env, ctx->cipher, g_cipherUpdateMethod, inDataBytes); + + if (outDataBytes && outm) + { + jsize outDataBytesLen = (*env)->GetArrayLength(env, outDataBytes); + *outl = outDataBytesLen; + (*env)->GetByteArrayRegion(env, outDataBytes, 0, outDataBytesLen, (jbyte*) outm); + (*env)->DeleteLocalRef(env, outDataBytes); + } + + (*env)->DeleteLocalRef(env, inDataBytes); + return CheckJNIExceptionsForAuthTagMismatch(env, authTagMismatch); +} + int32_t AndroidCryptoNative_CipherFinalEx(CipherCtx* ctx, uint8_t* outm, int32_t* outl) { if (!ctx) @@ -315,21 +374,9 @@ int32_t AndroidCryptoNative_AeadCipherFinalEx(CipherCtx* ctx, uint8_t* outm, int *authTagMismatch = 0; jbyteArray outBytes = (jbyteArray)(*env)->CallObjectMethod(env, ctx->cipher, g_cipherDoFinalMethod); - jthrowable ex = NULL; - if (TryGetJNIException(env, &ex, false)) + if (CheckJNIExceptionsForAuthTagMismatch(env, authTagMismatch) != SUCCESS) { - if (ex == NULL) - { - return FAIL; - } - - if ((*env)->IsInstanceOf(env, ex, g_AEADBadTagExceptionClass)) - { - *authTagMismatch = 1; - } - - (*env)->DeleteLocalRef(env, ex); return FAIL; } diff --git a/src/native/libs/System.Security.Cryptography.Native.Android/pal_cipher.h b/src/native/libs/System.Security.Cryptography.Native.Android/pal_cipher.h index dc1bbe2211df53..a258f97ee53b96 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Android/pal_cipher.h +++ b/src/native/libs/System.Security.Cryptography.Native.Android/pal_cipher.h @@ -35,6 +35,7 @@ PALEXPORT int32_t AndroidCryptoNative_CipherReset(CipherCtx* ctx, uint8_t* pIv, PALEXPORT int32_t AndroidCryptoNative_CipherCtxSetPadding(CipherCtx* ctx, int32_t padding); PALEXPORT int32_t AndroidCryptoNative_CipherUpdateAAD(CipherCtx* ctx, uint8_t* in, int32_t inl); PALEXPORT int32_t AndroidCryptoNative_CipherUpdate(CipherCtx* ctx, uint8_t* out, int32_t* outl, uint8_t* in, int32_t inl); +PALEXPORT int32_t AndroidCryptoNative_AeadCipherUpdate(CipherCtx* ctx, uint8_t* out, int32_t* outl, uint8_t* in, int32_t inl, int32_t* authTagMismatch); PALEXPORT int32_t AndroidCryptoNative_CipherFinalEx(CipherCtx* ctx, uint8_t* outm, int32_t* outl); PALEXPORT int32_t AndroidCryptoNative_AeadCipherFinalEx(CipherCtx* ctx, uint8_t* outm, int32_t* outl, int32_t* authTagMismatch); PALEXPORT CipherInfo* AndroidCryptoNative_Aes128Ecb(void); From dc6a5dd868e3e444b44a6c58412187851cfce6ed Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 2 Jun 2026 13:03:08 +0000 Subject: [PATCH 03/12] Update Android AES AEAD tag handling Co-authored-by: vcsjones <361677+vcsjones@users.noreply.github.com> --- .../Security/Cryptography/AesCcm.Android.cs | 15 +++++++++++++-- .../Security/Cryptography/AesGcm.Android.cs | 15 +++++++++++++-- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/AesCcm.Android.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/AesCcm.Android.cs index 0f7297af6aef58..7b222ada620fcc 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/AesCcm.Android.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/AesCcm.Android.cs @@ -159,9 +159,20 @@ private void DecryptCore( throw new CryptographicException(); } - if (!Interop.Crypto.EvpCipherUpdate(ctx, plaintext.Slice(plaintextBytesWritten), out int bytesWritten, tag)) + if (!Interop.Crypto.EvpAeadCipherUpdate( + ctx, + plaintext.Slice(plaintextBytesWritten), + out int bytesWritten, + tag, + out bool authTagMismatch)) { CryptographicOperations.ZeroMemory(plaintext); + + if (authTagMismatch) + { + throw new AuthenticationTagMismatchException(); + } + throw new CryptographicException(); } @@ -171,7 +182,7 @@ private void DecryptCore( ctx, plaintext.Slice(plaintextBytesWritten), out bytesWritten, - out bool authTagMismatch)) + out authTagMismatch)) { CryptographicOperations.ZeroMemory(plaintext); diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/AesGcm.Android.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/AesGcm.Android.cs index 551ef7e32ca1ff..0d9e9eccf561c9 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/AesGcm.Android.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/AesGcm.Android.cs @@ -137,9 +137,20 @@ private partial void DecryptCore( throw new CryptographicException(); } - if (!Interop.Crypto.EvpCipherUpdate(_ctxHandle, plaintext.Slice(plaintextBytesWritten), out int bytesWritten, tag)) + if (!Interop.Crypto.EvpAeadCipherUpdate( + _ctxHandle, + plaintext.Slice(plaintextBytesWritten), + out int bytesWritten, + tag, + out bool authTagMismatch)) { CryptographicOperations.ZeroMemory(plaintext); + + if (authTagMismatch) + { + throw new AuthenticationTagMismatchException(); + } + throw new CryptographicException(); } @@ -149,7 +160,7 @@ private partial void DecryptCore( _ctxHandle, plaintext.Slice(plaintextBytesWritten), out bytesWritten, - out bool authTagMismatch)) + out authTagMismatch)) { CryptographicOperations.ZeroMemory(plaintext); From b28e2582bb1dee60201bb6b71b203d222db3a95c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 2 Jun 2026 13:46:48 +0000 Subject: [PATCH 04/12] Use spans for Android AEAD update interop Co-authored-by: vcsjones <361677+vcsjones@users.noreply.github.com> --- .../Interop.Cipher.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libraries/Common/src/Interop/Android/System.Security.Cryptography.Native.Android/Interop.Cipher.cs b/src/libraries/Common/src/Interop/Android/System.Security.Cryptography.Native.Android/Interop.Cipher.cs index 94cf895f4396ce..ea2e16afc8507a 100644 --- a/src/libraries/Common/src/Interop/Android/System.Security.Cryptography.Native.Android/Interop.Cipher.cs +++ b/src/libraries/Common/src/Interop/Android/System.Security.Cryptography.Native.Android/Interop.Cipher.cs @@ -105,9 +105,9 @@ ref MemoryMarshal.GetReference(input), [return: MarshalAs(UnmanagedType.Bool)] private static partial bool EvpAeadCipherUpdate( SafeEvpCipherCtxHandle ctx, - ref byte @out, + Span output, out int outl, - ref byte @in, + ReadOnlySpan input, int inl, [MarshalAs(UnmanagedType.Bool)] out bool authTagMismatch); @@ -120,9 +120,9 @@ internal static bool EvpAeadCipherUpdate( { return EvpAeadCipherUpdate( ctx, - ref MemoryMarshal.GetReference(output), + output, out bytesWritten, - ref MemoryMarshal.GetReference(input), + input, input.Length, out authTagMismatch); } From ce2449d6701faa3254e82840026011fead44e1ac Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 3 Jun 2026 05:29:35 +0000 Subject: [PATCH 05/12] Check AEAD update exceptions before copying output Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com> --- .../pal_cipher.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/native/libs/System.Security.Cryptography.Native.Android/pal_cipher.c b/src/native/libs/System.Security.Cryptography.Native.Android/pal_cipher.c index ee37ab58dad789..e9dab8f7d8dc34 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Android/pal_cipher.c +++ b/src/native/libs/System.Security.Cryptography.Native.Android/pal_cipher.c @@ -323,6 +323,17 @@ int32_t AndroidCryptoNative_AeadCipherUpdate( *outl = 0; jbyteArray outDataBytes = (jbyteArray)(*env)->CallObjectMethod(env, ctx->cipher, g_cipherUpdateMethod, inDataBytes); + if (CheckJNIExceptionsForAuthTagMismatch(env, authTagMismatch) != SUCCESS) + { + if (outDataBytes) + { + (*env)->DeleteLocalRef(env, outDataBytes); + } + + (*env)->DeleteLocalRef(env, inDataBytes); + return FAIL; + } + if (outDataBytes && outm) { jsize outDataBytesLen = (*env)->GetArrayLength(env, outDataBytes); From 7bee3982ef9d7c16115e718ff74e531e4da714d9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 3 Jun 2026 05:30:44 +0000 Subject: [PATCH 06/12] Simplify AEAD update exception cleanup Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com> --- .../System.Security.Cryptography.Native.Android/pal_cipher.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/native/libs/System.Security.Cryptography.Native.Android/pal_cipher.c b/src/native/libs/System.Security.Cryptography.Native.Android/pal_cipher.c index e9dab8f7d8dc34..af6ff72c95ce31 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Android/pal_cipher.c +++ b/src/native/libs/System.Security.Cryptography.Native.Android/pal_cipher.c @@ -325,11 +325,6 @@ int32_t AndroidCryptoNative_AeadCipherUpdate( if (CheckJNIExceptionsForAuthTagMismatch(env, authTagMismatch) != SUCCESS) { - if (outDataBytes) - { - (*env)->DeleteLocalRef(env, outDataBytes); - } - (*env)->DeleteLocalRef(env, inDataBytes); return FAIL; } From 462cfb1f4c3c0556779f5ddfc49b77a07a0933b2 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Wed, 3 Jun 2026 10:37:10 +0200 Subject: [PATCH 07/12] Reduce code duplication and avoid uncaught exception crashes --- .../pal_cipher.c | 82 +++++++------------ 1 file changed, 29 insertions(+), 53 deletions(-) diff --git a/src/native/libs/System.Security.Cryptography.Native.Android/pal_cipher.c b/src/native/libs/System.Security.Cryptography.Native.Android/pal_cipher.c index af6ff72c95ce31..158e674471b4d3 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Android/pal_cipher.c +++ b/src/native/libs/System.Security.Cryptography.Native.Android/pal_cipher.c @@ -76,27 +76,23 @@ ARGS_NON_NULL_ALL static jobject GetAlgorithmName(JNIEnv* env, CipherInfo* type) return make_java_string(env, type->name); } -ARGS_NON_NULL_ALL static int32_t CheckJNIExceptionsForAuthTagMismatch(JNIEnv* env, int32_t* authTagMismatch) +ARGS_NON_NULL_ALL static bool CheckJNIExceptionsForAuthTagMismatch(JNIEnv* env, int32_t* authTagMismatch) { - jthrowable ex = NULL; + bool result = false; + INIT_LOCALS(loc, ex); - if (TryGetJNIException(env, &ex, false)) + if (TryGetJNIException(env, &loc[ex], /* printException: */ false)) { - if (ex == NULL) - { - return FAIL; - } + result = true; - if ((*env)->IsInstanceOf(env, ex, g_AEADBadTagExceptionClass)) + if (loc[ex] != NULL && (*env)->IsInstanceOf(env, loc[ex], g_AEADBadTagExceptionClass)) { *authTagMismatch = 1; } - - (*env)->DeleteLocalRef(env, ex); - return FAIL; } - return SUCCESS; + RELEASE_LOCALS(loc, env); + return result; } int32_t AndroidCryptoNative_CipherIsSupported(CipherInfo* type) @@ -270,33 +266,8 @@ int32_t AndroidCryptoNative_CipherUpdateAAD(CipherCtx* ctx, uint8_t* in, int32_t int32_t AndroidCryptoNative_CipherUpdate(CipherCtx* ctx, uint8_t* outm, int32_t* outl, uint8_t* in, int32_t inl) { - if (!ctx) - return FAIL; - - if (!outl && !in) - // it means caller wants us to record "inl" but we don't need it. - return SUCCESS; - - abort_if_invalid_pointer_argument(outl); - abort_if_invalid_pointer_argument(in); - - JNIEnv* env = GetJNIEnv(); - jbyteArray inDataBytes = make_java_byte_array(env, inl); - (*env)->SetByteArrayRegion(env, inDataBytes, 0, inl, (jbyte*)in); - - *outl = 0; - jbyteArray outDataBytes = (jbyteArray)(*env)->CallObjectMethod(env, ctx->cipher, g_cipherUpdateMethod, inDataBytes); - - if (outDataBytes && outm) - { - jsize outDataBytesLen = (*env)->GetArrayLength(env, outDataBytes); - *outl = outDataBytesLen; - (*env)->GetByteArrayRegion(env, outDataBytes, 0, outDataBytesLen, (jbyte*) outm); - (*env)->DeleteLocalRef(env, outDataBytes); - } - - (*env)->DeleteLocalRef(env, inDataBytes); - return CheckJNIExceptions(env) ? FAIL : SUCCESS; + int32_t authTagMismatch = 0; + return AndroidCryptoNative_AeadCipherUpdate(ctx, outm, outl, in, inl, &authTagMismatch); } int32_t AndroidCryptoNative_AeadCipherUpdate( @@ -316,29 +287,34 @@ int32_t AndroidCryptoNative_AeadCipherUpdate( abort_if_invalid_pointer_argument(outl); abort_if_invalid_pointer_argument(in); + int32_t result = FAIL; + INIT_LOCALS(loc, inDataBytes, outDataBytes); + JNIEnv* env = GetJNIEnv(); - jbyteArray inDataBytes = make_java_byte_array(env, inl); - (*env)->SetByteArrayRegion(env, inDataBytes, 0, inl, (jbyte*)in); + loc[inDataBytes] = make_java_byte_array(env, inl); + (*env)->SetByteArrayRegion(env, loc[inDataBytes], 0, inl, (jbyte*)in); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); *outl = 0; - jbyteArray outDataBytes = (jbyteArray)(*env)->CallObjectMethod(env, ctx->cipher, g_cipherUpdateMethod, inDataBytes); - - if (CheckJNIExceptionsForAuthTagMismatch(env, authTagMismatch) != SUCCESS) + loc[outDataBytes] = (jbyteArray)(*env)->CallObjectMethod(env, ctx->cipher, g_cipherUpdateMethod, loc[inDataBytes]); + if (CheckJNIExceptionsForAuthTagMismatch(env, authTagMismatch)) { - (*env)->DeleteLocalRef(env, inDataBytes); - return FAIL; + goto cleanup; } - if (outDataBytes && outm) + if (loc[outDataBytes] && outm) { - jsize outDataBytesLen = (*env)->GetArrayLength(env, outDataBytes); + jsize outDataBytesLen = (*env)->GetArrayLength(env, loc[outDataBytes]); *outl = outDataBytesLen; - (*env)->GetByteArrayRegion(env, outDataBytes, 0, outDataBytesLen, (jbyte*) outm); - (*env)->DeleteLocalRef(env, outDataBytes); + (*env)->GetByteArrayRegion(env, loc[outDataBytes], 0, outDataBytesLen, (jbyte*) outm); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); } - (*env)->DeleteLocalRef(env, inDataBytes); - return CheckJNIExceptionsForAuthTagMismatch(env, authTagMismatch); + result = SUCCESS; + +cleanup: + RELEASE_LOCALS(loc, env); + return result; } int32_t AndroidCryptoNative_CipherFinalEx(CipherCtx* ctx, uint8_t* outm, int32_t* outl) @@ -381,7 +357,7 @@ int32_t AndroidCryptoNative_AeadCipherFinalEx(CipherCtx* ctx, uint8_t* outm, int jbyteArray outBytes = (jbyteArray)(*env)->CallObjectMethod(env, ctx->cipher, g_cipherDoFinalMethod); - if (CheckJNIExceptionsForAuthTagMismatch(env, authTagMismatch) != SUCCESS) + if (CheckJNIExceptionsForAuthTagMismatch(env, authTagMismatch)) { return FAIL; } From 68f232a725360be1ae4bb345b11de758cdfaa654 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Wed, 3 Jun 2026 11:09:08 +0200 Subject: [PATCH 08/12] Do not change the behavior of printing exceptions --- .../pal_cipher.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/native/libs/System.Security.Cryptography.Native.Android/pal_cipher.c b/src/native/libs/System.Security.Cryptography.Native.Android/pal_cipher.c index 158e674471b4d3..19083145b7928b 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Android/pal_cipher.c +++ b/src/native/libs/System.Security.Cryptography.Native.Android/pal_cipher.c @@ -76,12 +76,12 @@ ARGS_NON_NULL_ALL static jobject GetAlgorithmName(JNIEnv* env, CipherInfo* type) return make_java_string(env, type->name); } -ARGS_NON_NULL_ALL static bool CheckJNIExceptionsForAuthTagMismatch(JNIEnv* env, int32_t* authTagMismatch) +ARGS_NON_NULL_ALL static bool CheckJNIExceptionsForAuthTagMismatch(JNIEnv* env, int32_t* authTagMismatch, bool printException) { bool result = false; INIT_LOCALS(loc, ex); - if (TryGetJNIException(env, &loc[ex], /* printException: */ false)) + if (TryGetJNIException(env, &loc[ex], printException)) { result = true; @@ -297,7 +297,7 @@ int32_t AndroidCryptoNative_AeadCipherUpdate( *outl = 0; loc[outDataBytes] = (jbyteArray)(*env)->CallObjectMethod(env, ctx->cipher, g_cipherUpdateMethod, loc[inDataBytes]); - if (CheckJNIExceptionsForAuthTagMismatch(env, authTagMismatch)) + if (CheckJNIExceptionsForAuthTagMismatch(env, authTagMismatch, /* printException: */ true)) { goto cleanup; } @@ -357,7 +357,7 @@ int32_t AndroidCryptoNative_AeadCipherFinalEx(CipherCtx* ctx, uint8_t* outm, int jbyteArray outBytes = (jbyteArray)(*env)->CallObjectMethod(env, ctx->cipher, g_cipherDoFinalMethod); - if (CheckJNIExceptionsForAuthTagMismatch(env, authTagMismatch)) + if (CheckJNIExceptionsForAuthTagMismatch(env, authTagMismatch, /* printException: */ false)) { return FAIL; } From 073749782d50ddc0b8243b7d4fd1ef0d9aaff7ac Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Wed, 3 Jun 2026 20:31:28 +0200 Subject: [PATCH 09/12] Treat GeneralSecurityException as auth tag mismatch for Android AEAD decrypt On some Android devices, when an AEAD decryption fails authentication, Conscrypt determines the thrown exception type by reading BoringSSL's thread-local error queue, which can still contain a stale error from a prior unrelated operation on the same thread (e.g. an RSA error). That stale error is read first (FIFO) and mapped to the wrong exception type (observed java.security.InvalidKeyException with an RSA MODULUS_TOO_LARGE message during a ChaCha20Poly1305 decrypt) instead of the expected javax.crypto.AEADBadTagException. Because detection only matched AEADBadTagException, authTagMismatch stayed false and a generic CryptographicException was thrown instead of AuthenticationTagMismatchException, intermittently failing ChaCha20Poly1305Tests.EncryptTamperAADDecrypt. For a successfully initialized AEAD cipher in decrypt mode, the key and parameters were already validated at Cipher.init, so the only legitimate failure at the tag-update/doFinal step is an authentication failure. Treat any java.security.GeneralSecurityException caught there (in decrypt mode) as an authentication tag mismatch. This also covers AES-GCM and AES-CCM, which share the same native AEAD paths. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../pal_cipher.c | 28 +++++++++++++++---- .../pal_jni.c | 4 +++ .../pal_jni.h | 3 ++ 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/native/libs/System.Security.Cryptography.Native.Android/pal_cipher.c b/src/native/libs/System.Security.Cryptography.Native.Android/pal_cipher.c index 19083145b7928b..db5dc712f745d4 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Android/pal_cipher.c +++ b/src/native/libs/System.Security.Cryptography.Native.Android/pal_cipher.c @@ -76,7 +76,7 @@ ARGS_NON_NULL_ALL static jobject GetAlgorithmName(JNIEnv* env, CipherInfo* type) return make_java_string(env, type->name); } -ARGS_NON_NULL_ALL static bool CheckJNIExceptionsForAuthTagMismatch(JNIEnv* env, int32_t* authTagMismatch, bool printException) +ARGS_NON_NULL_ALL static bool CheckJNIExceptionsForAuthTagMismatch(JNIEnv* env, int32_t* authTagMismatch, bool printException, bool decryptMode) { bool result = false; INIT_LOCALS(loc, ex); @@ -85,9 +85,27 @@ ARGS_NON_NULL_ALL static bool CheckJNIExceptionsForAuthTagMismatch(JNIEnv* env, { result = true; - if (loc[ex] != NULL && (*env)->IsInstanceOf(env, loc[ex], g_AEADBadTagExceptionClass)) + if (loc[ex] != NULL) { - *authTagMismatch = 1; + if ((*env)->IsInstanceOf(env, loc[ex], g_AEADBadTagExceptionClass)) + { + *authTagMismatch = 1; + } + else if (decryptMode && (*env)->IsInstanceOf(env, loc[ex], g_GeneralSecurityExceptionClass)) + { + // Workaround for an Android/Conscrypt issue. When an AEAD decryption fails + // authentication, the provider determines the thrown exception type by reading + // BoringSSL's thread-local error queue. On some devices that queue can still + // contain a stale error from a prior unrelated operation on the same thread + // (e.g. an RSA error), which is read first (FIFO) and mapped to the wrong + // exception type - we have observed java.security.InvalidKeyException instead of + // javax.crypto.AEADBadTagException. For a successfully initialized AEAD cipher in + // decrypt mode, the key and parameters were already validated at Cipher.init, so + // the only legitimate failure at the tag-update/doFinal step is an authentication + // failure. Treat any GeneralSecurityException here as an authentication tag + // mismatch so the correct AuthenticationTagMismatchException is reported. + *authTagMismatch = 1; + } } } @@ -297,7 +315,7 @@ int32_t AndroidCryptoNative_AeadCipherUpdate( *outl = 0; loc[outDataBytes] = (jbyteArray)(*env)->CallObjectMethod(env, ctx->cipher, g_cipherUpdateMethod, loc[inDataBytes]); - if (CheckJNIExceptionsForAuthTagMismatch(env, authTagMismatch, /* printException: */ true)) + if (CheckJNIExceptionsForAuthTagMismatch(env, authTagMismatch, /* printException: */ true, ctx->encMode == CIPHER_DECRYPT_MODE)) { goto cleanup; } @@ -357,7 +375,7 @@ int32_t AndroidCryptoNative_AeadCipherFinalEx(CipherCtx* ctx, uint8_t* outm, int jbyteArray outBytes = (jbyteArray)(*env)->CallObjectMethod(env, ctx->cipher, g_cipherDoFinalMethod); - if (CheckJNIExceptionsForAuthTagMismatch(env, authTagMismatch, /* printException: */ false)) + if (CheckJNIExceptionsForAuthTagMismatch(env, authTagMismatch, /* printException: */ false, ctx->encMode == CIPHER_DECRYPT_MODE)) { return FAIL; } diff --git a/src/native/libs/System.Security.Cryptography.Native.Android/pal_jni.c b/src/native/libs/System.Security.Cryptography.Native.Android/pal_jni.c index 81f11ab25c2ea7..4927476889388d 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Android/pal_jni.c +++ b/src/native/libs/System.Security.Cryptography.Native.Android/pal_jni.c @@ -91,6 +91,9 @@ jmethodID g_sslCtxGetDefaultSslParamsMethod; // javax/crypto/spec/AEADBadTagException jclass g_AEADBadTagExceptionClass; +// java/security/GeneralSecurityException +jclass g_GeneralSecurityExceptionClass; + // javax/crypto/spec/GCMParameterSpec jclass g_GCMParameterSpecClass; jmethodID g_GCMParameterSpecCtor; @@ -738,6 +741,7 @@ jint AndroidCryptoNative_InitLibraryOnLoad (JavaVM *vm, void *reserved) g_ivPsCtor = GetMethod(env, false, g_ivPsClass, "", "([B)V"); g_AEADBadTagExceptionClass = GetClassGRef(env, "javax/crypto/AEADBadTagException"); + g_GeneralSecurityExceptionClass = GetClassGRef(env, "java/security/GeneralSecurityException"); g_GCMParameterSpecClass = GetClassGRef(env, "javax/crypto/spec/GCMParameterSpec"); g_GCMParameterSpecCtor = GetMethod(env, false, g_GCMParameterSpecClass, "", "(I[B)V"); diff --git a/src/native/libs/System.Security.Cryptography.Native.Android/pal_jni.h b/src/native/libs/System.Security.Cryptography.Native.Android/pal_jni.h index 9285c123525a27..79037e740d945c 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Android/pal_jni.h +++ b/src/native/libs/System.Security.Cryptography.Native.Android/pal_jni.h @@ -74,6 +74,9 @@ extern jmethodID g_getBlockSizeMethod; // javax/crypto/spec/AEADBadTagException extern jclass g_AEADBadTagExceptionClass; +// java/security/GeneralSecurityException +extern jclass g_GeneralSecurityExceptionClass; + // javax/crypto/spec/IvParameterSpec extern jclass g_ivPsClass; extern jmethodID g_ivPsCtor; From 2a5936008884b0786482329cf459e2e6258e365c Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Thu, 4 Jun 2026 00:06:20 +0200 Subject: [PATCH 10/12] Log original exception when reclassifying Android AEAD decrypt failure Add a debug breadcrumb on the GeneralSecurityException fallback path so a genuine non-authentication failure, if ever reclassified as a tag mismatch, can still be diagnosed from logcat. This path does not run for the common AEADBadTagException case and is behavior-neutral for pass/fail. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../pal_cipher.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/native/libs/System.Security.Cryptography.Native.Android/pal_cipher.c b/src/native/libs/System.Security.Cryptography.Native.Android/pal_cipher.c index db5dc712f745d4..1ec1fab8579c99 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Android/pal_cipher.c +++ b/src/native/libs/System.Security.Cryptography.Native.Android/pal_cipher.c @@ -105,6 +105,19 @@ ARGS_NON_NULL_ALL static bool CheckJNIExceptionsForAuthTagMismatch(JNIEnv* env, // failure. Treat any GeneralSecurityException here as an authentication tag // mismatch so the correct AuthenticationTagMismatchException is reported. *authTagMismatch = 1; + + // Reaching this fallback means the provider reported the authentication failure + // with an unexpected exception type. Leave a breadcrumb with the original message + // so that a genuine non-authentication failure, if ever reclassified here, can + // still be diagnosed. This does not run for the common AEADBadTagException case. + jstring message = (jstring)(*env)->CallObjectMethod(env, loc[ex], g_ThrowableGetMessage); + const char* messageChars = message != NULL ? (*env)->GetStringUTFChars(env, message, NULL) : NULL; + LOG_DEBUG("AEAD decrypt reported authentication failure via an unexpected GeneralSecurityException; treating as tag mismatch: %s", + messageChars != NULL ? messageChars : "(no message)"); + if (messageChars != NULL) + (*env)->ReleaseStringUTFChars(env, message, messageChars); + if (message != NULL) + (*env)->DeleteLocalRef(env, message); } } } From 2409f7c92acf079dab7bc7ca9bb0d27fafe66bd4 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Thu, 4 Jun 2026 02:03:44 +0200 Subject: [PATCH 11/12] Harden JNI exception handling in Android AEAD breadcrumb path Guard GetStringUTFChars with an ExceptionCheck after getMessage() and clear any pending JNI exception before returning, so the fallback diagnostic path never leaves a stray Java exception for the caller (which raises the managed AuthenticationTagMismatchException next). No memory or gref leaks: only local refs are created and all are released. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../pal_cipher.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/native/libs/System.Security.Cryptography.Native.Android/pal_cipher.c b/src/native/libs/System.Security.Cryptography.Native.Android/pal_cipher.c index 1ec1fab8579c99..452323c0025033 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Android/pal_cipher.c +++ b/src/native/libs/System.Security.Cryptography.Native.Android/pal_cipher.c @@ -111,13 +111,19 @@ ARGS_NON_NULL_ALL static bool CheckJNIExceptionsForAuthTagMismatch(JNIEnv* env, // so that a genuine non-authentication failure, if ever reclassified here, can // still be diagnosed. This does not run for the common AEADBadTagException case. jstring message = (jstring)(*env)->CallObjectMethod(env, loc[ex], g_ThrowableGetMessage); - const char* messageChars = message != NULL ? (*env)->GetStringUTFChars(env, message, NULL) : NULL; + const char* messageChars = + (message != NULL && !(*env)->ExceptionCheck(env)) ? (*env)->GetStringUTFChars(env, message, NULL) : NULL; LOG_DEBUG("AEAD decrypt reported authentication failure via an unexpected GeneralSecurityException; treating as tag mismatch: %s", messageChars != NULL ? messageChars : "(no message)"); if (messageChars != NULL) (*env)->ReleaseStringUTFChars(env, message, messageChars); if (message != NULL) (*env)->DeleteLocalRef(env, message); + + // getMessage()/GetStringUTFChars() are not expected to throw, but make sure we never + // return to the caller with a pending JNI exception - the caller goes on to raise the + // managed AuthenticationTagMismatchException and must see a clean exception state. + TryClearJNIExceptions(env); } } } From 02cad94c871d82b331276889a8671828c724e9d2 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Thu, 4 Jun 2026 11:39:12 +0200 Subject: [PATCH 12/12] Replace native AEAD heuristic with managed retry-and-observe on Android The previous fix treated any GeneralSecurityException during an Android AEAD decrypt as an authentication tag mismatch. That depended on Conscrypt implementation details and risked false positives, so revert the three native commits (pal_cipher.c / pal_jni.c / pal_jni.h) back to recognizing only a genuine AEADBadTagException. Root cause: on AEAD decrypt failure Conscrypt derives the Java exception type by popping the oldest entry from BoringSSL's thread-local FIFO error queue. A stale error left by an unrelated prior operation on the same pooled thread (e.g. an RSA failure) is read first and mapped to the wrong type (InvalidKeyException), which is not a BadPaddingException and so is never converted to AEADBadTagException. Conscrypt clears the whole queue after reading, so the failed attempt leaves a clean queue. Fix: in the managed Android AEAD DecryptCore, when the first attempt throws a CryptographicException that is not AuthenticationTagMismatchException, retry the decrypt once on the same thread. The retry reads a clean error queue and observes the true result (a real tag mismatch surfaces as AEADBadTagException). A valid ciphertext authenticates regardless of the queue, so the retry only ever runs after a genuine failure and can never turn an authentication failure into unauthenticated plaintext. Validated on a physical 32-bit Android device (Samsung Galaxy A16, armeabi-v7a): 5x full System.Security.Cryptography test suite, 12373 tests, 0 failures, including all ChaCha20Poly1305 EncryptTamperAADDecrypt cases. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Security/Cryptography/AesCcm.Android.cs | 24 ++++++++++ .../Security/Cryptography/AesGcm.Android.cs | 24 ++++++++++ .../Cryptography/ChaCha20Poly1305.Android.cs | 24 ++++++++++ .../pal_cipher.c | 47 ++----------------- .../pal_jni.c | 4 -- .../pal_jni.h | 3 -- 6 files changed, 77 insertions(+), 49 deletions(-) diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/AesCcm.Android.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/AesCcm.Android.cs index 7b222ada620fcc..d9f284264ca502 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/AesCcm.Android.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/AesCcm.Android.cs @@ -125,6 +125,30 @@ private void DecryptCore( ReadOnlySpan tag, Span plaintext, ReadOnlySpan associatedData) + { + try + { + DecryptCoreOnce(nonce, ciphertext, tag, plaintext, associatedData); + } + catch (CryptographicException ex) when (ex is not AuthenticationTagMismatchException) + { + // Work around a transient Android/Conscrypt issue: an AEAD authentication + // failure can surface with the wrong exception type because the provider + // derives it from BoringSSL's thread-local error queue, which may still hold + // a stale error from an unrelated prior operation on the same thread. The + // failed attempt clears that queue, so an immediate same-thread retry observes + // the true result. A valid ciphertext cannot reach this path, so the retry can + // never turn an authentication failure into unauthenticated plaintext. + DecryptCoreOnce(nonce, ciphertext, tag, plaintext, associatedData); + } + } + + private void DecryptCoreOnce( + ReadOnlySpan nonce, + ReadOnlySpan ciphertext, + ReadOnlySpan tag, + Span plaintext, + ReadOnlySpan associatedData) { bool acquired = false; diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/AesGcm.Android.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/AesGcm.Android.cs index 0d9e9eccf561c9..093ae82ffd1f21 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/AesGcm.Android.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/AesGcm.Android.cs @@ -114,6 +114,30 @@ private partial void DecryptCore( ReadOnlySpan tag, Span plaintext, ReadOnlySpan associatedData) + { + try + { + DecryptCoreOnce(nonce, ciphertext, tag, plaintext, associatedData); + } + catch (CryptographicException ex) when (ex is not AuthenticationTagMismatchException) + { + // Work around a transient Android/Conscrypt issue: an AEAD authentication + // failure can surface with the wrong exception type because the provider + // derives it from BoringSSL's thread-local error queue, which may still hold + // a stale error from an unrelated prior operation on the same thread. The + // failed attempt clears that queue, so an immediate same-thread retry observes + // the true result. A valid ciphertext cannot reach this path, so the retry can + // never turn an authentication failure into unauthenticated plaintext. + DecryptCoreOnce(nonce, ciphertext, tag, plaintext, associatedData); + } + } + + private void DecryptCoreOnce( + ReadOnlySpan nonce, + ReadOnlySpan ciphertext, + ReadOnlySpan tag, + Span plaintext, + ReadOnlySpan associatedData) { if (!Interop.Crypto.CipherSetTagLength(_ctxHandle, tag.Length)) { diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/ChaCha20Poly1305.Android.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/ChaCha20Poly1305.Android.cs index b668c95a2d5b10..d1c118ac7b9c8a 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/ChaCha20Poly1305.Android.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/ChaCha20Poly1305.Android.cs @@ -109,6 +109,30 @@ private void DecryptCore( ReadOnlySpan tag, Span plaintext, ReadOnlySpan associatedData) + { + try + { + DecryptCoreOnce(nonce, ciphertext, tag, plaintext, associatedData); + } + catch (CryptographicException ex) when (ex is not AuthenticationTagMismatchException) + { + // Work around a transient Android/Conscrypt issue: an AEAD authentication + // failure can surface with the wrong exception type because the provider + // derives it from BoringSSL's thread-local error queue, which may still hold + // a stale error from an unrelated prior operation on the same thread. The + // failed attempt clears that queue, so an immediate same-thread retry observes + // the true result. A valid ciphertext cannot reach this path, so the retry can + // never turn an authentication failure into unauthenticated plaintext. + DecryptCoreOnce(nonce, ciphertext, tag, plaintext, associatedData); + } + } + + private void DecryptCoreOnce( + ReadOnlySpan nonce, + ReadOnlySpan ciphertext, + ReadOnlySpan tag, + Span plaintext, + ReadOnlySpan associatedData) { Interop.Crypto.EvpCipherSetKeyAndIV( _ctxHandle, diff --git a/src/native/libs/System.Security.Cryptography.Native.Android/pal_cipher.c b/src/native/libs/System.Security.Cryptography.Native.Android/pal_cipher.c index 452323c0025033..19083145b7928b 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Android/pal_cipher.c +++ b/src/native/libs/System.Security.Cryptography.Native.Android/pal_cipher.c @@ -76,7 +76,7 @@ ARGS_NON_NULL_ALL static jobject GetAlgorithmName(JNIEnv* env, CipherInfo* type) return make_java_string(env, type->name); } -ARGS_NON_NULL_ALL static bool CheckJNIExceptionsForAuthTagMismatch(JNIEnv* env, int32_t* authTagMismatch, bool printException, bool decryptMode) +ARGS_NON_NULL_ALL static bool CheckJNIExceptionsForAuthTagMismatch(JNIEnv* env, int32_t* authTagMismatch, bool printException) { bool result = false; INIT_LOCALS(loc, ex); @@ -85,46 +85,9 @@ ARGS_NON_NULL_ALL static bool CheckJNIExceptionsForAuthTagMismatch(JNIEnv* env, { result = true; - if (loc[ex] != NULL) + if (loc[ex] != NULL && (*env)->IsInstanceOf(env, loc[ex], g_AEADBadTagExceptionClass)) { - if ((*env)->IsInstanceOf(env, loc[ex], g_AEADBadTagExceptionClass)) - { - *authTagMismatch = 1; - } - else if (decryptMode && (*env)->IsInstanceOf(env, loc[ex], g_GeneralSecurityExceptionClass)) - { - // Workaround for an Android/Conscrypt issue. When an AEAD decryption fails - // authentication, the provider determines the thrown exception type by reading - // BoringSSL's thread-local error queue. On some devices that queue can still - // contain a stale error from a prior unrelated operation on the same thread - // (e.g. an RSA error), which is read first (FIFO) and mapped to the wrong - // exception type - we have observed java.security.InvalidKeyException instead of - // javax.crypto.AEADBadTagException. For a successfully initialized AEAD cipher in - // decrypt mode, the key and parameters were already validated at Cipher.init, so - // the only legitimate failure at the tag-update/doFinal step is an authentication - // failure. Treat any GeneralSecurityException here as an authentication tag - // mismatch so the correct AuthenticationTagMismatchException is reported. - *authTagMismatch = 1; - - // Reaching this fallback means the provider reported the authentication failure - // with an unexpected exception type. Leave a breadcrumb with the original message - // so that a genuine non-authentication failure, if ever reclassified here, can - // still be diagnosed. This does not run for the common AEADBadTagException case. - jstring message = (jstring)(*env)->CallObjectMethod(env, loc[ex], g_ThrowableGetMessage); - const char* messageChars = - (message != NULL && !(*env)->ExceptionCheck(env)) ? (*env)->GetStringUTFChars(env, message, NULL) : NULL; - LOG_DEBUG("AEAD decrypt reported authentication failure via an unexpected GeneralSecurityException; treating as tag mismatch: %s", - messageChars != NULL ? messageChars : "(no message)"); - if (messageChars != NULL) - (*env)->ReleaseStringUTFChars(env, message, messageChars); - if (message != NULL) - (*env)->DeleteLocalRef(env, message); - - // getMessage()/GetStringUTFChars() are not expected to throw, but make sure we never - // return to the caller with a pending JNI exception - the caller goes on to raise the - // managed AuthenticationTagMismatchException and must see a clean exception state. - TryClearJNIExceptions(env); - } + *authTagMismatch = 1; } } @@ -334,7 +297,7 @@ int32_t AndroidCryptoNative_AeadCipherUpdate( *outl = 0; loc[outDataBytes] = (jbyteArray)(*env)->CallObjectMethod(env, ctx->cipher, g_cipherUpdateMethod, loc[inDataBytes]); - if (CheckJNIExceptionsForAuthTagMismatch(env, authTagMismatch, /* printException: */ true, ctx->encMode == CIPHER_DECRYPT_MODE)) + if (CheckJNIExceptionsForAuthTagMismatch(env, authTagMismatch, /* printException: */ true)) { goto cleanup; } @@ -394,7 +357,7 @@ int32_t AndroidCryptoNative_AeadCipherFinalEx(CipherCtx* ctx, uint8_t* outm, int jbyteArray outBytes = (jbyteArray)(*env)->CallObjectMethod(env, ctx->cipher, g_cipherDoFinalMethod); - if (CheckJNIExceptionsForAuthTagMismatch(env, authTagMismatch, /* printException: */ false, ctx->encMode == CIPHER_DECRYPT_MODE)) + if (CheckJNIExceptionsForAuthTagMismatch(env, authTagMismatch, /* printException: */ false)) { return FAIL; } diff --git a/src/native/libs/System.Security.Cryptography.Native.Android/pal_jni.c b/src/native/libs/System.Security.Cryptography.Native.Android/pal_jni.c index 4927476889388d..81f11ab25c2ea7 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Android/pal_jni.c +++ b/src/native/libs/System.Security.Cryptography.Native.Android/pal_jni.c @@ -91,9 +91,6 @@ jmethodID g_sslCtxGetDefaultSslParamsMethod; // javax/crypto/spec/AEADBadTagException jclass g_AEADBadTagExceptionClass; -// java/security/GeneralSecurityException -jclass g_GeneralSecurityExceptionClass; - // javax/crypto/spec/GCMParameterSpec jclass g_GCMParameterSpecClass; jmethodID g_GCMParameterSpecCtor; @@ -741,7 +738,6 @@ jint AndroidCryptoNative_InitLibraryOnLoad (JavaVM *vm, void *reserved) g_ivPsCtor = GetMethod(env, false, g_ivPsClass, "", "([B)V"); g_AEADBadTagExceptionClass = GetClassGRef(env, "javax/crypto/AEADBadTagException"); - g_GeneralSecurityExceptionClass = GetClassGRef(env, "java/security/GeneralSecurityException"); g_GCMParameterSpecClass = GetClassGRef(env, "javax/crypto/spec/GCMParameterSpec"); g_GCMParameterSpecCtor = GetMethod(env, false, g_GCMParameterSpecClass, "", "(I[B)V"); diff --git a/src/native/libs/System.Security.Cryptography.Native.Android/pal_jni.h b/src/native/libs/System.Security.Cryptography.Native.Android/pal_jni.h index 79037e740d945c..9285c123525a27 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Android/pal_jni.h +++ b/src/native/libs/System.Security.Cryptography.Native.Android/pal_jni.h @@ -74,9 +74,6 @@ extern jmethodID g_getBlockSizeMethod; // javax/crypto/spec/AEADBadTagException extern jclass g_AEADBadTagExceptionClass; -// java/security/GeneralSecurityException -extern jclass g_GeneralSecurityExceptionClass; - // javax/crypto/spec/IvParameterSpec extern jclass g_ivPsClass; extern jmethodID g_ivPsCtor;