Example #1
0
        public Task <byte[]> GetEntropyAsync(EntropyPriority priority)
        {
            // Only returning the lower 32 bits of the timer, as the upper 32 bits will be pretty static.
            var result = BitConverter.GetBytes(unchecked ((uint)_Timer.ElapsedTicks));

            return(Task.FromResult(result));
        }
Example #2
0
        public async Task <byte[]> GetEntropyAsync(EntropyPriority priority)
        {
            // Determine the next poll time.
            var period      = PriorityToPeriod(priority);
            var nextRunTime = _LastPollDatestamp.Add(period);

            if (Log.IsTraceEnabled())
            {
                Log.Trace("Period for priority {0} is {1}. Next run time after {2} (utc).", priority, period, nextRunTime);
            }

            // If we're before the next run time, we don't run.
            if (nextRunTime >= DateTime.UtcNow)
            {
                Log.Trace("Not after next run time.");
                return(null);
            }

            // Now we get the real entropy.
            Log.Trace("Reading entropy...");
            var result = await GetInternalEntropyAsync(priority);

            Log.Trace("Read {0:N0} bytes of entropy.", (result == null ? 0 : result.Length));

            // And update when we last ran.
            _LastPollDatestamp = DateTime.UtcNow;
            Log.Trace("Next run at {0} UTC (at priority {1}).", _LastPollDatestamp.Add(period), period);

            return(result);
        }
Example #3
0
        public Task <byte[]> GetEntropyAsync(EntropyPriority priority)
        {
            var result = _Entropy;

            _Entropy = null;
            return(Task.FromResult(result));
        }
Example #4
0
            public async Task <byte[]> GetEntropyAsync(EntropyPriority priority)
            {
                var result = new byte[_ResultLength];

                _Rng.GetBytes(result);
                await Task.Delay(50);

                return(result);
            }
Example #5
0
        public Task <byte[]> GetEntropyAsync(EntropyPriority priority)
        {
            // When in high priority, we return double the normal amount.
            var length = (priority == EntropyPriority.High ? _ResultLength * 2 : _ResultLength);
            var result = new byte[length];

            _Rng.GetBytes(result);
            return(Task.FromResult(result));
        }
Example #6
0
        protected override Task <byte[]> GetInternalEntropyAsync(EntropyPriority priority)
        {
            // This reads details of all processes running on the system, and uses them as inputs to a hash for final result.
            // Often, different properties or processes will throw exceptions.
            // Given this isn't trivial work, we run in a separate threadpool task.

            return(Task.Run(() =>
            {
                Log.Trace("Beginning to gather entropy.");
                var ps = Process.GetProcesses();        // TODO: assert we can do this during initialisation?
                Log.Trace("Found {0:N0} processes.", ps.Length);

                var processStats = new long[ps.Length * _ItemsPerProcess];

                // Read details from all processes.
                // PERF: This takes several seconds, which isn't helped by the fact a large number of these will throw exceptions when not running as admin.
                for (int i = 0; i < ps.Length; i++)
                {
                    var p = ps[i];
                    processStats[(i * _ItemsPerProcess) + 0] = p.TryAndIgnoreException(x => x.Id);
                    processStats[(i * _ItemsPerProcess) + 1] = p.TryAndIgnoreException(x => x.MainWindowHandle.ToInt64());
                    processStats[(i * _ItemsPerProcess) + 2] = p.TryAndIgnoreException(x => x.MaxWorkingSet.ToInt64());
                    processStats[(i * _ItemsPerProcess) + 3] = p.TryAndIgnoreException(x => x.NonpagedSystemMemorySize64);
                    processStats[(i * _ItemsPerProcess) + 4] = p.TryAndIgnoreException(x => x.PagedMemorySize64);
                    processStats[(i * _ItemsPerProcess) + 5] = p.TryAndIgnoreException(x => x.PagedSystemMemorySize64);
                    processStats[(i * _ItemsPerProcess) + 6] = p.TryAndIgnoreException(x => x.PeakPagedMemorySize64);
                    processStats[(i * _ItemsPerProcess) + 7] = p.TryAndIgnoreException(x => x.PeakVirtualMemorySize64);
                    processStats[(i * _ItemsPerProcess) + 8] = p.TryAndIgnoreException(x => x.PeakWorkingSet64);
                    processStats[(i * _ItemsPerProcess) + 9] = p.TryAndIgnoreException(x => x.PrivateMemorySize64);
                    processStats[(i * _ItemsPerProcess) + 10] = p.TryAndIgnoreException(x => x.WorkingSet64);
                    processStats[(i * _ItemsPerProcess) + 11] = p.TryAndIgnoreException(x => x.VirtualMemorySize64);
                    processStats[(i * _ItemsPerProcess) + 12] = p.TryAndIgnoreException(x => x.UserProcessorTime.Ticks);
                    processStats[(i * _ItemsPerProcess) + 13] = p.TryAndIgnoreException(x => x.TotalProcessorTime.Ticks);
                    processStats[(i * _ItemsPerProcess) + 14] = p.TryAndIgnoreException(x => x.PrivilegedProcessorTime.Ticks);
                    processStats[(i * _ItemsPerProcess) + 15] = p.TryAndIgnoreException(x => x.StartTime.Ticks);
                    processStats[(i * _ItemsPerProcess) + 16] = p.TryAndIgnoreException(x => x.HandleCount);
                }

                // Remove all zero items (to prevent silly things like a mostly, or all, zero hash result).
                var processStatsNoZero = processStats.Where(x => x != 0L).ToArray();
                Log.Trace("Read {0:N0} non-zero stat items.", processStatsNoZero.Length);
                if (LogRawStats)
                {
                    Log.Trace("Raw stats: ", processStatsNoZero.LongsToHexString());
                }

                // Shuffle the details, so there isn't a repetition of similar stats.
                processStatsNoZero.ShuffleInPlace(_Rng);

                // Get digests of the stats to return.
                var result = ByteArrayHelpers.LongsToDigestBytes(processStatsNoZero, _ItemsPerResultChunk);
                Log.Trace("Converted stats to {0:N0} bytes of entropy.", result.Length);

                return result;
            }));
        }
 protected override Task <byte[]> GetInternalEntropyAsync(EntropyPriority priority)
 {
     if (_ApiKey == Guid.Empty)
     {
         return(GetPublicEntropyAsync(priority));
     }
     else
     {
         return(GetApiEntropyAsync(priority));
     }
 }
Example #8
0
        protected override async Task <byte[]> GetInternalEntropyAsync(EntropyPriority priority)
        {
            // Do x pings to y servers in parallel.
            // Time each of them, use the high precision part as the result.
            // TODO: perhaps do real DNS queries rather than ICMP pings, as many have disabled ping. Note that this will need a 3rd party library.

            // TODO: check to see if there is a network available before trying this. Eg: https://stackoverflow.com/a/8345173/117070

            // Select the servers we will ping.
            var serversToSample = new List <PingAndStopwatch>(_ServersPerSample);

            for (int i = 0; i < _ServersPerSample; i++)
            {
                if (_NextServer >= _Servers.Count)
                {
                    _NextServer = 0;
                }
                serversToSample.Add(new PingAndStopwatch(_Servers[_NextServer]));
                _NextServer = _NextServer + 1;
            }

            // Now ping the servers and time how long it takes.
            var result = new List <byte>((_ServersPerSample + _PingsPerSample) * sizeof(ushort));

            for (int c = 0; c < _PingsPerSample; c++)
            {
                if (!_UseRandomSourceForUnitTest)
                {
                    await Task.WhenAll(serversToSample.Select(x => x.ResetAndRun()).ToArray());

                    foreach (var s in serversToSample.Where(x => x.Timing.TotalMilliseconds > 0 && x.Timing.TotalMilliseconds < _Timeout))
                    {
                        var timingBytes = BitConverter.GetBytes(unchecked ((ushort)s.Timing.Ticks));
                        result.Add(timingBytes[0]);
                        result.Add(timingBytes[1]);
                    }
                }
                else
                {
                    // Unit tests simply read random bytes.
                    result.AddRange(_Rng.GetRandomBytes(2));
                }
            }

            // Check for IPs where every attempt was a failure: something is likely wrong.
            foreach (var server in serversToSample.Where(x => x.Failures == _PingsPerSample))
            {
                Log.Warn("Every attempt to ping IP {0} failed. Server is likely offline or firewalled.", server.IP);
            }

            return(result.ToArray());
        }
        private async Task <byte[]> GetPublicEntropyAsync(EntropyPriority priority)
        {
            // https://random.org

            Log.Trace("Beginning to gather entropy.");

            // Fetch data.
            var response = "";
            var sw       = Stopwatch.StartNew();

            if (!_UseDiskSourceForUnitTests)
            {
                var apiUri = new Uri("https://www.random.org/cgi-bin/randbyte?nbytes=" + _BytesPerRequest + "&format=h");
                var hc     = HttpClientHelpers.Create(userAgent: _UserAgent);
                try
                {
                    response = await hc.GetStringAsync(apiUri);
                }
                catch (Exception ex)
                {
                    Log.Warn(ex, "Unable to GET from {0}", apiUri);
                    return(null);
                }
                Log.Trace("Read {0:N0} characters of html in {1:N2}ms.", response.Length, sw.Elapsed.TotalMilliseconds);
            }
            else
            {
                using (var stream = File.OpenRead(HttpClientHelpers._BasePathToUnitTestData + "www.random.org.html"))
                {
                    response = await new StreamReader(stream).ReadToEndAsync();
                }
            }
            sw.Stop();


            // The entire content is random hex bytes.
            // Albeit with a bunch of whitespace.
            var randomString = response.Replace("\r", "").Replace("\n", "").Replace(" ", "");

            var randomBytes = randomString.ParseFromHexString()
                              .Concat(BitConverter.GetBytes(unchecked ((uint)sw.Elapsed.Ticks)))       // Don't forget to include network timing!
                              .ToArray();

            Log.Trace("Read {0:N0} bytes of entropy (including 4 bytes of timing info).", randomBytes.Length);

            return(randomBytes);
        }
Example #10
0
        public Task <byte[]> GetEntropyAsync(EntropyPriority priority)
        {
            byte[] result;
            if (!_HasRunOnce)
            {
                // On first run, we include the entire 64 bit value.
                result      = BitConverter.GetBytes(DateTime.UtcNow.Ticks);
                _HasRunOnce = true;
            }
            else
            {
                // All subsequent runs only include the lower 32 bits.
                result = BitConverter.GetBytes(unchecked ((uint)DateTime.UtcNow.Ticks));
            }

            return(Task.FromResult(result));
        }
Example #11
0
        public Task <byte[]> GetEntropyAsync(EntropyPriority priority)
        {
            uint gcCollections = 0;

            for (int i = GC.MaxGeneration; i >= 0; i--)
            {
                gcCollections = (gcCollections << 5) ^ (uint)GC.CollectionCount(i);
            }
            var low = BitConverter.GetBytes(gcCollections);

            var gcTotalMemory = GC.GetTotalMemory(false);
            var high          = BitConverter.GetBytes((uint)gcTotalMemory);

            var result = new byte[8];

            Buffer.BlockCopy(low, 0, result, 0, low.Length);
            Buffer.BlockCopy(high, 0, result, 4, high.Length);

            return(Task.FromResult(result));
        }
Example #12
0
        protected override async Task <byte[]> GetInternalEntropyAsync(EntropyPriority priority)
        {
            // Note that many of these servers will have similar content and it is publicly accessible.
            // We must mix in some local entropy to ensure differnt computers end up with different entropy.
            // Yes, this reduces the effectiveness of this source, but it will still contribute over time.
            var localEntropy = (await StaticLocalEntropy.Get32()).Concat(CheapEntropy.Get16()).ToArray();

            // Select the servers we will fetch from.
            var serversToSample = new List <ServerFetcher>(_ServersPerSample);

            for (int i = 0; i < _ServersPerSample; i++)
            {
                if (_NextSource >= _Sources.Count)
                {
                    _NextSource = 0;
                }
                serversToSample.Add(new ServerFetcher(_Sources[_NextSource], _UserAgent, localEntropy));
                _NextSource = _NextSource + 1;
            }
            if (!serversToSample.Any())
            {
                return(null);
            }


            byte[] response;
            if (!_UseRandomSourceForUnitTest)
            {
                // Now fetch from the servers and use the contents, and time to derive entropy.
                var responses = await Task.WhenAll(serversToSample.Select(x => x.ResetAndRun()));

                response = responses.SelectMany(x => x ?? new byte[0]).ToArray();
            }
            else
            {
                // For unit tests, we just get random bytes.
                response = _Rng.GetRandomBytes(_ServersPerSample * 32);
            }

            return(response);
        }
Example #13
0
 private TimeSpan PriorityToPeriod(EntropyPriority priority) => priority == EntropyPriority.Normal ? _PeriodNormalPriority
                                                              : priority == EntropyPriority.High ? _PeriodHighPriority
                                                              : priority == EntropyPriority.Low ? _PeriodLowPriority
                                                              : _PeriodNormalPriority;       // Shouldn't happen.
