From d129af65b2570d519b12009c54b12255d9fe870d Mon Sep 17 00:00:00 2001 From: Kevin Jones Date: Tue, 21 Jul 2020 09:58:36 -0400 Subject: [PATCH] Add CryptoStream.FlushFinalBlockAsync --- .../ref/System.Security.Cryptography.Primitives.cs | 1 + .../System/Security/Cryptography/CryptoStream.cs | 26 +++++++++++++++----- .../tests/CryptoStream.cs | 28 ++++++++++++++++++++++ 3 files changed, 49 insertions(+), 6 deletions(-) diff --git a/src/libraries/System.Security.Cryptography.Primitives/ref/System.Security.Cryptography.Primitives.cs b/src/libraries/System.Security.Cryptography.Primitives/ref/System.Security.Cryptography.Primitives.cs index 355c6c2..2add4b9 100644 --- a/src/libraries/System.Security.Cryptography.Primitives/ref/System.Security.Cryptography.Primitives.cs +++ b/src/libraries/System.Security.Cryptography.Primitives/ref/System.Security.Cryptography.Primitives.cs @@ -82,6 +82,7 @@ namespace System.Security.Cryptography public override void Flush() { } public override System.Threading.Tasks.Task FlushAsync(System.Threading.CancellationToken cancellationToken) { throw null; } public void FlushFinalBlock() { } + public System.Threading.Tasks.ValueTask FlushFinalBlockAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public override int Read(byte[] buffer, int offset, int count) { throw null; } public override System.Threading.Tasks.Task ReadAsync(byte[] buffer, int offset, int count, System.Threading.CancellationToken cancellationToken) { throw null; } public override int ReadByte() { throw null; } diff --git a/src/libraries/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/CryptoStream.cs b/src/libraries/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/CryptoStream.cs index e414e3c..2e426cc 100644 --- a/src/libraries/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/CryptoStream.cs +++ b/src/libraries/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/CryptoStream.cs @@ -100,9 +100,23 @@ namespace System.Security.Cryptography // byte[] ciphertext = ms.ToArray(); // cs.Close(); public void FlushFinalBlock() => - FlushFinalBlockAsync(useAsync: false).AsTask().GetAwaiter().GetResult(); + FlushFinalBlockAsync(useAsync: false, default).AsTask().GetAwaiter().GetResult(); + + /// + /// Asynchronously updates the underlying data source or repository with the + /// current state of the buffer, then clears the buffer. + /// + /// The token to monitor for cancellation requests. The default value is . + /// A task that represents the asynchronous flush operation. + public ValueTask FlushFinalBlockAsync(CancellationToken cancellationToken = default) + { + if (cancellationToken.IsCancellationRequested) + return ValueTask.FromCanceled(cancellationToken); + + return FlushFinalBlockAsync(useAsync: true, cancellationToken); + } - private async ValueTask FlushFinalBlockAsync(bool useAsync) + private async ValueTask FlushFinalBlockAsync(bool useAsync, CancellationToken cancellationToken) { if (_finalBlockTransformed) throw new NotSupportedException(SR.Cryptography_CryptoStream_FlushFinalBlockTwice); @@ -116,7 +130,7 @@ namespace System.Security.Cryptography byte[] finalBytes = _transform.TransformFinalBlock(_inputBuffer!, 0, _inputBufferIndex); if (useAsync) { - await _stream.WriteAsync(new ReadOnlyMemory(finalBytes)).ConfigureAwait(false); + await _stream.WriteAsync(new ReadOnlyMemory(finalBytes), cancellationToken).ConfigureAwait(false); } else { @@ -129,14 +143,14 @@ namespace System.Security.Cryptography { if (!innerCryptoStream.HasFlushedFinalBlock) { - await innerCryptoStream.FlushFinalBlockAsync(useAsync).ConfigureAwait(false); + await innerCryptoStream.FlushFinalBlockAsync(useAsync, cancellationToken).ConfigureAwait(false); } } else { if (useAsync) { - await _stream.FlushAsync().ConfigureAwait(false); + await _stream.FlushAsync(cancellationToken).ConfigureAwait(false); } else { @@ -691,7 +705,7 @@ namespace System.Security.Cryptography { if (!_finalBlockTransformed) { - await FlushFinalBlockAsync(useAsync: true).ConfigureAwait(false); + await FlushFinalBlockAsync(useAsync: true, default).ConfigureAwait(false); } if (!_leaveOpen) diff --git a/src/libraries/System.Security.Cryptography.Primitives/tests/CryptoStream.cs b/src/libraries/System.Security.Cryptography.Primitives/tests/CryptoStream.cs index 1d663a2..6156e9c 100644 --- a/src/libraries/System.Security.Cryptography.Primitives/tests/CryptoStream.cs +++ b/src/libraries/System.Security.Cryptography.Primitives/tests/CryptoStream.cs @@ -188,6 +188,34 @@ namespace System.Security.Cryptography.Encryption.Tests.Asymmetric } [Fact] + public static async Task FlushFinalBlockAsync() + { + ICryptoTransform encryptor = new IdentityTransform(1, 1, true); + using (MemoryStream output = new MemoryStream()) + using (CryptoStream encryptStream = new CryptoStream(output, encryptor, CryptoStreamMode.Write)) + { + await encryptStream.WriteAsync(new byte[] { 1, 2, 3, 4, 5 }, 0, 5); + await encryptStream.FlushFinalBlockAsync(); + Assert.True(encryptStream.HasFlushedFinalBlock); + Assert.Equal(5, output.ToArray().Length); + } + } + + [Fact] + public static async Task FlushFinalBlockAsync_Cancelled() + { + ICryptoTransform encryptor = new IdentityTransform(1, 1, true); + using (MemoryStream output = new MemoryStream()) + using (CryptoStream encryptStream = new CryptoStream(output, encryptor, CryptoStreamMode.Write)) + { + await encryptStream.WriteAsync(new byte[] { 1, 2, 3, 4, 5 }, 0, 5); + ValueTask waitable = encryptStream.FlushFinalBlockAsync(new Threading.CancellationToken(canceled: true)); + Assert.True(waitable.IsCanceled); + Assert.False(encryptStream.HasFlushedFinalBlock); + } + } + + [Fact] public static void FlushCalledOnFlushAsync_DeriveClass() { ICryptoTransform encryptor = new IdentityTransform(1, 1, true); -- 2.7.4