SlunkCrypt/gui/Utilities/SecureRandom.cs

147 lines
4.3 KiB
C#

/******************************************************************************/
/* SlunkCrypt, by LoRd_MuldeR <MuldeR2@GMX.de> */
/* This work has been released under the CC0 1.0 Universal license! */
/******************************************************************************/
using System;
using System.IO;
using System.Security.Cryptography;
namespace com.muldersoft.slunkcrypt.gui.utils
{
class SecureRandom : IDisposable
{
private volatile bool m_disposed = false;
private readonly RNGCryptoServiceProvider m_provider;
private readonly byte[] m_tempBuffer = new byte[256];
private int m_offset = int.MaxValue;
// =============================================================================
// Constructor
// =============================================================================
public SecureRandom()
{
try
{
m_provider = new RNGCryptoServiceProvider();
}
catch (Exception e)
{
throw new IOException("Failed to create RNGCryptoServiceProvider instance!", e);
}
}
~SecureRandom()
{
Dispose();
}
// =============================================================================
// Public methods
// =============================================================================
public int NextInt32()
{
if (m_disposed)
{
throw new ObjectDisposedException("SecureRandom");
}
EnsureBytesAvailable(sizeof(int));
int value = BitConverter.ToInt32(m_tempBuffer, m_offset);
m_offset += sizeof(int);
return value;
}
public uint NextUInt32()
{
if (m_disposed)
{
throw new ObjectDisposedException("SecureRandom");
}
EnsureBytesAvailable(sizeof(uint));
uint value = BitConverter.ToUInt32(m_tempBuffer, m_offset);
m_offset += sizeof(uint);
return value;
}
public long NextInt64()
{
if (m_disposed)
{
throw new ObjectDisposedException("SecureRandom");
}
EnsureBytesAvailable(sizeof(long));
long value = BitConverter.ToInt64(m_tempBuffer, m_offset);
m_offset += sizeof(long);
return value;
}
public ulong NextUInt64()
{
if (m_disposed)
{
throw new ObjectDisposedException("SecureRandom");
}
EnsureBytesAvailable(sizeof(ulong));
ulong value = BitConverter.ToUInt64(m_tempBuffer, m_offset);
m_offset += sizeof(ulong);
return value;
}
public void Dispose()
{
if (!m_disposed)
{
m_disposed = true;
GC.SuppressFinalize(this);
try
{
FillArray(m_tempBuffer, 0);
}
finally
{
try
{
m_provider.Dispose();
}
catch { }
}
}
}
// =============================================================================
// Internal methods
// =============================================================================
private void EnsureBytesAvailable(int length)
{
if ((m_offset >= m_tempBuffer.Length) || ((m_tempBuffer.Length - m_offset) < length))
{
try
{
m_provider.GetBytes(m_tempBuffer);
m_offset = 0;
}
catch (Exception e)
{
throw new IOException("Failed to generated random bytes!", e);
}
}
}
private static void FillArray(byte[] array, byte value)
{
if (!ReferenceEquals(array, null))
{
for (int i = 0; i < array.Length; ++i)
{
array[i] = value;
}
}
}
}
}