Example #14
0
 protected abstract Task <byte[]> GetInternalEntropyAsync(EntropyPriority priority);
        protected override async Task <byte[]> GetInternalEntropyAsync(EntropyPriority priority)
        {
            Log.Trace("Beginning to gather entropy.");

            // This supports SSL, but the cert isn't valid (it's for the uni, rather than the correct domain).
            // http://www.randomnumbers.info/content/Download.htm
            // This returns HTML, which means I'm doing some hacky parsing here.
            const int rangeOfNumbers = 4096 - 1;      // 12 bits per number (1.5 bytes).

            // Fetch data.
            var response = "";
            var sw       = Stopwatch.StartNew();

            if (!_UseDiskSourceForUnitTests)
            {
                var apiUri = new Uri("http://www.randomnumbers.info/cgibin/wqrng.cgi?amount=" + _NumberOfNumbers.ToString() + "&limit=" + rangeOfNumbers.ToString());
                var hc     = HttpClientHelpers.Create(userAgent: _UserAgent);
                try
                {
                    response = await hc.GetStringAsync(apiUri);
                }
                catch (Exception ex)
                {
                    Log.Warn(ex, "Unable to GET from {0}", apiUri);
                    return(null);
                }
                Log.Trace("Read {0:N0} characters of html in {1:N2}ms.", response.Length, sw.Elapsed.TotalMilliseconds);
            }
            else
            {
                using (var stream = File.OpenRead(HttpClientHelpers._BasePathToUnitTestData + "www.randomnumbers.info.html"))
                {
                    response = await new StreamReader(stream).ReadToEndAsync();
                }
            }
            sw.Stop();

            // Locate some pretty clear boundaries around the random numbers returned.
            var startIdxString = "Download random numbers from quantum origin";
            var startIdx       = response.IndexOf(startIdxString, StringComparison.OrdinalIgnoreCase);

            if (startIdx == -1)
            {
                Log.Error("Cannot locate start string in html of randomnumbers.info result: source will return nothing. Looking for '{0}'. Actual result in next message.", startIdxString);
                Log.Error(response);
                return(null);
            }
            var hrIdxString = "<hr>";

            startIdx = response.IndexOf(hrIdxString, startIdx, StringComparison.OrdinalIgnoreCase);
            if (startIdx == -1)
            {
                Log.Error("Cannot locate start string in html of randomnumbers.info result: source will return nothing. Looking for '{0}'. Actual result in next message.", hrIdxString);
                Log.Error(response);
                return(null);
            }
            var endIdxString = "</td>";
            var endIdx       = response.IndexOf("</td>", startIdx, StringComparison.OrdinalIgnoreCase);

            if (endIdx == -1)
            {
                Log.Error("Cannot locate end string in html of randomnumbers.info result: source will return nothing. Looking for '{0}'. Actual result in next message.", endIdxString);
                Log.Error(response);
                return(null);
            }
            Log.Trace("Parsed beginning and end of useful entropy.");

            var haystack            = response.Substring(startIdx, endIdx - startIdx);
            var numbersAndOtherJunk = haystack.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); // Numbers are space separated.
            var numbers             = numbersAndOtherJunk
                                      .Where(x => x.All(Char.IsDigit))                                           // Remove non-numeric junk.
                                      .Select(x => Int16.Parse(x))                                               // Parse to an int16.
                                      .ToList();
            var result = new byte[(numbers.Count() * 2) + sizeof(uint)];

            for (int i = 0; i < numbers.Count; i++)
            {
                // Take the Int16s in the range 0..4095 (4096 possibilities) and write them into the result array.
                // The top 4 bits will always be empty, but that doesn't matter too much as they will be hashed when added to a Pool.
                // This means only 75% of bits are truly random, so 16 bytes is only equivalent to 12 bytes.
                // TODO: some bit bashing to pack things more efficiently
                var twoBytes = BitConverter.GetBytes(numbers[i]);
                result[i * 2]       = twoBytes[0];
                result[(i * 2) + 1] = twoBytes[1];
            }
            var timingBytes = BitConverter.GetBytes(unchecked ((uint)sw.Elapsed.Ticks));

            result[result.Length - 4] = timingBytes[0];
            result[result.Length - 3] = timingBytes[1];
            result[result.Length - 2] = timingBytes[2];
            result[result.Length - 1] = timingBytes[3];

            Log.Trace("Read {0:N0} bytes of entropy (including 4 bytes of timing info).", result.Length);

            return(result);
        }
Example #16
0
 public Task <byte[]> GetEntropyAsync(EntropyPriority priority)
 {
     // Increment the counter and return its value.
     _Counter.Increment();
     return(Task.FromResult(_Counter.GetCounter()));
 }
