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); } } }