From f90c767b37f03160c9ff001bcf14922ccf02a6f3 Mon Sep 17 00:00:00 2001 From: Levi Broderick Date: Fri, 7 May 2021 17:41:01 -0700 Subject: [PATCH 1/2] Make RandomNumberGenerator.Create return a singleton --- ...omNumberGeneratorImplementation.Windows.cs | 9 +++++++ .../Cryptography/RandomNumberGenerator.cs | 5 +--- .../tests/RandomNumberGeneratorTests.cs | 24 +++++++++++++++++++ 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/libraries/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/RandomNumberGeneratorImplementation.Windows.cs b/src/libraries/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/RandomNumberGeneratorImplementation.Windows.cs index 876111a4ef45a8..67d6dfc18e7568 100644 --- a/src/libraries/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/RandomNumberGeneratorImplementation.Windows.cs +++ b/src/libraries/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/RandomNumberGeneratorImplementation.Windows.cs @@ -7,6 +7,15 @@ namespace System.Security.Cryptography { internal sealed partial class RandomNumberGeneratorImplementation { + // a singleton which always calls into a thread-safe implementation + // and whose Dispose method no-ops + internal static readonly RandomNumberGeneratorImplementation s_singleton = new RandomNumberGeneratorImplementation(); + + // private ctor used only by singleton + private RandomNumberGeneratorImplementation() + { + } + private static unsafe void GetBytes(byte* pbBuffer, int count) { Debug.Assert(count > 0); diff --git a/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/RandomNumberGenerator.cs b/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/RandomNumberGenerator.cs index a5c708092aac4d..baad2d1e5c6a20 100644 --- a/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/RandomNumberGenerator.cs +++ b/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/RandomNumberGenerator.cs @@ -12,10 +12,7 @@ public abstract class RandomNumberGenerator : IDisposable { protected RandomNumberGenerator() { } - public static RandomNumberGenerator Create() - { - return new RandomNumberGeneratorImplementation(); - } + public static RandomNumberGenerator Create() => RandomNumberGeneratorImplementation.s_singleton; [UnsupportedOSPlatform("browser")] [RequiresUnreferencedCode(CryptoConfig.CreateFromNameUnreferencedCodeMessage)] diff --git a/src/libraries/System.Security.Cryptography.Algorithms/tests/RandomNumberGeneratorTests.cs b/src/libraries/System.Security.Cryptography.Algorithms/tests/RandomNumberGeneratorTests.cs index 4c9d81f44773c3..d0f2ad8e3e9ff5 100644 --- a/src/libraries/System.Security.Cryptography.Algorithms/tests/RandomNumberGeneratorTests.cs +++ b/src/libraries/System.Security.Cryptography.Algorithms/tests/RandomNumberGeneratorTests.cs @@ -12,6 +12,30 @@ namespace System.Security.Cryptography.RNG.Tests { public class RandomNumberGeneratorTests { + [Fact] + public static void Create_ReturnsSingleton() + { + RandomNumberGenerator rng1 = RandomNumberGenerator.Create(); + RandomNumberGenerator rng2 = RandomNumberGenerator.Create(); + + Assert.Same(rng1, rng2); + } + + [Fact] + public static void Singleton_NoopsDispose() + { + byte[] random = new byte[1024]; + RandomNumberGenerator rng = RandomNumberGenerator.Create(); + rng.GetBytes(random); + RandomDataGenerator.VerifyRandomDistribution(random); + rng.Dispose(); // should no-op if called once + + random = new byte[1024]; + rng.GetBytes(random); // should still work even after earlier Dispose call + RandomDataGenerator.VerifyRandomDistribution(random); + rng.Dispose(); // should no-op if called twice + } + [Theory] [InlineData(2048)] [InlineData(65536)] From 22000a8c51660038128b4f1c97333cdf7f0a7438 Mon Sep 17 00:00:00 2001 From: Levi Broderick Date: Mon, 10 May 2021 17:10:05 -0700 Subject: [PATCH 2/2] Move PRNG singleton to correct file --- .../RandomNumberGeneratorImplementation.Windows.cs | 9 --------- .../Cryptography/RandomNumberGeneratorImplementation.cs | 9 +++++++++ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/libraries/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/RandomNumberGeneratorImplementation.Windows.cs b/src/libraries/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/RandomNumberGeneratorImplementation.Windows.cs index 67d6dfc18e7568..876111a4ef45a8 100644 --- a/src/libraries/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/RandomNumberGeneratorImplementation.Windows.cs +++ b/src/libraries/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/RandomNumberGeneratorImplementation.Windows.cs @@ -7,15 +7,6 @@ namespace System.Security.Cryptography { internal sealed partial class RandomNumberGeneratorImplementation { - // a singleton which always calls into a thread-safe implementation - // and whose Dispose method no-ops - internal static readonly RandomNumberGeneratorImplementation s_singleton = new RandomNumberGeneratorImplementation(); - - // private ctor used only by singleton - private RandomNumberGeneratorImplementation() - { - } - private static unsafe void GetBytes(byte* pbBuffer, int count) { Debug.Assert(count > 0); diff --git a/src/libraries/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/RandomNumberGeneratorImplementation.cs b/src/libraries/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/RandomNumberGeneratorImplementation.cs index e403b0a7c220cb..e00508d66c237f 100644 --- a/src/libraries/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/RandomNumberGeneratorImplementation.cs +++ b/src/libraries/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/RandomNumberGeneratorImplementation.cs @@ -7,6 +7,15 @@ namespace System.Security.Cryptography { internal sealed partial class RandomNumberGeneratorImplementation : RandomNumberGenerator { + // a singleton which always calls into a thread-safe implementation + // and whose Dispose method no-ops + internal static readonly RandomNumberGeneratorImplementation s_singleton = new RandomNumberGeneratorImplementation(); + + // private ctor used only by singleton + private RandomNumberGeneratorImplementation() + { + } + // As long as each implementation can provide a static GetBytes(ref byte buf, int length) // they can share this one implementation of FillSpan. internal static unsafe void FillSpan(Span data)