public async Task ForceReseed() { var sources = new IEntropySource[] { new CryptoRandomSource(64), new CurrentTimeSource(), new GCMemorySource(), new TimerSource(), new UserSuppliedSource(CypherBasedPrngGenerator.CreateWithCheapKey().GetRandomBytes(2048)) }; var acc = new EntropyAccumulator(new StandardRandomWrapperGenerator()); var rng = PooledEntropyCprngGenerator.Create(sources, accumulator: acc, config: Conf()); Assert.AreEqual(rng.BytesRequested, 0); Assert.AreEqual(rng.ReseedCount, 0); Assert.AreEqual(rng.IsRunning, false); Assert.AreEqual(rng.EntropyPriority, EntropyPriority.High); Assert.AreEqual(rng.SourceCount, 5); await rng.StartAndWaitForFirstSeed(); Assert.IsTrue(rng.ReseedCount >= 1); Assert.IsTrue(acc.TotalEntropyBytes > 0); Assert.AreNotEqual(rng.EntropyPriority, EntropyPriority.High); var reseedCount = rng.ReseedCount; var entropy = acc.TotalEntropyBytes; await rng.Reseed(); Assert.IsTrue(rng.ReseedCount > reseedCount); Assert.IsTrue(acc.TotalEntropyBytes > entropy); await rng.Stop(); }
public async Task CreatePrngFromPooled() { var sources = new IEntropySource[] { new CryptoRandomSource(64), new CurrentTimeSource(), new GCMemorySource(), new TimerSource(), new UserSuppliedSource(CypherBasedPrngGenerator.CreateWithCheapKey().GetRandomBytes(2048)) }; var acc = new EntropyAccumulator(new StandardRandomWrapperGenerator()); var rng = PooledEntropyCprngGenerator.Create(sources, accumulator: acc, config: Conf()); Assert.AreEqual(rng.BytesRequested, 0); Assert.AreEqual(rng.ReseedCount, 0); Assert.AreEqual(rng.IsRunning, false); Assert.AreEqual(rng.EntropyPriority, EntropyPriority.High); Assert.AreEqual(rng.SourceCount, 5); await rng.StartAndWaitForFirstSeed(); Assert.IsTrue(rng.ReseedCount >= 1); Assert.IsTrue(acc.TotalEntropyBytes > 0); System.Threading.Thread.Sleep(1); // EntropyPriority is only updated after the reseed event, so it might not be current. Assert.AreNotEqual(rng.EntropyPriority, EntropyPriority.High); var prng = rng.CreateCypherBasedGenerator(); Assert.IsNotNull(prng); var bytes = prng.GetRandomBytes(16); Assert.IsFalse(bytes.All(b => b == 0)); await rng.Stop(); }
public void ConstructMinimal() { var sources = new IEntropySource[] { new NullSource(), new NullSource() }; var rng = new PooledEntropyCprngGenerator(sources); // Creating a generator should not actually generate any bytes or even start the generator. Assert.AreEqual(rng.BytesRequested, 0); Assert.AreEqual(rng.ReseedCount, 0); Assert.AreEqual(rng.IsRunning, false); Assert.AreEqual(rng.EntropyPriority, EntropyPriority.High); }
public ApiV1Controller(PooledEntropyCprngGenerator terninger , PasswordRatingService ratingService , PasswordStatisticService statisticService , IpThrottlerService ipThrottler , DictionaryService dictionaryService) { _Terninger = terninger; _RatingService = ratingService; _StatisticService = statisticService; _IpThrottler = ipThrottler; _DictionaryService = dictionaryService; }
/// <summary> /// Creates a light weight PRNG from a Pooled Generator. /// If the Pooled Generator has not created its first seed, this will throw. /// </summary> public static IRandomNumberGenerator CreateCypherBasedGenerator(this PooledEntropyCprngGenerator pooledRng, int bufferSize) { if (pooledRng == null) { throw new ArgumentNullException(nameof(pooledRng)); } var key = pooledRng.GetRandomBytes(32); var result = CypherBasedPrngGenerator.Create(key, outputBufferSize: bufferSize); return(result); }
public void ConstructWithPrng() { var sources = new IEntropySource[] { new NullSource(), new NullSource() }; var prng = new CypherBasedPrngGenerator(new StandardRandomWrapperGenerator().GetRandomBytes(32)); var rng = new PooledEntropyCprngGenerator(sources, prng); // Creating a generator should not actually generate any bytes or even start the generator. Assert.AreEqual(rng.BytesRequested, 0); Assert.AreEqual(rng.ReseedCount, 0); Assert.AreEqual(rng.IsRunning, false); Assert.AreEqual(rng.EntropyPriority, EntropyPriority.High); }
public async Task PooledGenerator() { var sources = new IEntropySource[] { new CryptoRandomSource(64), new CurrentTimeSource(), new GCMemorySource(), new NetworkStatsSource(), new ProcessStatsSource(), new TimerSource() }; var acc = new EntropyAccumulator(new StandardRandomWrapperGenerator()); var rng = new PooledEntropyCprngGenerator(sources, acc); await rng.StartAndWaitForFirstSeed(); await FuzzGenerator(10000, 1, 64, rng, nameof(PooledEntropyCprngGenerator)); await rng.Stop(); }
public void ConstructWithLocalSources() { var sources = new IEntropySource[] { new CryptoRandomSource(), new CurrentTimeSource(), new GCMemorySource(), new NetworkStatsSource(), new ProcessStatsSource(), new TimerSource() }; var rng = new PooledEntropyCprngGenerator(sources); // Creating a generator should not actually generate any bytes or even start the generator. Assert.AreEqual(rng.BytesRequested, 0); Assert.AreEqual(rng.ReseedCount, 0); Assert.AreEqual(rng.IsRunning, false); Assert.AreEqual(rng.EntropyPriority, EntropyPriority.High); Assert.AreEqual(rng.SourceCount, 6); }
/// <summary> /// Creates a light weight PRNG from a Pooled Generator. /// This will wait until the Pooled Generator has created its first seed. /// </summary> public static Task <IRandomNumberGenerator> CreateCypherBasedGeneratorAsync(this PooledEntropyCprngGenerator pooledRng) { if (pooledRng == null) { throw new ArgumentNullException(nameof(pooledRng)); } if (pooledRng.ReseedCount > 0) { return(Task.FromResult(pooledRng.CreateCypherBasedGenerator())); } return(WaitAndGet(pooledRng)); }
/// <summary> /// Creates a pooled random number generator that conforms to the Fortuna spec. /// This is more conservative than Terninger; no randomised pools or low priority mode. /// </summary> public static PooledEntropyCprngGenerator CreateFortuna() => PooledEntropyCprngGenerator.Create( initialisedSources: BasicSources(), accumulator: new EntropyAccumulator(32, 0), config: new PooledEntropyCprngGenerator.PooledGeneratorConfig() { // Set the ways to enter low priority mode so high they should never be hit. ReseedCountBeforeSwitchToLowPriority = Int32.MaxValue, TimeBeforeSwitchToLowPriority = TimeSpan.MaxValue, // Reseed more aggressively as well. MaximumBytesGeneratedBeforeReseed = 1024L * 1024L, MinimumTimeBetweenReseeds = TimeSpan.FromHours(1), } );
public async Task EventIsRaisedOnReseed() { var sources = new IEntropySource[] { new CryptoRandomSource(64), new CurrentTimeSource(), new GCMemorySource(), new TimerSource(), new UserSuppliedSource(CypherBasedPrngGenerator.CreateWithCheapKey().GetRandomBytes(2048)) }; var acc = new EntropyAccumulator(new StandardRandomWrapperGenerator()); var rng = PooledEntropyCprngGenerator.Create(sources, accumulator: acc, config: Conf()); Object setInReseedEvent = null; rng.OnReseed += (o, e) => setInReseedEvent = new object(); Assert.AreEqual(rng.BytesRequested, 0); Assert.AreEqual(rng.ReseedCount, 0); Assert.AreEqual(rng.IsRunning, false); Assert.AreEqual(rng.EntropyPriority, EntropyPriority.High); Assert.AreEqual(rng.SourceCount, 5); await rng.StartAndWaitForFirstSeed(); Assert.IsNotNull(setInReseedEvent); await rng.Stop(); }
public async Task GetFirstSeed_MixedSyncAndAsyncSources() { var sources = new IEntropySource[] { new CryptoRandomSource(32), new CurrentTimeSource(), new GCMemorySource(), new TimerSource(), new AsyncCryptoRandomSource(), new ProcessStatsSource(), new NetworkStatsSource() }; var acc = new EntropyAccumulator(new StandardRandomWrapperGenerator()); var rng = PooledEntropyCprngGenerator.Create(sources, accumulator: acc, config: Conf()); Assert.AreEqual(rng.BytesRequested, 0); Assert.AreEqual(rng.ReseedCount, 0); Assert.AreEqual(rng.IsRunning, false); Assert.AreEqual(rng.EntropyPriority, EntropyPriority.High); Assert.AreEqual(rng.SourceCount, 7); await rng.StartAndWaitForFirstSeed(); Assert.IsTrue(rng.ReseedCount >= 1); Assert.IsTrue(acc.TotalEntropyBytes > 0); System.Threading.Thread.Sleep(1); // EntropyPriority is only updated after the reseed event, so it might not be current. Assert.AreNotEqual(rng.EntropyPriority, EntropyPriority.High); await rng.Stop(); }
public async Task FirstSeedYieldsDifferentBytes() { var sources = new IEntropySource[] { new CryptoRandomSource(64), new CurrentTimeSource(), new GCMemorySource(), new TimerSource(), new UserSuppliedSource(CypherBasedPrngGenerator.CreateWithCheapKey().GetRandomBytes(2048)) }; var acc1 = new EntropyAccumulator(new StandardRandomWrapperGenerator()); var rng1 = PooledEntropyCprngGenerator.Create(sources, accumulator: acc1, config: Conf()); await rng1.StartAndWaitForFirstSeed(); var acc2 = new EntropyAccumulator(new StandardRandomWrapperGenerator()); var rng2 = PooledEntropyCprngGenerator.Create(sources, accumulator: acc2, config: Conf()); await rng2.StartAndWaitForFirstSeed(); var bytesFrom1 = rng1.GetRandomBytes(64); Assert.IsFalse(bytesFrom1.All(b => b == 0)); var bytesFrom2 = rng2.GetRandomBytes(64); Assert.IsFalse(bytesFrom2.All(b => b == 0)); // Expect two generates with different inputs will give different bytes from from the start. Assert.IsFalse(bytesFrom1.SequenceEqual(bytesFrom2)); await rng1.Stop(); await rng2.Stop(); }
/// <summary> /// Creates a light weight PRNG from a Pooled Generator. /// If the Pooled Generator has not created its first seed, this will use the system crypto random to derive a seed. /// </summary> public static IRandomNumberGenerator CreateCypherBasedGeneratorOrUninitialised(this PooledEntropyCprngGenerator pooledRng) { if (pooledRng == null) { throw new ArgumentNullException(nameof(pooledRng)); } if (pooledRng.ReseedCount > 0) { return(pooledRng.CreateCypherBasedGenerator()); } else { return(CypherBasedPrngGenerator.CreateWithSystemCrngKey()); } }
/// <summary> /// Creates a pooled random number generator that makes improvements and changes to the Fortuna spec. /// This allows for less CPU usage, uses randomised pools, but isn't "official". /// </summary> public static PooledEntropyCprngGenerator CreateTerninger() => PooledEntropyCprngGenerator.Create( initialisedSources: BasicSources(), accumulator: new EntropyAccumulator(16, 16, CypherBasedPrngGenerator.CreateWithCheapKey()) );
private static GeneratorAndDescription CreateRandomGenerator() { var result = new GeneratorAndDescription(); if (generatorType == Generator.StockRandom) { result.Description = "deterministic PRNG - " + typeof(Rand).Namespace + "." + typeof(Rand).Name; var(seed, description) = DeriveSeed(); result.SeedDescription = description; result.Generator = new StandardRandomWrapperGenerator(new Rand(BitConverter.ToInt32(seed, 0))); result.WaitForGeneratorReady = () => { }; result.WaitForGeneratorStopped = () => { }; } else if (generatorType == Generator.CryptoRandom) { result.Description = "non-deterministic CPRNG - " + typeof(RandomNumberGenerator).Namespace + "." + typeof(RandomNumberGenerator).Name; result.SeedDescription = "No seed required"; result.Generator = new CryptoRandomWrapperGenerator(); result.WaitForGeneratorReady = () => { }; result.WaitForGeneratorStopped = () => { }; } else if (generatorType == Generator.TerningerCypher) { var primitive = GetCryptoPrimitive(); var hash = GetHashAlgorithm(); var counter = new CypherCounter(primitive.BlockSizeBytes); var entropyGetter = GetEntropyGetter(); var(seed, description) = DeriveSeed(); result.Description = $"{(nonDeterministic ? "non-" : "")}deterministic PRNG - " + typeof(CypherBasedPrngGenerator).Namespace + "." + typeof(CypherBasedPrngGenerator).Name; result.ExtraDescription = $"Using crypto primitive: {cryptoPrimitive}, hash: {hashAlgorithm}"; result.SeedDescription = description; result.Generator = CypherBasedPrngGenerator.Create(key: seed, cryptoPrimitive: primitive, hashAlgorithm: hash, initialCounter: counter, additionalEntropyGetter: entropyGetter); result.WaitForGeneratorReady = () => { }; result.WaitForGeneratorStopped = () => { }; } else if (generatorType == Generator.TerningerPooled) { var(seed, description) = DeriveSeed(); result.SeedDescription = description; // Accumulator. var accKey = SHA512.Create().ComputeHash( StaticLocalEntropy.Get32().GetAwaiter().GetResult().Concat(CheapEntropy.Get32()).ToArray() ).EnsureArraySize(32); var accPrng = CypherBasedPrngGenerator.Create(accKey, CryptoPrimitive.Aes256(), SHA512.Create()); var acc = new EntropyAccumulator(linearPools, randomPools, accPrng, SHA512.Create); // Generator. var primitive = GetCryptoPrimitive(); var hash = GetHashAlgorithm(); var genPrng = CypherBasedPrngGenerator.Create(new byte[32], primitive, hash); IEnumerable <IEntropySource> sources = new IEntropySource[] { new UserSuppliedSource(seed), new CurrentTimeSource(), new TimerSource(), new GCMemorySource(), new CryptoRandomSource(), new NetworkStatsSource(), new ProcessStatsSource(), }; if (includeNetworkSources) { sources = sources.Concat(new IEntropySource[] { new PingStatsSource(), new ExternalWebContentSource(), new AnuExternalRandomSource(), new BeaconNistExternalRandomSource(), new HotbitsExternalRandomSource(), new RandomNumbersInfoExternalRandomSource(), new RandomOrgExternalRandomSource(), }); } // As the pooled generator will be churning out entropy as fast as it can, we increase the reseed rate by polling faster and forcing reseeds more frequently. var config = new PooledEntropyCprngGenerator.PooledGeneratorConfig() { MaximumBytesGeneratedBeforeReseed = Int32.MaxValue, PollWaitTimeInNormalPriority = TimeSpan.FromSeconds(1), EntropyToTriggerReseedInNormalPriority = 64, }; var generator = new PooledEntropyCprngGenerator(sources, acc, genPrng, config); result.Generator = generator; result.Description = $"non-deterministic CPRNG - " + typeof(PooledEntropyCprngGenerator).Namespace + "." + typeof(PooledEntropyCprngGenerator).Name; result.ExtraDescription = $"Using {linearPools}+{randomPools} pools (linear+random), {sources.Count()} entropy sources, crypto primitive: {cryptoPrimitive}, hash: {hashAlgorithm}"; result.WaitForGeneratorReady = () => { generator.StartAndWaitForFirstSeed().Wait(TimeSpan.FromSeconds(60)); }; result.WaitForGeneratorStopped = () => { generator.Stop().Wait(TimeSpan.FromSeconds(60)); }; } else { throw new Exception("Unexpected Generator type: " + generatorType); } return(result); }
/// <summary> /// Creates a light weight PRNG from a Pooled Generator. /// If the Pooled Generator has not created its first seed, this will throw. /// </summary> public static IRandomNumberGenerator CreateCypherBasedGenerator(this PooledEntropyCprngGenerator pooledRng) => CreateCypherBasedGenerator(pooledRng, 1024);
private static async Task <IRandomNumberGenerator> WaitAndGet(PooledEntropyCprngGenerator pooledRng) { await pooledRng.StartAndWaitForFirstSeed(); return(pooledRng.CreateCypherBasedGenerator()); }
public ApiV1AlphaNumericController(PooledEntropyCprngGenerator terninger, PasswordRatingService ratingService, PasswordStatisticService statisticService, IpThrottlerService ipThrottler, DictionaryService dictionaryService) : base(terninger, ratingService, statisticService, ipThrottler, dictionaryService) { }
public ApiV1UnicodeController(PooledEntropyCprngGenerator terninger, PasswordRatingService ratingService, PasswordStatisticService statisticService, IpThrottlerService ipThrottler, DictionaryService dictionaryService , IMemoryCache memoryCache) : base(terninger, ratingService, statisticService, ipThrottler, dictionaryService) { _MemoryCache = memoryCache; }