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 ConstructWithAccumulator() { var sources = new IEntropySource[] { new NullSource(), new NullSource() }; var acc = new EntropyAccumulator(new StandardRandomWrapperGenerator()); var rng = new PooledEntropyCprngGenerator(sources, acc); // 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 Accumulator_NextSeedWithZeroEntropy() { var a = new EntropyAccumulator(_Rng); Assert.IsTrue(a.NextSeed().Length > 0); Assert.AreEqual(a.TotalEntropyBytes, 0); Assert.AreEqual(a.AvailableEntropyBytesSinceLastSeed, 0); Assert.AreEqual(a.TotalReseedEvents, 1); Assert.AreEqual(a.MaxPoolEntropyBytesSinceLastSeed, 0); Assert.AreEqual(a.MinPoolEntropyBytesSinceLastSeed, 0); Assert.AreEqual(a.PoolZeroEntropyBytesSinceLastSeed, 0); }
public void Accumulator_1kBEntropyPacket() { var a = new EntropyAccumulator(32, 0, _Rng); a.Add(EventFromBytes(_Zero1KBytes)); Assert.AreEqual(a.TotalEntropyBytes, _Zero1KBytes.Length); Assert.AreEqual(a.AvailableEntropyBytesSinceLastSeed, _Zero1KBytes.Length); Assert.AreEqual(a.TotalReseedEvents, 0); Assert.AreEqual(a.MaxPoolEntropyBytesSinceLastSeed, 32); Assert.AreEqual(a.MinPoolEntropyBytesSinceLastSeed, 32); Assert.AreEqual(a.PoolZeroEntropyBytesSinceLastSeed, 32); }
public void Accumulator_AddOnceIncreasesPoolEntropy() { var a = new EntropyAccumulator(_Rng); a.Add(EventFromBytes(_Zero8Bytes)); Assert.AreEqual(a.TotalEntropyBytes, 8); Assert.AreEqual(a.AvailableEntropyBytesSinceLastSeed, 8); Assert.AreEqual(a.TotalReseedEvents, 0); Assert.AreEqual(a.MaxPoolEntropyBytesSinceLastSeed, 8); Assert.AreEqual(a.MinPoolEntropyBytesSinceLastSeed, 0); Assert.AreEqual(a.PoolZeroEntropyBytesSinceLastSeed, 8); }
public void Accumulator_48ByteEntropyPacketUneven() { var a = new EntropyAccumulator(32, 0, _Rng); a.Add(EventFromBytes(new byte[48])); Assert.AreEqual(a.TotalEntropyBytes, 48); Assert.AreEqual(a.AvailableEntropyBytesSinceLastSeed, 48); Assert.AreEqual(a.TotalReseedEvents, 0); Assert.AreEqual(a.MaxPoolEntropyBytesSinceLastSeed, 16); Assert.AreEqual(a.MinPoolEntropyBytesSinceLastSeed, 0); Assert.AreEqual(a.PoolZeroEntropyBytesSinceLastSeed, 16); }
public void Accumulator_NextSeedResetsCountersSinceLastSeed() { var a = new EntropyAccumulator(_Rng); a.Add(EventFromBytes(_Zero8Bytes)); Assert.IsTrue(a.NextSeed().Length > 0); Assert.AreEqual(a.TotalEntropyBytes, 8); Assert.AreEqual(a.AvailableEntropyBytesSinceLastSeed, 0); Assert.AreEqual(a.TotalReseedEvents, 1); Assert.AreEqual(a.MaxPoolEntropyBytesSinceLastSeed, 0); Assert.AreEqual(a.MinPoolEntropyBytesSinceLastSeed, 0); Assert.AreEqual(a.PoolZeroEntropyBytesSinceLastSeed, 0); }
public void Accumulator_WithCustomHashFunction() { var a = new EntropyAccumulator(16, 16, _Rng, () => new SHA256Managed()); Assert.AreEqual(a.LinearPoolCount, 16); Assert.AreEqual(a.RandomPoolCount, 16); Assert.AreEqual(a.TotalPoolCount, 32); Assert.AreEqual(a.TotalEntropyBytes, 0); Assert.AreEqual(a.AvailableEntropyBytesSinceLastSeed, 0); Assert.AreEqual(a.TotalReseedEvents, 0); Assert.AreEqual(a.MaxPoolEntropyBytesSinceLastSeed, 0); Assert.AreEqual(a.MinPoolEntropyBytesSinceLastSeed, 0); Assert.AreEqual(a.PoolZeroEntropyBytesSinceLastSeed, 0); }
public void Accumulator_WithRandomGenerator() { var a = new EntropyAccumulator(_Rng); Assert.AreEqual(a.LinearPoolCount, 28); Assert.AreEqual(a.RandomPoolCount, 12); Assert.AreEqual(a.TotalPoolCount, 40); Assert.AreEqual(a.TotalEntropyBytes, 0); Assert.AreEqual(a.AvailableEntropyBytesSinceLastSeed, 0); Assert.AreEqual(a.TotalReseedEvents, 0); Assert.AreEqual(a.MaxPoolEntropyBytesSinceLastSeed, 0); Assert.AreEqual(a.MinPoolEntropyBytesSinceLastSeed, 0); Assert.AreEqual(a.PoolZeroEntropyBytesSinceLastSeed, 0); }
public void Accumulator_WithMaximumLinearPools() { var a = new EntropyAccumulator(64, 0, _Rng); Assert.AreEqual(a.LinearPoolCount, 64); Assert.AreEqual(a.RandomPoolCount, 0); Assert.AreEqual(a.TotalPoolCount, 64); Assert.AreEqual(a.TotalEntropyBytes, 0); Assert.AreEqual(a.AvailableEntropyBytesSinceLastSeed, 0); Assert.AreEqual(a.TotalReseedEvents, 0); Assert.AreEqual(a.MaxPoolEntropyBytesSinceLastSeed, 0); Assert.AreEqual(a.MinPoolEntropyBytesSinceLastSeed, 0); Assert.AreEqual(a.PoolZeroEntropyBytesSinceLastSeed, 0); }
public void Accumulator_2kBEntropyPacket() { // 2kB from one source is enough to trip the "too much entropy from one source" thing on pools. // 1kB extra is almost enough to balance it out. var a = new EntropyAccumulator(32, 0, _Rng); a.Add(EventFromBytes(_Zero1KBytes)); a.Add(EventFromBytes(_Zero2KBytes)); Assert.AreEqual(a.TotalEntropyBytes, 3072); Assert.AreEqual(a.AvailableEntropyBytesSinceLastSeed, 3072); Assert.AreEqual(a.TotalReseedEvents, 0); Assert.AreEqual(a.MaxPoolEntropyBytesSinceLastSeed, 96); Assert.AreEqual(a.MinPoolEntropyBytesSinceLastSeed, 96); Assert.AreEqual(a.PoolZeroEntropyBytesSinceLastSeed, 96); }
public void Accumulator_RandomEntropyPacketSizes() { var a = new EntropyAccumulator(32, 0, _Rng); int totalEntropy = 0; for (int i = 0; i < 1000; i++) { var bytes = new byte[_Rng.GetRandomInt32(128) + 1]; a.Add(EventFromBytes(bytes)); totalEntropy = totalEntropy + bytes.Length; } Assert.AreEqual(a.TotalEntropyBytes, totalEntropy); Assert.AreEqual(a.AvailableEntropyBytesSinceLastSeed, totalEntropy); Assert.AreEqual(a.TotalReseedEvents, 0); }
public void Accumulator_AddPoolCountTwiceAddsToAllPools() { var a = new EntropyAccumulator(_Rng); for (int i = 0; i < a.TotalPoolCount * 2; i++) { a.Add(EventFromBytes(_Zero8Bytes)); } Assert.AreEqual(a.TotalEntropyBytes, _Zero8Bytes.Length * a.TotalPoolCount * 2); Assert.AreEqual(a.AvailableEntropyBytesSinceLastSeed, _Zero8Bytes.Length * a.TotalPoolCount * 2); Assert.AreEqual(a.TotalReseedEvents, 0); Assert.AreEqual(a.MaxPoolEntropyBytesSinceLastSeed, 16); Assert.AreEqual(a.MinPoolEntropyBytesSinceLastSeed, 16); Assert.AreEqual(a.PoolZeroEntropyBytesSinceLastSeed, 16); }
public void Accumulator_AddPoolCountPlusOneAddsToAllPoolsAndFirstPool() { var a = new EntropyAccumulator(_Rng); for (int i = 0; i < a.TotalPoolCount; i++) { a.Add(EventFromBytes(_Zero8Bytes)); } a.Add(EventFromBytes(_Zero8Bytes)); Assert.AreEqual(a.TotalEntropyBytes, (_Zero8Bytes.Length * a.TotalPoolCount) + _Zero8Bytes.Length); Assert.AreEqual(a.AvailableEntropyBytesSinceLastSeed, (_Zero8Bytes.Length * a.TotalPoolCount) + _Zero8Bytes.Length); Assert.AreEqual(a.TotalReseedEvents, 0); Assert.AreEqual(a.MaxPoolEntropyBytesSinceLastSeed, 16); Assert.AreEqual(a.MinPoolEntropyBytesSinceLastSeed, 8); Assert.AreEqual(a.PoolZeroEntropyBytesSinceLastSeed, 16); }
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 void Accumulator_ListLinearAndRandomPoolsUsedIn1000SeedEvents() { var a = new EntropyAccumulator(16, 16, _Rng); using (var sw = new StreamWriter("accumulator_linearAndRandomUsage.txt", false, Encoding.UTF8)) { sw.WriteLine($"Seed:Ent'py:# :Pools Used (linear) :Pools Used (random) "); for (int i = 0; i < 10000; i++) { for (int j = 0; j < a.TotalPoolCount; j++) { a.Add(EventFromBytes(_Incrementing16Bytes)); } var availableEntropy = (long)a.AvailableEntropyBytesSinceLastSeed; var seed = a.NextSeed(); sw.WriteLine($"{i + 1:00000}:{availableEntropy:000000}:{a.PoolCountUsedInLastSeedGeneration:00}:{Convert.ToString((long)a.LinearPoolsUsedInLastSeedGeneration, 2),32}:{Convert.ToString((long)a.RandomPoolsUsedInLastSeedGeneration, 2),32}"); Assert.IsTrue(availableEntropy >= a.TotalPoolCount * _Incrementing16Bytes.Length); // Not every pool is used, so we may have extra bytes here. Assert.IsTrue(seed.Length > 0); } } Assert.AreEqual(a.TotalReseedEvents, 10000); }
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(); }
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); }