-
Notifications
You must be signed in to change notification settings - Fork 5.5k
Support ChaCha20 Poly1305 on Unix #52522
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
15f899c
0a7d906
fc2852c
81c9a4f
c73c744
fa37b9b
7f8a492
a75bb46
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,3 +2,4 @@ | |
|
|
||
| #cmakedefine01 HAVE_OPENSSL_EC2M | ||
| #cmakedefine01 HAVE_OPENSSL_ALPN | ||
| #cmakedefine01 HAVE_OPENSSL_CHACHA20POLY1305 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,136 @@ | ||
| // 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; | ||
| using Microsoft.Win32.SafeHandles; | ||
|
|
||
| namespace System.Security.Cryptography | ||
| { | ||
| public sealed partial class ChaCha20Poly1305 | ||
| { | ||
| public static bool IsSupported { get; } = Interop.Crypto.EvpChaCha20Poly1305() != IntPtr.Zero; | ||
|
vcsjones marked this conversation as resolved.
|
||
|
|
||
| private SafeEvpCipherCtxHandle _ctxHandle; | ||
|
|
||
| [MemberNotNull(nameof(_ctxHandle))] | ||
| private void ImportKey(ReadOnlySpan<byte> key) | ||
| { | ||
| _ctxHandle = Interop.Crypto.EvpCipherCreatePartial(GetCipher(key.Length * 8)); | ||
|
|
||
| Interop.Crypto.CheckValidOpenSslHandle(_ctxHandle); | ||
| Interop.Crypto.EvpCipherSetKeyAndIV( | ||
| _ctxHandle, | ||
| key, | ||
| Span<byte>.Empty, | ||
| Interop.Crypto.EvpCipherDirection.NoChange); | ||
| } | ||
|
|
||
| private void EncryptCore( | ||
| ReadOnlySpan<byte> nonce, | ||
| ReadOnlySpan<byte> plaintext, | ||
| Span<byte> ciphertext, | ||
| Span<byte> tag, | ||
| ReadOnlySpan<byte> associatedData = default) | ||
| { | ||
| Interop.Crypto.EvpCipherSetKeyAndIV( | ||
| _ctxHandle, | ||
| Span<byte>.Empty, | ||
| nonce, | ||
| Interop.Crypto.EvpCipherDirection.Encrypt); | ||
|
|
||
| if (associatedData.Length != 0) | ||
| { | ||
| if (!Interop.Crypto.EvpCipherUpdate(_ctxHandle, Span<byte>.Empty, out _, associatedData)) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Out of morbid curiosity, what happens if multiple threads call this at the same time on the same instance? Is there a potential for buffer overrun? (I know this is copied from the existing AEAD code, so I'm not suggesting changes at this time. Just trying to calculate risk exposure.) |
||
| { | ||
| throw Interop.Crypto.CreateOpenSslCryptographicException(); | ||
| } | ||
| } | ||
|
|
||
| if (!Interop.Crypto.EvpCipherUpdate(_ctxHandle, ciphertext, out int ciphertextBytesWritten, plaintext)) | ||
| { | ||
| throw Interop.Crypto.CreateOpenSslCryptographicException(); | ||
| } | ||
|
|
||
| if (!Interop.Crypto.EvpCipherFinalEx( | ||
| _ctxHandle, | ||
| ciphertext.Slice(ciphertextBytesWritten), | ||
| out int bytesWritten)) | ||
| { | ||
| throw Interop.Crypto.CreateOpenSslCryptographicException(); | ||
| } | ||
|
|
||
| ciphertextBytesWritten += bytesWritten; | ||
|
|
||
| if (ciphertextBytesWritten != ciphertext.Length) | ||
| { | ||
| Debug.Fail($"ChaCha20Poly1305 encrypt wrote {ciphertextBytesWritten} of {ciphertext.Length} bytes."); | ||
| throw new CryptographicException(); | ||
| } | ||
|
|
||
| Interop.Crypto.EvpCipherGetAeadTag(_ctxHandle, tag); | ||
| } | ||
|
|
||
| private void DecryptCore( | ||
| ReadOnlySpan<byte> nonce, | ||
| ReadOnlySpan<byte> ciphertext, | ||
| ReadOnlySpan<byte> tag, | ||
| Span<byte> plaintext, | ||
| ReadOnlySpan<byte> associatedData) | ||
| { | ||
| Interop.Crypto.EvpCipherSetKeyAndIV( | ||
| _ctxHandle, | ||
| ReadOnlySpan<byte>.Empty, | ||
| nonce, | ||
| Interop.Crypto.EvpCipherDirection.Decrypt); | ||
|
|
||
| if (associatedData.Length != 0) | ||
| { | ||
| if (!Interop.Crypto.EvpCipherUpdate(_ctxHandle, Span<byte>.Empty, out _, associatedData)) | ||
| { | ||
| throw Interop.Crypto.CreateOpenSslCryptographicException(); | ||
| } | ||
| } | ||
|
|
||
| if (!Interop.Crypto.EvpCipherUpdate(_ctxHandle, plaintext, out int plaintextBytesWritten, ciphertext)) | ||
| { | ||
| throw Interop.Crypto.CreateOpenSslCryptographicException(); | ||
| } | ||
|
|
||
| Interop.Crypto.EvpCipherSetAeadTag(_ctxHandle, tag); | ||
|
|
||
| if (!Interop.Crypto.EvpCipherFinalEx( | ||
| _ctxHandle, | ||
| plaintext.Slice(plaintextBytesWritten), | ||
| out int bytesWritten)) | ||
| { | ||
| CryptographicOperations.ZeroMemory(plaintext); | ||
| throw new CryptographicException(SR.Cryptography_AuthTagMismatch); | ||
| } | ||
|
|
||
| plaintextBytesWritten += bytesWritten; | ||
|
|
||
| if (plaintextBytesWritten != plaintext.Length) | ||
| { | ||
| Debug.Fail($"ChaCha20Poly1305 decrypt wrote {plaintextBytesWritten} of {plaintext.Length} bytes."); | ||
| throw new CryptographicException(); | ||
| } | ||
| } | ||
|
|
||
| private static IntPtr GetCipher(int keySizeInBits) | ||
| { | ||
| switch (keySizeInBits) | ||
| { | ||
| case 256: return Interop.Crypto.EvpChaCha20Poly1305(); | ||
| default: | ||
| Debug.Fail("Key size should already be validated"); | ||
| return IntPtr.Zero; | ||
| } | ||
| } | ||
|
|
||
| public void Dispose() | ||
| { | ||
| _ctxHandle.Dispose(); | ||
| } | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.