Example #17
0
        protected override async Task <byte[]> GetInternalEntropyAsync(EntropyPriority priority)
        {
            // https://beacon.nist.gov/
            // Note that this will return the same result for 60 second period.
            // We must mix in some local entropy to ensure differnt computers end up with different entropy.
            // Yes, this reduces the effectiveness of this source, but it will still contribute over time.

            Log.Trace("Beginning to gather entropy.");

            // Fetch data.
            var response = "";
            var sw       = Stopwatch.StartNew();

            if (!_UseDiskSourceForUnitTests)
            {
                var apiUri = new Uri("https://beacon.nist.gov/rest/record/last");
                var hc     = HttpClientHelpers.Create(userAgent: _UserAgent);
                try
                {
                    response = await hc.GetStringAsync(apiUri);
                }
                catch (Exception ex)
                {
                    Log.Warn(ex, "Unable to GET from {0}", apiUri);
                    return(null);
                }
                Log.Trace("Read {0:N0} characters of html in {1:N2}ms.", response.Length, sw.Elapsed.TotalMilliseconds);
            }
            else
            {
                using (var stream = File.OpenRead(HttpClientHelpers._BasePathToUnitTestData + "beacon.nist.gov-last.xml"))
                {
                    response = await new StreamReader(stream).ReadToEndAsync();
                }
            }
            sw.Stop();

            var localEntropy = (await StaticLocalEntropy.Get32()).Concat(CheapEntropy.Get16())
                               .Concat(BitConverter.GetBytes((uint)sw.Elapsed.Ticks))
                               .ToArray();

            Log.Trace("Got {0:N0} bytes of local entropy to mix.", localEntropy.Length);

            // Parse out the useful parts of the response.
            // Keeping away from XML parsing to minimise dependencies. At least for now.

            // The first two return 64 random bytes each, the signature is 256 bytes. All are hashed to 64 bytes when combined with local entropy.
            var lastOutputBytes  = GetWithinXmlTags(response, "previousOutputValue").ParseFromHexString();
            var outputValueBytes = GetWithinXmlTags(response, "outputValue").ParseFromHexString();
            var signatureBytes   = GetWithinXmlTags(response, "signatureValue").ParseFromHexString();

            Log.Trace("Got {0:N0} output bytes, {1:N0} last output bytes, {2:N0} signature bytes.", outputValueBytes.Length, lastOutputBytes.Length, signatureBytes.Length);

            // Mix in some local entropy.
            var hasher = SHA512.Create();
            var result = hasher.ComputeHash(lastOutputBytes.Concat(localEntropy).ToArray())
                         .Concat(hasher.ComputeHash(outputValueBytes.Concat(localEntropy).ToArray()))
                         .Concat(hasher.ComputeHash(signatureBytes.Concat(localEntropy).ToArray()))
                         .Concat(BitConverter.GetBytes(unchecked ((uint)sw.Elapsed.Ticks)))    // Don't forget to include network timing!
                         .ToArray();

            Log.Trace("Read {0:N0} bytes of entropy.", result.Length);

            return(result);
        }
Example #18
0
        protected override Task <byte[]> GetInternalEntropyAsync(EntropyPriority priority)
        {
            // This reads details of all network interfaces running on the system, and uses them as inputs to a hash for final result.
            // Given this isn't trivial work, we run in a separate threadpool task.

            return(Task.Run(() =>
            {
                Log.Trace("Beginning to gather entropy.");
                var ins = NetworkInterface.GetAllNetworkInterfaces();
                Log.Trace("Found {0:N0} interfaces.", ins.Length);

                // First result includes IP address, hardware address, etc.
                var allStats = new List <long>();
                if (!_HasRunOnce)
                {
                    Log.Trace("Including static properties on first run.");
                    allStats.AddRange(GetNetworkInterfaceStaticProperties(ins));
                    _HasRunOnce = true;
                }

                // After that, its just the number of packets, etc.
                foreach (var i in ins)
                {
                    // Most of these will be zero.
                    // Note that these can throw on some platforms, so we do a bunch of exception wrapping.
                    var stats = i.GetIPStatistics();
                    if (!_BytesReceivedFailed)
                    {
                        ExceptionHelper.TryAndIgnoreException(() => Uh.ToUnit(() => allStats.Add(stats.BytesReceived)), ref _BytesReceivedFailed);
                    }
                    if (!_BytesSentFailed)
                    {
                        ExceptionHelper.TryAndIgnoreException(() => Uh.ToUnit(() => allStats.Add(stats.BytesSent)), ref _BytesSentFailed);
                    }
                    if (!_IncomingPacketsDiscardedFailed)
                    {
                        ExceptionHelper.TryAndIgnoreException(() => Uh.ToUnit(() => allStats.Add(stats.IncomingPacketsDiscarded)), ref _IncomingPacketsDiscardedFailed);
                    }
                    if (!_IncomingPacketsWithErrorsFailed)
                    {
                        ExceptionHelper.TryAndIgnoreException(() => Uh.ToUnit(() => allStats.Add(stats.IncomingPacketsWithErrors)), ref _IncomingPacketsWithErrorsFailed);
                    }
                    if (!_IncomingUnknownProtocolPacketsFailed)
                    {
                        ExceptionHelper.TryAndIgnoreException(() => Uh.ToUnit(() => allStats.Add(stats.IncomingUnknownProtocolPackets)), ref _IncomingUnknownProtocolPacketsFailed);
                    }
                    if (!_NonUnicastPacketsReceivedFailed)
                    {
                        ExceptionHelper.TryAndIgnoreException(() => Uh.ToUnit(() => allStats.Add(stats.NonUnicastPacketsReceived)), ref _NonUnicastPacketsReceivedFailed);
                    }
                    if (!_NonUnicastPacketsSentFailed)
                    {
                        ExceptionHelper.TryAndIgnoreException(() => Uh.ToUnit(() => allStats.Add(stats.NonUnicastPacketsSent)), ref _NonUnicastPacketsSentFailed);
                    }
                    if (!_OutgoingPacketsDiscardedFailed)
                    {
                        ExceptionHelper.TryAndIgnoreException(() => Uh.ToUnit(() => allStats.Add(stats.OutgoingPacketsDiscarded)), ref _OutgoingPacketsDiscardedFailed);
                    }
                    if (!_OutgoingPacketsWithErrorsFailed)
                    {
                        ExceptionHelper.TryAndIgnoreException(() => Uh.ToUnit(() => allStats.Add(stats.OutgoingPacketsWithErrors)), ref _OutgoingPacketsWithErrorsFailed);
                    }
                    if (!_OutputQueueLengthFailed)
                    {
                        ExceptionHelper.TryAndIgnoreException(() => Uh.ToUnit(() => allStats.Add(stats.OutputQueueLength)), ref _OutputQueueLengthFailed);
                    }
                    if (!_UnicastPacketsReceivedFailed)
                    {
                        ExceptionHelper.TryAndIgnoreException(() => Uh.ToUnit(() => allStats.Add(stats.UnicastPacketsReceived)), ref _UnicastPacketsReceivedFailed);
                    }
                    if (!_UnicastPacketsSentFailed)
                    {
                        ExceptionHelper.TryAndIgnoreException(() => Uh.ToUnit(() => allStats.Add(stats.UnicastPacketsSent)), ref _UnicastPacketsSentFailed);
                    }

                    // Remaining lease duration.
                    if (!_AddressValidLifetimeFailed)
                    {
                        ExceptionHelper.TryAndIgnoreException(() => Uh.ToUnit(() =>
                        {
                            var props = i.GetIPProperties();
                            allStats.AddRange(props.UnicastAddresses.Select(x => x.AddressValidLifetime));
                        }), ref _AddressValidLifetimeFailed);
                    }
                }

                // Remove zeros and shuffle to prevent obvious correlations.
                var statsNoZero = allStats.Where(x => x != 0L).ToArray();
                Log.Trace("Read {0:N0} non-zero stat items.", statsNoZero.Length);
                if (LogRawStats)
                {
                    Log.Trace("Raw stats: ", statsNoZero.LongsToHexString());
                }

                // Shuffle the details, so there isn't a repetition of similar stats.
                statsNoZero.ShuffleInPlace(_Rng);

                // Convert to digest byte array to return.
                var result = ByteArrayHelpers.LongsToDigestBytes(statsNoZero, _ItemsPerResultChunk);
                Log.Trace("Converted stats to {0:N0} bytes of entropy.", result.Length);

                return result;
            }));
        }
