unit uCspring;
{$mode objfpc}
interface
{ cross-platform cspring }
function SystemCSPRNG(var Buffer; Bytes: LongWord): Boolean;inline;
implementation
uses
{$ifdef mswindows}windows,bcrypt;{$endif}
{$ifdef UNIX}cthreads;{$endif}
{$ifdef mswindows}
function WinCSPRNG(var Buffer; Bytes: LongWord): Boolean;
var
hAlgorithm: PBCRYPT_ALG_HANDLE;
begin
Result := False;
if BCryptOpenAlgorithmProvider(@hAlgorithm, BCRYPT_RNG_ALGORITHM, nil, 0) = STATUS_SUCCESS then
try
if BCryptGenRandom(PtrUint(hAlgorithm), @Buffer, Bytes, 0) = STATUS_SUCCESS then
Result := True;
finally
BCryptCloseAlgorithmProvider(ptrUint(hAlgorithm), 0);
end;
end;
(*
{ this is for XP, that does not have bcrypt, change windows to jwaWindows. }
function WinLegacyCSPRNG(var Buffer; Count: DWORD): Boolean;
var
hProv: HCRYPTPROV;
begin
Result := CryptAcquireContext(hProv, nil, nil, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
if Result then
try
Result := CryptGenRandom(hProv, Count, @Buffer);
finally
CryptReleaseContext(hProv, 0);
end;
end;
*)
{$else}
{ The Linux CSPRING can simply be read from /dev/urandom on modern
kernels >= 4.8 and is cryptographically secure. Entropy is determined
during system startup and so directly available when startup is finished.
Older kernels, though, used a simpler less secure PRNG, without taking
enough entropy from the hardware }
function UnixCSPRNG(var Buffer; Bytes: LongWord): Boolean;
var
f: File of byte;
begin
Result := False;
Assign(f, '/dev/urandom');
Reset(f, 1);
try
BlockRead(f, Buffer, Bytes);
Result := True;
finally
Close(f);
end;
end;
{$endif}
function SystemCSPRNG(var Buffer; Bytes: LongWord): Boolean;
begin
{$IFDEF WINDOWS}
Result := WinCSPRNG(Buffer, Bytes);
{$ENDIF}
{$IFDEF UNIX }
Result := UnixCSPRNG(Buffer, Bytes);
{$ENDIF}
end;
end.