Skip to content

Instantly share code, notes, and snippets.

@mjs3339
Last active November 16, 2018 05:16
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/e466c7dc78d55bcb8c26e0eb9d3dc6fc to your computer and use it in GitHub Desktop.
Save mjs3339/e466c7dc78d55bcb8c26e0eb9d3dc6fc to your computer and use it in GitHub Desktop.
C# Get a Cryptographically Strong Byte Array
public class CryptoGetBytes : RandomNumberGenerator
{
private readonly int _hashSizeInBytes;
private int _availableCacheBytes;
private volatile byte[] _buffer;
private volatile byte[] _cache;
private volatile int _ptr;
public HashAlgorithm Algorithm;
#if DEBUG
public TinyDictionary<int, long> BytesRequestList = new TinyDictionary<int, long>();
#endif
public CryptoGetBytes(byte[] seed, HashAlgorithm algorithm = null)
{
Algorithm = algorithm ?? new SHA512CryptoServiceProvider();
_cache = new byte[CacheSize];
_availableCacheBytes = 0;
_ptr = 0;
_buffer = Algorithm.ComputeHash(seed);
_hashSizeInBytes = Algorithm.ComputeHash(2.GetBytes()).Length;
FillCache();
}
public CryptoGetBytes(HashAlgorithm algorithm = null)
{
Algorithm = algorithm ?? new SHA512CryptoServiceProvider();
_cache = new byte[CacheSize];
_availableCacheBytes = 0;
_ptr = 0;
_buffer = Algorithm.ComputeHash(new CryptoEntropy().Entropy);
_hashSizeInBytes = Algorithm.ComputeHash(2.GetBytes()).Length;
FillCache();
}
public CryptoGetBytes(int cacheSize, HashAlgorithm algorithm = null)
{
Algorithm = algorithm ?? new SHA512CryptoServiceProvider();
CacheSize = cacheSize;
_cache = new byte[CacheSize];
_availableCacheBytes = 0;
_ptr = 0;
_buffer = Algorithm.ComputeHash(new CryptoEntropy().Entropy);
_hashSizeInBytes = Algorithm.ComputeHash(2.GetBytes()).Length;
FillCache();
}
public int CacheSize{get; set;} = 1048576;
public int CacheFills{get; private set;}
public override void GetBytes(byte[] data)
{
lock(this)
{
if(data.IsNull())
throw new ArgumentException("Error: data is null in function: GetBytes, module: CryptoGetBytes.");
#if DEBUG
if (!BytesRequestList.ContainsKey(data.Length))
BytesRequestList.Add(data.Length, 1);
else
BytesRequestList[data.Length]++;
#endif
if(CacheSize != _cache.Length)
_cache = new byte[CacheSize];
if(_availableCacheBytes == 0 || _availableCacheBytes < data.Length)
{
if(CacheSize < data.Length)
{
CacheSize = data.Length;
_cache = new byte[CacheSize];
}
FillCache();
}
if(_ptr + data.Length > CacheSize)
FillCache();
Buffer.BlockCopy(_cache, _ptr, data, 0, data.Length);
_ptr += data.Length;
_availableCacheBytes -= data.Length;
}
}
private void FillCache()
{
CacheFills++;
_availableCacheBytes = 0;
_ptr = 0;
var p = 0;
var moveSize = _hashSizeInBytes;
do
{
_buffer = Algorithm.ComputeHash(_buffer);
var blit = CacheSize - _availableCacheBytes;
if(blit < moveSize)
moveSize = blit;
if(p + moveSize >= CacheSize)
break;
if(_cache.Length != CacheSize)
_cache = new byte[CacheSize];
Buffer.BlockCopy(_buffer, 0, _cache, p, moveSize);
p += moveSize;
_availableCacheBytes += moveSize;
} while(_availableCacheBytes < CacheSize);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment