Browse Source

API improvements for OSRandom

Ugochukwu Mmaduekwe 6 years ago
parent
commit
3808c28ffa

+ 103 - 18
CryptoLib/src/Include/CryptoLib.inc

@@ -19,12 +19,52 @@
 
 (* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
 {$IFDEF FPC}
-{$I CryptoLibHelper.inc} // Had to Include this Since Delphi Does not allow "FPC_FULLVERSION" to Compile.
-{$UNDEF DELPHI}
+   {$I CryptoLibHelper.inc} // Had to Include this Since Delphi Does not allow "FPC_FULLVERSION" to Compile.
+   {$UNDEF DELPHI}
 {$MODE delphi}
 
-{$IF (DEFINED(DARWIN) AND (DEFINED(CPUARM) OR DEFINED(CPUAARCH64) OR DEFINED(IPHONESIM)))}
-{$DEFINE IOSFPC}
+{$IFDEF CPU386}
+   {$DEFINE CRYPTOLIB_X86}
+{$ENDIF}
+
+{$IFDEF CPUX64}
+   {$DEFINE CRYPTOLIB_X86_64}
+{$ENDIF}
+
+{$IFDEF CPUARM}
+   {$DEFINE CRYPTOLIB_ARM}
+{$ENDIF}
+
+{$IFDEF CPUAARCH64}
+   {$DEFINE CRYPTOLIB_AARCH64}
+{$ENDIF}
+
+{$IFDEF IPHONESIM}
+   {$DEFINE CRYPTOLIB_IOSSIM}
+{$ENDIF}
+
+{$IF DEFINED(MSWINDOWS)}
+   {$DEFINE CRYPTOLIB_MSWINDOWS}
+{$ELSEIF DEFINED(UNIX)}
+   {$DEFINE CRYPTOLIB_UNIX}
+   {$IF DEFINED(BSD)}
+      {$IF DEFINED(DARWIN)}
+         {$DEFINE CRYPTOLIB_APPLE}
+         {$IF DEFINED(CRYPTOLIB_ARM) OR DEFINED(CRYPTOLIB_AARCH64)}
+            {$DEFINE CRYPTOLIB_IOS}
+         {$ELSE}
+            {$DEFINE CRYPTOLIB_MACOSX}
+         {$IFEND}
+      {$ELSEIF DEFINED(FREEBSD) OR DEFINED(NETBSD) OR DEFINED(OPENBSD)}
+         {$DEFINE CRYPTOLIB_TRUEBSD}
+      {$IFEND}
+  {$ELSEIF DEFINED(LINUX)}
+     {$DEFINE CRYPTOLIB_LINUX}
+  {$ELSE}
+     {$DEFINE CRYPTOLIB_UNDEFINED_UNIX_VARIANTS}
+  {$IFEND}
+{$ELSE}
+   {$MESSAGE ERROR 'UNSUPPORTED TARGET.'}
 {$ENDIF}
 
 {$DEFINE USE_UNROLLED_VARIANT}
@@ -49,20 +89,65 @@
 {$OPTIMIZATION STRENGTH}
 {$OPTIMIZATION CSE}
 {$OPTIMIZATION DFA}
+
 {$IFDEF CPUI386}
-{$OPTIMIZATION USEEBP}
+   {$OPTIMIZATION USEEBP}
 {$ENDIF}
+
 {$IFDEF CPUX86_64}
-{$OPTIMIZATION USERBP}
+   {$OPTIMIZATION USERBP}
 {$ENDIF}
+
 {$ENDIF FPC}
 
 (* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
 
 {$IFDEF DELPHI}
 
-{$IF DEFINED(IOS)}
-{$DEFINE IOSDELPHI}
+{$IFDEF CPU386}
+   {$DEFINE CRYPTOLIB_X86}
+{$ENDIF}
+
+{$IFDEF CPUX64}
+   {$DEFINE CRYPTOLIB_X86_64}
+{$ENDIF}
+
+{$IFDEF CPUARM32}
+   {$DEFINE CRYPTOLIB_ARM}
+{$ENDIF}
+
+{$IFDEF CPUARM64}
+   {$DEFINE CRYPTOLIB_AARCH64}
+{$ENDIF}
+
+{$IFDEF IOS}
+  {$IFNDEF CPUARM}
+     {$DEFINE CRYPTOLIB_IOSSIM}
+  {$ENDIF}
+{$ENDIF}
+
+{$IFDEF IOS}
+   {$DEFINE CRYPTOLIB_IOS}
+{$IFEND}
+
+{$IFDEF MSWINDOWS}
+   {$DEFINE CRYPTOLIB_MSWINDOWS}
+{$ENDIF}
+
+{$IFDEF MACOS}
+   {$DEFINE CRYPTOLIB_MACOSX}
+{$ENDIF}
+
+{$IF DEFINED(CRYPTOLIB_IOS) OR DEFINED(CRYPTOLIB_MACOSX)}
+   {$DEFINE CRYPTOLIB_APPLE}
+{$IFEND}
+
+{$IF DEFINED(LINUX) OR DEFINED(ANDROID)}
+   {$DEFINE CRYPTOLIB_LINUX}
+{$ENDIF}
+
+{$IF DEFINED(CRYPTOLIB_APPLE) OR DEFINED(CRYPTOLIB_LINUX)}
+   {$DEFINE CRYPTOLIB_UNIX}
 {$ENDIF}
 
 {$DEFINE USE_UNROLLED_VARIANT}
@@ -89,32 +174,32 @@
 
  // XE3 and Above
 {$IF CompilerVersion >= 24.0}
-{$DEFINE DELPHIXE3_UP}
-{$DEFINE SUPPORT_TSTREAM_READ_BYTEARRAY_OVERLOAD}
-{$DEFINE SUPPORT_TSTREAM_WRITE_BYTEARRAY_OVERLOAD}
-{$LEGACYIFEND ON}
-{$ZEROBASEDSTRINGS OFF}
+   {$DEFINE DELPHIXE3_UP}
+   {$DEFINE SUPPORT_TSTREAM_READ_BYTEARRAY_OVERLOAD}
+   {$DEFINE SUPPORT_TSTREAM_WRITE_BYTEARRAY_OVERLOAD}
+   {$LEGACYIFEND ON}
+   {$ZEROBASEDSTRINGS OFF}
 {$IFEND}
 
   // XE and Above
 {$IF CompilerVersion >= 22.0}
-{$DEFINE DELPHIXE_UP}
+   {$DEFINE DELPHIXE_UP}
 {$IFEND}
 
  // XE4 and Above
 {$IF CompilerVersion >= 25.0}
-{$DEFINE DELPHIXE4_UP}
-{$DEFINE SHIFT_OVERFLOW_BUG_FIXED}
+   {$DEFINE DELPHIXE4_UP}
+   {$DEFINE SHIFT_OVERFLOW_BUG_FIXED}
 {$IFEND}
 
   // 10.2 Tokyo and Above
 {$IF CompilerVersion >= 32.0}
-{$DEFINE DELPHI10.2_TOKYO_UP}
+   {$DEFINE DELPHI10.2_TOKYO_UP}
 {$IFEND}
 
   // 10.2 Tokyo and Above
 {$IFNDEF DELPHI10.2_TOKYO_UP}
-{$MESSAGE ERROR 'This Library requires Delphi Tokyo or higher.'}
+   {$MESSAGE ERROR 'This Library requires Delphi Tokyo or higher.'}
 {$ENDIF}
 
 

+ 2 - 2
CryptoLib/src/Include/CryptoLibHelper.inc

@@ -17,10 +17,10 @@
 
 {$MACRO ON}
 {$IFDEF ENDIAN_BIG}
-{$MESSAGE FATAL 'This Library does not support "Big Endian" processors yet.'}
+   {$MESSAGE FATAL 'This Library does not support "Big Endian" processors yet.'}
 {$ENDIF}
 // FPC 3.0.4 and Above
 // Had to Include this here since Delphi does not allow it Compile in "CryptoLib.inc".
 {$IF FPC_FULLVERSION < 30004}
-{$MESSAGE ERROR 'This Library requires FreePascal 3.0.4 or higher.'}
+   {$MESSAGE ERROR 'This Library requires FreePascal 3.0.4 or higher.'}
 {$IFEND}

+ 289 - 108
CryptoLib/src/Utils/Randoms/ClpOSRandom.pas

@@ -22,33 +22,65 @@ unit ClpOSRandom;
 interface
 
 uses
-{$IF DEFINED(MSWINDOWS)}
+{$IFDEF CRYPTOLIB_MSWINDOWS}
   Windows,
-  SysUtils,
-{$ELSEIF DEFINED(IOSDELPHI)}
-  // iOS stuffs for Delphi
-  Macapi.Dispatch,
-  iOSapi.Foundation,
-{$ELSEIF DEFINED(IOSFPC)}
-  // iOS stuffs for FreePascal
+{$ENDIF} // ENDIF CRYPTOLIB_MSWINDOWS
+{$IFDEF CRYPTOLIB_APPLE}
+{$IFDEF FPC}
 {$LINKFRAMEWORK Security}
 {$ELSE}
+  // Macapi.Dispatch, or
+  Macapi.ObjCRuntime,
+{$IF DEFINED(CRYPTOLIB_IOS)}
+  iOSapi.Foundation,
+{$ELSEIF DEFINED(CRYPTOLIB_MACOSX)}
+  Macapi.Foundation,
+{$ELSE}
+{$MESSAGE ERROR 'UNSUPPORTED TARGET.'}
+{$IFEND} // ENDIF CRYPTOLIB_MACOSX
+{$ENDIF}  // ENDIF FPC
+{$ENDIF}   // ENDIF CRYPTOLIB_APPLE
+{$IFDEF CRYPTOLIB_LINUX}
+{$IFDEF FPC}
+  BaseUnix,
+  dl,
+{$ELSE}
+  Posix.Errno,
+  Posix.Dlfcn,
+  Posix.Base,
+  /// remove
+{$ENDIF}
+{$ENDIF}  // ENDIF CRYPTOLIB_LINUX
+{$IFDEF CRYPTOLIB_PUREBSD}
+  // PureBSD (NetBSD, FreeBSD, OpenBSD)
+{$ENDIF}  // ENDIF CRYPTOLIB_PUREBSD
+{$IFDEF CRYPTOLIB_UNIX}
   Classes,
+{$ENDIF}  // ENDIF CRYPTOLIB_UNIX
   SysUtils,
-{$IFEND MSWINDOWS}
   ClpCryptoLibTypes;
 
 resourcestring
-{$IF DEFINED(MSWINDOWS)}
+{$IFDEF CRYPTOLIB_MSWINDOWS}
   SMSWIndowsCryptographyAPIGenerationError =
     'An Error Occured while generating random data using MS WIndows Cryptography API.';
-{$ELSEIF (DEFINED(IOSDELPHI) OR DEFINED(IOSFPC))}
-  SIOSSecRandomCopyBytesGenerationError =
+{$ENDIF}
+{$IFDEF CRYPTOLIB_APPLE}
+  SAppleSecRandomCopyBytesGenerationError =
     'An Error Occured while generating random data using SecRandomCopyBytes API.';
-{$ELSE}
-  SUnixRandomReadError =
-    'An Error Occured while reading random data from /dev/urandom or /dev/random.';
-{$IFEND MSWINDOWS}
+{$ENDIF}
+{$IFDEF CRYPTOLIB_LINUX}
+  SLinuxGetRandomError =
+    'An Error Occured while generating random data using getRandom API';
+{$ENDIF}
+{$IFDEF CRYPTOLIB_TRUEBSD}
+  SArc4RandomBufGenerationError =
+    'An Error Occured while generating random data using getRandom API.';
+{$ENDIF}
+{$IFDEF CRYPTOLIB_UNIX}
+  SdevurandomreadError =
+    'An Error Occured while getting random data using dev/(u)random';
+{$ENDIF}
 
 type
 
@@ -59,23 +91,78 @@ type
   /// <para>
   /// This class returns random bytes from an OS-specific randomness
   /// source. The returned data should be unpredictable enough for
-  /// cryptographic applications, though its exact quality depends on the
-  /// OS implementation.
-  /// On a UNIX-like system this will read directly from /dev/urandom or /dev/random
-  /// (if the former is not available),
-  /// on iOS, calls SecRandomCopyBytes as /dev/(u)random is sandboxed,
-  /// on MSWINDOWS it will call CryptGenRandom().
+  /// cryptographic applications, though it's exact quality depends on
+  /// the OS implementation.
   /// </para>
+  /// <list type="table">
+  /// <listheader>
+  /// <term>OS</term>
+  /// <description>Interface</description>
+  /// </listheader>
+  /// <item>
+  /// <term>Linux, Android</term>
+  /// <description><see href="http://man7.org/linux/man-pages/man2/getrandom.2.html">
+  /// getrandom</see> system call if available, otherwise ( <b>
+  /// /dev/urandom</b> or <b>/dev/random</b>) (which ever is
+  /// available)</description>
+  /// </item>
+  /// <item>
+  /// <term>Windows</term>
+  /// <description><see href="https://docs.microsoft.com/en-us/windows/desktop/api/wincrypt/nf-wincrypt-cryptgenrandom">
+  /// CryptGenRandom</see> for <b>XP</b>, <see href="https://docs.microsoft.com/en-us/windows/desktop/api/bcrypt/nf-bcrypt-bcryptgenrandom">
+  /// BCryptGenRandom</see> for <b>Vista</b> Upwards</description>
+  /// </item>
+  /// <item>
+  /// <term>macOS, iOS</term>
+  /// <description><see href="https://developer.apple.com/documentation/security/1399291-secrandomcopybytes?language=objc">
+  /// SecRandomCopyBytes</see><br /></description>
+  /// </item>
+  /// <item>
+  /// <term>FreeBSD</term>
+  /// <description><see href="https://www.freebsd.org/cgi/man.cgi?query=arc4random&amp;sektion=3&amp;manpath=FreeBSD+12.0-RELEASE+and+Ports">
+  /// arc4random_buf</see></description>
+  /// </item>
+  /// <item>
+  /// <term>NetBSD</term>
+  /// <description><see href="https://www.netbsd.org/~riastradh/tmp/20141116/arc4random.html">
+  /// arc4random_buf</see></description>
+  /// </item>
+  /// <item>
+  /// <term>OpenBSD</term>
+  /// <description><see href="http://man.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man3/arc4random.3">
+  /// arc4random_buf</see></description>
+  /// </item>
+  /// </list>
   /// </summary>
-
   TOSRandom = class sealed(TObject)
 
   strict private
 
-    class function NoZeroes(const data: TCryptoLibByteArray): Boolean;
-      static; inline;
+    // ================================================================//
+
+{$IFDEF CRYPTOLIB_LINUX}
+  type
+    TGetRandom = function(pbBuffer: PByte; buflen: LongWord; flags: UInt32)
+      : Int32; cdecl;
+
+  class var
+
+    FIsGetRandomSupportedOnOS: Boolean;
+    FGetRandom: TGetRandom;
+
+    class function ErrorNo: Int32; static; inline;
 
-{$IF DEFINED(MSWINDOWS)}
+    class function GetIsGetRandomSupportedOnOS(): Boolean; static; inline;
+
+    class function IsGetRandomAvailable(): Boolean; static;
+
+    class property IsGetRandomSupportedOnOS: Boolean
+      read GetIsGetRandomSupportedOnOS;
+
+{$ENDIF}
+    // ================================================================//
+
+{$IFDEF CRYPTOLIB_MSWINDOWS}
 
   type
     BCRYPT_ALG_HANDLE = THandle;
@@ -101,30 +188,45 @@ type
       static; inline;
 
     class function IsCngBCryptGenRandomAvailable(): Boolean; static;
-    class function GenRandomBytesWindows(len: Int32; const data: PByte)
+    class function GenRandomBytesWindows(len: Int32; data: PByte)
       : Int32; static;
     class property IsCngBCryptGenRandomSupportedOnOS: Boolean
       read GetIsCngBCryptGenRandomSupportedOnOS;
-{$ELSEIF DEFINED(IOSDELPHI)}
-    class function GenRandomBytesIOSDelphi(len: Int32; const data: PByte)
+{$ENDIF}
+
+    // ================================================================//
+{$IFDEF CRYPTOLIB_APPLE}
+    class function GenRandomBytesApple(len: Int32; data: PByte): Int32; static;
+{$ENDIF}
+    // ================================================================//
+{$IFDEF CRYPTOLIB_LINUX}
+    class function GenRandomBytesLinux(len: Int32; data: PByte): Int32; static;
+{$ENDIF}
+    // ================================================================//
+{$IFDEF CRYPTOLIB_TRUEBSD}
+    class function GenRandomBytesTrueBSD(len: Int32; data: PByte)
       : Int32; static;
-{$ELSEIF DEFINED(IOSFPC)}
-    class function GenRandomBytesIOSFPC(len: Int32; const data: PByte)
-      : Int32; static;
-{$ELSE}
-    class function GenRandomBytesUnix(len: Int32; const data: PByte)
-      : Int32; static;
-{$IFEND $MSWINDOWS}
+{$ENDIF}
+    // ================================================================//
+{$IFDEF CRYPTOLIB_UNIX}
+    class function dev_urandom_read(len: Int32; data: PByte): Int32; static;
+{$ENDIF}
+    // ================================================================//
+
+    class function NoZeroes(const data: TCryptoLibByteArray): Boolean;
+      static; inline;
     class procedure Boot(); static;
     class constructor OSRandom();
-  public
 
+  public
     class procedure GetBytes(const data: TCryptoLibByteArray); static;
     class procedure GetNonZeroBytes(const data: TCryptoLibByteArray); static;
 
   end;
 
-{$IFDEF MSWINDOWS}
+  // ************************************************************************//
+
+{$IFDEF CRYPTOLIB_MSWINDOWS}
 
 const
   ADVAPI32 = 'advapi32.dll';
@@ -138,21 +240,10 @@ function CryptGenRandom(hProv: THandle; dwLen: DWORD; pbBuffer: PByte): BOOL;
 
 function CryptReleaseContext(hProv: THandle; dwFlags: DWORD): BOOL; stdcall;
   external ADVAPI32 Name 'CryptReleaseContext';
-{$ENDIF MSWINDOWS}
-{$IFDEF IOSDELPHI}
-
-type
-  SecRandomRef = Pointer;
-
-const
-  libSecurity = '/System/Library/Frameworks/Security.framework/Security';
-
-function kSecRandomDefault: Pointer;
-
-function SecRandomCopyBytes(rnd: SecRandomRef; count: LongWord; bytes: PByte)
-  : Integer; cdecl; external libSecurity Name _PU + 'SecRandomCopyBytes';
-{$ENDIF IOSDELPHI}
-{$IFDEF IOSFPC}
+{$ENDIF}
+// ************************************************************************//
+{$IFDEF CRYPTOLIB_APPLE}
+{$IFDEF FPC}
 
 type
   // similar to a TOpaqueData already defined in newer FPC but not available in 3.0.4
@@ -162,37 +253,29 @@ type
   // similar to an OpaquePointer already defined in newer FPC but not available in 3.0.4
   SecRandomRef = ^__SecRandom;
 
-const
-  { * This is a synonym for NULL, if you'd rather use a named constant.   This
-    refers to a cryptographically secure random number generator.  * }
-  kSecRandomDefault: SecRandomRef = Nil;
-
 function SecRandomCopyBytes(rnd: SecRandomRef; count: LongWord; bytes: PByte)
-  : Integer; cdecl; external;
+  : Int32; cdecl; external;
 
-{$ENDIF IOSFPC}
+{$ELSE}
 
-implementation
+type
+  SecRandomRef = Pointer;
 
-class procedure TOSRandom.Boot;
-begin
-{$IFDEF MSWINDOWS}
-  FIsCngBCryptGenRandomSupportedOnOS := IsCngBCryptGenRandomAvailable();
-{$ENDIF MSWINDOWS}
-end;
+const
+  libSecurity = '/System/Library/Frameworks/Security.framework/Security';
 
-class constructor TOSRandom.OSRandom;
-begin
-  TOSRandom.Boot();
-end;
+function SecRandomCopyBytes(rnd: SecRandomRef; count: LongWord; bytes: PByte)
+  : Int32; cdecl; external libSecurity Name _PU + 'SecRandomCopyBytes';
 
-{$IFDEF IOSDELPHI}
+{$ENDIF}
+{$ENDIF}
+// ************************************************************************//
+{$IFDEF CRYPTOLIB_TRUEBSD}
+procedure arc4random_buf(bytes: PByte; count: LongWord); cdecl; external;
+// 'c' name 'arc4random_buf';
+{$ENDIF}
 
-function kSecRandomDefault: Pointer;
-begin
-  result := CocoaPointerConst(libSecurity, 'kSecRandomDefault');
-end;
-{$ENDIF IOSDELPHI}
+implementation
 
 class function TOSRandom.NoZeroes(const data: TCryptoLibByteArray): Boolean;
 var
@@ -207,10 +290,24 @@ begin
       Exit;
     end;
   end;
+end;
 
+class procedure TOSRandom.Boot;
+begin
+{$IFDEF CRYPTOLIB_MSWINDOWS}
+  FIsCngBCryptGenRandomSupportedOnOS := IsCngBCryptGenRandomAvailable();
+{$ENDIF}
+{$IFDEF CRYPTOLIB_LINUX}
+  FIsGetRandomSupportedOnOS := IsGetRandomAvailable();
+{$ENDIF}
+end;
+
+class constructor TOSRandom.OSRandom;
+begin
+  TOSRandom.Boot();
 end;
 
-{$IF DEFINED(MSWINDOWS)}
+{$IFDEF CRYPTOLIB_MSWINDOWS}
 
 class function TOSRandom.GetIsCngBCryptGenRandomSupportedOnOS(): Boolean;
 begin
@@ -247,8 +344,7 @@ begin
   end;
 end;
 
-class function TOSRandom.GenRandomBytesWindows(len: Int32;
-  const data: PByte): Int32;
+class function TOSRandom.GenRandomBytesWindows(len: Int32; data: PByte): Int32;
 
   function BCRYPT_SUCCESS(AStatus: NTStatus): Boolean; inline;
   begin
@@ -277,7 +373,7 @@ begin
 
     try
       if (not BCRYPT_SUCCESS(FBCryptGenRandom(hProv, PUCHAR(data),
-        LongWord(len), 0))) then
+        ULONG(len), 0))) then
       begin
         result := HResultFromWin32(GetLastError);
         Exit;
@@ -297,7 +393,7 @@ begin
     end;
 
     try
-      if not CryptGenRandom(hProv, len, data) then
+      if not CryptGenRandom(hProv, DWORD(len), data) then
       begin
         result := HResultFromWin32(GetLastError);
         Exit;
@@ -309,26 +405,28 @@ begin
   result := S_OK;
 end;
 
-{$ELSEIF DEFINED(IOSDELPHI)}
+{$ENDIF}
+{$IFDEF CRYPTOLIB_APPLE}
 
-class function TOSRandom.GenRandomBytesIOSDelphi(len: Int32;
-  const data: PByte): Int32;
-begin
-  result := SecRandomCopyBytes(kSecRandomDefault, LongWord(len), data);
-end;
+class function TOSRandom.GenRandomBytesApple(len: Int32; data: PByte): Int32;
 
-{$ELSEIF DEFINED(IOSFPC)}
+  function kSecRandomDefault: SecRandomRef;
+  begin
+{$IFDEF FPC}
+    result := Nil;
+{$ELSE}
+    result := CocoaPointerConst(libSecurity, 'kSecRandomDefault');
+{$ENDIF}
+  end;
 
-class function TOSRandom.GenRandomBytesIOSFPC(len: Int32;
-  const data: PByte): Int32;
 begin
-  // UNTESTED !!!, Please Take Note.
   result := SecRandomCopyBytes(kSecRandomDefault, LongWord(len), data);
 end;
-{$ELSE}
 
-class function TOSRandom.GenRandomBytesUnix(len: Int32;
-  const data: PByte): Int32;
+{$ENDIF}
+{$IFDEF CRYPTOLIB_UNIX}
+
+class function TOSRandom.dev_urandom_read(len: Int32; data: PByte): Int32;
 var
   LStream: TFileStream;
   RandGen: String;
@@ -357,41 +455,124 @@ begin
     LStream.Free;
   end;
 end;
+{$ENDIF}
+{$IFDEF CRYPTOLIB_LINUX}
+
+class function TOSRandom.ErrorNo: Int32;
+begin
+  result := Errno;
+end;
+
+class function TOSRandom.GetIsGetRandomSupportedOnOS(): Boolean;
+begin
+  result := FIsGetRandomSupportedOnOS;
+end;
+
+class function TOSRandom.IsGetRandomAvailable(): Boolean;
+const
+  LIBC_SO_6 = 'libc.so.6';
+var
+  Lib: {$IFDEF FPC} PtrInt {$ELSE} NativeUInt {$ENDIF};
+begin
+  FGetRandom := Nil;
+  Lib := {$IFDEF FPC}PtrInt{$ENDIF}(dlopen(LIBC_SO_6, RTLD_NOW));
+  if Lib <> 0 then
+  begin
+    FGetRandom := dlsym(Lib, 'getrandom');
+    dlclose(Lib);
+  end;
+  result := System.Assigned(FGetRandom);
+end;
+
+class function TOSRandom.GenRandomBytesLinux(len: Int32; data: PByte): Int32;
+const
+  GRND_DEFAULT: Int32 = $0000;
+  EINTR: Int32 = 4;
+var
+  n: Int64;
+begin
+  if IsGetRandomSupportedOnOS then
+  begin
+    while (len > 0) do
+    begin
+
+      repeat
+        n := FGetRandom(data, LongWord(len), GRND_DEFAULT);
+      until ((n > 0) and (ErrorNo <> EINTR));
+
+      if (n <= 0) then
+      begin
+        result := -1;
+        Exit;
+      end;
+      System.Inc(data, n);
+      System.Dec(len, n);
+    end;
+    result := 0;
+  end
+  else
+  begin
+    // fallback for when getrandom API is not available
+    result := dev_urandom_read(len, data);
+  end;
+end;
+
+{$ENDIF}
+{$IFDEF CRYPTOLIB_TRUEBSD}
 
-{$IFEND MSWINDOWS}
+class function TOSRandom.GenRandomBytesTrueBSD(len: Int32; data: PByte): Int32;
+
+begin
+  arc4random_buf(data, LongWord(len));
+  result := 0;
+end;
+{$ENDIF}
 
 class procedure TOSRandom.GetBytes(const data: TCryptoLibByteArray);
 var
   count: Int32;
 begin
   count := System.Length(data);
-{$IF DEFINED(MSWINDOWS)}
+
+  if count <= 0 then
+  begin
+    Exit;
+  end;
+
+{$IF DEFINED(CRYPTOLIB_MSWINDOWS)}
   if GenRandomBytesWindows(count, PByte(data)) <> 0 then
   begin
     raise EAccessCryptoLibException.CreateRes
       (@SMSWIndowsCryptographyAPIGenerationError);
   end;
 
-{$ELSEIF DEFINED(IOSDELPHI)}
-  if GenRandomBytesIOSDelphi(count, PByte(data)) <> 0 then
+{$ELSEIF DEFINED(CRYPTOLIB_APPLE)}
+  if GenRandomBytesApple(count, PByte(data)) <> 0 then
   begin
     raise EAccessCryptoLibException.CreateRes
-      (@SIOSSecRandomCopyBytesGenerationError);
+      (@SAppleSecRandomCopyBytesGenerationError);
   end;
 
