Esempio n. 1
0
        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();
        }
Esempio n. 2
0
        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();
        }
Esempio n. 3
0
        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);
        }
Esempio n. 4
0
        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();
        }
Esempio n. 5
0
        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);
        }
Esempio n. 6
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);
        }
Esempio n. 7
0
        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);
        }
Esempio n. 8
0
        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);
        }
Esempio n. 9
0
        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);
        }
Esempio n. 10
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);
        }
Esempio n. 11
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);
        }
Esempio n. 12
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);
        }
Esempio n. 13
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);
        }
Esempio n. 14
0
        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);
        }
Esempio n. 15
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);
        }
Esempio n. 16
0
        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);
        }
Esempio n. 17
0
        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();
        }
Esempio n. 18
0
        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();
        }
Esempio n. 19
0
        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);
        }
Esempio n. 20
0
        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();
        }
Esempio n. 21
0
        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);
        }