Example #19
0
        protected override async Task <byte[]> GetInternalEntropyAsync(EntropyPriority priority)
        {
            // http://qrng.anu.edu.au/index.php

            Log.Trace("Beginning to gather entropy.");

            // Fetch data.
            // This always returns 1024 bytes!!
            var response = "";
            var sw       = Stopwatch.StartNew();

            if (!_UseDiskSourceForUnitTests)
            {
                var apiUri = new Uri("https://qrng.anu.edu.au/RawHex.php");
                var hc     = HttpClientHelpers.Create(userAgent: _UserAgent);
                try
                {
                    response = await hc.GetStringAsync(apiUri);
                }
                catch (Exception ex)
                {
                    Log.Warn(ex, "Unable to GET from {0}", apiUri);
                    return(null);
                }
                Log.Trace("Read {0:N0} characters of html in {1:N2}ms.", response.Length, sw.Elapsed.TotalMilliseconds);
            }
            else
            {
                using (var stream = File.OpenRead(HttpClientHelpers._BasePathToUnitTestData + "qrng.anu.edu.au-RawHex.php.html"))
                {
                    response = await new StreamReader(stream).ReadToEndAsync();
                }
            }
            sw.Stop();


            // Locate some pretty clear boundaries around the random numbers returned.
            var startIdxString = "1024 bytes of randomness in hexadecimal form";
            var startIdx       = response.IndexOf(startIdxString, StringComparison.OrdinalIgnoreCase);

            if (startIdx == -1)
            {
                Log.Error("Cannot locate start string in html of anu result: source will return nothing. Looking for '{0}', actual result in next message.", startIdxString);
                Log.Error(response);
                return(null);
            }

            var startIdxString2 = "<td>";

            startIdx = response.IndexOf(startIdxString2, startIdx, StringComparison.OrdinalIgnoreCase) + startIdxString2.Length;
            if (startIdx == -1)
            {
                Log.Error("Cannot locate start string in html of anu result: source will return nothing. Looking for '{0}', actual result in next message.", startIdxString2);
                Log.Error(response);
                return(null);
            }

            var endIdxString = "</td>";
            var endIdx       = response.IndexOf(endIdxString, startIdx, StringComparison.OrdinalIgnoreCase);

            if (endIdx == -1)
            {
                Log.Error("Cannot locate end string in html of anu result: source will return nothing. Looking for '{0}', actual result in next message.", endIdxString);
                Log.Error(response);
                return(null);
            }
            Log.Trace("Parsed beginning and end of useful entropy.");

            // Trim and parse.
            var randomString = response.Substring(startIdx, endIdx - startIdx).Trim();
            var randomBytes  = randomString.ParseFromHexString()
                               .Concat(BitConverter.GetBytes(unchecked ((uint)sw.Elapsed.Ticks)))      // Don't forget to include network timing!
                               .ToArray();

            Log.Trace("Read {0:N0} bytes of entropy (including 4 bytes of timing info).", randomBytes.Length);

            return(randomBytes);
        }
