Last active
November 16, 2018 05:16
-
-
Save mjs3339/e466c7dc78d55bcb8c26e0eb9d3dc6fc to your computer and use it in GitHub Desktop.
C# Get a Cryptographically Strong Byte Array
This file contains hidden or 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 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