using System.Runtime.InteropServices;
using System.Security.Cryptography;
namespace XFESystem.NativeEntropy;
/// Native-only BC entropy port. There is no OpenSSL, host RNG or public-material fallback.
public static unsafe class NativeEntropy
{
public const int MaximumRequestBytes = 1_048_576;
[DllImport("xfe_pal", EntryPoint = "xfe_runtime_random_fill", CallingConvention = CallingConvention.Cdecl)]
private static extern int FillNative(byte* destination, uint length);
public static void Fill(Span destination)
{
if (destination.Length > MaximumRequestBytes) throw new ArgumentOutOfRangeException(nameof(destination));
if (destination.IsEmpty) return;
int result;
try { fixed (byte* pointer = destination) result = FillNative(pointer, (uint)destination.Length); }
catch { destination.Clear(); throw; }
if (result != 1)
{
destination.Clear();
throw new CryptographicException("The native hardware entropy source failed; no fallback is permitted.");
}
}
public static RandomNumberGenerator Create() => new HardwareRandomNumberGenerator();
private static void RequireHardware(RandomNumberGenerator source)
{
ArgumentNullException.ThrowIfNull(source);
if (source is not HardwareRandomNumberGenerator)
throw new CryptographicException("The native BC port only accepts its explicit hardware entropy provider.");
}
public static void GetBytes(RandomNumberGenerator source, byte[] destination)
{ RequireHardware(source); source.GetBytes(destination); }
public static void GetBytes(RandomNumberGenerator source, byte[] destination, int offset, int count)
{ RequireHardware(source); source.GetBytes(destination, offset, count); }
public static void GetBytes(RandomNumberGenerator source, Span destination)
{ RequireHardware(source); source.GetBytes(destination); }
public static void Dispose(RandomNumberGenerator source)
{ RequireHardware(source); source.Dispose(); }
// The base constructor has no OS initialization. All byte production uses
// our checked native ABI; BCL RNGImplementation/OpenSSL is never instantiated.
private sealed class HardwareRandomNumberGenerator : RandomNumberGenerator
{
private bool disposed;
private void Check() => ObjectDisposedException.ThrowIf(disposed, this);
public override void GetBytes(byte[] data)
{ Check(); ArgumentNullException.ThrowIfNull(data); Fill(data); }
public override void GetBytes(byte[] data, int offset, int count)
{ Check(); ArgumentNullException.ThrowIfNull(data); Fill(data.AsSpan(offset, count)); }
public override void GetBytes(Span data) { Check(); Fill(data); }
protected override void Dispose(bool disposing) { disposed = true; base.Dispose(disposing); }
}
}