diff options
Diffstat (limited to 'src/libraries')
14 files changed, 139 insertions, 30 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 8b987ce31ea..8cc861a948c 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 @@ -136,6 +136,34 @@ internal static partial class Interop return EvpCipherFinalEx(ctx, ref MemoryMarshal.GetReference(output), out bytesWritten); } + [LibraryImport(Libraries.AndroidCryptoNative, EntryPoint = "AndroidCryptoNative_AeadCipherFinalEx")] + [return: MarshalAs(UnmanagedType.Bool)] + private static unsafe partial bool EvpAeadCipherFinalEx( + SafeEvpCipherCtxHandle ctx, + byte* outm, + out int outl, + [MarshalAs(UnmanagedType.Bool)] out bool authTagMismatch); + + internal static unsafe bool EvpAeadCipherFinalEx( + SafeEvpCipherCtxHandle ctx, + Span<byte> output, + out int bytesWritten, + out bool authTagMismatch) + { + scoped Span<byte> notNullOutput = output; + + // We can't pass null down to the native shim, so create a valid pointer if we have an empty span. + if (notNullOutput.IsEmpty) + { + notNullOutput = (stackalloc byte[1]).Slice(1); + } + + fixed (byte* pOutput = &MemoryMarshal.GetReference(notNullOutput)) + { + return EvpAeadCipherFinalEx(ctx, pOutput, out bytesWritten, out authTagMismatch); + } + } + [LibraryImport(Libraries.AndroidCryptoNative, EntryPoint = "AndroidCryptoNative_CipherSetTagLength")] [return: MarshalAs(UnmanagedType.Bool)] internal static partial bool CipherSetTagLength( diff --git a/src/libraries/System.Security.Cryptography/ref/System.Security.Cryptography.cs b/src/libraries/System.Security.Cryptography/ref/System.Security.Cryptography.cs index 99e9063d8ec..a90b8977d5b 100644 --- a/src/libraries/System.Security.Cryptography/ref/System.Security.Cryptography.cs +++ b/src/libraries/System.Security.Cryptography/ref/System.Security.Cryptography.cs @@ -270,6 +270,12 @@ namespace System.Security.Cryptography public abstract void SetHashAlgorithm(string strName); public abstract void SetKey(System.Security.Cryptography.AsymmetricAlgorithm key); } + public sealed partial class AuthenticationTagMismatchException : System.Security.Cryptography.CryptographicException + { + public AuthenticationTagMismatchException() { } + public AuthenticationTagMismatchException(string? message) { } + public AuthenticationTagMismatchException(string? message, System.Exception? inner) { } + } [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("ios")] [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("tvos")] diff --git a/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj b/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj index 996f80f6687..ed68d33a835 100644 --- a/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj +++ b/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj @@ -283,6 +283,7 @@ <Compile Include="System\Security\Cryptography\AsymmetricKeyExchangeFormatter.cs" /> <Compile Include="System\Security\Cryptography\AsymmetricSignatureDeformatter.cs" /> <Compile Include="System\Security\Cryptography\AsymmetricSignatureFormatter.cs" /> + <Compile Include="System\Security\Cryptography\AuthenticationTagMismatchException.cs" /> <Compile Include="System\Security\Cryptography\Base64Transforms.cs" /> <Compile Include="System\Security\Cryptography\BasicSymmetricCipher.cs" /> <Compile Include="System\Security\Cryptography\ChaCha20Poly1305.cs" /> diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/AeadCommon.Windows.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/AeadCommon.Windows.cs index fe10a0ed2ca..909f650a7aa 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/AeadCommon.Windows.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/AeadCommon.Windows.cs @@ -104,7 +104,7 @@ namespace System.Security.Cryptography CryptographicOperations.ZeroMemory(plaintext); } - throw new CryptographicException(SR.Cryptography_AuthTagMismatch); + throw new AuthenticationTagMismatchException(); default: throw CreateCryptographicException(ntStatus); } 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 39247bed98e..b7089bd3d10 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 @@ -69,11 +69,13 @@ namespace System.Security.Cryptography throw new CryptographicException(); } - if (!Interop.Crypto.EvpCipherFinalEx( + if (!Interop.Crypto.EvpAeadCipherFinalEx( ctx, ciphertextAndTag.Slice(ciphertextBytesWritten), - out int bytesWritten)) + out int bytesWritten, + out bool authTagMismatch)) { + Debug.Assert(!authTagMismatch); throw new CryptographicException(); } @@ -141,13 +143,20 @@ namespace System.Security.Cryptography plaintextBytesWritten += bytesWritten; - if (!Interop.Crypto.EvpCipherFinalEx( + if (!Interop.Crypto.EvpAeadCipherFinalEx( ctx, plaintext.Slice(plaintextBytesWritten), - out bytesWritten)) + out bytesWritten, + out bool authTagMismatch)) { CryptographicOperations.ZeroMemory(plaintext); - throw new CryptographicException(SR.Cryptography_AuthTagMismatch); + + if (authTagMismatch) + { + throw new AuthenticationTagMismatchException(); + } + + throw new CryptographicException(SR.Arg_CryptographyException); } plaintextBytesWritten += bytesWritten; diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/AesCcm.OpenSsl.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/AesCcm.OpenSsl.cs index 6c78bee075e..0aedd34fe2d 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/AesCcm.OpenSsl.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/AesCcm.OpenSsl.cs @@ -104,7 +104,7 @@ namespace System.Security.Cryptography if (!Interop.Crypto.EvpCipherUpdate(ctx, plaintext, out int plaintextBytesWritten, ciphertext)) { plaintext.Clear(); - throw new CryptographicException(SR.Cryptography_AuthTagMismatch); + throw new AuthenticationTagMismatchException(); } if (plaintextBytesWritten != plaintext.Length) 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 3e36ef16d38..471338a8e8a 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 @@ -74,11 +74,13 @@ namespace System.Security.Cryptography throw new CryptographicException(); } - if (!Interop.Crypto.EvpCipherFinalEx( + if (!Interop.Crypto.EvpAeadCipherFinalEx( _ctxHandle, ciphertextAndTag.Slice(ciphertextBytesWritten), - out int bytesWritten)) + out int bytesWritten, + out bool authTagMismatch)) { + Debug.Assert(!authTagMismatch); throw new CryptographicException(); } @@ -141,13 +143,20 @@ namespace System.Security.Cryptography plaintextBytesWritten += bytesWritten; - if (!Interop.Crypto.EvpCipherFinalEx( + if (!Interop.Crypto.EvpAeadCipherFinalEx( _ctxHandle, plaintext.Slice(plaintextBytesWritten), - out bytesWritten)) + out bytesWritten, + out bool authTagMismatch)) { CryptographicOperations.ZeroMemory(plaintext); - throw new CryptographicException(SR.Cryptography_AuthTagMismatch); + + if (authTagMismatch) + { + throw new AuthenticationTagMismatchException(); + } + + throw new CryptographicException(SR.Arg_CryptographyException); } plaintextBytesWritten += bytesWritten; diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/AesGcm.OpenSsl.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/AesGcm.OpenSsl.cs index 1691f3357db..f11936951bc 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/AesGcm.OpenSsl.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/AesGcm.OpenSsl.cs @@ -106,7 +106,7 @@ namespace System.Security.Cryptography out int bytesWritten)) { CryptographicOperations.ZeroMemory(plaintext); - throw new CryptographicException(SR.Cryptography_AuthTagMismatch); + throw new AuthenticationTagMismatchException(); } plaintextBytesWritten += bytesWritten; diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/AuthenticationTagMismatchException.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/AuthenticationTagMismatchException.cs new file mode 100644 index 00000000000..6c63045da0f --- /dev/null +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/AuthenticationTagMismatchException.cs @@ -0,0 +1,47 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Security.Cryptography +{ + /// <summary> + /// The exception that is thrown when a decryption operation with an authenticated cipher + /// has an authentication tag mismatch. + /// </summary> + public sealed class AuthenticationTagMismatchException : CryptographicException + { + /// <summary> + /// Initializes a new instance of the <see cref="AuthenticationTagMismatchException" /> class with default + /// properties. + /// </summary> + public AuthenticationTagMismatchException() : base(SR.Cryptography_AuthTagMismatch) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="AuthenticationTagMismatchException" /> class with a specified + /// error message. + /// </summary> + /// <param name="message"> + /// The error message that explains the reason for the exception. + /// </param> + public AuthenticationTagMismatchException(string? message) : base(message) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="AuthenticationTagMismatchException" /> class with a specified + /// error message and a reference to the inner exception that is the cause of this exception. + /// </summary> + /// <param name="message"> + /// The error message that explains the reason for the exception. + /// </param> + /// <param name="inner"> + /// The exception that is the cause of the current exception. If the parameter is not + /// <see langword="null" />, the current exception is raised in a catch block that handles the inner exception. + /// </param> + public AuthenticationTagMismatchException(string? message, Exception? inner) + : base(message, inner) + { + } + } +} 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 a36599202e3..3c6f78d5425 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 @@ -71,11 +71,13 @@ namespace System.Security.Cryptography throw new CryptographicException(); } - if (!Interop.Crypto.EvpCipherFinalEx( + if (!Interop.Crypto.EvpAeadCipherFinalEx( _ctxHandle, ciphertextAndTag.Slice(ciphertextBytesWritten), - out int bytesWritten)) + out int bytesWritten, + out bool authTagMismatch)) { + Debug.Assert(!authTagMismatch); throw new CryptographicException(); } @@ -133,13 +135,20 @@ namespace System.Security.Cryptography plaintextBytesWritten += bytesWritten; - if (!Interop.Crypto.EvpCipherFinalEx( + if (!Interop.Crypto.EvpAeadCipherFinalEx( _ctxHandle, plaintext.Slice(plaintextBytesWritten), - out bytesWritten)) + out bytesWritten, + out bool authTagMismatch)) { CryptographicOperations.ZeroMemory(plaintext); - throw new CryptographicException(SR.Cryptography_AuthTagMismatch); + + if (authTagMismatch) + { + throw new AuthenticationTagMismatchException(); + } + + throw new CryptographicException(SR.Arg_CryptographyException); } plaintextBytesWritten += bytesWritten; diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/ChaCha20Poly1305.OpenSsl.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/ChaCha20Poly1305.OpenSsl.cs index 6fd211689ae..353f7429403 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/ChaCha20Poly1305.OpenSsl.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/ChaCha20Poly1305.OpenSsl.cs @@ -106,7 +106,7 @@ namespace System.Security.Cryptography out int bytesWritten)) { CryptographicOperations.ZeroMemory(plaintext); - throw new CryptographicException(SR.Cryptography_AuthTagMismatch); + throw new AuthenticationTagMismatchException(); } plaintextBytesWritten += bytesWritten; diff --git a/src/libraries/System.Security.Cryptography/tests/AesCcmTests.cs b/src/libraries/System.Security.Cryptography/tests/AesCcmTests.cs index 1d662f9a085..8b68d7f1d61 100644 --- a/src/libraries/System.Security.Cryptography/tests/AesCcmTests.cs +++ b/src/libraries/System.Security.Cryptography/tests/AesCcmTests.cs @@ -34,7 +34,7 @@ namespace System.Security.Cryptography.Tests additionalData[0] ^= 1; byte[] decrypted = new byte[dataLength]; - Assert.Throws<CryptographicException>( + Assert.Throws<AuthenticationTagMismatchException>( () => aesCcm.Decrypt(nonce, ciphertext, tag, decrypted, additionalData)); } } @@ -305,7 +305,7 @@ namespace System.Security.Cryptography.Tests tag[0] ^= 1; - Assert.Throws<CryptographicException>( + Assert.Throws<AuthenticationTagMismatchException>( () => aesCcm.Decrypt(nonce, data, tag, data)); Assert.Equal(new byte[data.Length], data); } @@ -347,7 +347,7 @@ namespace System.Security.Cryptography.Tests byte[] plaintext = new byte[testCase.Plaintext.Length]; RandomNumberGenerator.Fill(plaintext); - Assert.Throws<CryptographicException>( + Assert.Throws<AuthenticationTagMismatchException>( () => aesCcm.Decrypt(testCase.Nonce, ciphertext, tag, plaintext, testCase.AssociatedData)); Assert.Equal(new byte[plaintext.Length], plaintext); } @@ -370,7 +370,7 @@ namespace System.Security.Cryptography.Tests byte[] plaintext = new byte[testCase.Plaintext.Length]; RandomNumberGenerator.Fill(plaintext); - Assert.Throws<CryptographicException>( + Assert.Throws<AuthenticationTagMismatchException>( () => aesCcm.Decrypt(testCase.Nonce, ciphertext, tag, plaintext, testCase.AssociatedData)); Assert.Equal(new byte[plaintext.Length], plaintext); } diff --git a/src/libraries/System.Security.Cryptography/tests/AesGcmTests.cs b/src/libraries/System.Security.Cryptography/tests/AesGcmTests.cs index 1a41a2beb3f..6ef5391e40e 100644 --- a/src/libraries/System.Security.Cryptography/tests/AesGcmTests.cs +++ b/src/libraries/System.Security.Cryptography/tests/AesGcmTests.cs @@ -34,7 +34,7 @@ namespace System.Security.Cryptography.Tests additionalData[0] ^= 1; byte[] decrypted = new byte[dataLength]; - Assert.Throws<CryptographicException>( + Assert.Throws<AuthenticationTagMismatchException>( () => aesGcm.Decrypt(nonce, ciphertext, tag, decrypted, additionalData)); } } @@ -312,7 +312,7 @@ namespace System.Security.Cryptography.Tests tag[0] ^= 1; - Assert.Throws<CryptographicException>( + Assert.Throws<AuthenticationTagMismatchException>( () => aesGcm.Decrypt(nonce, data, tag, data)); Assert.Equal(new byte[data.Length], data); } @@ -354,7 +354,7 @@ namespace System.Security.Cryptography.Tests byte[] plaintext = new byte[testCase.Plaintext.Length]; RandomNumberGenerator.Fill(plaintext); - Assert.Throws<CryptographicException>( + Assert.Throws<AuthenticationTagMismatchException>( () => aesGcm.Decrypt(testCase.Nonce, ciphertext, tag, plaintext, testCase.AssociatedData)); Assert.Equal(new byte[plaintext.Length], plaintext); } @@ -377,7 +377,7 @@ namespace System.Security.Cryptography.Tests byte[] plaintext = new byte[testCase.Plaintext.Length]; RandomNumberGenerator.Fill(plaintext); - Assert.Throws<CryptographicException>( + Assert.Throws<AuthenticationTagMismatchException>( () => aesGcm.Decrypt(testCase.Nonce, ciphertext, tag, plaintext, testCase.AssociatedData)); Assert.Equal(new byte[plaintext.Length], plaintext); } diff --git a/src/libraries/System.Security.Cryptography/tests/ChaCha20Poly1305Tests.cs b/src/libraries/System.Security.Cryptography/tests/ChaCha20Poly1305Tests.cs index 7d39b45922f..f381e17e73d 100644 --- a/src/libraries/System.Security.Cryptography/tests/ChaCha20Poly1305Tests.cs +++ b/src/libraries/System.Security.Cryptography/tests/ChaCha20Poly1305Tests.cs @@ -35,7 +35,7 @@ namespace System.Security.Cryptography.Tests additionalData[0] ^= 1; byte[] decrypted = new byte[dataLength]; - Assert.Throws<CryptographicException>( + Assert.Throws<AuthenticationTagMismatchException>( () => chaChaPoly.Decrypt(nonce, ciphertext, tag, decrypted, additionalData)); } } @@ -271,7 +271,7 @@ namespace System.Security.Cryptography.Tests tag[0] ^= 1; - Assert.Throws<CryptographicException>( + Assert.Throws<AuthenticationTagMismatchException>( () => chaChaPoly.Decrypt(nonce, data, tag, data)); Assert.Equal(new byte[data.Length], data); } @@ -310,7 +310,7 @@ namespace System.Security.Cryptography.Tests tag[0] ^= 1; byte[] plaintext = RandomNumberGenerator.GetBytes(testCase.Plaintext.Length); - Assert.Throws<CryptographicException>( + Assert.Throws<AuthenticationTagMismatchException>( () => chaChaPoly.Decrypt(testCase.Nonce, ciphertext, tag, plaintext, testCase.AssociatedData)); Assert.Equal(new byte[plaintext.Length], plaintext); } |