diff options
author | Kevin Jones <kevin@vcsjones.com> | 2022-10-01 19:02:03 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-01 19:02:03 +0300 |
commit | 72ac50cef091a46d9c02b43f6f4f1785011afe4a (patch) | |
tree | d61bea911ea2f6f7ec017456b6f2c06ba382d0d8 /src/libraries | |
parent | 65a15783e334039dfc303fa62b22dcc872029257 (diff) |
Implement ChaCha20Poly1305 with CryptoKit on macOS
Co-authored-by: Filip Navara <filip.navara@gmail.com>
Diffstat (limited to 'src/libraries')
4 files changed, 202 insertions, 3 deletions
diff --git a/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Aead.cs b/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Aead.cs new file mode 100644 index 00000000000..62102ac0a59 --- /dev/null +++ b/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Aead.cs @@ -0,0 +1,120 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Security.Cryptography; +using System.Security.Cryptography.Apple; + +internal static partial class Interop +{ + internal static partial class AppleCrypto + { + internal static unsafe void ChaCha20Poly1305Encrypt( + ReadOnlySpan<byte> key, + ReadOnlySpan<byte> nonce, + ReadOnlySpan<byte> plaintext, + Span<byte> ciphertext, + Span<byte> tag, + ReadOnlySpan<byte> aad) + { + fixed (byte* keyPtr = key) + fixed (byte* noncePtr = nonce) + fixed (byte* plaintextPtr = plaintext) + fixed (byte* ciphertextPtr = ciphertext) + fixed (byte* tagPtr = tag) + fixed (byte* aadPtr = aad) + { + const int Success = 1; + int result = AppleCryptoNative_ChaCha20Poly1305Encrypt( + keyPtr, key.Length, + noncePtr, nonce.Length, + plaintextPtr, plaintext.Length, + ciphertextPtr, ciphertext.Length, + tagPtr, tag.Length, + aadPtr, aad.Length); + + if (result != Success) + { + Debug.Assert(result == 0); + CryptographicOperations.ZeroMemory(ciphertext); + CryptographicOperations.ZeroMemory(tag); + throw new CryptographicException(); + } + } + } + + internal static unsafe void ChaCha20Poly1305Decrypt( + ReadOnlySpan<byte> key, + ReadOnlySpan<byte> nonce, + ReadOnlySpan<byte> ciphertext, + ReadOnlySpan<byte> tag, + Span<byte> plaintext, + ReadOnlySpan<byte> aad) + { + fixed (byte* keyPtr = key) + fixed (byte* noncePtr = nonce) + fixed (byte* ciphertextPtr = ciphertext) + fixed (byte* tagPtr = tag) + fixed (byte* plaintextPtr = plaintext) + fixed (byte* aadPtr = aad) + { + const int Success = 1; + const int AuthTagMismatch = -1; + int result = AppleCryptoNative_ChaCha20Poly1305Decrypt( + keyPtr, key.Length, + noncePtr, nonce.Length, + ciphertextPtr, ciphertext.Length, + tagPtr, tag.Length, + plaintextPtr, plaintext.Length, + aadPtr, aad.Length); + + if (result != Success) + { + CryptographicOperations.ZeroMemory(plaintext); + + if (result == AuthTagMismatch) + { + throw new AuthenticationTagMismatchException(); + } + else + { + Debug.Assert(result == 0); + throw new CryptographicException(); + } + } + } + } + + [LibraryImport(Libraries.AppleCryptoNative)] + private static unsafe partial int AppleCryptoNative_ChaCha20Poly1305Encrypt( + byte* keyPtr, + int keyLength, + byte* noncePtr, + int nonceLength, + byte* plaintextPtr, + int plaintextLength, + byte* ciphertextPtr, + int ciphertextLength, + byte* tagPtr, + int tagLength, + byte* aadPtr, + int aadLength); + + [LibraryImport(Libraries.AppleCryptoNative)] + private static unsafe partial int AppleCryptoNative_ChaCha20Poly1305Decrypt( + byte* keyPtr, + int keyLength, + byte* noncePtr, + int nonceLength, + byte* ciphertextPtr, + int ciphertextLength, + byte* tagPtr, + int tagLength, + byte* plaintextPtr, + int plaintextLength, + byte* aadPtr, + int aadLength); + } +} 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 0840f45a3ae..b8d2342e227 100644 --- a/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj +++ b/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj @@ -788,6 +788,7 @@ <Compile Include="System\Security\Cryptography\CapiHelper.DSA.Shared.cs" /> <Compile Include="System\Security\Cryptography\CapiHelper.Shared.cs" /> <Compile Include="System\Security\Cryptography\CapiHelper.Unix.cs" /> + <Compile Include="System\Security\Cryptography\ChaCha20Poly1305.OpenSsl.cs" /> <Compile Include="System\Security\Cryptography\Cng.NotSupported.cs" /> <Compile Include="System\Security\Cryptography\CspKeyContainerInfo.NotSupported.cs" /> <Compile Include="System\Security\Cryptography\DESCryptoServiceProvider.Unix.cs" /> @@ -868,7 +869,6 @@ Link="Common\Interop\Unix\System.Security.Cryptography.Native\Interop.EVP.Cipher.cs" /> <Compile Include="$(CommonPath)Microsoft\Win32\SafeHandles\SafeEvpCipherCtxHandle.Unix.cs" Link="Common\Microsoft\Win32\SafeHandles\SafeEvpCipherCtxHandle.Unix.cs" /> - <Compile Include="System\Security\Cryptography\ChaCha20Poly1305.OpenSsl.cs" /> <Compile Include="System\Security\Cryptography\AesCcm.OpenSsl.cs" /> <Compile Include="System\Security\Cryptography\AesGcm.OpenSsl.cs" /> </ItemGroup> @@ -1257,6 +1257,8 @@ Link="Common\Interop\Unix\System.Security.Cryptography.Native\Interop.EvpPkey.Rsa.cs" /> <Compile Include="$(CommonPath)Interop\Unix\System.Security.Cryptography.Native\Interop.OpenSslVersion.cs" Link="Common\Interop\Unix\System.Security.Cryptography.Native\Interop.OpenSslVersion.cs" /> + <Compile Include="$(CommonPath)Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.Aead.cs" + Link="Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.Aead.cs" /> <Compile Include="$(CommonPath)Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.Keychain.macOS.cs" Link="Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.Keychain.macOS.cs" /> <Compile Include="$(CommonPath)Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.Pbkdf2.cs" @@ -1289,6 +1291,7 @@ Link="Common\System\Security\Cryptography\RSASecurityTransforms.macOS.cs" /> <Compile Include="$(CommonPath)System\Security\Cryptography\RSAOpenSsl.cs" Link="Common\System\Security\Cryptography\RSAOpenSsl.cs" /> + <Compile Include="System\Security\Cryptography\ChaCha20Poly1305.macOS.cs" /> <Compile Include="System\Security\Cryptography\DSA.Create.SecurityTransforms.cs" /> <Compile Include="System\Security\Cryptography\DSACryptoServiceProvider.Unix.cs" /> <Compile Include="System\Security\Cryptography\DSAOpenSsl.cs" /> diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/ChaCha20Poly1305.macOS.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/ChaCha20Poly1305.macOS.cs new file mode 100644 index 00000000000..82f1633c188 --- /dev/null +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/ChaCha20Poly1305.macOS.cs @@ -0,0 +1,72 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; + +namespace System.Security.Cryptography +{ + public sealed partial class ChaCha20Poly1305 + { + // CryptoKit added ChaCha20Poly1305 in macOS 10.15, which is our minimum target for macOS. + public static bool IsSupported => true; + private byte[]? _key; + + [MemberNotNull(nameof(_key))] + private void ImportKey(ReadOnlySpan<byte> key) + { + // We should only be calling this in the constructor, so there shouldn't be a previous key. + Debug.Assert(_key is null); + + // Pin the array on the POH so that the GC doesn't move it around to allow zeroing to be more effective. + _key = GC.AllocateArray<byte>(key.Length, pinned: true); + key.CopyTo(_key); + } + + private void EncryptCore( + ReadOnlySpan<byte> nonce, + ReadOnlySpan<byte> plaintext, + Span<byte> ciphertext, + Span<byte> tag, + ReadOnlySpan<byte> associatedData = default) + { + CheckDisposed(); + Interop.AppleCrypto.ChaCha20Poly1305Encrypt( + _key, + nonce, + plaintext, + ciphertext, + tag, + associatedData); + } + + private void DecryptCore( + ReadOnlySpan<byte> nonce, + ReadOnlySpan<byte> ciphertext, + ReadOnlySpan<byte> tag, + Span<byte> plaintext, + ReadOnlySpan<byte> associatedData = default) + { + CheckDisposed(); + Interop.AppleCrypto.ChaCha20Poly1305Decrypt( + _key, + nonce, + ciphertext, + tag, + plaintext, + associatedData); + } + + public void Dispose() + { + CryptographicOperations.ZeroMemory(_key); + _key = null; + } + + [MemberNotNull(nameof(_key))] + private void CheckDisposed() + { + ObjectDisposedException.ThrowIf(_key is null, this); + } + } +} diff --git a/src/libraries/System.Security.Cryptography/tests/ChaCha20Poly1305Tests.cs b/src/libraries/System.Security.Cryptography/tests/ChaCha20Poly1305Tests.cs index f381e17e73d..40f17690cdf 100644 --- a/src/libraries/System.Security.Cryptography/tests/ChaCha20Poly1305Tests.cs +++ b/src/libraries/System.Security.Cryptography/tests/ChaCha20Poly1305Tests.cs @@ -457,8 +457,12 @@ namespace System.Security.Cryptography.Tests // OpenSSL is present, and a high enough version, // but the distro build options turned off ChaCha/Poly. } - else if (PlatformDetection.OpenSslPresentOnSystem && - (PlatformDetection.IsOSX || PlatformDetection.IsOpenSslSupported)) + else if (PlatformDetection.IsOSX) + { + // CryptoKit is supported on macOS 10.15+, which is our minimum target. + expectedIsSupported = true; + } + else if (PlatformDetection.OpenSslPresentOnSystem && PlatformDetection.IsOpenSslSupported) { const int OpenSslChaChaMinimumVersion = 0x1_01_00_00_F; //major_minor_fix_patch_status expectedIsSupported = SafeEvpPKeyHandle.OpenSslVersion >= OpenSslChaChaMinimumVersion; |