You've already forked linux-packaging-mono
Imported Upstream version 5.16.0.100
Former-commit-id: 38faa55fb9669e35e7d8448b15c25dc447f25767
This commit is contained in:
parent
0a9828183b
commit
7d7f676260
@@ -7,6 +7,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Security.Cryptograph
|
||||
{DF73E985-E143-4BF5-9FA4-E199E7D36235} = {DF73E985-E143-4BF5-9FA4-E199E7D36235}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Security.Cryptography.Primitives.Performance.Tests", "tests\Performance\System.Security.Cryptography.Primitives.Performance.Tests.csproj", "{FB3EA273-567D-414F-B36D-3698BE8D198B}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{DF73E985-E143-4BF5-9FA4-E199E7D36235} = {DF73E985-E143-4BF5-9FA4-E199E7D36235}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Security.Cryptography.Primitives", "src\System.Security.Cryptography.Primitives.csproj", "{DF73E985-E143-4BF5-9FA4-E199E7D36235}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{F050C895-297F-41C6-98C3-406D791AD515} = {F050C895-297F-41C6-98C3-406D791AD515}
|
||||
@@ -30,6 +35,10 @@ Global
|
||||
{101EB757-55A4-4F48-841C-C088640B8F57}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
|
||||
{101EB757-55A4-4F48-841C-C088640B8F57}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
|
||||
{101EB757-55A4-4F48-841C-C088640B8F57}.Release|Any CPU.Build.0 = netcoreapp-Release|Any CPU
|
||||
{FB3EA273-567D-414F-B36D-3698BE8D198B}.Debug|Any CPU.ActiveCfg = netcoreapp-Debug|Any CPU
|
||||
{FB3EA273-567D-414F-B36D-3698BE8D198B}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
|
||||
{FB3EA273-567D-414F-B36D-3698BE8D198B}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
|
||||
{FB3EA273-567D-414F-B36D-3698BE8D198B}.Release|Any CPU.Build.0 = netcoreapp-Release|Any CPU
|
||||
{DF73E985-E143-4BF5-9FA4-E199E7D36235}.Debug|Any CPU.ActiveCfg = netcoreapp-Debug|Any CPU
|
||||
{DF73E985-E143-4BF5-9FA4-E199E7D36235}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
|
||||
{DF73E985-E143-4BF5-9FA4-E199E7D36235}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
|
||||
@@ -44,6 +53,7 @@ Global
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{101EB757-55A4-4F48-841C-C088640B8F57} = {1A2F9F4A-A032-433E-B914-ADD5992BB178}
|
||||
{FB3EA273-567D-414F-B36D-3698BE8D198B} = {1A2F9F4A-A032-433E-B914-ADD5992BB178}
|
||||
{DF73E985-E143-4BF5-9FA4-E199E7D36235} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD}
|
||||
{F050C895-297F-41C6-98C3-406D791AD515} = {2E666815-2EDB-464B-9DF6-380BF4789AD4}
|
||||
EndGlobalSection
|
||||
|
@@ -36,6 +36,11 @@ namespace System.Security.Cryptography
|
||||
[System.ComponentModel.EditorBrowsableAttribute((System.ComponentModel.EditorBrowsableState)(1))]
|
||||
OFB = 3,
|
||||
}
|
||||
public static partial class CryptographicOperations
|
||||
{
|
||||
public static bool FixedTimeEquals(System.ReadOnlySpan<byte> left, System.ReadOnlySpan<byte> right) => throw null;
|
||||
public static void ZeroMemory(System.Span<byte> buffer) => throw null;
|
||||
}
|
||||
public partial class CryptographicUnexpectedOperationException : System.Security.Cryptography.CryptographicException
|
||||
{
|
||||
public CryptographicUnexpectedOperationException() { }
|
||||
|
@@ -17,4 +17,4 @@
|
||||
<ProjectReference Include="..\..\System.Threading.Tasks\ref\System.Threading.Tasks.csproj" />
|
||||
</ItemGroup>
|
||||
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
|
||||
</Project>
|
||||
</Project>
|
||||
|
@@ -79,6 +79,9 @@
|
||||
<data name="Cryptography_CryptoStream_FlushFinalBlockTwice" xml:space="preserve">
|
||||
<value>FlushFinalBlock() method was called twice on a CryptoStream. It can only be called once.</value>
|
||||
</data>
|
||||
<data name="Cryptography_DefaultAlgorithm_NotSupported" xml:space="preserve">
|
||||
<value>This platform does not allow the automatic selection of an algorithm.</value>
|
||||
</data>
|
||||
<data name="Cryptography_HashNotYetFinalized" xml:space="preserve">
|
||||
<value>Hash must be finalized before the hash value is retrieved.</value>
|
||||
</data>
|
||||
|
@@ -13,6 +13,8 @@
|
||||
<ItemGroup>
|
||||
<Compile Include="System\Security\Cryptography\AsymmetricAlgorithm.cs" />
|
||||
<Compile Include="System\Security\Cryptography\CipherMode.cs" />
|
||||
<Compile Include="System\Security\Cryptography\CryptoConfigForwarder.cs" />
|
||||
<Compile Include="System\Security\Cryptography\CryptographicOperations.cs" />
|
||||
<Compile Include="System\Security\Cryptography\CryptographicUnexpectedOperationException.cs" />
|
||||
<Compile Include="System\Security\Cryptography\CryptoStream.cs" />
|
||||
<Compile Include="System\Security\Cryptography\CryptoStreamMode.cs" />
|
||||
|
@@ -11,15 +11,11 @@ namespace System.Security.Cryptography
|
||||
|
||||
protected AsymmetricAlgorithm() { }
|
||||
|
||||
public static AsymmetricAlgorithm Create()
|
||||
{
|
||||
return Create("System.Security.Cryptography.AsymmetricAlgorithm");
|
||||
}
|
||||
public static AsymmetricAlgorithm Create() =>
|
||||
throw new PlatformNotSupportedException(SR.Cryptography_DefaultAlgorithm_NotSupported);
|
||||
|
||||
public static AsymmetricAlgorithm Create(string algName)
|
||||
{
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
public static AsymmetricAlgorithm Create(string algName) =>
|
||||
(AsymmetricAlgorithm)CryptoConfigForwarder.CreateFromName(algName);
|
||||
|
||||
public virtual int KeySize
|
||||
{
|
||||
|
@@ -0,0 +1,33 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Reflection;
|
||||
|
||||
namespace System.Security.Cryptography
|
||||
{
|
||||
internal static class CryptoConfigForwarder
|
||||
{
|
||||
private static readonly Func<string, object> s_createFromName = BindCreateFromName();
|
||||
|
||||
private static Func<string, object> BindCreateFromName()
|
||||
{
|
||||
const string CryptoConfigTypeName =
|
||||
"System.Security.Cryptography.CryptoConfig, System.Security.Cryptography.Algorithms";
|
||||
|
||||
const string CreateFromNameMethodName = "CreateFromName";
|
||||
|
||||
Type t = Type.GetType(CryptoConfigTypeName, throwOnError: true);
|
||||
MethodInfo createFromName = t.GetMethod(CreateFromNameMethodName, new[] { typeof(string) });
|
||||
|
||||
if (createFromName == null)
|
||||
{
|
||||
throw new MissingMethodException(t.FullName, CreateFromNameMethodName);
|
||||
}
|
||||
|
||||
return (Func<string, object>)createFromName.CreateDelegate(typeof(Func<string, object>));
|
||||
}
|
||||
|
||||
internal static object CreateFromName(string name) => s_createFromName(name);
|
||||
}
|
||||
}
|
@@ -2,6 +2,7 @@
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Buffers;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -238,7 +239,7 @@ namespace System.Security.Cryptography
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
CheckReadArguments(buffer, offset, count);
|
||||
return ReadAsyncCore(buffer, offset, count, default(CancellationToken), useAsync: false).ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
return ReadAsyncCore(buffer, offset, count, default(CancellationToken), useAsync: false).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
private void CheckReadArguments(byte[] buffer, int offset, int count)
|
||||
@@ -270,6 +271,8 @@ namespace System.Security.Cryptography
|
||||
Buffer.BlockCopy(_outputBuffer, 0, buffer, offset, _outputBufferIndex);
|
||||
bytesToDeliver -= _outputBufferIndex;
|
||||
currentOutputIndex += _outputBufferIndex;
|
||||
int toClear = _outputBuffer.Length - _outputBufferIndex;
|
||||
CryptographicOperations.ZeroMemory(new Span<byte>(_outputBuffer, _outputBufferIndex, toClear));
|
||||
_outputBufferIndex = 0;
|
||||
}
|
||||
else
|
||||
@@ -277,6 +280,10 @@ namespace System.Security.Cryptography
|
||||
Buffer.BlockCopy(_outputBuffer, 0, buffer, offset, count);
|
||||
Buffer.BlockCopy(_outputBuffer, count, _outputBuffer, 0, _outputBufferIndex - count);
|
||||
_outputBufferIndex -= count;
|
||||
|
||||
int toClear = _outputBuffer.Length - _outputBufferIndex;
|
||||
CryptographicOperations.ZeroMemory(new Span<byte>(_outputBuffer, _outputBufferIndex, toClear));
|
||||
|
||||
return (count);
|
||||
}
|
||||
}
|
||||
@@ -294,65 +301,98 @@ namespace System.Security.Cryptography
|
||||
int numOutputBytes;
|
||||
|
||||
// OK, see first if it's a multi-block transform and we can speed up things
|
||||
if (bytesToDeliver > _outputBlockSize)
|
||||
int blocksToProcess = bytesToDeliver / _outputBlockSize;
|
||||
|
||||
if (blocksToProcess > 1 && _transform.CanTransformMultipleBlocks)
|
||||
{
|
||||
if (_transform.CanTransformMultipleBlocks)
|
||||
int numWholeBlocksInBytes = blocksToProcess * _inputBlockSize;
|
||||
byte[] tempInputBuffer = ArrayPool<byte>.Shared.Rent(numWholeBlocksInBytes);
|
||||
byte[] tempOutputBuffer = null;
|
||||
|
||||
try
|
||||
{
|
||||
int BlocksToProcess = bytesToDeliver / _outputBlockSize;
|
||||
int numWholeBlocksInBytes = BlocksToProcess * _inputBlockSize;
|
||||
byte[] tempInputBuffer = new byte[numWholeBlocksInBytes];
|
||||
// get first the block already read
|
||||
Buffer.BlockCopy(_inputBuffer, 0, tempInputBuffer, 0, _inputBufferIndex);
|
||||
amountRead = _inputBufferIndex;
|
||||
amountRead += useAsync ?
|
||||
await _stream.ReadAsync(tempInputBuffer, _inputBufferIndex, numWholeBlocksInBytes - _inputBufferIndex, cancellationToken) :
|
||||
amountRead = useAsync ?
|
||||
await _stream.ReadAsync(new Memory<byte>(tempInputBuffer, _inputBufferIndex, numWholeBlocksInBytes - _inputBufferIndex), cancellationToken) :
|
||||
_stream.Read(tempInputBuffer, _inputBufferIndex, numWholeBlocksInBytes - _inputBufferIndex);
|
||||
|
||||
_inputBufferIndex = 0;
|
||||
if (amountRead <= _inputBlockSize)
|
||||
int totalInput = _inputBufferIndex + amountRead;
|
||||
|
||||
// If there's still less than a block, copy the new data into the hold buffer and move to the slow read.
|
||||
if (totalInput < _inputBlockSize)
|
||||
{
|
||||
_inputBuffer = tempInputBuffer;
|
||||
_inputBufferIndex = amountRead;
|
||||
goto slow;
|
||||
Buffer.BlockCopy(tempInputBuffer, _inputBufferIndex, _inputBuffer, _inputBufferIndex, amountRead);
|
||||
_inputBufferIndex = totalInput;
|
||||
}
|
||||
// Make amountRead an integral multiple of _InputBlockSize
|
||||
int numWholeReadBlocksInBytes = (amountRead / _inputBlockSize) * _inputBlockSize;
|
||||
int numIgnoredBytes = amountRead - numWholeReadBlocksInBytes;
|
||||
if (numIgnoredBytes != 0)
|
||||
else
|
||||
{
|
||||
_inputBufferIndex = numIgnoredBytes;
|
||||
Buffer.BlockCopy(tempInputBuffer, numWholeReadBlocksInBytes, _inputBuffer, 0, numIgnoredBytes);
|
||||
// Copy any held data into tempInputBuffer now that we know we're proceeding
|
||||
Buffer.BlockCopy(_inputBuffer, 0, tempInputBuffer, 0, _inputBufferIndex);
|
||||
CryptographicOperations.ZeroMemory(new Span<byte>(_inputBuffer, 0, _inputBufferIndex));
|
||||
amountRead += _inputBufferIndex;
|
||||
_inputBufferIndex = 0;
|
||||
|
||||
// Make amountRead an integral multiple of _InputBlockSize
|
||||
int numWholeReadBlocks = amountRead / _inputBlockSize;
|
||||
int numWholeReadBlocksInBytes = numWholeReadBlocks * _inputBlockSize;
|
||||
int numIgnoredBytes = amountRead - numWholeReadBlocksInBytes;
|
||||
|
||||
if (numIgnoredBytes != 0)
|
||||
{
|
||||
_inputBufferIndex = numIgnoredBytes;
|
||||
Buffer.BlockCopy(tempInputBuffer, numWholeReadBlocksInBytes, _inputBuffer, 0, numIgnoredBytes);
|
||||
}
|
||||
|
||||
tempOutputBuffer = ArrayPool<byte>.Shared.Rent(numWholeReadBlocks * _outputBlockSize);
|
||||
numOutputBytes = _transform.TransformBlock(tempInputBuffer, 0, numWholeReadBlocksInBytes, tempOutputBuffer, 0);
|
||||
Buffer.BlockCopy(tempOutputBuffer, 0, buffer, currentOutputIndex, numOutputBytes);
|
||||
|
||||
// Clear what was written while we know how much that was
|
||||
CryptographicOperations.ZeroMemory(new Span<byte>(tempOutputBuffer, 0, numOutputBytes));
|
||||
ArrayPool<byte>.Shared.Return(tempOutputBuffer);
|
||||
tempOutputBuffer = null;
|
||||
|
||||
bytesToDeliver -= numOutputBytes;
|
||||
currentOutputIndex += numOutputBytes;
|
||||
}
|
||||
byte[] tempOutputBuffer = new byte[(numWholeReadBlocksInBytes / _inputBlockSize) * _outputBlockSize];
|
||||
numOutputBytes = _transform.TransformBlock(tempInputBuffer, 0, numWholeReadBlocksInBytes, tempOutputBuffer, 0);
|
||||
Buffer.BlockCopy(tempOutputBuffer, 0, buffer, currentOutputIndex, numOutputBytes);
|
||||
// Now, tempInputBuffer and tempOutputBuffer are no more needed, so zeroize them to protect plain text
|
||||
Array.Clear(tempInputBuffer, 0, tempInputBuffer.Length);
|
||||
Array.Clear(tempOutputBuffer, 0, tempOutputBuffer.Length);
|
||||
bytesToDeliver -= numOutputBytes;
|
||||
currentOutputIndex += numOutputBytes;
|
||||
}
|
||||
finally
|
||||
{
|
||||
// If we rented and then an exception happened we don't know how much was written to,
|
||||
// clear the whole thing and return it.
|
||||
if (tempOutputBuffer != null)
|
||||
{
|
||||
CryptographicOperations.ZeroMemory(tempOutputBuffer);
|
||||
ArrayPool<byte>.Shared.Return(tempOutputBuffer);
|
||||
tempOutputBuffer = null;
|
||||
}
|
||||
|
||||
CryptographicOperations.ZeroMemory(new Span<byte>(tempInputBuffer, 0, numWholeBlocksInBytes));
|
||||
ArrayPool<byte>.Shared.Return(tempInputBuffer);
|
||||
tempInputBuffer = null;
|
||||
}
|
||||
}
|
||||
|
||||
slow:
|
||||
// try to fill _InputBuffer so we have something to transform
|
||||
while (bytesToDeliver > 0)
|
||||
{
|
||||
while (_inputBufferIndex < _inputBlockSize)
|
||||
{
|
||||
amountRead = useAsync ?
|
||||
await _stream.ReadAsync(_inputBuffer, _inputBufferIndex, _inputBlockSize - _inputBufferIndex, cancellationToken) :
|
||||
await _stream.ReadAsync(new Memory<byte>(_inputBuffer, _inputBufferIndex, _inputBlockSize - _inputBufferIndex), cancellationToken) :
|
||||
_stream.Read(_inputBuffer, _inputBufferIndex, _inputBlockSize - _inputBufferIndex);
|
||||
|
||||
// first, check to see if we're at the end of the input stream
|
||||
if (amountRead == 0) goto ProcessFinalBlock;
|
||||
_inputBufferIndex += amountRead;
|
||||
}
|
||||
|
||||
numOutputBytes = _transform.TransformBlock(_inputBuffer, 0, _inputBlockSize, _outputBuffer, 0);
|
||||
_inputBufferIndex = 0;
|
||||
|
||||
if (bytesToDeliver >= numOutputBytes)
|
||||
{
|
||||
Buffer.BlockCopy(_outputBuffer, 0, buffer, currentOutputIndex, numOutputBytes);
|
||||
CryptographicOperations.ZeroMemory(new Span<byte>(_outputBuffer, 0, numOutputBytes));
|
||||
currentOutputIndex += numOutputBytes;
|
||||
bytesToDeliver -= numOutputBytes;
|
||||
}
|
||||
@@ -361,6 +401,8 @@ namespace System.Security.Cryptography
|
||||
Buffer.BlockCopy(_outputBuffer, 0, buffer, currentOutputIndex, bytesToDeliver);
|
||||
_outputBufferIndex = numOutputBytes - bytesToDeliver;
|
||||
Buffer.BlockCopy(_outputBuffer, bytesToDeliver, _outputBuffer, 0, _outputBufferIndex);
|
||||
int toClear = _outputBuffer.Length - _outputBufferIndex;
|
||||
CryptographicOperations.ZeroMemory(new Span<byte>(_outputBuffer, _outputBufferIndex, toClear));
|
||||
return count;
|
||||
}
|
||||
}
|
||||
@@ -381,6 +423,8 @@ namespace System.Security.Cryptography
|
||||
Buffer.BlockCopy(_outputBuffer, 0, buffer, currentOutputIndex, bytesToDeliver);
|
||||
_outputBufferIndex -= bytesToDeliver;
|
||||
Buffer.BlockCopy(_outputBuffer, bytesToDeliver, _outputBuffer, 0, _outputBufferIndex);
|
||||
int toClear = _outputBuffer.Length - _outputBufferIndex;
|
||||
CryptographicOperations.ZeroMemory(new Span<byte>(_outputBuffer, _outputBufferIndex, toClear));
|
||||
return (count);
|
||||
}
|
||||
else
|
||||
@@ -388,6 +432,7 @@ namespace System.Security.Cryptography
|
||||
Buffer.BlockCopy(_outputBuffer, 0, buffer, currentOutputIndex, _outputBufferIndex);
|
||||
bytesToDeliver -= _outputBufferIndex;
|
||||
_outputBufferIndex = 0;
|
||||
CryptographicOperations.ZeroMemory(_outputBuffer);
|
||||
return (count - bytesToDeliver);
|
||||
}
|
||||
}
|
||||
@@ -475,7 +520,7 @@ namespace System.Security.Cryptography
|
||||
if (_outputBufferIndex > 0)
|
||||
{
|
||||
if (useAsync)
|
||||
await _stream.WriteAsync(_outputBuffer, 0, _outputBufferIndex, cancellationToken);
|
||||
await _stream.WriteAsync(new ReadOnlyMemory<byte>(_outputBuffer, 0, _outputBufferIndex), cancellationToken);
|
||||
else
|
||||
_stream.Write(_outputBuffer, 0, _outputBufferIndex);
|
||||
_outputBufferIndex = 0;
|
||||
@@ -488,7 +533,7 @@ namespace System.Security.Cryptography
|
||||
numOutputBytes = _transform.TransformBlock(_inputBuffer, 0, _inputBlockSize, _outputBuffer, 0);
|
||||
// write out the bytes we just got
|
||||
if (useAsync)
|
||||
await _stream.WriteAsync(_outputBuffer, 0, numOutputBytes, cancellationToken);
|
||||
await _stream.WriteAsync(new ReadOnlyMemory<byte>(_outputBuffer, 0, numOutputBytes), cancellationToken);
|
||||
else
|
||||
_stream.Write(_outputBuffer, 0, numOutputBytes);
|
||||
|
||||
@@ -500,21 +545,38 @@ namespace System.Security.Cryptography
|
||||
if (bytesToWrite >= _inputBlockSize)
|
||||
{
|
||||
// We have at least an entire block's worth to transform
|
||||
int numWholeBlocks = bytesToWrite / _inputBlockSize;
|
||||
|
||||
// If the transform will handle multiple blocks at once, do that
|
||||
if (_transform.CanTransformMultipleBlocks)
|
||||
if (_transform.CanTransformMultipleBlocks && numWholeBlocks > 1)
|
||||
{
|
||||
int numWholeBlocks = bytesToWrite / _inputBlockSize;
|
||||
int numWholeBlocksInBytes = numWholeBlocks * _inputBlockSize;
|
||||
byte[] _tempOutputBuffer = new byte[numWholeBlocks * _outputBlockSize];
|
||||
numOutputBytes = _transform.TransformBlock(buffer, currentInputIndex, numWholeBlocksInBytes, _tempOutputBuffer, 0);
|
||||
byte[] tempOutputBuffer = ArrayPool<byte>.Shared.Rent(numWholeBlocks * _outputBlockSize);
|
||||
numOutputBytes = 0;
|
||||
|
||||
if (useAsync)
|
||||
await _stream.WriteAsync(_tempOutputBuffer, 0, numOutputBytes, cancellationToken);
|
||||
else
|
||||
_stream.Write(_tempOutputBuffer, 0, numOutputBytes);
|
||||
try
|
||||
{
|
||||
numOutputBytes =
|
||||
_transform.TransformBlock(buffer, currentInputIndex, numWholeBlocksInBytes, tempOutputBuffer, 0);
|
||||
|
||||
currentInputIndex += numWholeBlocksInBytes;
|
||||
bytesToWrite -= numWholeBlocksInBytes;
|
||||
if (useAsync)
|
||||
{
|
||||
await _stream.WriteAsync(new ReadOnlyMemory<byte>(tempOutputBuffer, 0, numOutputBytes), cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
_stream.Write(tempOutputBuffer, 0, numOutputBytes);
|
||||
}
|
||||
|
||||
currentInputIndex += numWholeBlocksInBytes;
|
||||
bytesToWrite -= numWholeBlocksInBytes;
|
||||
}
|
||||
finally
|
||||
{
|
||||
CryptographicOperations.ZeroMemory(new Span<byte>(tempOutputBuffer, 0, numOutputBytes));
|
||||
ArrayPool<byte>.Shared.Return(tempOutputBuffer);
|
||||
tempOutputBuffer = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -522,7 +584,7 @@ namespace System.Security.Cryptography
|
||||
numOutputBytes = _transform.TransformBlock(buffer, currentInputIndex, _inputBlockSize, _outputBuffer, 0);
|
||||
|
||||
if (useAsync)
|
||||
await _stream.WriteAsync(_outputBuffer, 0, numOutputBytes, cancellationToken);
|
||||
await _stream.WriteAsync(new ReadOnlyMemory<byte>(_outputBuffer, 0, numOutputBytes), cancellationToken);
|
||||
else
|
||||
_stream.Write(_outputBuffer, 0, numOutputBytes);
|
||||
|
||||
|
@@ -0,0 +1,63 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace System.Security.Cryptography
|
||||
{
|
||||
public static class CryptographicOperations
|
||||
{
|
||||
/// <summary>
|
||||
/// Determine the equality of two byte sequences in an amount of time which depends on
|
||||
/// the length of the sequences, but not the values.
|
||||
/// </summary>
|
||||
/// <param name="left">The first buffer to compare.</param>
|
||||
/// <param name="right">The second buffer to compare.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if <paramref name="left"/> and <paramref name="right"/> have the same
|
||||
/// values for <see cref="ReadOnlySpan{T}.Length"/> and the same contents, <c>false</c>
|
||||
/// otherwise.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// This method compares two buffers' contents for equality in a manner which does not
|
||||
/// leak timing information, making it ideal for use within cryptographic routines.
|
||||
/// This method will short-circuit and return <c>false</c> only if <paramref name="left"/>
|
||||
/// and <paramref name="right"/> have different lengths.
|
||||
///
|
||||
/// Fixed-time behavior is guaranteed in all other cases, including if <paramref name="left"/>
|
||||
/// and <paramref name="right"/> reference the same address.
|
||||
/// </remarks>
|
||||
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
|
||||
public static bool FixedTimeEquals(ReadOnlySpan<byte> left, ReadOnlySpan<byte> right)
|
||||
{
|
||||
// NoOptimization because we want this method to be exactly as non-short-circuiting
|
||||
// as written.
|
||||
//
|
||||
// NoInlining because the NoOptimization would get lost if the method got inlined.
|
||||
|
||||
if (left.Length != right.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int length = left.Length;
|
||||
int accum = 0;
|
||||
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
accum |= left[i] - right[i];
|
||||
}
|
||||
|
||||
return accum == 0;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
|
||||
public static void ZeroMemory(Span<byte> buffer)
|
||||
{
|
||||
// NoOptimize to prevent the optimizer from deciding this call is unnecessary
|
||||
// NoInlining to prevent the inliner from forgetting that the method was no-optimize
|
||||
buffer.Clear();
|
||||
}
|
||||
}
|
||||
}
|
@@ -17,9 +17,11 @@ namespace System.Security.Cryptography
|
||||
|
||||
protected HMAC() { }
|
||||
|
||||
public static new HMAC Create() => Create("System.Security.Cryptography.HMAC");
|
||||
public static new HMAC Create() =>
|
||||
throw new PlatformNotSupportedException(SR.Cryptography_DefaultAlgorithm_NotSupported);
|
||||
|
||||
public static new HMAC Create(string algorithmName) => throw new PlatformNotSupportedException();
|
||||
public static new HMAC Create(string algorithmName) =>
|
||||
(HMAC)CryptoConfigForwarder.CreateFromName(algorithmName);
|
||||
|
||||
public string HashName
|
||||
{
|
||||
|
@@ -16,9 +16,11 @@ namespace System.Security.Cryptography
|
||||
|
||||
protected HashAlgorithm() { }
|
||||
|
||||
public static HashAlgorithm Create() => Create("System.Security.Cryptography.HashAlgorithm");
|
||||
public static HashAlgorithm Create() =>
|
||||
throw new PlatformNotSupportedException(SR.Cryptography_DefaultAlgorithm_NotSupported);
|
||||
|
||||
public static HashAlgorithm Create(string hashName) => throw new PlatformNotSupportedException();
|
||||
public static HashAlgorithm Create(string hashName) =>
|
||||
(HashAlgorithm)CryptoConfigForwarder.CreateFromName(hashName);
|
||||
|
||||
public virtual int HashSize => HashSizeValue;
|
||||
|
||||
@@ -96,13 +98,23 @@ namespace System.Security.Cryptography
|
||||
throw new ObjectDisposedException(null);
|
||||
|
||||
// Default the buffer size to 4K.
|
||||
byte[] buffer = new byte[4096];
|
||||
int bytesRead;
|
||||
while ((bytesRead = inputStream.Read(buffer, 0, buffer.Length)) > 0)
|
||||
byte[] buffer = ArrayPool<byte>.Shared.Rent(4096);
|
||||
|
||||
try
|
||||
{
|
||||
HashCore(buffer, 0, bytesRead);
|
||||
int bytesRead;
|
||||
while ((bytesRead = inputStream.Read(buffer, 0, buffer.Length)) > 0)
|
||||
{
|
||||
HashCore(buffer, 0, bytesRead);
|
||||
}
|
||||
|
||||
return CaptureHashCodeAndReinitialize();
|
||||
}
|
||||
finally
|
||||
{
|
||||
CryptographicOperations.ZeroMemory(buffer);
|
||||
ArrayPool<byte>.Shared.Return(buffer);
|
||||
}
|
||||
return CaptureHashCodeAndReinitialize();
|
||||
}
|
||||
|
||||
private byte[] CaptureHashCodeAndReinitialize()
|
||||
|
@@ -8,15 +8,11 @@ namespace System.Security.Cryptography
|
||||
{
|
||||
protected KeyedHashAlgorithm() { }
|
||||
|
||||
public static new KeyedHashAlgorithm Create()
|
||||
{
|
||||
return Create("System.Security.Cryptography.KeyedHashAlgorithm");
|
||||
}
|
||||
public static new KeyedHashAlgorithm Create() =>
|
||||
throw new PlatformNotSupportedException(SR.Cryptography_DefaultAlgorithm_NotSupported);
|
||||
|
||||
public static new KeyedHashAlgorithm Create(string algName)
|
||||
{
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
public static new KeyedHashAlgorithm Create(string algName) =>
|
||||
(KeyedHashAlgorithm)CryptoConfigForwarder.CreateFromName(algName);
|
||||
|
||||
public virtual byte[] Key
|
||||
{
|
||||
|
@@ -12,15 +12,11 @@ namespace System.Security.Cryptography
|
||||
PaddingValue = PaddingMode.PKCS7;
|
||||
}
|
||||
|
||||
public static SymmetricAlgorithm Create()
|
||||
{
|
||||
return Create("System.Security.Cryptography.SymmetricAlgorithm");
|
||||
}
|
||||
public static SymmetricAlgorithm Create() =>
|
||||
throw new PlatformNotSupportedException(SR.Cryptography_DefaultAlgorithm_NotSupported);
|
||||
|
||||
public static SymmetricAlgorithm Create(string algName)
|
||||
{
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
public static SymmetricAlgorithm Create(string algName) =>
|
||||
(SymmetricAlgorithm)CryptoConfigForwarder.CreateFromName(algName);
|
||||
|
||||
public virtual int FeedbackSize
|
||||
{
|
||||
|
@@ -9,20 +9,151 @@ namespace System.Security.Cryptography.CryptoConfigTests
|
||||
public static class CryptoConfigTests
|
||||
{
|
||||
[Fact]
|
||||
public static void StaticCreateMethods()
|
||||
[SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
|
||||
public static void DefaultStaticCreateMethods()
|
||||
{
|
||||
// These are not supported because CryptoConfig exists in Algorithms assembly.
|
||||
// CryptoConfig exists in Algorithms partly because it requires the Oid class in Encoding assembly.
|
||||
// .NET Core does not allow the base classes to pick an algorithm.
|
||||
Assert.Throws<PlatformNotSupportedException>(() => AsymmetricAlgorithm.Create());
|
||||
Assert.Throws<PlatformNotSupportedException>(() => AsymmetricAlgorithm.Create(null));
|
||||
Assert.Throws<PlatformNotSupportedException>(() => HashAlgorithm.Create());
|
||||
Assert.Throws<PlatformNotSupportedException>(() => HashAlgorithm.Create(null));
|
||||
Assert.Throws<PlatformNotSupportedException>(() => KeyedHashAlgorithm.Create());
|
||||
Assert.Throws<PlatformNotSupportedException>(() => KeyedHashAlgorithm.Create(null));
|
||||
Assert.Throws<PlatformNotSupportedException>(() => HMAC.Create());
|
||||
Assert.Throws<PlatformNotSupportedException>(() => HMAC.Create(null));
|
||||
Assert.Throws<PlatformNotSupportedException>(() => SymmetricAlgorithm.Create());
|
||||
Assert.Throws<PlatformNotSupportedException>(() => SymmetricAlgorithm.Create(null));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void NamedCreateMethods_NullInput()
|
||||
{
|
||||
AssertExtensions.Throws<ArgumentNullException>("name", () => AsymmetricAlgorithm.Create(null));
|
||||
AssertExtensions.Throws<ArgumentNullException>("name", () => HashAlgorithm.Create(null));
|
||||
AssertExtensions.Throws<ArgumentNullException>("name", () => KeyedHashAlgorithm.Create(null));
|
||||
AssertExtensions.Throws<ArgumentNullException>("name", () => HMAC.Create(null));
|
||||
AssertExtensions.Throws<ArgumentNullException>("name", () => SymmetricAlgorithm.Create(null));
|
||||
}
|
||||
|
||||
// The returned types on .NET Framework can differ when the machine is in FIPS mode.
|
||||
// So check hash algorithms via a more complicated manner.
|
||||
[Theory]
|
||||
[InlineData("MD5", typeof(MD5))]
|
||||
[InlineData("http://www.w3.org/2001/04/xmldsig-more#md5", typeof(MD5))]
|
||||
[InlineData("System.Security.Cryptography.HashAlgorithm", typeof(SHA1))]
|
||||
[InlineData("SHA1", typeof(SHA1))]
|
||||
[InlineData("http://www.w3.org/2000/09/xmldsig#sha1", typeof(SHA1))]
|
||||
[InlineData("SHA256", typeof(SHA256))]
|
||||
[InlineData("SHA-256", typeof(SHA256))]
|
||||
[InlineData("http://www.w3.org/2001/04/xmlenc#sha256", typeof(SHA256))]
|
||||
[InlineData("SHA384", typeof(SHA384))]
|
||||
[InlineData("SHA-384", typeof(SHA384))]
|
||||
[InlineData("http://www.w3.org/2001/04/xmldsig-more#sha384", typeof(SHA384))]
|
||||
[InlineData("SHA512", typeof(SHA512))]
|
||||
[InlineData("SHA-512", typeof(SHA512))]
|
||||
[InlineData("http://www.w3.org/2001/04/xmlenc#sha512", typeof(SHA512))]
|
||||
public static void NamedHashAlgorithmCreate(string identifier, Type baseType)
|
||||
{
|
||||
using (HashAlgorithm created = HashAlgorithm.Create(identifier))
|
||||
{
|
||||
Assert.NotNull(created);
|
||||
Assert.IsAssignableFrom(baseType, created);
|
||||
|
||||
using (HashAlgorithm equivalent =
|
||||
(HashAlgorithm)baseType.GetMethod("Create", Array.Empty<Type>()).Invoke(null, null))
|
||||
{
|
||||
byte[] input = { 1, 2, 3, 4, 5 };
|
||||
byte[] equivHash = equivalent.ComputeHash(input);
|
||||
byte[] createdHash = created.ComputeHash(input);
|
||||
Assert.Equal(equivHash, createdHash);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("System.Security.Cryptography.HMAC", typeof(HMACSHA1))]
|
||||
[InlineData("System.Security.Cryptography.KeyedHashAlgorithm", typeof(HMACSHA1))]
|
||||
[InlineData("System.Security.Cryptography.HMACSHA1", typeof(HMACSHA1))]
|
||||
[InlineData("HMACSHA1", typeof(HMACSHA1))]
|
||||
[InlineData("http://www.w3.org/2000/09/xmldsig#hmac-sha1", typeof(HMACSHA1))]
|
||||
[InlineData("System.Security.Cryptography.HMACSHA256", typeof(HMACSHA256))]
|
||||
[InlineData("HMACSHA256", typeof(HMACSHA256))]
|
||||
[InlineData("http://www.w3.org/2001/04/xmldsig-more#hmac-sha256", typeof(HMACSHA256))]
|
||||
[InlineData("System.Security.Cryptography.HMACSHA384", typeof(HMACSHA384))]
|
||||
[InlineData("HMACSHA384", typeof(HMACSHA384))]
|
||||
[InlineData("http://www.w3.org/2001/04/xmldsig-more#hmac-sha384", typeof(HMACSHA384))]
|
||||
[InlineData("System.Security.Cryptography.HMACSHA512", typeof(HMACSHA512))]
|
||||
[InlineData("HMACSHA512", typeof(HMACSHA512))]
|
||||
[InlineData("http://www.w3.org/2001/04/xmldsig-more#hmac-sha512", typeof(HMACSHA512))]
|
||||
[InlineData("System.Security.Cryptography.HMACMD5", typeof(HMACMD5))]
|
||||
[InlineData("HMACMD5", typeof(HMACMD5))]
|
||||
[InlineData("http://www.w3.org/2001/04/xmldsig-more#hmac-md5", typeof(HMACMD5))]
|
||||
public static void NamedKeyedHashAlgorithmCreate(string identifier, Type actualType)
|
||||
{
|
||||
using (KeyedHashAlgorithm kha = KeyedHashAlgorithm.Create(identifier))
|
||||
{
|
||||
Assert.IsType(actualType, kha);
|
||||
|
||||
// .NET Core only has HMAC keyed hash algorithms, so combine the two tests
|
||||
using (HMAC hmac = HMAC.Create(identifier))
|
||||
{
|
||||
Assert.IsType(actualType, hmac);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("AES", typeof(Aes))]
|
||||
[InlineData("Rijndael", typeof(Rijndael))]
|
||||
[InlineData("System.Security.Cryptography.Rijndael", typeof(Rijndael))]
|
||||
[InlineData("http://www.w3.org/2001/04/xmlenc#aes128-cbc", typeof(Rijndael))]
|
||||
[InlineData("http://www.w3.org/2001/04/xmlenc#aes192-cbc", typeof(Rijndael))]
|
||||
[InlineData("http://www.w3.org/2001/04/xmlenc#aes256-cbc", typeof(Rijndael))]
|
||||
[InlineData("3DES", typeof(TripleDES))]
|
||||
[InlineData("TripleDES", typeof(TripleDES))]
|
||||
[InlineData("System.Security.Cryptography.TripleDES", typeof(TripleDES))]
|
||||
[InlineData("http://www.w3.org/2001/04/xmlenc#tripledes-cbc", typeof(TripleDES))]
|
||||
[InlineData("DES", typeof(DES))]
|
||||
[InlineData("System.Security.Cryptography.DES", typeof(DES))]
|
||||
[InlineData("http://www.w3.org/2001/04/xmlenc#des-cbc", typeof(DES))]
|
||||
public static void NamedSymmetricAlgorithmCreate(string identifier, Type baseType)
|
||||
{
|
||||
using (SymmetricAlgorithm created = SymmetricAlgorithm.Create(identifier))
|
||||
{
|
||||
Assert.NotNull(created);
|
||||
Assert.IsAssignableFrom(baseType, created);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("RSA", typeof(RSA))]
|
||||
[InlineData("System.Security.Cryptography.RSA", typeof(RSA))]
|
||||
[InlineData("ECDsa", typeof(ECDsa))]
|
||||
[InlineData("DSA", typeof(DSA))]
|
||||
[InlineData("System.Security.Cryptography.DSA", typeof(DSA))]
|
||||
public static void NamedAsymmetricAlgorithmCreate(string identifier, Type baseType)
|
||||
{
|
||||
using (AsymmetricAlgorithm created = AsymmetricAlgorithm.Create(identifier))
|
||||
{
|
||||
Assert.NotNull(created);
|
||||
Assert.IsAssignableFrom(baseType, created);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void NamedCreate_Mismatch()
|
||||
{
|
||||
Assert.Throws<InvalidCastException>(() => AsymmetricAlgorithm.Create("SHA1"));
|
||||
Assert.Throws<InvalidCastException>(() => KeyedHashAlgorithm.Create("SHA1"));
|
||||
Assert.Throws<InvalidCastException>(() => HMAC.Create("SHA1"));
|
||||
Assert.Throws<InvalidCastException>(() => SymmetricAlgorithm.Create("SHA1"));
|
||||
Assert.Throws<InvalidCastException>(() => HashAlgorithm.Create("RSA"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void NamedCreate_Unknown()
|
||||
{
|
||||
const string UnknownAlgorithmName = "XYZZY";
|
||||
Assert.Null(AsymmetricAlgorithm.Create(UnknownAlgorithmName));
|
||||
Assert.Null(HashAlgorithm.Create(UnknownAlgorithmName));
|
||||
Assert.Null(KeyedHashAlgorithm.Create(UnknownAlgorithmName));
|
||||
Assert.Null(HMAC.Create(UnknownAlgorithmName));
|
||||
Assert.Null(SymmetricAlgorithm.Create(UnknownAlgorithmName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
109
external/corefx/src/System.Security.Cryptography.Primitives/tests/FixedTimeEqualsTests.cs
vendored
Normal file
109
external/corefx/src/System.Security.Cryptography.Primitives/tests/FixedTimeEqualsTests.cs
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Buffers;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Xunit;
|
||||
|
||||
namespace System.Security.Cryptography.Primitives.Tests
|
||||
{
|
||||
public static class FixedTimeEqualsTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(0)]
|
||||
[InlineData(1)]
|
||||
[InlineData(128 / 8)]
|
||||
[InlineData(256 / 8)]
|
||||
[InlineData(512 / 8)]
|
||||
[InlineData(96)]
|
||||
[InlineData(1024)]
|
||||
public static void EqualReturnsTrue(int byteLength)
|
||||
{
|
||||
byte[] rented = ArrayPool<byte>.Shared.Rent(byteLength);
|
||||
Span<byte> testSpan = new Span<byte>(rented, 0, byteLength);
|
||||
RandomNumberGenerator.Fill(testSpan);
|
||||
|
||||
byte[] rented2 = ArrayPool<byte>.Shared.Rent(byteLength);
|
||||
Span<byte> testSpan2 = new Span<byte>(rented2, 0, byteLength);
|
||||
|
||||
testSpan.CopyTo(testSpan2);
|
||||
|
||||
bool isEqual = CryptographicOperations.FixedTimeEquals(testSpan, testSpan2);
|
||||
|
||||
ArrayPool<byte>.Shared.Return(rented);
|
||||
ArrayPool<byte>.Shared.Return(rented2);
|
||||
|
||||
Assert.True(isEqual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(1)]
|
||||
[InlineData(128 / 8)]
|
||||
[InlineData(256 / 8)]
|
||||
[InlineData(512 / 8)]
|
||||
[InlineData(96)]
|
||||
[InlineData(1024)]
|
||||
public static void UnequalReturnsFalse(int byteLength)
|
||||
{
|
||||
byte[] rented = ArrayPool<byte>.Shared.Rent(byteLength);
|
||||
Span<byte> testSpan = new Span<byte>(rented, 0, byteLength);
|
||||
RandomNumberGenerator.Fill(testSpan);
|
||||
|
||||
byte[] rented2 = ArrayPool<byte>.Shared.Rent(byteLength);
|
||||
Span<byte> testSpan2 = new Span<byte>(rented2, 0, byteLength);
|
||||
|
||||
testSpan.CopyTo(testSpan2);
|
||||
testSpan[testSpan[0] % testSpan.Length] ^= 0xFF;
|
||||
|
||||
bool isEqual = CryptographicOperations.FixedTimeEquals(testSpan, testSpan2);
|
||||
|
||||
ArrayPool<byte>.Shared.Return(rented);
|
||||
ArrayPool<byte>.Shared.Return(rented2);
|
||||
|
||||
Assert.False(isEqual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(1)]
|
||||
[InlineData(128 / 8)]
|
||||
[InlineData(256 / 8)]
|
||||
[InlineData(512 / 8)]
|
||||
[InlineData(96)]
|
||||
[InlineData(1024)]
|
||||
public static void DifferentLengthsReturnFalse(int byteLength)
|
||||
{
|
||||
byte[] rented = ArrayPool<byte>.Shared.Rent(byteLength);
|
||||
Span<byte> testSpan = new Span<byte>(rented, 0, byteLength);
|
||||
RandomNumberGenerator.Fill(testSpan);
|
||||
|
||||
byte[] rented2 = ArrayPool<byte>.Shared.Rent(byteLength);
|
||||
Span<byte> testSpan2 = new Span<byte>(rented2, 0, byteLength);
|
||||
|
||||
testSpan.CopyTo(testSpan2);
|
||||
|
||||
bool isEqualA = CryptographicOperations.FixedTimeEquals(testSpan, testSpan2.Slice(0, byteLength - 1));
|
||||
bool isEqualB = CryptographicOperations.FixedTimeEquals(testSpan.Slice(0, byteLength - 1), testSpan2);
|
||||
|
||||
ArrayPool<byte>.Shared.Return(rented);
|
||||
ArrayPool<byte>.Shared.Return(rented2);
|
||||
|
||||
Assert.False(isEqualA, "value, value missing last byte");
|
||||
Assert.False(isEqualB, "value missing last byte, value");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void HasCorrectMethodImpl()
|
||||
{
|
||||
Type t = typeof(CryptographicOperations);
|
||||
MethodInfo mi = t.GetMethod(nameof(CryptographicOperations.FixedTimeEquals));
|
||||
|
||||
// This method cannot be optimized, or it loses its fixed time guarantees.
|
||||
// It cannot be inlined, or it loses its no-optimization guarantee.
|
||||
Assert.Equal(
|
||||
MethodImplAttributes.NoInlining | MethodImplAttributes.NoOptimization,
|
||||
mi.MethodImplementationFlags);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<BuildConfigurations>
|
||||
netcoreapp;
|
||||
</BuildConfigurations>
|
||||
</PropertyGroup>
|
||||
</Project>
|
@@ -0,0 +1,115 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Microsoft.Xunit.Performance;
|
||||
using Test.Cryptography;
|
||||
using Xunit;
|
||||
|
||||
namespace System.Security.Cryptography.Primitives.Tests.Performance
|
||||
{
|
||||
public class Perf_FixedTimeEquals
|
||||
{
|
||||
private const int IterationCountFor256Bit = 300000;
|
||||
|
||||
[Benchmark(InnerIterationCount = IterationCountFor256Bit)]
|
||||
public static void FixedTimeEquals_256Bit_Equal()
|
||||
{
|
||||
MeasureFixedTimeEquals(
|
||||
"741202531e19d673ad7fff334594549e7c81a285dd02865ddd12530612a96336",
|
||||
"0000000000000000000000000000000000000000000000000000000000000000");
|
||||
}
|
||||
|
||||
[Benchmark(InnerIterationCount = IterationCountFor256Bit)]
|
||||
public static void FixedTimeEquals_256Bit_LastBitDifferent()
|
||||
{
|
||||
MeasureFixedTimeEquals(
|
||||
"741202531e19d673ad7fff334594549e7c81a285dd02865ddd12530612a96336",
|
||||
"0000000000000000000000000000000000000000000000000000000000000001");
|
||||
}
|
||||
|
||||
[Benchmark(InnerIterationCount = IterationCountFor256Bit)]
|
||||
public static void FixedTimeEquals_256Bit_FirstBitDifferent()
|
||||
{
|
||||
MeasureFixedTimeEquals(
|
||||
"741202531e19d673ad7fff334594549e7c81a285dd02865ddd12530612a96336",
|
||||
"8000000000000000000000000000000000000000000000000000000000000000");
|
||||
}
|
||||
|
||||
[Benchmark(InnerIterationCount = IterationCountFor256Bit)]
|
||||
public static void FixedTimeEquals_256Bit_CascadingErrors()
|
||||
{
|
||||
MeasureFixedTimeEquals(
|
||||
"741202531e19d673ad7fff334594549e7c81a285dd02865ddd12530612a96336",
|
||||
"0102040810204080112244880000000000000000000000000000000000000000");
|
||||
}
|
||||
|
||||
[Benchmark(InnerIterationCount = IterationCountFor256Bit)]
|
||||
public static void FixedTimeEquals_256Bit_AllBitsDifferent()
|
||||
{
|
||||
MeasureFixedTimeEquals(
|
||||
"741202531e19d673ad7fff334594549e7c81a285dd02865ddd12530612a96336",
|
||||
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
|
||||
}
|
||||
|
||||
[Benchmark(InnerIterationCount = IterationCountFor256Bit)]
|
||||
public static void FixedTimeEquals_256Bit_VersusZero()
|
||||
{
|
||||
MeasureFixedTimeEquals(
|
||||
"741202531e19d673ad7fff334594549e7c81a285dd02865ddd12530612a96336",
|
||||
"741202531e19d673ad7fff334594549e7c81a285dd02865ddd12530612a96336");
|
||||
}
|
||||
|
||||
[Benchmark(InnerIterationCount = IterationCountFor256Bit)]
|
||||
public static void FixedTimeEquals_256Bit_SameReference()
|
||||
{
|
||||
byte[] test = "741202531e19d673ad7fff334594549e7c81a285dd02865ddd12530612a96336".HexToByteArray();
|
||||
|
||||
Span<byte> left = test;
|
||||
Span<byte> right = test;
|
||||
|
||||
foreach (BenchmarkIteration iteration in Benchmark.Iterations)
|
||||
{
|
||||
using (iteration.StartMeasurement())
|
||||
{
|
||||
for (int i = 0; i < Benchmark.InnerIterationCount; i++)
|
||||
{
|
||||
CryptographicOperations.FixedTimeEquals(left, right);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The important statistics from these perf runs aren't the mean, but the t-test for
|
||||
// every set of the same length being the same as when it was equal.
|
||||
private static void MeasureFixedTimeEquals(string baseValueHex, string errorVectorHex)
|
||||
{
|
||||
if (errorVectorHex.Length != baseValueHex.Length)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
byte[] a = baseValueHex.HexToByteArray();
|
||||
byte[] b = errorVectorHex.HexToByteArray();
|
||||
|
||||
for (int i = 0; i < a.Length; i++)
|
||||
{
|
||||
b[i] ^= a[i];
|
||||
}
|
||||
|
||||
Span<byte> left = a;
|
||||
Span<byte> right = b;
|
||||
|
||||
foreach (BenchmarkIteration iteration in Benchmark.Iterations)
|
||||
{
|
||||
using (iteration.StartMeasurement())
|
||||
{
|
||||
for (int i = 0; i < Benchmark.InnerIterationCount; i++)
|
||||
{
|
||||
CryptographicOperations.FixedTimeEquals(left, right);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
|
||||
<Import Project="$(CommonTestPath)\Tests.props" />
|
||||
<PropertyGroup>
|
||||
<IncludePerformanceTests>true</IncludePerformanceTests>
|
||||
<ProjectGuid>{FB3EA273-567D-414F-B36D-3698BE8D198B}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Debug|AnyCPU'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />
|
||||
<ItemGroup>
|
||||
<Compile Include="$(CommonTestPath)\System\PerfUtils.cs">
|
||||
<Link>Common\System\PerfUtils.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonTestPath)\System\Security\Cryptography\ByteUtils.cs">
|
||||
<Link>CommonTest\System\Security\Cryptography\ByteUtils.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="Perf.FixedTimeEquals.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="$(CommonPath)\..\perf\PerfRunner\PerfRunner.csproj">
|
||||
<Project>{69e46a6f-9966-45a5-8945-2559fe337827}</Project>
|
||||
<Name>PerfRunner</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
|
||||
</ItemGroup>
|
||||
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
|
||||
</Project>
|
@@ -11,8 +11,13 @@
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
|
||||
<ItemGroup>
|
||||
<Compile Include="$(CommonTestPath)\System\IO\PositionValueStream.cs">
|
||||
<Link>CommonTest\System\IO\PositionValueStream.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="AsymmetricAlgorithm\Trivial.cs" />
|
||||
<Compile Include="CryptoConfigTests.cs" />
|
||||
<Compile Include="CryptoStream.cs" />
|
||||
<Compile Include="CryptographicException.cs" />
|
||||
<Compile Include="HmacAlgorithmTest.cs" />
|
||||
<Compile Include="KeyedHashAlgorithmTests.cs" />
|
||||
<Compile Include="Length32Hash.cs" />
|
||||
@@ -20,14 +25,11 @@
|
||||
<Compile Include="Sum32Hash.cs" />
|
||||
<Compile Include="SymmetricAlgorithm\Minimal.cs" />
|
||||
<Compile Include="SymmetricAlgorithm\Trivial.cs" />
|
||||
<Compile Include="CryptographicException.cs" />
|
||||
<Compile Include="$(CommonTestPath)\System\IO\PositionValueStream.cs">
|
||||
<Link>CommonTest\System\IO\PositionValueStream.cs</Link>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(TargetGroup)'=='netcoreapp'">
|
||||
<Compile Include="CryptoConfigTests.cs" />
|
||||
<Compile Include="FixedTimeEqualsTests.cs" />
|
||||
<Compile Include="HashAlgorithmTest.netcoreapp.cs" />
|
||||
<Compile Include="ZeroMemoryTests.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
|
||||
</Project>
|
||||
</Project>
|
||||
|
77
external/corefx/src/System.Security.Cryptography.Primitives/tests/ZeroMemoryTests.cs
vendored
Normal file
77
external/corefx/src/System.Security.Cryptography.Primitives/tests/ZeroMemoryTests.cs
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Buffers;
|
||||
using System.Reflection;
|
||||
using Xunit;
|
||||
|
||||
namespace System.Security.Cryptography.Primitives.Tests
|
||||
{
|
||||
public static class ZeroMemoryTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(1)]
|
||||
[InlineData(128 / 8)]
|
||||
[InlineData(256 / 8)]
|
||||
[InlineData(512 / 8)]
|
||||
[InlineData(96)]
|
||||
[InlineData(1024)]
|
||||
public static void MemoryGetsCleared(int byteLength)
|
||||
{
|
||||
byte[] rented = ArrayPool<byte>.Shared.Rent(byteLength);
|
||||
Span<byte> testSpan = new Span<byte>(rented, 0, byteLength);
|
||||
|
||||
bool hasData = false;
|
||||
|
||||
// i should really only iterate when byteLength is 1, and then
|
||||
// only 1/256 executions.
|
||||
//
|
||||
// The chances of this failing are 1 in 1.2e24, unless the RNG is broken.
|
||||
for (int i = 0; i < 10 && !hasData; i++)
|
||||
{
|
||||
RandomNumberGenerator.Fill(testSpan);
|
||||
|
||||
for (int j = 0; j < testSpan.Length; j++)
|
||||
{
|
||||
if (testSpan[j] != 0)
|
||||
{
|
||||
hasData = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasData)
|
||||
{
|
||||
throw new InvalidOperationException("RNG provided all zero-values");
|
||||
}
|
||||
|
||||
// This test cannot guarantee the effect of the memory being cleared
|
||||
// on an otherwise abandoned reference; since the act of measuring it
|
||||
// changes what the optimizer could have done.
|
||||
//
|
||||
// But it can check for it calling clear.
|
||||
CryptographicOperations.ZeroMemory(testSpan);
|
||||
|
||||
for (int i = 0; i < testSpan.Length; i++)
|
||||
{
|
||||
Assert.Equal(0, testSpan[i]);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void HasCorrectMethodImpl()
|
||||
{
|
||||
Type t = typeof(CryptographicOperations);
|
||||
MethodInfo mi = t.GetMethod(nameof(CryptographicOperations.ZeroMemory));
|
||||
|
||||
// This method cannot be optimized, or the optimizer can decide that a call to Clear
|
||||
// is unnecessary.
|
||||
// It cannot be inlined, or it loses its no-optimization guarantee.
|
||||
Assert.Equal(
|
||||
MethodImplAttributes.NoInlining | MethodImplAttributes.NoOptimization,
|
||||
mi.MethodImplementationFlags);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user