From cf1ad240147c298b6adabad399a8bf0f5756f606 Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Fri, 19 Aug 2022 15:13:06 +0700 Subject: Implement NextBytes(Span 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 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 /// Index to start filling at. /// Length of segment to fill. void NextBytes(byte[] bytes, int start, int len); + +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + void NextBytes(Span 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 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 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 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 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); diff --git a/crypto/src/security/SecureRandom.cs b/crypto/src/security/SecureRandom.cs index e8cac56f5..4e118e77a 100644 --- a/crypto/src/security/SecureRandom.cs +++ b/crypto/src/security/SecureRandom.cs @@ -181,6 +181,22 @@ namespace Org.BouncyCastle.Security generator.NextBytes(buf, off, len); } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public override void NextBytes(Span buffer) + { + if (generator != null) + { + generator.NextBytes(buffer); + } + else + { + byte[] tmp = new byte[buffer.Length]; + NextBytes(tmp); + tmp.CopyTo(buffer); + } + } +#endif + private static readonly double DoubleScale = 1.0 / Convert.ToDouble(1L << 53); public override double NextDouble() -- cgit 1.4.1