Created
November 12, 2018 10:54
-
-
Save mjs3339/7fcab260d689b9c29eea40d32b294caf to your computer and use it in GitHub Desktop.
C# Create a Crypto Strength Seed Buffer from CPU Jitter or Noise
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 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