Skip to content

Commit

Permalink
Use Span overloads with Rfc2898DeriveBytes computations (dotnet/coref…
Browse files Browse the repository at this point in the history
…x#23269)

Change from ComputeHash(byte[])=>byte[] to TryComputeHash(src, dest) to
reduce the number of allocations involved.

For iteration counts of 1000, 10000, and 100000 it shows a 15% reduction in time,
and almost entire elimination of GC (most of that 15%).

Commit migrated from dotnet/corefx@b9010ec
  • Loading branch information
bartonjs authored and stephentoub committed Aug 15, 2017
1 parent a914d73 commit fa95637
Showing 1 changed file with 28 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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.Text;
using System.Diagnostics;

Expand Down Expand Up @@ -249,30 +250,45 @@ private void Initialize()
}

// This function is defined as follows:
// Func (S, i) = HMAC(S || i) | HMAC2(S || i) | ... | HMAC(iterations) (S || i)
// Func (S, i) = HMAC(S || i) ^ HMAC2(S || i) ^ ... ^ HMAC(iterations) (S || i)
// where i is the block number.
private byte[] Func()
{
byte[] temp = new byte[_salt.Length + sizeof(uint)];
Buffer.BlockCopy(_salt, 0, temp, 0, _salt.Length);
Helpers.WriteInt(_block, temp, _salt.Length);

temp = _hmac.ComputeHash(temp);

byte[] ret = temp;
for (int i = 2; i <= _iterations; i++)
byte[] ui = ArrayPool<byte>.Shared.Rent(_blockSize);
try
{
temp = _hmac.ComputeHash(temp);
Span<byte> uiSpan = new Span<byte>(ui, 0, _blockSize);

for (int j = 0; j < _blockSize; j++)
if (!_hmac.TryComputeHash(temp, uiSpan, out int bytesWritten) || bytesWritten != _blockSize)
throw new CryptographicException();

byte[] ret = new byte[_blockSize];
uiSpan.CopyTo(ret);

for (int i = 2; i <= _iterations; i++)
{
ret[j] ^= temp[j];
if (!_hmac.TryComputeHash(uiSpan, uiSpan, out bytesWritten) || bytesWritten != _blockSize)
throw new CryptographicException();

for (int j = 0; j < _blockSize; j++)
{
ret[j] ^= ui[j];
}
}
}

// increment the block count.
_block++;
return ret;
// increment the block count.
_block++;
return ret;
}
finally
{
Array.Clear(ui, 0, _blockSize);
ArrayPool<byte>.Shared.Return(ui);
}
}
}
}

0 comments on commit fa95637

Please sign in to comment.