Example #20
0
 public Task <byte[]> GetEntropyAsync(EntropyPriority priority)
 {
     return(Task.FromResult(new byte[8]));
 }
        private async Task <byte[]> GetApiEntropyAsync(EntropyPriority priority)
        {
            // http://www.random.org/

            // https://api.random.org/json-rpc/2/introduction
            // https://api.random.org/json-rpc/2/basic
            // https://api.random.org/json-rpc/2/request-builder

            // Fetch data.
            var response = "";
            var sw       = Stopwatch.StartNew();

            if (!_UseDiskSourceForUnitTests)
            {
                var apiUri      = new Uri("https://api.random.org/json-rpc/2/invoke");
                var hc          = HttpClientHelpers.Create(userAgent: _UserAgent);
                var requestBody = "{\"jsonrpc\":\"2.0\",\"method\":\"generateBlobs\",\"params\":{\"apiKey\":\"" + _ApiKey.ToString("D") + "\",\"n\":1,\"size\":" + (_BytesPerRequest * 8) + ",\"format\":\"base64\"},\"id\":1}";
                try
                {
                    response = await hc.PostStringAsync(apiUri, requestBody, "application/json");
                }
                catch (Exception ex)
                {
                    Log.Warn(ex, "Unable to POST to {0} with body {1}", apiUri, requestBody);
                    return(null);
                }
                Log.Trace("Read {0:N0} characters of html in {1:N2}ms.", response.Length, sw.Elapsed.TotalMilliseconds);
            }
            else
            {
                using (var stream = File.OpenRead(HttpClientHelpers._BasePathToUnitTestData + "api.random.org.html"))
                {
                    response = await new StreamReader(stream).ReadToEndAsync();
                }
            }
            sw.Stop();

            // To avoid using dynamic or a Json library, we do hacky string parsing!

            // Check for error.
            if (response.IndexOf("\"error\":") != -1)
            {
                Log.Error("Random.org API returned error result. Full result in next message.");
                Log.Error(response);
                return(null);
            }
            int dataIdx = response.IndexOf("\"data\":[\"");

            if (dataIdx == -1)
            {
                Log.Error("Cannot locate random result in random.org API result: source will return nothing. Actual result in next message.");
                Log.Error(response);
                return(null);
            }
            dataIdx = dataIdx + "\"data\":[\"".Length;
            int endIdx = response.IndexOf("\"]", dataIdx);

            if (endIdx == -1)
            {
                Log.Error("Cannot locate end of random result in random.org API result: source will return nothing. Actual result in next message.");
                Log.Error(response);
                return(null);
            }
            Log.Trace("Parsed Json result.");

            // Trim and parse.
            var randomString = response.Substring(dataIdx, endIdx - dataIdx).Trim();
            var randomBytes  = Convert.FromBase64String(randomString)
                               .Concat(BitConverter.GetBytes(unchecked ((uint)sw.Elapsed.Ticks))) // Don't forget to include network timing!
                               .ToArray();

            Log.Trace("Read {0:N0} bytes of entropy (including 4 bytes of timing info).", randomBytes.Length);

            return(randomBytes);
        }
