JitterCacheRng.cs

Posted on June 4, 2020June 28, 2020Tags , ,   Leave a comment on JitterCacheRng.cs
using System;
using System.Security.Cryptography;
using System.Threading;
[Serializable]
public class JitterCacheRng : RandomNumberGenerator
{
    private const    int        ReSecureThreshold = 10;
    private readonly SHA3ModInt _algorithm;
    private readonly JitterEx   _jit;
    private readonly int        _moveSize;
    private          int        _availableCacheBytes;
    private          byte[]     _cache;
    private          byte[]     _cacheBuffer;
    private          int        _cacheSize;
    private          int        _ptr;
    public           int        cacheFills;
    public JitterCacheRng() : this(1048576, 256, 256, 4)
    {
    }
    public JitterCacheRng(int cacheSize) : this(cacheSize, 256, 256, 4)
    {
    }
    public JitterCacheRng(int cacheSize, int seedSize) : this(cacheSize, seedSize, 256, 4)
    {
    }
    public JitterCacheRng(int cacheSize, int seedSize, int sha3Size) : this(cacheSize, seedSize, sha3Size, 4)
    {
    }
    public JitterCacheRng(int cacheSize, int seedSize, int sha3Size, int sha3Rounds)
    {
        if (cacheSize == 0)
            throw new ArgumentException("Cache Size cannot be zero");
        if (seedSize < 256)
            throw new ArgumentException("The seed size should be 256 or more bytes.");
        if (sha3Size < 64 && sha3Size % 64 != 0)
            throw new ArgumentException("The bitWidth of the SHA3 hash algorithm need to be at least 64 bits and a multiple of 64.");
        if (sha3Rounds < 4)
            throw new ArgumentException("Sha3 rounds of less than 4 might produce some short run repetitive sequences.");
        _cacheSize   = cacheSize;
        _jit         = new JitterEx(seedSize);
        _cacheBuffer = _jit.GetBuffer();
        _cache       = new byte[_cacheSize];
        _algorithm   = new SHA3ModInt(sha3Size, sha3Rounds);
        _moveSize    = _algorithm.ComputeHash(2.GetBytes()).Length;
        FillCache();
    }
    public bool Protect
    {
        get;
        set;
    }
    protected override void Dispose(bool disposing)
    {
        _cache.Fill(0);
        _availableCacheBytes = 0;
        _algorithm.Dispose();
    }
    public override void GetBytes(byte[] data)
    {
        if (data.Length > _cacheSize)
        {
            _cacheSize = data.Length;
            _cache     = new byte[_cacheSize];
            FillCache();
        }
        if (_availableCacheBytes == 0 || _availableCacheBytes < data.Length)
        {
            if (_cacheSize < data.Length)
            {
                _cacheSize = data.Length;
                _cache     = new byte[_cacheSize];
            }
            FillCache();
        }
        if (_ptr + data.Length > _cacheSize)
            FillCache();
        if (Protect)
            ProtectedMemory.Unprotect(_cache, MemoryProtectionScope.SameLogon);
        Buffer.BlockCopy(_cache, _ptr, data, 0, data.Length);
        if (Protect)
            ProtectedMemory.Protect(_cache, MemoryProtectionScope.SameLogon);
        _ptr                 += data.Length;
        _availableCacheBytes -= data.Length;
    }
    private void FillCache()
    {
        var btrd = new Thread(() =>
        {
            _availableCacheBytes = 0;
            _ptr                 = 0;
            var p        = 0;
            var moveSize = _moveSize;
            cacheFills++;
            if (cacheFills % ReSecureThreshold == 0)
                _cacheBuffer = _jit.GetBuffer();
            if (Protect)
                ProtectedMemory.Unprotect(_cache, MemoryProtectionScope.SameLogon);
            while (true)
            {
                var remainingBytesToMove = _cacheSize - _availableCacheBytes;
                if (remainingBytesToMove < moveSize)
                    moveSize = remainingBytesToMove;
                if (remainingBytesToMove <= 0)
                    break;
                _cacheBuffer = _algorithm.ComputeHash(_cacheBuffer);
                Buffer.BlockCopy(_cacheBuffer, 0, _cache, p, moveSize);
                p                    += moveSize;
                _availableCacheBytes += moveSize;
            }
            if (Protect)
                ProtectedMemory.Protect(_cache, MemoryProtectionScope.SameLogon);
        }) {Priority = ThreadPriority.Highest};
        btrd.Start();
        btrd.Join();
    }
}

JitterEx.cs

