destination[ps.Length + 2] = 0;
// 2(a). Fill PS with random data from a CSPRNG, but no zero-values.
- FillNonZeroBytes(ps);
+ RandomNumberGeneratorImplementation.FillNonZeroBytes(ps);
source.CopyTo(mInEM);
}
}
}
- // This is a copy of RandomNumberGeneratorImplementation.GetNonZeroBytes, but adapted
- // to the object-less RandomNumberGenerator.Fill.
- private static void FillNonZeroBytes(Span<byte> data)
- {
- while (data.Length > 0)
- {
- // Fill the remaining portion of the span with random bytes.
- RandomNumberGenerator.Fill(data);
-
- // Find the first zero in the remaining portion.
- int indexOfFirst0Byte = data.IndexOf((byte)0);
- if (indexOfFirst0Byte < 0)
- {
- break;
- }
-
- // If there were any zeros, shift down all non-zeros.
- for (int i = indexOfFirst0Byte + 1; i < data.Length; i++)
- {
- if (data[i] != 0)
- {
- data[indexOfFirst0Byte++] = data[i];
- }
- }
-
- // Request new random bytes if necessary; dont re-use
- // existing bytes since they were shifted down.
- data = data.Slice(indexOfFirst0Byte);
- }
- }
-
/// <summary>
/// Bitwise XOR of <paramref name="b"/> into <paramref name="a"/>.
/// </summary>
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using System.Runtime.InteropServices;
-
namespace System.Security.Cryptography
{
internal sealed partial class RandomNumberGeneratorImplementation : RandomNumberGenerator
{
ArgumentNullException.ThrowIfNull(data);
- GetNonZeroBytes(new Span<byte>(data));
+ FillNonZeroBytes(data);
}
public override void GetNonZeroBytes(Span<byte> data)
+ {
+ FillNonZeroBytes(data);
+ }
+
+ internal static void FillNonZeroBytes(Span<byte> data)
{
while (data.Length > 0)
{
// Fill the remaining portion of the span with random bytes.
- GetBytes(data);
+ FillSpan(data);
- // Find the first zero in the remaining portion.
- int indexOfFirst0Byte = data.IndexOf((byte)0);
- if (indexOfFirst0Byte < 0)
+ // Find the first zero in the remaining portion. If there isn't any, we're all done.
+ int first0Byte = data.IndexOf((byte)0);
+ if (first0Byte < 0)
{
return;
}
- // If there were any zeros, shift down all non-zeros.
- for (int i = indexOfFirst0Byte + 1; i < data.Length; i++)
+ // There's at least one zero. Shift down all non-zeros.
+ int zerosFound = 1;
+ Span<byte> remainder = data.Slice(first0Byte + 1);
+ while (true)
{
- if (data[i] != 0)
+ // Find the next zero.
+ int next0Byte = remainder.IndexOf((byte)0);
+ if (next0Byte < 0)
{
- data[indexOfFirst0Byte++] = data[i];
+ // There weren't any more zeros. Copy the remaining valid data down.
+ remainder.CopyTo(data.Slice(first0Byte));
+ break;
}
+
+ // Copy down until the next zero, then reset to continue copying from there.
+ remainder.Slice(0, next0Byte).CopyTo(data.Slice(first0Byte));
+ zerosFound++;
+ first0Byte += next0Byte;
+ remainder = remainder.Slice(next0Byte + 1);
}
- // Request new random bytes if necessary; dont re-use
- // existing bytes since they were shifted down.
- data = data.Slice(indexOfFirst0Byte);
+ // Slice to any remaining space that needs to be filled. This is equal to the
+ // number of zeros found.
+ data = data.Slice(data.Length - zerosFound);
}
}
}