예제 #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();
        }
예제 #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();
        }
예제 #3
0
        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);
        }
예제 #4
0
 public ApiV1Controller(PooledEntropyCprngGenerator terninger
                        , PasswordRatingService ratingService
                        , PasswordStatisticService statisticService
                        , IpThrottlerService ipThrottler
                        , DictionaryService dictionaryService)
 {
     _Terninger         = terninger;
     _RatingService     = ratingService;
     _StatisticService  = statisticService;
     _IpThrottler       = ipThrottler;
     _DictionaryService = dictionaryService;
 }
예제 #5
0
        /// <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);
        }
예제 #6
0
        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);
        }
예제 #7
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();
        }
예제 #8
0
        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);
        }
예제 #9
0
        /// <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));
        }
예제 #10
0
 /// <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),
 }
     );
예제 #11
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();
        }
예제 #12
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();
        }
예제 #13
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();
        }
예제 #14
0
        /// <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());
            }
        }
예제 #15
0
 /// <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())
     );
예제 #16
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);
        }
예제 #17
0
 /// <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);
예제 #18
0
        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)
 {
 }
예제 #20
0
 public ApiV1UnicodeController(PooledEntropyCprngGenerator terninger, PasswordRatingService ratingService, PasswordStatisticService statisticService, IpThrottlerService ipThrottler, DictionaryService dictionaryService
                               , IMemoryCache memoryCache)
     : base(terninger, ratingService, statisticService, ipThrottler, dictionaryService)
 {
     _MemoryCache = memoryCache;
 }