Posted on June 4, 2020June 28, 2020Tags , , ,   Leave a comment on JitterEx.cs
using System;
using System.Diagnostics;
using System.Linq;
using System.Management;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using System.Threading;
[Serializable]
public class JitterEx
{
    private const    int                      DesaturationLoopLimit = 500;
    private const    int                      UpperCpuLoadLimit     = 90;
    private const    int                      LowerCpuLoadLimit     = 10;
    private static   bool                     _scaleSet;
    private readonly int                      _bufferSize;
    private readonly object                   _lock = new object();
    private readonly RNGCryptoServiceProvider _prng;
    private          byte[]                   _rngCache;
    private          int                      _tscLoopLimitCpu  = 20;
    private          int                      _tscSampleSizeRam = 10;
    public JitterEx(int buffersize)
    {
        if (buffersize < 256)
            throw new ArgumentException("Buffer Size cannot be less than 256 bytes.");
        _bufferSize = buffersize;
        _rngCache   = new byte[_bufferSize];
        _prng       = new RNGCryptoServiceProvider();
        SetScale();
    }
    private float GetCpuSpeed()
    {
        void Loop()
        {
            var i = 0;
            while (true)
                i = i + 1 - 1;
        }
        var cpuCounter = new PerformanceCounter("Processor Information", "% Processor Performance", "_Total");
        var cpuValue   = cpuCounter.NextValue();
        var loop       = new Thread(() => Loop()) {Priority = ThreadPriority.Highest};
        var Speed      = 0f;
        lock (_lock)
        {
            loop.Start();
            Thread.Sleep(60);
            cpuValue = cpuCounter.NextValue();
            loop.Abort();
        }
        foreach (ManagementObject obj in new ManagementObjectSearcher("SELECT *, Name FROM Win32_Processor").Get())
            Speed = Convert.ToSingle(obj["MaxClockSpeed"]) / 1000 * cpuValue / 100;
        return Speed;
    }
    /// <summary>
    ///     This is a fairly arbitrary value which is based on the CPU speed
    /// </summary>
    private void SetScale()
    {
        if (_scaleSet)
            return;
        _scaleSet = true;
        const float baseFreq = 4.277f;
        var         thisFreq = GetCpuSpeed();
        var         rat      = baseFreq / thisFreq;
        _tscLoopLimitCpu  = (int) Math.Ceiling(_tscLoopLimitCpu  * rat);
        _tscSampleSizeRam = (int) Math.Ceiling(_tscSampleSizeRam * rat);
    }
    private void LoadBlock()
    {
        var DesaturationLoops = 0;
        var dump              = CpuTotalPc.CPULoad;
        do
        {
            Thread.Sleep(0);
            DesaturationLoops++;
        } while (DesaturationLoops < DesaturationLoopLimit && ((int) CpuTotalPc.CPULoad > UpperCpuLoadLimit || (int) CpuTotalPc.CPULoad < LowerCpuLoadLimit));
    }
    [MethodImpl(MethodImplOptions.NoInlining)]
    private byte[] GetBufferCpu()
    {
        var jitterBuffer = new byte[_bufferSize];
        var loop         = 0;
        while (true)
        {
            var ptr = 0;
            var x   = 0;
            LoadBlock();
            lock (_lock)
            {
                var start = Rdtsc.TimestampP();
                do
                {
                    for (var i = 0; i < _tscLoopLimitCpu; i++)
                        x = x + 1 - 1;
                    var stop = Rdtsc.TimestampP();
                    Buffer.BlockCopy((100000.0 / ((stop - start) * 100000.0)).GetBytes(), 0, jitterBuffer, ptr, 4);
                    start =  stop;
                    ptr   += 4;
                } while (ptr < _bufferSize);
                return jitterBuffer;
            }
        }
        return jitterBuffer;
    }
    [MethodImpl(MethodImplOptions.NoInlining)]
    private unsafe byte[] GetBufferRam()
    {
        LoadBlock();
        var jitterBuffer = new byte[_bufferSize];
        lock (_lock)
        {
            if (_rngCache.Length != _bufferSize)
                _rngCache = new byte[_bufferSize];
            _prng.GetBytes(_rngCache);
            var  ptr = 0;
            byte tempByte;
            var  start = Rdtsc.TimestampP();
            while (true)
            {
                fixed (byte* p1 = _rngCache)
                {
                    var x1 = p1;
                    for (var j = 0; j < _tscSampleSizeRam; ++j, ++x1)
                        tempByte = *x1;
                }
                var stop = Rdtsc.TimestampP();
                Buffer.BlockCopy((100000.0 / ((stop - start) * 100000.0)).GetBytes(), 0, jitterBuffer, ptr, 4);
                start =  stop;
                ptr   += 4;
                if (ptr < _bufferSize)
                {
                    if (_rngCache.Length != _bufferSize)
                        _rngCache = new byte[_bufferSize];
                    _prng.GetBytes(_rngCache);
                }
                else
                {
                    break;
                }
            }
        }
        return jitterBuffer;
    }
    private double Entropy(byte[] ba)
    {
        var map = new int[256];
        foreach (var i in ba)
            map[i]++;
        var lot = Math.Log(2);
        return map.Where(item => item > 0).Select(item => item / (double) ba.Length).Aggregate(0.0, (current, frequency) => current - frequency * (Math.Log(frequency) / lot));
    }
    public byte[] GetBuffer()
    {
        var firstBuffer  = GetBufferCpu();
        var secondBuffer = GetBufferRam();
        var finalBuffer  = new byte[_bufferSize];
        for (var j = 0; j < _bufferSize; ++j)
            finalBuffer[j] = (byte) (firstBuffer[j] ^ secondBuffer[j]);
        return finalBuffer;
    }
}