Skip to content

Instantly share code, notes, and snippets.

@mjs3339
Created November 12, 2018 10:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mjs3339/7fcab260d689b9c29eea40d32b294caf to your computer and use it in GitHub Desktop.
Save mjs3339/7fcab260d689b9c29eea40d32b294caf to your computer and use it in GitHub Desktop.
C# Create a Crypto Strength Seed Buffer from CPU Jitter or Noise
public class CryptoJitterSeedBytes
{
private readonly object _lock = new object();
public byte[] SeedBuffer => !BypassEntropy ? GetSeed() : MeasureCPUJitter(SeedBufferSize);
public bool BypassEntropy {get; set;}
public bool LoopTesting {get; set;}
public double BufferEntropy {get; private set;}
public bool BypassCPULoadTest {get; set;}
public int SeedBufferSize {get; set;} = 64;
public int PCLimit {get; set;} = 80000;
public int SeedBufferSizeLimit {get; set;} = 20480;
public double MinimumEntropyThreshold {get; set;} = 5.0;
public double CriticalFailureEntropyThreshold{get; set;} = 3.0;
[DllImport("kernel32.dll")]
private static extern bool QueryPerformanceCounter(out long lpPerformanceCount);
[DllImport("kernel32.dll")]
private static extern bool QueryPerformanceFrequency(out long lpFrequency);
private byte[] GetSeed()
{
while(true)
{
var _seedBuffer = MeasureCPUJitter(SeedBufferSize);
if(BufferEntropy < MinimumEntropyThreshold && SeedBufferSize < SeedBufferSizeLimit)
SeedBufferSize *= 2;
else
return _seedBuffer;
}
}
private byte[] MeasureCPUJitter(int bufsize)
{
var c = 0;
var JitterBuffer = new byte[bufsize];
var _ptr = 0;
var inc = 0;
var th1 = new Thread(() =>
{
if(!BypassCPULoadTest)
{
var dump = CPUTotalPC.CPULoad;
do
{
Thread.Sleep(0);
c++;
if(c >= 500)
break;
} while((int) CPUTotalPC.CPULoad > 50);
}
lock(_lock)
{
QueryPerformanceFrequency(out var Frequency);
QueryPerformanceCounter(out var start);
while(true)
{
for(var i = 0; i < PCLimit; i++)
{
inc++;
inc++;
inc++;
inc++;
inc++;
inc++;
inc++;
inc++;
inc++;
inc++;
inc++;
inc++;
inc++;
inc++;
inc++;
inc++;
inc++;
inc++;
inc++;
inc++;
inc++;
inc++;
inc++;
inc++;
inc++;
inc++;
inc++;
inc++;
inc++;
inc++;
inc++;
inc++;
inc++;
inc++;
inc++;
inc++;
inc++;
inc++;
inc++;
inc++;
inc++;
inc++;
inc++;
inc++;
inc++;
inc++;
inc++;
inc++;
}
QueryPerformanceCounter(out var stop);
Buffer.BlockCopy((1000000.0 / ((stop - start) * 1000000.0 / Frequency / 1000.0)).GetBytes(), 0, JitterBuffer, _ptr, 4);
start = stop;
_ptr += 4;
if(_ptr >= bufsize)
break;
}
}
}) {Priority = ThreadPriority.Highest};
th1.Start();
th1.Join();
if(!LoopTesting)
if((BufferEntropy = Entropy(JitterBuffer)) <= CriticalFailureEntropyThreshold)
throw new Exception($"Buffer entropy {BufferEntropy:0.0} has fallen below the critical failure level {CriticalFailureEntropyThreshold:0.0}");
return JitterBuffer;
}
private static double Entropy(byte[] ba)
{
var map = new int[256];
foreach(var i in ba)
map[i]++;
var lot = Math.Log(2);
return(from item in map where item > 0 select item / (double) ba.Length).Aggregate(0.0, (current, frequency) => current - frequency * (Math.Log(frequency) / lot));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment