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)); }
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); }
public Task <byte[]> GetEntropyAsync(EntropyPriority priority) { var result = _Entropy; _Entropy = null; return(Task.FromResult(result)); }
public async Task <byte[]> GetEntropyAsync(EntropyPriority priority) { var result = new byte[_ResultLength]; _Rng.GetBytes(result); await Task.Delay(50); return(result); }
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)); }
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)); } }
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); }
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)); }
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)); }
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); }
private TimeSpan PriorityToPeriod(EntropyPriority priority) => priority == EntropyPriority.Normal ? _PeriodNormalPriority : priority == EntropyPriority.High ? _PeriodHighPriority : priority == EntropyPriority.Low ? _PeriodLowPriority : _PeriodNormalPriority; // Shouldn't happen.
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); }
public Task <byte[]> GetEntropyAsync(EntropyPriority priority) { // Increment the counter and return its value. _Counter.Increment(); return(Task.FromResult(_Counter.GetCounter())); }
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); }
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; })); }
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); }
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); }
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); }