diff --git a/crypto/src/crypto/prng/CryptoApiRandomGenerator.cs b/crypto/src/crypto/prng/CryptoApiRandomGenerator.cs
index 7803ddd3d..11d29a818 100644
--- a/crypto/src/crypto/prng/CryptoApiRandomGenerator.cs
+++ b/crypto/src/crypto/prng/CryptoApiRandomGenerator.cs
@@ -45,6 +45,9 @@ namespace Org.BouncyCastle.Crypto.Prng
if (bytes.Length < (start + len))
throw new ArgumentException("Byte array too small for requested offset and length");
+#if NETCOREAPP2_0_OR_GREATER || NETSTANDARD2_0_OR_GREATER
+ rndProv.GetBytes(bytes, start, len);
+#else
if (bytes.Length == len && start == 0)
{
NextBytes(bytes);
@@ -55,8 +58,16 @@ namespace Org.BouncyCastle.Crypto.Prng
NextBytes(tmpBuf);
Array.Copy(tmpBuf, 0, bytes, start, len);
}
+#endif
}
- #endregion
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual void NextBytes(Span<byte> bytes)
+ {
+ rndProv.GetBytes(bytes);
+ }
+#endif
+
+#endregion
}
}
diff --git a/crypto/src/crypto/prng/DigestRandomGenerator.cs b/crypto/src/crypto/prng/DigestRandomGenerator.cs
index 024db2852..3587956b6 100644
--- a/crypto/src/crypto/prng/DigestRandomGenerator.cs
+++ b/crypto/src/crypto/prng/DigestRandomGenerator.cs
@@ -90,6 +90,28 @@ namespace Org.BouncyCastle.Crypto.Prng
}
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual void NextBytes(Span<byte> bytes)
+ {
+ lock (this)
+ {
+ int stateOff = 0;
+
+ GenerateState();
+
+ for (int i = 0; i < bytes.Length; ++i)
+ {
+ if (stateOff == state.Length)
+ {
+ GenerateState();
+ stateOff = 0;
+ }
+ bytes[i] = state[stateOff++];
+ }
+ }
+ }
+#endif
+
private void CycleSeed()
{
DigestUpdate(seed);
diff --git a/crypto/src/crypto/prng/IRandomGenerator.cs b/crypto/src/crypto/prng/IRandomGenerator.cs
index 8dbe4068f..051f8f8c6 100644
--- a/crypto/src/crypto/prng/IRandomGenerator.cs
+++ b/crypto/src/crypto/prng/IRandomGenerator.cs
@@ -22,5 +22,9 @@ namespace Org.BouncyCastle.Crypto.Prng
/// <param name="start">Index to start filling at.</param>
/// <param name="len">Length of segment to fill.</param>
void NextBytes(byte[] bytes, int start, int len);
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ void NextBytes(Span<byte> bytes);
+#endif
}
}
diff --git a/crypto/src/crypto/prng/SP800SecureRandom.cs b/crypto/src/crypto/prng/SP800SecureRandom.cs
index 2e1484125..fb5c3a677 100644
--- a/crypto/src/crypto/prng/SP800SecureRandom.cs
+++ b/crypto/src/crypto/prng/SP800SecureRandom.cs
@@ -70,6 +70,13 @@ namespace Org.BouncyCastle.Crypto.Prng
}
}
+ // TODO Add efficient override (needs ISP80090Drbg support for spans)
+//#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+// public override void NextBytes(Span<byte> buffer)
+// {
+// }
+//#endif
+
public override byte[] GenerateSeed(int numBytes)
{
return EntropyUtilities.GenerateSeed(mEntropySource, numBytes);
diff --git a/crypto/src/crypto/prng/VMPCRandomGenerator.cs b/crypto/src/crypto/prng/VMPCRandomGenerator.cs
index 64f287d13..72e6b5e7d 100644
--- a/crypto/src/crypto/prng/VMPCRandomGenerator.cs
+++ b/crypto/src/crypto/prng/VMPCRandomGenerator.cs
@@ -110,5 +110,23 @@ namespace Org.BouncyCastle.Crypto.Prng
}
}
}
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual void NextBytes(Span<byte> bytes)
+ {
+ lock (P)
+ {
+ for (int i = 0; i != bytes.Length; i++)
+ {
+ s = P[(s + P[n & 0xff]) & 0xff];
+ bytes[i] = P[(P[(P[s & 0xff]) & 0xff] + 1) & 0xff];
+ byte temp = P[n & 0xff];
+ P[n & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ n = (byte) ((n + 1) & 0xff);
+ }
+ }
+ }
+#endif
}
}
diff --git a/crypto/src/crypto/prng/X931Rng.cs b/crypto/src/crypto/prng/X931Rng.cs
index 53c982c25..f0bfdc9f1 100644
--- a/crypto/src/crypto/prng/X931Rng.cs
+++ b/crypto/src/crypto/prng/X931Rng.cs
@@ -103,6 +103,67 @@ namespace Org.BouncyCastle.Crypto.Prng
return outputLen * 8;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ internal int Generate(Span<byte> output, bool predictionResistant)
+ {
+ int outputLen = output.Length;
+
+ if (mR.Length == 8) // 64 bit block size
+ {
+ if (mReseedCounter > BLOCK64_RESEED_MAX)
+ return -1;
+
+ if (outputLen > BLOCK64_MAX_BITS_REQUEST / 8)
+ throw new ArgumentException("Number of bits per request limited to " + BLOCK64_MAX_BITS_REQUEST, "output");
+ }
+ else
+ {
+ if (mReseedCounter > BLOCK128_RESEED_MAX)
+ return -1;
+
+ if (outputLen > BLOCK128_MAX_BITS_REQUEST / 8)
+ throw new ArgumentException("Number of bits per request limited to " + BLOCK128_MAX_BITS_REQUEST, "output");
+ }
+
+ if (predictionResistant || mV == null)
+ {
+ mV = mEntropySource.GetEntropy();
+ if (mV.Length != mEngine.GetBlockSize())
+ throw new InvalidOperationException("Insufficient entropy returned");
+ }
+
+ int m = outputLen / mR.Length;
+
+ for (int i = 0; i < m; i++)
+ {
+ mEngine.ProcessBlock(mDT, 0, mI, 0);
+ Process(mR, mI, mV);
+ Process(mV, mR, mI);
+
+ mR.CopyTo(output[(i * mR.Length)..]);
+
+ Increment(mDT);
+ }
+
+ int bytesToCopy = (outputLen - m * mR.Length);
+
+ if (bytesToCopy > 0)
+ {
+ mEngine.ProcessBlock(mDT, 0, mI, 0);
+ Process(mR, mI, mV);
+ Process(mV, mR, mI);
+
+ mR.AsSpan(0, bytesToCopy).CopyTo(output[(m * mR.Length)..]);
+
+ Increment(mDT);
+ }
+
+ mReseedCounter++;
+
+ return outputLen * 8;
+ }
+#endif
+
/**
* Reseed the RNG.
*/
diff --git a/crypto/src/crypto/prng/X931SecureRandom.cs b/crypto/src/crypto/prng/X931SecureRandom.cs
index 1402e5c31..01678af8f 100644
--- a/crypto/src/crypto/prng/X931SecureRandom.cs
+++ b/crypto/src/crypto/prng/X931SecureRandom.cs
@@ -60,6 +60,21 @@ namespace Org.BouncyCastle.Crypto.Prng
}
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public override void NextBytes(Span<byte> buffer)
+ {
+ lock (this)
+ {
+ // check if a reseed is required...
+ if (mDrbg.Generate(buffer, mPredictionResistant) < 0)
+ {
+ mDrbg.Reseed();
+ mDrbg.Generate(buffer, mPredictionResistant);
+ }
+ }
+ }
+#endif
+
public override byte[] GenerateSeed(int numBytes)
{
return EntropyUtilities.GenerateSeed(mDrbg.EntropySource, numBytes);
|