Adds IntelHW RDRand for Mac/Linux.

This commit is contained in:
Kamron Batman 2018-08-09 00:06:23 -07:00
parent fad41140d1
commit 62b95f4d74
No known key found for this signature in database
GPG key ID: 9F6247D24FA2AAD4
2 changed files with 144 additions and 4 deletions

View file

@ -21,11 +21,11 @@ namespace Server {
private static readonly IRandomImpl _Random;
static RandomImpl() {
if ( Core.Unix ) {
_Random = new CSPRandom();
if (Core.Unix && File.Exists("rdrand.so")) {
_Random = new RDRandUnix();
} else if (Core.Is64Bit && File.Exists("rdrand64.dll")) {
_Random = new RDRand64();
} else if ( !Core.Is64Bit && File.Exists("rdrand32.dll") ) {
} else if (File.Exists("rdrand.dll")) {
_Random = new RDRand32();
} else {
_Random = new CSPRandom();
@ -215,8 +215,148 @@ namespace Server {
}
}
public sealed class RDRandUnix : IRandomImpl, IHardwareRNG
{
internal class SafeNativeMethods
{
[DllImport("rdrand.so")]
internal static extern RDRandError rdrand_32(ref uint rand, bool retry);
[DllImport("rdrand.so")]
internal static extern RDRandError rdrand_get_bytes(int n, byte[] buffer);
}
private static int BUFFER_SIZE = 0x10000;
private static int LARGE_REQUEST = 0x40;
private byte[] _Working = new byte[BUFFER_SIZE];
private byte[] _Buffer = new byte[BUFFER_SIZE];
private int _Index = 0;
private object _sync = new object();
private ManualResetEvent _filled = new ManualResetEvent(false);
public RDRandUnix()
{
SafeNativeMethods.rdrand_get_bytes(BUFFER_SIZE, _Working);
ThreadPool.QueueUserWorkItem(new WaitCallback(Fill));
}
public bool IsSupported()
{
uint r = 0;
return SafeNativeMethods.rdrand_32(ref r, true) == RDRandError.Success;
}
private void CheckSwap(int c)
{
if (_Index + c < BUFFER_SIZE)
return;
_filled.WaitOne();
byte[] b = _Working;
_Working = _Buffer;
_Buffer = b;
_Index = 0;
_filled.Reset();
ThreadPool.QueueUserWorkItem(new WaitCallback(Fill));
}
private void Fill(object o)
{
SafeNativeMethods.rdrand_get_bytes(BUFFER_SIZE, _Buffer);
_filled.Set();
}
private void _GetBytes(byte[] b)
{
int c = b.Length;
lock (_sync)
{
CheckSwap(c);
Buffer.BlockCopy(_Working, _Index, b, 0, c);
_Index += c;
}
}
private void _GetBytes(byte[] b, int offset, int count)
{
lock (_sync)
{
CheckSwap(count);
Buffer.BlockCopy(_Working, _Index, b, offset, count);
_Index += count;
}
}
public int Next(int c)
{
return (int)(c * NextDouble());
}
public bool NextBool()
{
return (NextByte() & 1) == 1;
}
private byte NextByte()
{
lock (_sync)
{
CheckSwap(1);
return _Working[_Index++];
}
}
public void NextBytes(byte[] b)
{
int c = b.Length;
if (c >= LARGE_REQUEST)
{
SafeNativeMethods.rdrand_get_bytes(c, b);
return;
}
_GetBytes(b);
}
public unsafe double NextDouble()
{
byte[] b = new byte[8];
if (BitConverter.IsLittleEndian)
{
b[7] = 0;
_GetBytes(b, 0, 7);
}
else
{
b[0] = 0;
_GetBytes(b, 1, 7);
}
ulong r = 0;
fixed (byte* buf = b)
r = *(ulong*)(&buf[0]) >> 3;
/* double: 53 bits of significand precision
* ulong.MaxValue >> 11 = 9007199254740991
* 2^53 = 9007199254740992
*/
return (double)r / 9007199254740992;
}
}
public sealed class RDRand32 : IRandomImpl, IHardwareRNG {
internal class SafeNativeMethods {
internal class SafeNativeMethods
{
[DllImport("rdrand32")]
internal static extern RDRandError rdrand_32(ref uint rand, bool retry);

BIN
rdrand.so Executable file

Binary file not shown.