-{$ELSEIF DEFINED(IOSFPC)}
-  if GenRandomBytesIOSFPC(count, PByte(data)) <> 0 then
+{$ELSEIF DEFINED(CRYPTOLIB_LINUX)}
+  if GenRandomBytesLinux(count, PByte(data)) <> 0 then
   begin
-    raise EAccessCryptoLibException.CreateRes
-      (@SIOSSecRandomCopyBytesGenerationError);
+    raise EAccessCryptoLibException.CreateRes(@SLinuxGetRandomError);
   end;
 
-{$ELSE}
-  if GenRandomBytesUnix(count, PByte(data)) <> 0 then
+{$ELSEIF DEFINED(CRYPTOLIB_TRUEBSD)}
+  if GenRandomBytesTrueBSD(count, PByte(data)) <> 0 then
   begin
-    raise EAccessCryptoLibException.CreateRes(@SUnixRandomReadError);
+    raise EAccessCryptoLibException.CreateRes(@SArc4RandomBufGenerationError);
   end;
-{$IFEND MSWINDOWS}
+{$ELSEIF DEFINED(CRYPTOLIB_UNIX)}
+  // fallback option for other Unspecified Unix OSes
+  if dev_urandom_read(count, PByte(data)) <> 0 then
+  begin
+    raise EAccessCryptoLibException.CreateRes(@SdevurandomreadError);
+  end;
+{$ELSE}
+{$MESSAGE ERROR 'UNSUPPORTED TARGET.'}
+{$IFEND}
 end;
 
 class procedure TOSRandom.GetNonZeroBytes(const data: TCryptoLibByteArray);