Example #22
0
        protected override async Task <byte[]> GetInternalEntropyAsync(EntropyPriority priority)
        {
            // http://qrng.ethz.ch/http_api/

            Log.Trace("Beginning to gather entropy.");

            // Fetch data.
            var response = "";
            var sw       = Stopwatch.StartNew();

            if (!_UseDiskSourceForUnitTests)
            {
                var apiUri = new Uri("http://qrng.ethz.ch/api/randint?min=0&max=255&size=" + _BytesPerRequest);
                var hc     = HttpClientHelpers.Create(userAgent: _UserAgent);
                try
                {
                    response = await hc.GetStringAsync(apiUri);
                }
                catch (Exception ex)
                {
                    Log.Warn(ex, "Unable to GET from {0}", apiUri);
                    return(null);
                }
                Log.Trace("Read {0:N0} characters of json in {1:N2}ms.", response.Length, sw.Elapsed.TotalMilliseconds);
            }
            else
            {
                using (var stream = File.OpenRead(HttpClientHelpers._BasePathToUnitTestData + "qrng.ethz.ch-randint.txt"))
                {
                    response = await new StreamReader(stream).ReadToEndAsync();
                }
            }
            sw.Stop();


            // To avoid using dynamic or a Json library, we do hacky string parsing!

            // Check for valid result.
            if (response.IndexOf("\"result\":") == -1)
            {
                Log.Error("qrng.ethz.ch returned unknown result. Full result in next message.");
                Log.Error(response);
                return(null);
            }
            int dataIdx = response.IndexOf("[");

            if (dataIdx == -1)
            {
                Log.Error("Cannot locate random result in qrng.ethz.ch response: source will return nothing. Actual result in next message.");
                Log.Error(response);
                return(null);
            }
            dataIdx = dataIdx + 1;
            int endIdx = response.IndexOf("]", dataIdx);

            if (endIdx == -1)
            {
                Log.Error("Cannot locate end of random result in qrng.ethz.ch response: source will return nothing. Actual result in next message.");
                Log.Error(response);
                return(null);
            }
            Log.Trace("Parsed Json result.");

            // Trim and parse.
            var randomInts          = response.Substring(dataIdx, endIdx - dataIdx).Trim();
            var numbersAndOtherJunk = randomInts.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            var result = numbersAndOtherJunk
                         .Select(x => (x ?? "").Trim())
                         .Where(x => x.All(Char.IsDigit))                                   // Remove non-numeric junk.
                         .Select(x => Byte.Parse(x))                                        // Parse to byte.
                         .Concat(BitConverter.GetBytes(unchecked ((uint)sw.Elapsed.Ticks))) // Don't forget to include network timing!
                         .ToArray();

            Log.Trace("Read {0:N0} bytes of entropy (including 4 bytes of timing info).", result.Length);

            return(result);
        }
        protected override async Task <byte[]> GetInternalEntropyAsync(EntropyPriority priority)
        {
            // http://www.fourmilab.ch/hotbits/
            Log.Trace("Beginning to gather entropy.");

            string pseudoSource, apiKey;

            if (String.IsNullOrWhiteSpace(_ApiKey))
            {
                pseudoSource = "&pseudo=pseudo";
                apiKey       = "&apikey=";
            }
            else
            {
                pseudoSource = "";
                apiKey       = "&apikey=" + _ApiKey;
            }

            // Fetch data.
            var response = "";
            var sw       = Stopwatch.StartNew();

            if (!_UseDiskSourceForUnitTests)
            {
                var apiUri = new Uri("https://www.fourmilab.ch/cgi-bin/Hotbits.api?nbytes=" + _BytesPerRequest + "&fmt=hex&npass=1&lpass=8&pwtype=3" + apiKey + pseudoSource);
                var hc     = HttpClientHelpers.Create(userAgent: _UserAgent);
                try
                {
                    response = await hc.GetStringAsync(apiUri);
                }
                catch (Exception ex)
                {
                    Log.Warn(ex, "Unable to GET from {0}", apiUri);
                    return(null);
                }
                Log.Trace("Read {0:N0} characters of html in {1:N2}ms.", response.Length, sw.Elapsed.TotalMilliseconds);
            }
            else
            {
                using (var stream = File.OpenRead(HttpClientHelpers._BasePathToUnitTestData + "hotbits.html"))
                {
                    response = await new StreamReader(stream).ReadToEndAsync();
                }
            }
            sw.Stop();


            // Locate some pretty clear boundaries around the random numbers returned.
            var startIdx = response.IndexOf("<pre>", StringComparison.OrdinalIgnoreCase) + "<pre>".Length;

            if (startIdx == -1)
            {
                Log.Error("Cannot locate start string in html of hotbits result: source will return nothing. Actual result in next message.");
                Log.Error(response);
                return(null);
            }
            var endIdx = response.IndexOf("</pre>", startIdx, StringComparison.OrdinalIgnoreCase);

            if (endIdx == -1)
            {
                Log.Error("Cannot locate end string in html of hotbits result: source will return nothing. Actual result in next message.");
                Log.Error(response);
                return(null);
            }
            var randomString = response.Substring(startIdx, endIdx - startIdx).Trim().Replace("\r", "").Replace("\n", "");

            Log.Trace("Parsed beginning and end of useful entropy.");

            var randomBytes = randomString.ParseFromHexString()
                              .Concat(BitConverter.GetBytes(unchecked ((uint)sw.Elapsed.Ticks)))       // Don't forget to include network timing!
                              .ToArray();

            Log.Trace("Read {0:N0} bytes of entropy (including 4 bytes of timing info).", randomBytes.Length);

            return(randomBytes);
        }