Last active
August 29, 2015 14:04
-
-
Save SidShetye/97631352f54a68184418 to your computer and use it in GitHub Desktop.
Cleaned up, non-interactive, non-threaded version of http://upokecenter.dreamhosters.com/articles/2011/04/entropy-source-random-seed-generator-in-c/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class Entropy | |
{ | |
private const long Prime = 179426549; | |
private const long Prime2 = 46633; // another prime | |
public static long GetEntropySeed() | |
{ | |
return Ticks ^ ProcessInfoKey() ^ MemorySizeKey() ^ EnvironmentKey(); | |
} | |
private static long Ticks | |
{ | |
get | |
{ | |
if (Environment.OSVersion.Platform == PlatformID.Win32Windows || | |
Environment.OSVersion.Platform == PlatformID.Win32NT) | |
{ | |
long x = 0; | |
NativeMethods.QueryPerformanceCounter(ref x); | |
return x; | |
} | |
return DateTime.Now.Ticks; | |
} | |
} | |
[SuppressUnmanagedCodeSecurity] | |
private static class NativeMethods | |
{ | |
/// <summary> | |
/// High resolution timer (less than 1us) | |
/// </summary> | |
/// <param name="x"></param> | |
/// <returns></returns> | |
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)] | |
public static extern int QueryPerformanceCounter(ref long x); | |
} | |
private static string GetCommandOutput(string fn, string args) | |
{ | |
var psi = new ProcessStartInfo(fn, args) | |
{ | |
RedirectStandardOutput = true, | |
RedirectStandardError = true, | |
UseShellExecute = false, | |
CreateNoWindow = true, | |
WindowStyle = ProcessWindowStyle.Hidden | |
}; | |
try | |
{ | |
using (var process = Process.Start(psi)) | |
{ | |
if (process != null) | |
{ | |
var o = process.StandardOutput.ReadToEnd(); | |
var e = process.StandardError.ReadToEnd(); | |
process.WaitForExit(); | |
return o + e; | |
} | |
} | |
} | |
catch (Win32Exception) { } | |
catch (SystemException) { } | |
return String.Empty; | |
} | |
#region [Sources of entropy] | |
private static long ProcessInfoKey() | |
{ | |
var commandHashes = new List<int>(); | |
var processOffset = 0; | |
long data; | |
if (Environment.OSVersion.Platform == PlatformID.Unix) | |
{ | |
if (processOffset >= commandHashes.Count) | |
{ | |
commandHashes.Clear(); | |
var cmd = GetCommandOutput("/bin/ps", "-A v"); | |
for (var i = 0; i < cmd.Length; i++) | |
commandHashes.Add(cmd.Substring(i, Math.Min(cmd.Length - i, 512)).GetHashCode()); | |
} | |
processOffset = 0; | |
data = unchecked((Ticks & 0xFFFFFFFF) ^ (Ticks >> 32)); | |
while (processOffset < commandHashes.Count) | |
{ | |
long ret = unchecked(commandHashes[processOffset++]); | |
ret ^= unchecked(data); | |
return ret; | |
} | |
return unchecked(data); | |
} | |
else | |
{ | |
processOffset = 0; | |
var processes = Process.GetProcesses(); | |
data = unchecked((int)((Ticks & 0xFFFFFFFF) ^ (Ticks >> 32))); | |
while (processOffset < processes.Length) | |
{ | |
long ret = 0; | |
if (ProcessInfoHash(processes[processOffset++], out ret)) | |
{ | |
ret ^= unchecked(data); | |
return ret; | |
} | |
} | |
return unchecked(data); | |
} | |
} | |
private static long MemorySizeKey() | |
{ | |
if (Environment.OSVersion.Platform == PlatformID.Win32NT) | |
{ | |
var proc = Process.GetCurrentProcess(); | |
try | |
{ | |
long data = proc.PagedMemorySize64 & 0xFFFFFFFF; | |
data = unchecked(data << 32); | |
data |= proc.PrivateMemorySize64 & 0xFFFFFFFF; | |
return unchecked(data); | |
} | |
catch (PlatformNotSupportedException) | |
{ | |
return unchecked((Ticks & 0xFFFFFFFF) ^ (Ticks >> 32)); | |
} | |
} | |
if (Environment.OSVersion.Platform == PlatformID.Unix) | |
{ | |
var data = unchecked((Ticks & 0xFFFFFFFF) ^ (Ticks >> 32)); | |
if ((data & 0xFF) < 64) | |
{ | |
using (var fs = new FileStream("/dev/urandom", | |
FileMode.Open)) | |
{ | |
var data2 = new byte[8]; | |
fs.Read(data2, 0, data2.Length); | |
data ^= BitConverter.ToInt64(data2, 0); | |
} | |
} | |
return unchecked(data); | |
} | |
return unchecked((Ticks & 0xFFFFFFFF) ^ (Ticks >> 32)); | |
} | |
private static long EnvironmentKey() | |
{ | |
long data = unchecked(((Ticks & 0xFFFFFFFF) ^ (Ticks >> 32))); | |
try | |
{ | |
var dict = Environment.GetEnvironmentVariables(); | |
data = unchecked(data*Prime + dict.Count); | |
var keylist = new List<string>(); | |
foreach (var o in dict.Keys) | |
{ | |
keylist.Add((string) o); | |
} | |
for (var i = 0; i < keylist.Count; i++) | |
{ | |
int shuffle = unchecked((int)((dict.Count == 0) ? 0 : (data & 0xFFFF) % dict.Count)); | |
var index = (i + shuffle)%keylist.Count; | |
var key = keylist[index]; | |
var k = key.GetHashCode(); | |
var v = dict[key].GetHashCode(); | |
unchecked | |
{ | |
data = data * Prime + k; | |
data = data * Prime + v; | |
} | |
} | |
} | |
catch (SecurityException) | |
{ | |
} | |
unchecked | |
{ | |
data *= Prime; | |
data += (int)Environment.OSVersion.Platform; | |
data *= Prime; | |
data += Environment.StackTrace.GetHashCode(); | |
} | |
return unchecked(data); | |
} | |
private static bool ProcessInfoHash(Process proc, out long retval) | |
{ | |
long value = Prime2; | |
unchecked | |
{ | |
if (Environment.OSVersion.Platform == PlatformID.Win32NT) | |
{ | |
long shuffle = 0; /* variable designed to shuffle the order | |
in which the process data is incorporated | |
into the hash code, to add unpredictability*/ | |
try | |
{ | |
value = value * Prime + proc.StartTime.Ticks.GetHashCode(); | |
value = value * Prime + proc.PrivilegedProcessorTime.Ticks.GetHashCode(); | |
value = value * Prime + proc.TotalProcessorTime.Ticks.GetHashCode(); | |
shuffle = ((value ^ (Ticks & 0xFFFF)) % 6); | |
shuffle = Math.Abs(shuffle); | |
} | |
catch (NotSupportedException) | |
{ | |
} | |
catch (InvalidOperationException) | |
{ | |
} | |
catch (Win32Exception) | |
{ | |
value = proc.PagedMemorySize64.GetHashCode(); | |
shuffle = ((value ^ (Ticks & 0xFFFF)) % 6); | |
shuffle = Math.Abs(shuffle); | |
} | |
for (var i = 0; i < 6; i++) | |
{ | |
var rv = (shuffle + i) % 6; | |
switch (rv) | |
{ | |
case 0: | |
value *= Prime; | |
try | |
{ | |
value += proc.Id; | |
} | |
catch (InvalidOperationException) | |
{ | |
} | |
break; | |
case 1: | |
value = value * Prime + proc.PrivateMemorySize64.GetHashCode(); | |
break; | |
case 2: | |
value = value * Prime + proc.WorkingSet64.GetHashCode(); | |
break; | |
case 3: | |
value = value * Prime + proc.PagedMemorySize64.GetHashCode(); | |
break; | |
case 4: | |
try | |
{ | |
value = value * Prime + proc.Threads.Count; | |
if (proc.Threads.Count > 0) | |
{ | |
var shuffle2 = Math.Abs(value % proc.Threads.Count); | |
for (var j = 0; j < proc.Threads.Count; j++) | |
{ | |
var idx = (int) ((j + shuffle2) % proc.Threads.Count); | |
value = value * Prime + proc.Threads[idx].Id; | |
try | |
{ | |
value = value * Prime + | |
proc.Threads[idx].TotalProcessorTime.GetHashCode(); | |
value = value * Prime + | |
proc.Threads[idx].PrivilegedProcessorTime.GetHashCode(); | |
} | |
catch (NotSupportedException) | |
{ | |
} | |
catch (Win32Exception) | |
{ | |
} | |
} | |
} | |
} | |
catch (SystemException) | |
{ | |
} | |
break; | |
case 5: | |
value = value * Prime; | |
try | |
{ | |
value += proc.ProcessName.GetHashCode(); | |
} | |
catch (SystemException) | |
{ | |
} | |
break; | |
} | |
} | |
} | |
else if (Environment.OSVersion.Platform == PlatformID.Win32Windows) | |
{ | |
try | |
{ | |
proc.StartInfo.UseShellExecute = false; | |
value = value * Prime; | |
try | |
{ | |
value += proc.ProcessName.GetHashCode(); | |
} | |
catch (SystemException) | |
{ | |
} | |
value = value * Prime + (int)proc.HandleCount; | |
try | |
{ | |
value = value * Prime + proc.Threads.Count; | |
if (proc.Threads.Count > 0) | |
{ | |
var shuffle2 = Math.Abs(value % proc.Threads.Count); | |
for (var j = 0; j < proc.Threads.Count; j++) | |
{ | |
var idx = (int) (j + shuffle2) % proc.Threads.Count; | |
value = value * Prime + proc.Threads[idx].Id; | |
} | |
} | |
} | |
catch (SystemException) | |
{ | |
} | |
try | |
{ | |
value = value * Prime + proc.Id; | |
} | |
catch (InvalidOperationException) | |
{ | |
} | |
} | |
catch (PlatformNotSupportedException) | |
{ | |
value = value * Prime; | |
value += unchecked((int)((Ticks & 0xFFFFFFFF) ^ (Ticks >> 32))); | |
} | |
} | |
else | |
{ | |
value = value * Prime; | |
value += unchecked((int)((Ticks & 0xFFFFFFFF) ^ (Ticks >> 32))); | |
} | |
} | |
retval = unchecked(value); | |
return true; | |
} | |
#endregion | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment