Ugochukwu Mmaduekwe 5 часов назад
Родитель
Сommit
7bd57c2b44

+ 1 - 0
CryptoLib.Tests/Delphi.Tests/CryptoLib.Tests.dpr

@@ -438,6 +438,7 @@ uses
   ClpOSRandomProvider in '..\..\CryptoLib\src\Rngs\Providers\ClpOSRandomProvider.pas',
   ClpIRandomNumberGenerator in '..\..\CryptoLib\src\Interfaces\Rngs\ClpIRandomNumberGenerator.pas',
   ClpAesRandomProvider in '..\..\CryptoLib\src\Rngs\Providers\ClpAesRandomProvider.pas',
+  ClpDevRandomReader in '..\..\CryptoLib\src\Rngs\Providers\ClpDevRandomReader.pas',
   ClpAsn1Parsers in '..\..\CryptoLib\src\Asn1\ClpAsn1Parsers.pas',
   ClpAsn1Core in '..\..\CryptoLib\src\Asn1\ClpAsn1Core.pas',
   ClpIAsn1Parsers in '..\..\CryptoLib\src\Interfaces\Asn1\ClpIAsn1Parsers.pas',

+ 5 - 1
CryptoLib/src/Packages/FPC/CryptoLib4PascalPackage.lpk

@@ -25,7 +25,7 @@
  Acknowledgements: 
 Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring the development of this library "/>
     <Version Major="3" Minor="3"/>
-    <Files Count="467">
+    <Files Count="468">
       <Item1>
         <Filename Value="..\..\Asn1\ClpOidTokenizer.pas"/>
         <UnitName Value="ClpOidTokenizer"/>
@@ -1895,6 +1895,10 @@ Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring the devel
         <Filename Value="..\..\X509\Extension\ClpX509ExtensionUtilities.pas"/>
         <UnitName Value="ClpX509ExtensionUtilities"/>
       </Item467>
+      <Item468>
+        <Filename Value="..\..\Rngs\Providers\ClpDevRandomReader.pas"/>
+        <UnitName Value="ClpDevRandomReader"/>
+      </Item468>
     </Files>
     <CompatibilityMode Value="True"/>
     <RequiredPkgs Count="3">

+ 1 - 1
CryptoLib/src/Packages/FPC/CryptoLib4PascalPackage.pas

@@ -154,7 +154,7 @@ uses
   ClpX509AttrCertParser, ClpAttributeCertificateIssuer, 
   ClpAttributeCertificateHolder, ClpX509Utilities, ClpX509Generators, 
   ClpDeltaCertificateTool, ClpX509Attribute, ClpX509ExtensionBase, 
-  ClpX509ExtensionUtilities;
+  ClpX509ExtensionUtilities, ClpDevRandomReader;
 
 implementation
 

+ 8 - 8
CryptoLib/src/Rngs/ClpCryptoApiRandomGenerator.pas

@@ -40,11 +40,11 @@ type
 
   strict private
   var
-    FrndProv: IRandomNumberGenerator;
+    FRandomProvider: IRandomNumberGenerator;
 
   public
     /// <summary>
-    /// Uses TRandomNumberGenerator.Create() to Get randomness generator
+    /// Uses `TRandomNumberGenerator.Create()` to get randomness generator
     /// </summary>
     constructor Create(); overload;
     constructor Create(const ARng: IRandomNumberGenerator); overload;
@@ -89,7 +89,7 @@ end;
 constructor TCryptoApiRandomGenerator.Create(const ARng: IRandomNumberGenerator);
 begin
   inherited Create();
-  FRndProv := ARng;
+  FRandomProvider := ARng;
 end;
 
 constructor TCryptoApiRandomGenerator.Create;
@@ -99,13 +99,13 @@ end;
 
 procedure TCryptoApiRandomGenerator.NextBytes(const ABytes: TCryptoLibByteArray);
 begin
-  FRndProv.GetBytes(ABytes);
+  FRandomProvider.GetBytes(ABytes);
 end;
 
 procedure TCryptoApiRandomGenerator.NextBytes(const ABytes: TCryptoLibByteArray;
   AStart, ALen: Int32);
 var
-  LTmpBuf: TCryptoLibByteArray;
+  LTempBuffer: TCryptoLibByteArray;
 begin
   if (AStart < 0) then
   begin
@@ -123,10 +123,10 @@ begin
   end
   else
   begin
-    System.SetLength(LTmpBuf, ALen);
-    NextBytes(LTmpBuf);
+    System.SetLength(LTempBuffer, ALen);
+    NextBytes(LTempBuffer);
 
-    System.Move(LTmpBuf[0], ABytes[AStart], ALen * System.SizeOf(Byte));
+    System.Move(LTempBuffer[0], ABytes[AStart], ALen * System.SizeOf(Byte));
 
   end;
 end;

+ 17 - 17
CryptoLib/src/Rngs/ClpDigestRandomGenerator.pas

@@ -52,16 +52,16 @@ type
     procedure CycleSeed(); inline;
     procedure GenerateState(); inline;
     procedure DigestAddCounter(ASeedVal: Int64); inline;
-    procedure DigestUpdate(const AInSeed: TCryptoLibByteArray); inline;
+    procedure DigestUpdate(const ASeed: TCryptoLibByteArray); inline;
     procedure DigestDoFinal(const AResult: TCryptoLibByteArray); inline;
 
   public
 
     constructor Create(const ADigest: IDigest);
     destructor Destroy; override;
-    procedure AddSeedMaterial(const AInSeed: TCryptoLibByteArray);
+    procedure AddSeedMaterial(const ASeed: TCryptoLibByteArray);
       overload; inline;
-    procedure AddSeedMaterial(ARSeed: Int64); overload; inline;
+    procedure AddSeedMaterial(ASeed: Int64); overload; inline;
     procedure NextBytes(const ABytes: TCryptoLibByteArray); overload; inline;
     procedure NextBytes(const ABytes: TCryptoLibByteArray;
       AStart, ALen: Int32); overload;
@@ -80,10 +80,10 @@ begin
   FDigest.BlockUpdate(LBytes, 0, System.Length(LBytes));
 end;
 
-procedure TDigestRandomGenerator.DigestUpdate(const AInSeed
+procedure TDigestRandomGenerator.DigestUpdate(const ASeed
   : TCryptoLibByteArray);
 begin
-  FDigest.BlockUpdate(AInSeed, 0, System.Length(AInSeed));
+  FDigest.BlockUpdate(ASeed, 0, System.Length(ASeed));
 end;
 
 procedure TDigestRandomGenerator.DigestDoFinal(const AResult
@@ -92,11 +92,11 @@ begin
   FDigest.DoFinal(AResult, 0);
 end;
 
-procedure TDigestRandomGenerator.AddSeedMaterial(ARSeed: Int64);
+procedure TDigestRandomGenerator.AddSeedMaterial(ASeed: Int64);
 begin
   FLock.Acquire;
   try
-    DigestAddCounter(ARSeed);
+    DigestAddCounter(ASeed);
     DigestUpdate(FSeed);
     DigestDoFinal(FSeed);
   finally
@@ -104,12 +104,12 @@ begin
   end;
 end;
 
-procedure TDigestRandomGenerator.AddSeedMaterial(const AInSeed
+procedure TDigestRandomGenerator.AddSeedMaterial(const ASeed
   : TCryptoLibByteArray);
 begin
   FLock.Acquire;
   try
-    DigestUpdate(AInSeed);
+    DigestUpdate(ASeed);
     DigestUpdate(FSeed);
     DigestDoFinal(FSeed);
   finally
@@ -164,24 +164,24 @@ end;
 procedure TDigestRandomGenerator.NextBytes(const ABytes: TCryptoLibByteArray;
   AStart, ALen: Int32);
 var
-  LStateOff, LEndPoint: Int32;
+  LStateOffset, LEnd: Int32;
   LI: Int32;
 begin
   FLock.Acquire;
   try
-    LStateOff := 0;
+    LStateOffset := 0;
     GenerateState();
-    LEndPoint := AStart + ALen;
+    LEnd := AStart + ALen;
 
-    for LI := AStart to System.Pred(LEndPoint) do
+    for LI := AStart to System.Pred(LEnd) do
     begin
-      if (LStateOff = System.Length(FState)) then
+      if (LStateOffset = System.Length(FState)) then
       begin
         GenerateState();
-        LStateOff := 0;
+        LStateOffset := 0;
       end;
-      ABytes[LI] := FState[LStateOff];
-      System.Inc(LStateOff);
+      ABytes[LI] := FState[LStateOffset];
+      System.Inc(LStateOffset);
     end;
 
   finally

+ 2 - 2
CryptoLib/src/Rngs/ClpRandomNumberGenerator.pas

@@ -86,7 +86,7 @@ end;
 
 class function TRandomNumberGenerator.CreateRng: IRandomNumberGenerator;
 begin
-  result := TDefaultRandomNumberGenerator.Create(TOSRandomProvider.Instance);
+  Result := TDefaultRandomNumberGenerator.Create(TOSRandomProvider.Instance);
 end;
 
 class function TRandomNumberGenerator.CreateRng(const ARandomSource
@@ -96,7 +96,7 @@ begin
   begin
     raise EArgumentNilCryptoLibException.CreateRes(@SRandomSourceProviderNil);
   end;
-  result := TDefaultRandomNumberGenerator.Create(ARandomSource);
+  Result := TDefaultRandomNumberGenerator.Create(ARandomSource);
 end;
 
 { TDefaultRandomNumberGenerator }

+ 52 - 33
CryptoLib/src/Rngs/Providers/ClpAesRandomProvider.pas

@@ -37,7 +37,7 @@ uses
   ClpCryptoLibTypes;
 
 resourcestring
-  SInvalidAESRNGSeedLength =
+  SInvalidAesRngSeedLength =
     'AES RNG Seed Length must be either one of these "128/192/256 bits".';
 
 type
@@ -57,7 +57,7 @@ type
   var
     FInternalLock: TCriticalSection;
     FCounter: TCryptoLibByteArray;
-    FAESRNGSeedLength, FBytesSinceSeed, FReseedAfterBytes: Int32;
+    FAesRngSeedLength, FBytesSinceSeed, FReseedAfterBytes: Int32;
     FCipher: IBufferedCipher;
 
     class function GetInstance: IRandomSourceProvider; static;
@@ -69,13 +69,13 @@ type
     class constructor Create();
     class destructor Destroy();
 
-    class procedure ValidateAESRNGSeedLength(ASeedLength: Int32);
+    class procedure ValidateAesRngSeedLength(ASeedLength: Int32);
 
     constructor Create(const AAesRngSeed: TCryptoLibByteArray; AReseedAfterBytes: Int32); overload;
 
     procedure DoIncrementCounter();
 
-    procedure DoSeed(const AAESRNGSeed: TCryptoLibByteArray);
+    procedure DoSeed(const AAesRngSeed: TCryptoLibByteArray);
 
   public
     constructor Create(AAesRngSeedLength: Int32 = 32; AReseedAfterBytes: Int32 = 1024 * 1024); overload;
@@ -118,12 +118,12 @@ begin
   Result := TAesRandomProvider.Create();
 end;
 
-class procedure TAesRandomProvider.ValidateAESRNGSeedLength(ASeedLength: Int32);
+class procedure TAesRandomProvider.ValidateAesRngSeedLength(ASeedLength: Int32);
 begin
   if ((ASeedLength < 16) or (ASeedLength > 32) or ((ASeedLength and 7) <> 0))
   then
   begin
-    raise EArgumentCryptoLibException.CreateRes(@SInvalidAESRNGSeedLength);
+    raise EArgumentCryptoLibException.CreateRes(@SInvalidAesRngSeedLength);
   end;
 end;
 
@@ -156,24 +156,24 @@ end;
 
 procedure TAesRandomProvider.DoIncrementCounter;
 var
-  i: Int32;
+  LI: Int32;
 begin
-  for i := System.Low(FCounter) to System.High(FCounter) do
+  for LI := System.Low(FCounter) to System.High(FCounter) do
   begin
-    System.Inc(FCounter[i]);
+    System.Inc(FCounter[LI]);
     // Check whether we need to loop again to carry the one.
-    if (FCounter[i] <> 0) then
+    if (FCounter[LI] <> 0) then
     begin
       break;
     end;
   end;
 end;
 
-procedure TAesRandomProvider.DoSeed(const AAESRNGSeed: TCryptoLibByteArray);
+procedure TAesRandomProvider.DoSeed(const AAesRngSeed: TCryptoLibByteArray);
 var
   LKeyParameter: IKeyParameter;
 begin
-  LKeyParameter := TKeyParameter.Create(AAESRNGSeed);
+  LKeyParameter := TKeyParameter.Create(AAesRngSeed);
   FInternalLock.Acquire;
   try
     FCipher.Init(True, LKeyParameter);
@@ -187,21 +187,24 @@ constructor TAesRandomProvider.Create(const AAesRngSeed: TCryptoLibByteArray; AR
 var
   LAesEngine: IAesEngine;
   LBlockCipher: IBlockCipher;
-  LAESRNGSeed: TCryptoLibByteArray;
+  LAesRngSeed: TCryptoLibByteArray;
 begin
   inherited Create();
-  LAESRNGSeed := System.Copy(AAesRngSeed);
+  LAesRngSeed := System.Copy(AAesRngSeed);
   FInternalLock := TCriticalSection.Create;
   // Set up engine
   LAesEngine := TAesEngine.Create();
   LBlockCipher := LAesEngine as IBlockCipher; // ECB no padding
   FCipher := TBufferedBlockCipher.Create(LBlockCipher) as IBufferedBlockCipher;
   System.SetLength(FCounter, CounterSize);
-  FAESRNGSeedLength := System.Length(LAESRNGSeed);
+  FAesRngSeedLength := System.Length(LAesRngSeed);
   FReseedAfterBytes := AReseedAfterBytes;
-  ValidateAESRNGSeedLength(FAESRNGSeedLength);
-  DoSeed(LAESRNGSeed);
-  TArrayUtilities.Fill<Byte>(LAESRNGSeed, 0, System.Length(LAESRNGSeed), Byte(0)); // clear key from memory
+  ValidateAesRngSeedLength(FAesRngSeedLength);
+  try
+    DoSeed(LAesRngSeed);
+  finally
+    TArrayUtilities.Fill<Byte>(LAesRngSeed, 0, System.Length(LAesRngSeed), Byte(0)); // clear key from memory
+  end;
 end;
 
 constructor TAesRandomProvider.Create(AAesRngSeedLength, AReseedAfterBytes: Int32);
@@ -209,9 +212,12 @@ var
   LSeed: TCryptoLibByteArray;
 begin
   System.SetLength(LSeed, AAesRngSeedLength);
-  GetRawEntropy(LSeed); // pure entropy from OS
-  Create(LSeed, AReseedAfterBytes);
-  TArrayUtilities.Fill<Byte>(LSeed, 0, System.Length(LSeed), Byte(0)); // clear seed from memory
+  try
+    GetRawEntropy(LSeed); // pure entropy from OS
+    Create(LSeed, AReseedAfterBytes);
+  finally
+    TArrayUtilities.Fill<Byte>(LSeed, 0, System.Length(LSeed), Byte(0)); // clear seed from memory
+  end;
 end;
 
 destructor TAesRandomProvider.Destroy;
@@ -222,7 +228,7 @@ end;
 
 procedure TAesRandomProvider.GetBytes(const AData: TCryptoLibByteArray);
 var
-  LDataLength, LDatum, LResultLength: Int32;
+  LDataLength, LOffset, LResultLength: Int32;
   LSeed, LResult: TCryptoLibByteArray;
 begin
   LDataLength := System.Length(AData);
@@ -233,22 +239,25 @@ begin
 
   if (FBytesSinceSeed > FReseedAfterBytes) then
   begin
-    System.SetLength(LSeed, FAESRNGSeedLength);
-    GetRawEntropy(LSeed); // pure entropy from OS
-    DoSeed(LSeed);
-    TArrayUtilities.Fill<Byte>(LSeed, 0, System.Length(LSeed), Byte(0)); // clear seed from memory
+    System.SetLength(LSeed, FAesRngSeedLength);
+    try
+      GetRawEntropy(LSeed); // pure entropy from OS
+      DoSeed(LSeed);
+    finally
+      TArrayUtilities.Fill<Byte>(LSeed, 0, System.Length(LSeed), Byte(0)); // clear seed from memory
+    end;
   end;
 
-  LDatum := 0;
+  LOffset := 0;
 
   FInternalLock.Acquire;
   try
     while (LDataLength shr 4) > 0 do
     begin
       DoIncrementCounter;
-      LResultLength := FCipher.DoFinal(FCounter, AData, LDatum);
+      LResultLength := FCipher.DoFinal(FCounter, AData, LOffset);
 
-      System.Inc(LDatum, LResultLength);
+      System.Inc(LOffset, LResultLength);
       System.Inc(FBytesSinceSeed, LResultLength);
       System.Dec(LDataLength, LResultLength);
     end;
@@ -257,7 +266,7 @@ begin
     begin
       DoIncrementCounter;
       LResult := FCipher.DoFinal(FCounter);
-      System.Move(LResult[0], AData[LDatum], LDataLength * System.SizeOf(Byte));
+      System.Move(LResult[0], AData[LOffset], LDataLength * System.SizeOf(Byte));
       System.Inc(FBytesSinceSeed, LDataLength);
     end;
 
@@ -267,10 +276,20 @@ begin
 end;
 
 procedure TAesRandomProvider.GetNonZeroBytes(const AData: TCryptoLibByteArray);
+var
+  LI: Int32;
+  LTmp: TCryptoLibByteArray;
 begin
-  repeat
-    GetBytes(AData);
-  until (TArrayUtilities.NoZeroes(AData));
+  GetBytes(AData);
+  System.SetLength(LTmp, 1);
+  for LI := System.Low(AData) to System.High(AData) do
+  begin
+    while AData[LI] = 0 do
+    begin
+      GetBytes(LTmp);
+      AData[LI] := LTmp[0];
+    end;
+  end;
 end;
 
 function TAesRandomProvider.GetIsAvailable: Boolean;

+ 39 - 122
CryptoLib/src/Rngs/Providers/ClpAppleRandomProvider.pas

@@ -21,8 +21,8 @@ unit ClpAppleRandomProvider;
 
 interface
 
-uses
 {$IFDEF CRYPTOLIB_APPLE}
+uses
 {$IFDEF FPC}
 {$LINKFRAMEWORK Security}
 {$IFDEF CRYPTOLIB_MACOS}
@@ -37,39 +37,21 @@ uses
   Macapi.AppKit,
   Macapi.Foundation,
 {$ENDIF}
-{$ENDIF}
-{$ENDIF}
-{$IFDEF CRYPTOLIB_UNIX}
-  Classes,
-{$IFDEF FPC}
-  BaseUnix,
-{$ELSE}
-  Posix.Errno,
-{$ENDIF}
 {$ENDIF}
   SysUtils,
   ClpCryptoLibTypes,
   ClpIRandomSourceProvider;
 
 resourcestring
-  SAppleSecRandomCopyBytesGenerationError =
-    'An Error Occured while generating random data using SecRandomCopyBytes API.';
+  SAppleSecRandomError =
+    'An Error Occurred while generating random data using SecRandomCopyBytes API.';
 
 type
-{$IFDEF CRYPTOLIB_APPLE}
 {$IFDEF FPC}
-  // similar to a TOpaqueData already defined in newer FPC but not available in 3.0.4
-  // TODO when we upgrade to FPC 3.2.0, remove " __SecRandom = record end;" declaration
-  __SecRandom = record
-  end;
+  SecRandomRef = OpaquePointer;
 
-  // similar to POpaqueData (or an OpaquePointer) already defined in newer FPC but not available in 3.0.4
-  // TODO when we upgrade to FPC 3.2.0, use inbuilt OpaquePointer instead
-  // replace "SecRandomRef = ^__SecRandom;" with "SecRandomRef = OpaquePointer;"
-  SecRandomRef = ^__SecRandom;
-
-function SecRandomCopyBytes(rnd: SecRandomRef; count: LongWord; bytes: PByte)
-  : Int32; cdecl; external;
+function SecRandomCopyBytes(ARnd: SecRandomRef; ACount: NativeUInt;
+  ABytes: PByte): Int32; cdecl; external;
 
 {$ELSE}
 
@@ -79,10 +61,10 @@ type
 const
   libSecurity = '/System/Library/Frameworks/Security.framework/Security';
 
-function SecRandomCopyBytes(rnd: SecRandomRef; count: LongWord; bytes: PByte)
-  : Int32; cdecl; external libSecurity Name _PU + 'SecRandomCopyBytes';
+function SecRandomCopyBytes(ARnd: SecRandomRef; ACount: NativeUInt;
+  ABytes: PByte): Int32; cdecl;
+  external libSecurity Name _PU + 'SecRandomCopyBytes';
 
-{$ENDIF}
 {$ENDIF}
 
   /// <summary>
@@ -92,13 +74,9 @@ function SecRandomCopyBytes(rnd: SecRandomRef; count: LongWord; bytes: PByte)
   TAppleRandomProvider = class sealed(TInterfacedObject, IRandomSourceProvider)
 
   strict private
-{$IFDEF CRYPTOLIB_UNIX}
   const
-    EINTR = {$IFDEF FPC}ESysEINTR {$ELSE}Posix.Errno.EINTR{$ENDIF};
+    NSAppKitVersionNumber10_7 = 1138;
 
-    function ErrorNo: Int32;
-    function DevRandomDeviceRead(ALen: Int32; AData: PByte): Int32;
-{$ENDIF}
     function GenRandomBytesApple(ALen: Int32; AData: PByte): Int32;
 
   public
@@ -111,10 +89,13 @@ function SecRandomCopyBytes(rnd: SecRandomRef; count: LongWord; bytes: PByte)
 
   end;
 
+{$ENDIF}
+
 implementation
 
+{$IFDEF CRYPTOLIB_APPLE}
 uses
-  ClpArrayUtilities;
+  ClpDevRandomReader;
 
 { TAppleRandomProvider }
 
@@ -123,100 +104,33 @@ begin
   inherited Create();
 end;
 
-{$IFDEF CRYPTOLIB_UNIX}
-
-function TAppleRandomProvider.ErrorNo: Int32;
-begin
-  result := Errno;
-end;
-
-function TAppleRandomProvider.DevRandomDeviceRead(ALen: Int32;
-  AData: PByte): Int32;
-var
-  LStream: TFileStream;
-  LRandGen: String;
-  LGot, LMaxChunkSize: Int32;
-begin
-  LMaxChunkSize := ALen;
-  LRandGen := '/dev/urandom';
-
-  if not FileExists(LRandGen) then
-  begin
-    LRandGen := '/dev/random';
-
-    if not FileExists(LRandGen) then
-    begin
-      result := -1;
-      Exit;
-    end;
-  end;
-
-  LStream := TFileStream.Create(LRandGen, fmOpenRead);
-
-  try
-    while (ALen > 0) do
-    begin
-      if ALen <= LMaxChunkSize then
-      begin
-        LMaxChunkSize := ALen;
-      end;
-
-      LGot := LStream.Read(AData^, LMaxChunkSize);
-
-      if (LGot = 0) then
-      begin
-        if ErrorNo = EINTR then
-        begin
-          continue;
-        end;
-
-        result := -1;
-        Exit;
-      end;
-
-      System.Inc(AData, LGot);
-      System.Dec(ALen, LGot);
-    end;
-    result := 0;
-  finally
-    LStream.Free;
-  end;
-end;
-
-{$ENDIF}
-
 function TAppleRandomProvider.GenRandomBytesApple(ALen: Int32;
   AData: PByte): Int32;
-{$IFDEF CRYPTOLIB_APPLE}
+
   function kSecRandomDefault: SecRandomRef;
   begin
 {$IFDEF FPC}
-    result := nil;
+    Result := nil;
 {$ELSE}
-    result := CocoaPointerConst(libSecurity, 'kSecRandomDefault');
+    Result := CocoaPointerConst(libSecurity, 'kSecRandomDefault');
 {$ENDIF}
   end;
-{$ENDIF}
 
 begin
-{$IFDEF CRYPTOLIB_APPLE}
 {$IF DEFINED(CRYPTOLIB_MACOS)}
   // >= (Mac OS X 10.7+)
-  if NSAppKitVersionNumber >= 1138 then // NSAppKitVersionNumber10_7
+  if NSAppKitVersionNumber >= NSAppKitVersionNumber10_7 then
   begin
-    result := SecRandomCopyBytes(kSecRandomDefault, LongWord(ALen), AData);
+    Result := SecRandomCopyBytes(kSecRandomDefault, NativeUInt(ALen), AData);
   end
   else
   begin
     // fallback for when SecRandomCopyBytes API is not available
-    result := DevRandomDeviceRead(ALen, AData);
+    Result := TDevRandomReader.Read(ALen, AData, ALen);
   end;
 {$ELSE}
-  result := SecRandomCopyBytes(kSecRandomDefault, LongWord(ALen), AData);
+  Result := SecRandomCopyBytes(kSecRandomDefault, NativeUInt(ALen), AData);
 {$IFEND}
-{$ELSE}
-  result := -1;
-{$ENDIF}
 end;
 
 procedure TAppleRandomProvider.GetBytes(const AData: TCryptoLibByteArray);
@@ -230,36 +144,39 @@ begin
     Exit;
   end;
 
-{$IFDEF CRYPTOLIB_APPLE}
   if GenRandomBytesApple(LCount, PByte(AData)) <> 0 then
   begin
-    raise EOSRandomCryptoLibException.CreateRes
-      (@SAppleSecRandomCopyBytesGenerationError);
+    raise EOSRandomCryptoLibException.CreateRes(@SAppleSecRandomError);
   end;
-{$ELSE}
-  raise EOSRandomCryptoLibException.Create('AppleRandomProvider is only available on Apple platforms');
-{$ENDIF}
 end;
 
 procedure TAppleRandomProvider.GetNonZeroBytes(const AData: TCryptoLibByteArray);
+var
+  LI: Int32;
+  LTmp: TCryptoLibByteArray;
 begin
-  repeat
-    GetBytes(AData);
-  until (TArrayUtilities.NoZeroes(AData));
+  GetBytes(AData);
+  System.SetLength(LTmp, 1);
+  for LI := System.Low(AData) to System.High(AData) do
+  begin
+    while AData[LI] = 0 do
+    begin
+      GetBytes(LTmp);
+      AData[LI] := LTmp[0];
+    end;
+  end;
 end;
 
 function TAppleRandomProvider.GetIsAvailable: Boolean;
 begin
-{$IFDEF CRYPTOLIB_APPLE}
-  result := True;
-{$ELSE}
-  result := False;
-{$ENDIF}
+  Result := True;
 end;
 
 function TAppleRandomProvider.GetName: String;
 begin
-  result := 'Apple';
+  Result := 'Apple';
 end;
 
+{$ENDIF}
+
 end.

+ 127 - 0
CryptoLib/src/Rngs/Providers/ClpDevRandomReader.pas

@@ -0,0 +1,127 @@
+{ *********************************************************************************** }
+{ *                              CryptoLib Library                                  * }
+{ *                Copyright (c) 2018 - 20XX Ugochukwu Mmaduekwe                    * }
+{ *                 Github Repository <https://github.com/Xor-el>                   * }
+
+{ *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
+{ *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
+
+{ *                              Acknowledgements:                                  * }
+{ *                                                                                 * }
+{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
+{ *                           development of this library                           * }
+
+{ * ******************************************************************************* * }
+
+(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
+
+unit ClpDevRandomReader;
+
+{$I ..\..\Include\CryptoLib.inc}
+
+interface
+
+{$IFDEF CRYPTOLIB_UNIX}
+uses
+  Classes,
+{$IFDEF FPC}
+  BaseUnix,
+{$ELSE}
+  Posix.Errno,
+{$ENDIF}
+  SysUtils;
+
+const
+  EINTR = {$IFDEF FPC}ESysEINTR{$ELSE}Posix.Errno.EINTR{$ENDIF};
+
+type
+  /// <summary>
+  /// Shared utility for reading cryptographically random bytes from
+  /// /dev/urandom (preferred) or /dev/random (fallback) device files.
+  /// Used by Apple, Linux, Solaris, and Unix random providers.
+  /// </summary>
+  TDevRandomReader = class sealed
+  public
+    /// <summary>
+    /// Returns the current errno value from the OS.
+    /// </summary>
+    class function GetErrNo: Int32; static; inline;
+
+    /// <summary>
+    /// Reads ALength random bytes into AData from /dev/urandom or /dev/random.
+    /// AMaxChunkSize controls the maximum number of bytes read per iteration.
+    /// Pass ALength to read in a single chunk.
+    /// Returns 0 on success, -1 on failure.
+    /// </summary>
+    class function Read(ALength: Int32; AData: PByte;
+      AMaxChunkSize: Int32): Int32; static;
+  end;
+
+{$ENDIF}
+
+implementation
+
+{$IFDEF CRYPTOLIB_UNIX}
+
+{ TDevRandomReader }
+
+class function TDevRandomReader.GetErrNo: Int32;
+begin
+  Result := Errno;
+end;
+
+class function TDevRandomReader.Read(ALength: Int32; AData: PByte;
+  AMaxChunkSize: Int32): Int32;
+var
+  LStream: TFileStream;
+  LDevicePath: String;
+  LBytesRead: Int32;
+begin
+  LDevicePath := '/dev/urandom';
+
+  if not FileExists(LDevicePath) then
+  begin
+    LDevicePath := '/dev/random';
+
+    if not FileExists(LDevicePath) then
+    begin
+      Result := -1;
+      Exit;
+    end;
+  end;
+
+  LStream := TFileStream.Create(LDevicePath, fmOpenRead);
+
+  try
+    while (ALength > 0) do
+    begin
+      if ALength <= AMaxChunkSize then
+      begin
+        AMaxChunkSize := ALength;
+      end;
+
+      LBytesRead := LStream.Read(AData^, AMaxChunkSize);
+
+      if (LBytesRead = 0) then
+      begin
+        if GetErrNo = EINTR then
+        begin
+          continue;
+        end;
+
+        Result := -1;
+        Exit;
+      end;
+
+      System.Inc(AData, LBytesRead);
+      System.Dec(ALength, LBytesRead);
+    end;
+    Result := 0;
+  finally
+    LStream.Free;
+  end;
+end;
+
+{$ENDIF}
+
+end.

+ 26 - 26
CryptoLib/src/Rngs/Providers/ClpGenericBSDRandomProvider.pas

@@ -21,6 +21,7 @@ unit ClpGenericBSDRandomProvider;
 
 interface
 
+{$IFDEF CRYPTOLIB_GENERIC_BSD}
 uses
   SysUtils,
   ClpCryptoLibTypes,
@@ -28,14 +29,12 @@ uses
 
 resourcestring
   SArc4RandomBufGenerationError =
-    'An Error Occured while generating random data using arc4random_buf API.';
+    'An Error Occurred while generating random data using arc4random_buf API.';
 
-type
-{$IFDEF CRYPTOLIB_GENERIC_BSD}
-procedure arc4random_buf(bytes: PByte; count: LongWord); cdecl;
+procedure arc4random_buf(ABytes: PByte; ACount: NativeUInt); cdecl;
   external 'c' name 'arc4random_buf';
-{$ENDIF}
 
+type
   /// <summary>
   /// Generic BSD OS random source provider.
   /// Implements BSD variants using arc4random_buf
@@ -55,10 +54,11 @@ procedure arc4random_buf(bytes: PByte; count: LongWord); cdecl;
 
   end;
 
+{$ENDIF}
+
 implementation
 
-uses
-  ClpArrayUtilities;
+{$IFDEF CRYPTOLIB_GENERIC_BSD}
 
 { TGenericBSDRandomProvider }
 
@@ -70,12 +70,8 @@ end;
 function TGenericBSDRandomProvider.GenRandomBytesGenericBSD(ALen: Int32;
   AData: PByte): Int32;
 begin
-{$IFDEF CRYPTOLIB_GENERIC_BSD}
-  arc4random_buf(AData, LongWord(ALen));
-  result := 0;
-{$ELSE}
-  result := -1;
-{$ENDIF}
+  arc4random_buf(AData, NativeUInt(ALen));
+  Result := 0;
 end;
 
 procedure TGenericBSDRandomProvider.GetBytes(const AData: TCryptoLibByteArray);
@@ -89,35 +85,39 @@ begin
     Exit;
   end;
 
-{$IFDEF CRYPTOLIB_GENERIC_BSD}
   if GenRandomBytesGenericBSD(LCount, PByte(AData)) <> 0 then
   begin
     raise EOSRandomCryptoLibException.CreateRes(@SArc4RandomBufGenerationError);
   end;
-{$ELSE}
-  raise EOSRandomCryptoLibException.Create('GenericBSDRandomProvider is only available on BSD platforms');
-{$ENDIF}
 end;
 
 procedure TGenericBSDRandomProvider.GetNonZeroBytes(const AData: TCryptoLibByteArray);
+var
+  LI: Int32;
+  LTmp: TCryptoLibByteArray;
 begin
-  repeat
-    GetBytes(AData);
-  until (TArrayUtilities.NoZeroes(AData));
+  GetBytes(AData);
+  System.SetLength(LTmp, 1);
+  for LI := System.Low(AData) to System.High(AData) do
+  begin
+    while AData[LI] = 0 do
+    begin
+      GetBytes(LTmp);
+      AData[LI] := LTmp[0];
+    end;
+  end;
 end;
 
 function TGenericBSDRandomProvider.GetIsAvailable: Boolean;
 begin
-{$IFDEF CRYPTOLIB_GENERIC_BSD}
-  result := True;
-{$ELSE}
-  result := False;
-{$ENDIF}
+  Result := True;
 end;
 
 function TGenericBSDRandomProvider.GetName: String;
 begin
-  result := 'GenericBSD';
+  Result := 'GenericBSD';
 end;
 
+{$ENDIF}
+
 end.

+ 45 - 113
CryptoLib/src/Rngs/Providers/ClpLinuxRandomProvider.pas

@@ -21,20 +21,16 @@ unit ClpLinuxRandomProvider;
 
 interface
 
+{$IFDEF CRYPTOLIB_LINUX}
 uses
-{$IFDEF CRYPTOLIB_UNIX}
-  Classes,
 {$IFDEF FPC}
-  BaseUnix,
 {$IFDEF CRYPTOLIB_HAS_GETRANDOM}
   dl,
 {$ENDIF}
 {$ELSE}
-  Posix.Errno,
 {$IFDEF CRYPTOLIB_HAS_GETRANDOM}
   Posix.Dlfcn,
 {$ENDIF}
-{$ENDIF}
 {$ENDIF}
   SysUtils,
   ClpCryptoLibTypes,
@@ -42,11 +38,10 @@ uses
 
 resourcestring
   SLinuxGetRandomError =
-    'An Error Occured while generating random data using getRandom API';
+    'An Error Occurred while generating random data using getRandom API';
 
 type
 {$IFDEF CRYPTOLIB_HAS_GETRANDOM}
-{$IFDEF CRYPTOLIB_LINUX}
 {$IFDEF CRYPTOLIB_ANDROID}
 const
   LIBC_SO = 'libc.so';
@@ -54,11 +49,14 @@ const
 const
   LIBC_SO = 'libc.so.6';
 {$ENDIF}
-{$ENDIF}
+
+const
+  GRND_NONBLOCK = $0001;  // Don't block; return EAGAIN if no entropy
+  GRND_RANDOM   = $0002;  // Use /dev/random pool instead of /dev/urandom
 
 type
-  TGetRandom = function(pbBuffer: PByte; buflen: LongWord; flags: UInt32)
-    : Int32; cdecl;
+  TGetRandom = function(ABuffer: PByte; ABufferLength: NativeUInt;
+    AFlags: UInt32): NativeInt; cdecl;
 {$ENDIF}
 
   /// <summary>
@@ -68,17 +66,9 @@ type
   TLinuxRandomProvider = class sealed(TInterfacedObject, IRandomSourceProvider)
 
   strict private
-{$IFDEF CRYPTOLIB_UNIX}
-  const
-    EINTR = {$IFDEF FPC}ESysEINTR {$ELSE}Posix.Errno.EINTR{$ENDIF};
-    GRND_DEFAULT: Int32 = $0000;
-
-    function ErrorNo: Int32;
-    function DevRandomDeviceRead(ALen: Int32; AData: PByte): Int32;
-{$ENDIF}
 {$IFDEF CRYPTOLIB_HAS_GETRANDOM}
   var
-    FIsGetRandomSupportedOnOS: Boolean;
+    FHasGetRandom: Boolean;
     FGetRandom: TGetRandom;
 
     function IsGetRandomAvailable(): Boolean;
@@ -95,10 +85,13 @@ type
 
   end;
 
+{$ENDIF}
+
 implementation
 
+{$IFDEF CRYPTOLIB_LINUX}
 uses
-  ClpArrayUtilities;
+  ClpDevRandomReader;
 
 { TLinuxRandomProvider }
 
@@ -106,85 +99,24 @@ constructor TLinuxRandomProvider.Create;
 begin
   inherited Create();
 {$IFDEF CRYPTOLIB_HAS_GETRANDOM}
-  FIsGetRandomSupportedOnOS := IsGetRandomAvailable();
+  FHasGetRandom := IsGetRandomAvailable();
 {$ENDIF}
 end;
 
-{$IFDEF CRYPTOLIB_UNIX}
-
-function TLinuxRandomProvider.ErrorNo: Int32;
-begin
-  result := Errno;
-end;
-
-function TLinuxRandomProvider.DevRandomDeviceRead(ALen: Int32;
-  AData: PByte): Int32;
-var
-  LStream: TFileStream;
-  LRandGen: String;
-  LGot, LMaxChunkSize: Int32;
-begin
-  LMaxChunkSize := ALen;
-  LRandGen := '/dev/urandom';
-
-  if not FileExists(LRandGen) then
-  begin
-    LRandGen := '/dev/random';
-
-    if not FileExists(LRandGen) then
-    begin
-      result := -1;
-      Exit;
-    end;
-  end;
-
-  LStream := TFileStream.Create(LRandGen, fmOpenRead);
-
-  try
-    while (ALen > 0) do
-    begin
-      if ALen <= LMaxChunkSize then
-      begin
-        LMaxChunkSize := ALen;
-      end;
-
-      LGot := LStream.Read(AData^, LMaxChunkSize);
-
-      if (LGot = 0) then
-      begin
-        if ErrorNo = EINTR then
-        begin
-          continue;
-        end;
-
-        result := -1;
-        Exit;
-      end;
-
-      System.Inc(AData, LGot);
-      System.Dec(ALen, LGot);
-    end;
-    result := 0;
-  finally
-    LStream.Free;
-  end;
-end;
-
-{$ENDIF}
 {$IFDEF CRYPTOLIB_HAS_GETRANDOM}
 
 function TLinuxRandomProvider.IsGetRandomAvailable(): Boolean;
 var
-  LLib: {$IFDEF FPC} PtrInt {$ELSE} NativeUInt {$ENDIF};
+  LLib: NativeUInt;
 begin
   FGetRandom := nil;
-  LLib := {$IFDEF FPC}PtrInt{$ENDIF}(dlopen(LIBC_SO, RTLD_NOW));
+  LLib := {$IFDEF FPC}NativeUInt{$ENDIF}(dlopen(LIBC_SO, RTLD_NOW));
   if LLib <> 0 then
   begin
     FGetRandom := dlsym(LLib, 'getrandom');
     dlclose(LLib);
   end;
-  result := System.Assigned(FGetRandom);
+  Result := System.Assigned(FGetRandom);
 end;
 
 {$ENDIF}
@@ -192,40 +124,36 @@ end;
 function TLinuxRandomProvider.GenRandomBytesLinux(ALen: Int32;
   AData: PByte): Int32;
 var
-  LGot: Int32;
+  LBytesRead: NativeInt;
 begin
-{$IFDEF CRYPTOLIB_LINUX}
 {$IFDEF CRYPTOLIB_HAS_GETRANDOM}
-  if FIsGetRandomSupportedOnOS then
+  if FHasGetRandom then
   begin
     while (ALen > 0) do
     begin
-      LGot := FGetRandom(AData, LongWord(ALen), GRND_DEFAULT);
+      LBytesRead := FGetRandom(AData, NativeUInt(ALen), 0);
 
-      if (LGot < 0) then
+      if (LBytesRead < 0) then
       begin
-        if ErrorNo = EINTR then
+        if TDevRandomReader.GetErrNo = EINTR then
         begin
           continue;
         end;
-        result := -1;
+        Result := -1;
         Exit;
       end;
-      System.Inc(AData, LGot);
-      System.Dec(ALen, LGot);
+      System.Inc(AData, LBytesRead);
+      System.Dec(ALen, LBytesRead);
     end;
-    result := 0;
+    Result := 0;
   end
   else
   begin
     // fallback for when getrandom API is not available
-    result := DevRandomDeviceRead(ALen, AData);
+    Result := TDevRandomReader.Read(ALen, AData, ALen);
   end;
 {$ELSE}
-  result := DevRandomDeviceRead(ALen, AData);
-{$ENDIF}
-{$ELSE}
-  result := -1;
+  Result := TDevRandomReader.Read(ALen, AData, ALen);
 {$ENDIF}
 end;
 
@@ -240,35 +168,39 @@ begin
     Exit;
   end;
 
-{$IFDEF CRYPTOLIB_LINUX}
   if GenRandomBytesLinux(LCount, PByte(AData)) <> 0 then
   begin
     raise EOSRandomCryptoLibException.CreateRes(@SLinuxGetRandomError);
   end;
-{$ELSE}
-  raise EOSRandomCryptoLibException.Create('LinuxRandomProvider is only available on Linux');
-{$ENDIF}
 end;
 
 procedure TLinuxRandomProvider.GetNonZeroBytes(const AData: TCryptoLibByteArray);
+var
+  LI: Int32;
+  LTmp: TCryptoLibByteArray;
 begin
-  repeat
-    GetBytes(AData);
-  until (TArrayUtilities.NoZeroes(AData));
+  GetBytes(AData);
+  System.SetLength(LTmp, 1);
+  for LI := System.Low(AData) to System.High(AData) do
+  begin
+    while AData[LI] = 0 do
+    begin
+      GetBytes(LTmp);
+      AData[LI] := LTmp[0];
+    end;
+  end;
 end;
 
 function TLinuxRandomProvider.GetIsAvailable: Boolean;
 begin
-{$IFDEF CRYPTOLIB_LINUX}
-  result := True;
-{$ELSE}
-  result := False;
-{$ENDIF}
+  Result := True;
 end;
 
 function TLinuxRandomProvider.GetName: String;
 begin
-  result := 'Linux';
+  Result := 'Linux';
 end;
 
+{$ENDIF}
+
 end.

+ 1 - 1
CryptoLib/src/Rngs/Providers/ClpOSRandomProvider.pas

@@ -119,7 +119,7 @@ begin
       FLock.Leave;
     end;
   end;
-  result := FInstance;
+  Result := FInstance;
 end;
 
 class procedure TOSRandomProvider.Boot;

+ 51 - 115
CryptoLib/src/Rngs/Providers/ClpSolarisRandomProvider.pas

@@ -21,20 +21,16 @@ unit ClpSolarisRandomProvider;
 
 interface
 
+{$IFDEF CRYPTOLIB_SOLARIS}
 uses
-{$IFDEF CRYPTOLIB_UNIX}
-  Classes,
 {$IFDEF FPC}
-  BaseUnix,
 {$IFDEF CRYPTOLIB_HAS_GETRANDOM}
   dl,
 {$ENDIF}
 {$ELSE}
-  Posix.Errno,
 {$IFDEF CRYPTOLIB_HAS_GETRANDOM}
   Posix.Dlfcn,
 {$ENDIF}
-{$ENDIF}
 {$ENDIF}
   SysUtils,
   ClpCryptoLibTypes,
@@ -42,18 +38,23 @@ uses
 
 resourcestring
   SSolarisGetRandomError =
-    'An Error Occured while generating random data using getRandom API';
+    'An Error Occurred while generating random data using getRandom API';
 
 type
 {$IFDEF CRYPTOLIB_HAS_GETRANDOM}
-{$IFDEF CRYPTOLIB_SOLARIS}
 const
   LIBC_SO = 'libc.so.1';
-{$ENDIF}
+
+  // Solaris getrandom flags (from sys/random.h)
+  GRND_NONBLOCK = $0001;  // Don't block; return EAGAIN if no entropy
+  GRND_RANDOM   = $0002;  // Use /dev/random pool instead of /dev/urandom
+
+  // Maximum buffer size supported by Solaris getrandom (EINVAL if exceeded)
+  SolarisGetRandomMaxBuffer = 1024;
 
 type
-  TGetRandom = function(pbBuffer: PByte; buflen: LongWord; flags: UInt32)
-    : Int32; cdecl;
+  TGetRandom = function(ABuffer: PByte; ABufferLength: NativeUInt;
+    AFlags: UInt32): NativeInt; cdecl;
 {$ENDIF}
 
   /// <summary>
@@ -63,17 +64,9 @@ type
   TSolarisRandomProvider = class sealed(TInterfacedObject, IRandomSourceProvider)
 
   strict private
-{$IFDEF CRYPTOLIB_UNIX}
-  const
-    EINTR = {$IFDEF FPC}ESysEINTR {$ELSE}Posix.Errno.EINTR{$ENDIF};
-    GRND_DEFAULT: Int32 = $0000;
-
-    function ErrorNo: Int32;
-    function DevRandomDeviceRead(ALen: Int32; AData: PByte): Int32;
-{$ENDIF}
 {$IFDEF CRYPTOLIB_HAS_GETRANDOM}
   var
-    FIsGetRandomSupportedOnOS: Boolean;
+    FHasGetRandom: Boolean;
     FGetRandom: TGetRandom;
 
     function IsGetRandomAvailable(): Boolean;
@@ -90,10 +83,13 @@ type
 
   end;
 
+{$ENDIF}
+
 implementation
 
+{$IFDEF CRYPTOLIB_SOLARIS}
 uses
-  ClpArrayUtilities;
+  ClpDevRandomReader;
 
 { TSolarisRandomProvider }
 
@@ -101,86 +97,24 @@ constructor TSolarisRandomProvider.Create;
 begin
   inherited Create();
 {$IFDEF CRYPTOLIB_HAS_GETRANDOM}
-  FIsGetRandomSupportedOnOS := IsGetRandomAvailable();
+  FHasGetRandom := IsGetRandomAvailable();
 {$ENDIF}
 end;
 
-{$IFDEF CRYPTOLIB_UNIX}
-
-function TSolarisRandomProvider.ErrorNo: Int32;
-begin
-  result := Errno;
-end;
-
-function TSolarisRandomProvider.DevRandomDeviceRead(ALen: Int32;
-  AData: PByte): Int32;
-var
-  LStream: TFileStream;
-  LRandGen: String;
-  LGot, LMaxChunkSize: Int32;
-begin
-  LMaxChunkSize := 128 * 1040; // 128 * 1040 bytes
-  LRandGen := '/dev/urandom';
-
-  if not FileExists(LRandGen) then
-  begin
-    LMaxChunkSize := 1040; // 1040 bytes
-    LRandGen := '/dev/random';
-
-    if not FileExists(LRandGen) then
-    begin
-      result := -1;
-      Exit;
-    end;
-  end;
-
-  LStream := TFileStream.Create(LRandGen, fmOpenRead);
-
-  try
-    while (ALen > 0) do
-    begin
-      if ALen <= LMaxChunkSize then
-      begin
-        LMaxChunkSize := ALen;
-      end;
-
-      LGot := LStream.Read(AData^, LMaxChunkSize);
-
-      if (LGot = 0) then
-      begin
-        if ErrorNo = EINTR then
-        begin
-          continue;
-        end;
-
-        result := -1;
-        Exit;
-      end;
-
-      System.Inc(AData, LGot);
-      System.Dec(ALen, LGot);
-    end;
-    result := 0;
-  finally
-    LStream.Free;
-  end;
-end;
-
-{$ENDIF}
 {$IFDEF CRYPTOLIB_HAS_GETRANDOM}
 
 function TSolarisRandomProvider.IsGetRandomAvailable(): Boolean;
 var
-  LLib: {$IFDEF FPC} PtrInt {$ELSE} NativeUInt {$ENDIF};
+  LLib: NativeUInt;
 begin
   FGetRandom := nil;
-  LLib := {$IFDEF FPC}PtrInt{$ENDIF}(dlopen(LIBC_SO, RTLD_NOW));
+  LLib := {$IFDEF FPC}NativeUInt{$ENDIF}(dlopen(LIBC_SO, RTLD_NOW));
   if LLib <> 0 then
   begin
     FGetRandom := dlsym(LLib, 'getrandom');
     dlclose(LLib);
   end;
-  result := System.Assigned(FGetRandom);
+  Result := System.Assigned(FGetRandom);
 end;
 
 {$ENDIF}
@@ -188,13 +122,13 @@ end;
 function TSolarisRandomProvider.GenRandomBytesSolaris(ALen: Int32;
   AData: PByte): Int32;
 var
-  LGot, LMaxChunkSize: Int32;
+  LBytesRead: NativeInt;
+  LMaxChunkSize: Int32;
 begin
-  LMaxChunkSize := 256; // 256 bytes
+  LMaxChunkSize := SolarisGetRandomMaxBuffer;
 
-{$IFDEF CRYPTOLIB_SOLARIS}
 {$IFDEF CRYPTOLIB_HAS_GETRANDOM}
-  if FIsGetRandomSupportedOnOS then
+  if FHasGetRandom then
   begin
     while (ALen > 0) do
     begin
@@ -203,32 +137,30 @@ begin
         LMaxChunkSize := ALen;
       end;
 
-      LGot := FGetRandom(AData, LongWord(LMaxChunkSize), GRND_DEFAULT);
+      LBytesRead := FGetRandom(AData, NativeUInt(LMaxChunkSize), 0);
 
-      if (LGot = 0) then
+      // Hardened: covers 0 (error per Solaris docs) and -1 (EAGAIN defensive)
+      if (LBytesRead <= 0) then
       begin
-        if ErrorNo = EINTR then
+        if TDevRandomReader.GetErrNo = EINTR then
         begin
           continue;
         end;
-        result := -1;
+        Result := -1;
         Exit;
       end;
-      System.Inc(AData, LGot);
-      System.Dec(ALen, LGot);
+      System.Inc(AData, LBytesRead);
+      System.Dec(ALen, LBytesRead);
     end;
-    result := 0;
+    Result := 0;
   end
   else
   begin
     // fallback for when getrandom API is not available
-    result := DevRandomDeviceRead(ALen, AData);
+    Result := TDevRandomReader.Read(ALen, AData, SolarisGetRandomMaxBuffer);
   end;
 {$ELSE}
-  result := DevRandomDeviceRead(ALen, AData);
-{$ENDIF}
-{$ELSE}
-  result := -1;
+  Result := TDevRandomReader.Read(ALen, AData, SolarisGetRandomMaxBuffer);
 {$ENDIF}
 end;
 
@@ -243,35 +175,39 @@ begin
     Exit;
   end;
 
-{$IFDEF CRYPTOLIB_SOLARIS}
   if GenRandomBytesSolaris(LCount, PByte(AData)) <> 0 then
   begin
     raise EOSRandomCryptoLibException.CreateRes(@SSolarisGetRandomError);
   end;
-{$ELSE}
-  raise EOSRandomCryptoLibException.Create('SolarisRandomProvider is only available on Solaris');
-{$ENDIF}
 end;
 
 procedure TSolarisRandomProvider.GetNonZeroBytes(const AData: TCryptoLibByteArray);
+var
+  LI: Int32;
+  LTmp: TCryptoLibByteArray;
 begin
-  repeat
-    GetBytes(AData);
-  until (TArrayUtilities.NoZeroes(AData));
+  GetBytes(AData);
+  System.SetLength(LTmp, 1);
+  for LI := System.Low(AData) to System.High(AData) do
+  begin
+    while AData[LI] = 0 do
+    begin
+      GetBytes(LTmp);
+      AData[LI] := LTmp[0];
+    end;
+  end;
 end;
 
 function TSolarisRandomProvider.GetIsAvailable: Boolean;
 begin
-{$IFDEF CRYPTOLIB_SOLARIS}
-  result := True;
-{$ELSE}
-  result := False;
-{$ENDIF}
+  Result := True;
 end;
 
 function TSolarisRandomProvider.GetName: String;
 begin
-  result := 'Solaris';
+  Result := 'Solaris';
 end;
 
+{$ENDIF}
+
 end.

+ 27 - 89
CryptoLib/src/Rngs/Providers/ClpUnixRandomProvider.pas

@@ -21,22 +21,15 @@ unit ClpUnixRandomProvider;
 
 interface
 
-uses
 {$IFDEF CRYPTOLIB_UNIX}
-  Classes,
-{$IFDEF FPC}
-  BaseUnix,
-{$ELSE}
-  Posix.Errno,
-{$ENDIF}
-{$ENDIF}
+uses
   SysUtils,
   ClpCryptoLibTypes,
   ClpIRandomSourceProvider;
 
 resourcestring
   SRandomDeviceReadError =
-    'An Error Occured while reading random data from random device (file)';
+    'An Error Occurred while reading random data from random device (file)';
 
 type
   /// <summary>
@@ -46,13 +39,7 @@ type
   TUnixRandomProvider = class sealed(TInterfacedObject, IRandomSourceProvider)
 
   strict private
-{$IFDEF CRYPTOLIB_UNIX}
-  const
-    EINTR = {$IFDEF FPC}ESysEINTR {$ELSE}Posix.Errno.EINTR{$ENDIF};
-
-    function ErrorNo: Int32;
-    function DevRandomDeviceRead(ALen: Int32; AData: PByte): Int32;
-{$ENDIF}
+    function GenRandomBytesUnix(ALen: Int32; AData: PByte): Int32;
 
   public
     constructor Create();
@@ -64,10 +51,13 @@ type
 
   end;
 
+{$ENDIF}
+
 implementation
 
+{$IFDEF CRYPTOLIB_UNIX}
 uses
-  ClpArrayUtilities;
+  ClpDevRandomReader;
 
 { TUnixRandomProvider }
 
@@ -76,68 +66,12 @@ begin
   inherited Create();
 end;
 
-{$IFDEF CRYPTOLIB_UNIX}
-
-function TUnixRandomProvider.ErrorNo: Int32;
-begin
-  result := Errno;
-end;
-
-function TUnixRandomProvider.DevRandomDeviceRead(ALen: Int32;
+function TUnixRandomProvider.GenRandomBytesUnix(ALen: Int32;
   AData: PByte): Int32;
-var
-  LStream: TFileStream;
-  LRandGen: String;
-  LGot, LMaxChunkSize: Int32;
 begin
-  LMaxChunkSize := ALen;
-  LRandGen := '/dev/urandom';
-
-  if not FileExists(LRandGen) then
-  begin
-    LRandGen := '/dev/random';
-
-    if not FileExists(LRandGen) then
-    begin
-      result := -1;
-      Exit;
-    end;
-  end;
-
-  LStream := TFileStream.Create(LRandGen, fmOpenRead);
-
-  try
-    while (ALen > 0) do
-    begin
-      if ALen <= LMaxChunkSize then
-      begin
-        LMaxChunkSize := ALen;
-      end;
-
-      LGot := LStream.Read(AData^, LMaxChunkSize);
-
-      if (LGot = 0) then
-      begin
-        if ErrorNo = EINTR then
-        begin
-          continue;
-        end;
-
-        result := -1;
-        Exit;
-      end;
-
-      System.Inc(AData, LGot);
-      System.Dec(ALen, LGot);
-    end;
-    result := 0;
-  finally
-    LStream.Free;
-  end;
+  Result := TDevRandomReader.Read(ALen, AData, ALen);
 end;
 
-{$ENDIF}
-
 procedure TUnixRandomProvider.GetBytes(const AData: TCryptoLibByteArray);
 var
   LCount: Int32;
@@ -149,35 +83,39 @@ begin
     Exit;
   end;
 
-{$IFDEF CRYPTOLIB_UNIX}
-  if DevRandomDeviceRead(LCount, PByte(AData)) <> 0 then
+  if GenRandomBytesUnix(LCount, PByte(AData)) <> 0 then
   begin
     raise EOSRandomCryptoLibException.CreateRes(@SRandomDeviceReadError);
   end;
-{$ELSE}
-  raise EOSRandomCryptoLibException.Create('UnixRandomProvider is only available on Unix platforms');
-{$ENDIF}
 end;
 
 procedure TUnixRandomProvider.GetNonZeroBytes(const AData: TCryptoLibByteArray);
+var
+  LI: Int32;
+  LTmp: TCryptoLibByteArray;
 begin
-  repeat
-    GetBytes(AData);
-  until (TArrayUtilities.NoZeroes(AData));
+  GetBytes(AData);
+  System.SetLength(LTmp, 1);
+  for LI := System.Low(AData) to System.High(AData) do
+  begin
+    while AData[LI] = 0 do
+    begin
+      GetBytes(LTmp);
+      AData[LI] := LTmp[0];
+    end;
+  end;
 end;
 
 function TUnixRandomProvider.GetIsAvailable: Boolean;
 begin
-{$IFDEF CRYPTOLIB_UNIX}
-  result := True;
-{$ELSE}
-  result := False;
-{$ENDIF}
+  Result := True;
 end;
 
 function TUnixRandomProvider.GetName: String;
 begin
-  result := 'Unix';
+  Result := 'Unix';
 end;
 
+{$ENDIF}
+
 end.

+ 141 - 134
CryptoLib/src/Rngs/Providers/ClpWindowsRandomProvider.pas

@@ -21,71 +21,69 @@ unit ClpWindowsRandomProvider;
 
 interface
 
-uses
 {$IFDEF CRYPTOLIB_MSWINDOWS}
+uses
   Windows,
-{$ENDIF}
   SysUtils,
   ClpCryptoLibTypes,
   ClpIRandomSourceProvider;
 
 resourcestring
-  SMSWIndowsCryptographyAPIGenerationError =
-    'An Error Occured while generating random data using MS Windows Cryptography API.';
+  SWindowsCryptoApiGenerationError =
+    'An Error Occurred while generating random data using MS Windows Cryptography API.';
 
 type
   /// <summary>
   /// Windows OS random source provider.
-  /// Implements Windows random APIs in order: RtlGenRandom -> CryptGenRandom -> BCryptGenRandom
+  /// Implements Windows random APIs in order: BCryptGenRandom -> RtlGenRandom -> CryptGenRandom
   /// </summary>
   TWindowsRandomProvider = class sealed(TInterfacedObject, IRandomSourceProvider)
 
   strict private
   const
-    BCRYPT = 'bcrypt.dll';
-    ADVAPI32 = 'advapi32.dll';
+    BCRYPT_DLL = 'bcrypt.dll';
+    ADVAPI32_DLL = 'advapi32.dll';
+    BCRYPT_USE_SYSTEM_PREFERRED_RNG = $00000002;
 
   type
     BCRYPT_ALG_HANDLE = THandle;
     NTStatus = HRESULT;
 
-    TBCryptGenRandom = function(hAlgorithm: BCRYPT_ALG_HANDLE; pbBuffer: PUCHAR;
-      cbBuffer, dwFlags: ULONG): NTStatus; stdcall;
-
-    TBCryptOpenAlgorithmProvider = function(phAlgorithm: PVOID;
-      pszAlgId, pszImplementation: LPCWSTR; dwFlags: ULONG): NTStatus; stdcall;
-
-    TBCryptCloseAlgorithmProvider = function(hAlgorithm: BCRYPT_ALG_HANDLE;
-      dwFlags: ULONG): NTStatus; stdcall;
+    TBCryptGenRandom = function(AAlgorithm: BCRYPT_ALG_HANDLE;
+      ABuffer: PUCHAR; ABufferSize: ULONG; AFlags: ULONG): NTStatus; stdcall;
 
-    TCryptGenRandom = function(hProv: THandle; dwLen: DWORD; pbBuffer: PByte)
-      : BOOL; stdcall;
+    TCryptGenRandom = function(AProviderHandle: THandle; ALength: DWORD;
+      ABuffer: PByte): BOOL; stdcall;
 
-    TCryptAcquireContextW = function(phProv: Pointer; pszContainer: LPCWSTR;
-      pszProvider: LPCWSTR; dwProvType: DWORD; dwFlags: DWORD): BOOL; stdcall;
+    TCryptAcquireContextW = function(AProviderHandle: Pointer;
+      AContainer: LPCWSTR; AProvider: LPCWSTR; AProviderType: DWORD;
+      AFlags: DWORD): BOOL; stdcall;
 
-    TCryptReleaseContext = function(hProv: THandle; dwFlags: DWORD)
-      : BOOL; stdcall;
+    TCryptReleaseContext = function(AProviderHandle: THandle;
+      AFlags: DWORD): BOOL; stdcall;
 
-    TRtlGenRandom = function(RandomBuffer: PVOID; RandomBufferLength: ULONG)
-      : Boolean; stdcall;
+    TRtlGenRandom = function(ABuffer: PVOID;
+      ABufferLength: ULONG): Boolean; stdcall;
 
   var
-    FIsCngBCryptGenRandomSupportedOnOS: Boolean;
-    FIsCryptGenRandomSupportedOnOS: Boolean;
-    FIsRtlGenRandomSupportedOnOS: Boolean;
+    FHasBCryptGenRandom: Boolean;
+    FHasCryptGenRandom: Boolean;
+    FHasRtlGenRandom: Boolean;
+    FBCryptModuleHandle: THandle;
+    FAdvapi32ModuleHandle: THandle;
     FBCryptGenRandom: TBCryptGenRandom;
-    FBCryptOpenAlgorithmProvider: TBCryptOpenAlgorithmProvider;
-    FBCryptCloseAlgorithmProvider: TBCryptCloseAlgorithmProvider;
     FCryptGenRandom: TCryptGenRandom;
     FCryptAcquireContextW: TCryptAcquireContextW;
     FCryptReleaseContext: TCryptReleaseContext;
     FRtlGenRandom: TRtlGenRandom;
 
+    class function BCRYPT_SUCCESS(AStatus: NTStatus): Boolean;
+      static; inline;
+
     function GetProcedureAddress(AModuleHandle: THandle;
       const AProcedureName: String; var AFunctionFound: Boolean): Pointer;
 
-    function IsCngBCryptGenRandomAvailable(): Boolean;
+    function IsBCryptGenRandomAvailable(): Boolean;
     function IsCryptGenRandomAvailable(): Boolean;
     function IsRtlGenRandomAvailable(): Boolean;
 
@@ -93,6 +91,7 @@ type
 
   public
     constructor Create();
+    destructor Destroy; override;
 
     procedure GetBytes(const AData: TCryptoLibByteArray);
     procedure GetNonZeroBytes(const AData: TCryptoLibByteArray);
@@ -101,175 +100,180 @@ type
 
   end;
 
+{$ENDIF}
+
 implementation
 
-uses
-  ClpArrayUtilities;
+{$IFDEF CRYPTOLIB_MSWINDOWS}
 
 { TWindowsRandomProvider }
 
 constructor TWindowsRandomProvider.Create;
 begin
   inherited Create();
-  FIsCngBCryptGenRandomSupportedOnOS := IsCngBCryptGenRandomAvailable();
-  FIsCryptGenRandomSupportedOnOS := IsCryptGenRandomAvailable();
-  FIsRtlGenRandomSupportedOnOS := IsRtlGenRandomAvailable();
+  FBCryptModuleHandle := 0;
+  FAdvapi32ModuleHandle := 0;
+  // Load advapi32.dll once for both RtlGenRandom and CryptGenRandom
+  FAdvapi32ModuleHandle := SafeLoadLibrary(ADVAPI32_DLL, SEM_FAILCRITICALERRORS);
+  // Priority order: BCryptGenRandom -> RtlGenRandom -> CryptGenRandom
+  FHasBCryptGenRandom := IsBCryptGenRandomAvailable();
+  FHasRtlGenRandom := IsRtlGenRandomAvailable();
+  FHasCryptGenRandom := IsCryptGenRandomAvailable();
+end;
+
+destructor TWindowsRandomProvider.Destroy;
+begin
+  if FBCryptModuleHandle <> 0 then
+  begin
+    FreeLibrary(FBCryptModuleHandle);
+    FBCryptModuleHandle := 0;
+  end;
+  if FAdvapi32ModuleHandle <> 0 then
+  begin
+    FreeLibrary(FAdvapi32ModuleHandle);
+    FAdvapi32ModuleHandle := 0;
+  end;
+  inherited Destroy;
+end;
+
+class function TWindowsRandomProvider.BCRYPT_SUCCESS(
+  AStatus: NTStatus): Boolean;
+begin
+  Result := AStatus >= 0;
 end;
 
 function TWindowsRandomProvider.GetProcedureAddress(AModuleHandle: THandle;
   const AProcedureName: String; var AFunctionFound: Boolean): Pointer;
 begin
-  result := GetProcAddress(AModuleHandle, PChar(AProcedureName));
-  if result = nil then
+  Result := GetProcAddress(AModuleHandle, PChar(AProcedureName));
+  if Result = nil then
   begin
     AFunctionFound := False;
   end;
 end;
 
-function TWindowsRandomProvider.IsCngBCryptGenRandomAvailable(): Boolean;
+function TWindowsRandomProvider.IsBCryptGenRandomAvailable(): Boolean;
 var
-  LModuleHandle: THandle;
   LFunctionFound: Boolean;
+  LTestBuffer: array[0..7] of Byte;
 begin
-  result := False;
-  LModuleHandle := SafeLoadLibrary(BCRYPT, SEM_FAILCRITICALERRORS);
-  if LModuleHandle <> 0 then
+  Result := False;
+  FBCryptModuleHandle := SafeLoadLibrary(BCRYPT_DLL, SEM_FAILCRITICALERRORS);
+  if FBCryptModuleHandle <> 0 then
   begin
-    result := True;
-    LFunctionFound := True;
-    FBCryptOpenAlgorithmProvider := GetProcedureAddress(LModuleHandle,
-      'BCryptOpenAlgorithmProvider', LFunctionFound);
-    result := result and LFunctionFound;
     LFunctionFound := True;
-    FBCryptCloseAlgorithmProvider := GetProcedureAddress(LModuleHandle,
-      'BCryptCloseAlgorithmProvider', LFunctionFound);
-    result := result and LFunctionFound;
-    LFunctionFound := True;
-    FBCryptGenRandom := GetProcedureAddress(LModuleHandle,
+    FBCryptGenRandom := GetProcedureAddress(FBCryptModuleHandle,
       'BCryptGenRandom', LFunctionFound);
-    result := result and LFunctionFound;
+    if LFunctionFound then
+    begin
+      // Probe: verify BCRYPT_USE_SYSTEM_PREFERRED_RNG works on this OS version
+      // (requires Windows Vista SP2+ or Windows Server 2008+)
+      Result := BCRYPT_SUCCESS(FBCryptGenRandom(0, @LTestBuffer[0], 8,
+        BCRYPT_USE_SYSTEM_PREFERRED_RNG));
+    end;
+    if not Result then
+    begin
+      FreeLibrary(FBCryptModuleHandle);
+      FBCryptModuleHandle := 0;
+      FBCryptGenRandom := nil;
+    end;
   end;
 end;
 
-function TWindowsRandomProvider.IsCryptGenRandomAvailable(): Boolean;
+function TWindowsRandomProvider.IsRtlGenRandomAvailable(): Boolean;
 var
-  LModuleHandle: THandle;
   LFunctionFound: Boolean;
 begin
-  result := False;
-  LModuleHandle := SafeLoadLibrary(ADVAPI32, SEM_FAILCRITICALERRORS);
-  if LModuleHandle <> 0 then
+  Result := False;
+  if FAdvapi32ModuleHandle <> 0 then
   begin
-    result := True;
-    LFunctionFound := True;
-    FCryptAcquireContextW := GetProcedureAddress(LModuleHandle,
-      'CryptAcquireContextW', LFunctionFound);
-    result := result and LFunctionFound;
-    LFunctionFound := True;
-    FCryptReleaseContext := GetProcedureAddress(LModuleHandle,
-      'CryptReleaseContext', LFunctionFound);
-    result := result and LFunctionFound;
     LFunctionFound := True;
-    FCryptGenRandom := GetProcedureAddress(LModuleHandle,
-      'CryptGenRandom', LFunctionFound);
-    result := result and LFunctionFound;
+    FRtlGenRandom := GetProcedureAddress(FAdvapi32ModuleHandle,
+      'SystemFunction036', LFunctionFound);
+    Result := LFunctionFound;
   end;
 end;
 
-function TWindowsRandomProvider.IsRtlGenRandomAvailable(): Boolean;
+function TWindowsRandomProvider.IsCryptGenRandomAvailable(): Boolean;
 var
-  LModuleHandle: THandle;
   LFunctionFound: Boolean;
 begin
-  result := False;
-  LModuleHandle := SafeLoadLibrary(ADVAPI32, SEM_FAILCRITICALERRORS);
-  if LModuleHandle <> 0 then
+  Result := False;
+  if FAdvapi32ModuleHandle <> 0 then
   begin
-    result := True;
+    Result := True;
     LFunctionFound := True;
-    FRtlGenRandom := GetProcedureAddress(LModuleHandle,
-      'SystemFunction036', LFunctionFound);
-    result := result and LFunctionFound;
+    FCryptAcquireContextW := GetProcedureAddress(FAdvapi32ModuleHandle,
+      'CryptAcquireContextW', LFunctionFound);
+    Result := Result and LFunctionFound;
+    LFunctionFound := True;
+    FCryptReleaseContext := GetProcedureAddress(FAdvapi32ModuleHandle,
+      'CryptReleaseContext', LFunctionFound);
+    Result := Result and LFunctionFound;
+    LFunctionFound := True;
+    FCryptGenRandom := GetProcedureAddress(FAdvapi32ModuleHandle,
+      'CryptGenRandom', LFunctionFound);
+    Result := Result and LFunctionFound;
   end;
 end;
 
 function TWindowsRandomProvider.GenRandomBytesWindows(ALen: Int32;
   AData: PByte): Int32;
-
-  function BCRYPT_SUCCESS(AStatus: NTStatus): Boolean; inline;
-  begin
-    result := AStatus >= 0;
-  end;
-
 var
-  LhProv: THandle;
+  LProviderHandle: THandle;
 const
   PROV_RSA_FULL = 1;
   CRYPT_VERIFYCONTEXT = DWORD($F0000000);
   CRYPT_SILENT = $00000040;
-  // BCryptOpenAlgorithmProvider.AlgorithmID
-  BCRYPT_RNG_ALGORITHM: WideString = 'RNG';
-
 begin
-  // first check if RtlGenRandom is available to avoid the memory overhead
-  // of pulling in 'CryptoAPI'
-  if FIsRtlGenRandomSupportedOnOS then
+  // Priority order: BCryptGenRandom -> RtlGenRandom -> CryptGenRandom
+  if FHasBCryptGenRandom then
   begin
-    // Availability: Windows XP / Server 2003 and Above
-    if not FRtlGenRandom(AData, ULONG(ALen)) then
+    // Availability: Windows Vista SP2+ / Server 2008 and Above
+    // Uses BCRYPT_USE_SYSTEM_PREFERRED_RNG to avoid per-call provider overhead
+    if not BCRYPT_SUCCESS(FBCryptGenRandom(0, PUCHAR(AData),
+      ULONG(ALen), BCRYPT_USE_SYSTEM_PREFERRED_RNG)) then
     begin
-      result := HResultFromWin32(GetLastError);
+      Result := HResultFromWin32(GetLastError);
       Exit;
     end;
   end
-  else if FIsCryptGenRandomSupportedOnOS then
+  else if FHasRtlGenRandom then
   begin
     // Availability: Windows XP / Server 2003 and Above
-    if not FCryptAcquireContextW(@LhProv, nil, nil, PROV_RSA_FULL,
-      CRYPT_VERIFYCONTEXT or CRYPT_SILENT) then
+    if not FRtlGenRandom(AData, ULONG(ALen)) then
     begin
-      result := HResultFromWin32(GetLastError);
+      Result := HResultFromWin32(GetLastError);
       Exit;
     end;
-
-    try
-      if not FCryptGenRandom(LhProv, DWORD(ALen), AData) then
-      begin
-        result := HResultFromWin32(GetLastError);
-        Exit;
-      end;
-    finally
-      FCryptReleaseContext(LhProv, 0);
-    end;
   end
-  else if FIsCngBCryptGenRandomSupportedOnOS then
+  else if FHasCryptGenRandom then
   begin
-    // Availability: Windows Vista / Server 2008 and Above
-    if (not BCRYPT_SUCCESS(FBCryptOpenAlgorithmProvider(@LhProv,
-      PWideChar(BCRYPT_RNG_ALGORITHM), nil, 0))) then
+    // Availability: Windows XP / Server 2003 and Above
+    if not FCryptAcquireContextW(@LProviderHandle, nil, nil, PROV_RSA_FULL,
+      CRYPT_VERIFYCONTEXT or CRYPT_SILENT) then
     begin
-      result := HResultFromWin32(GetLastError);
+      Result := HResultFromWin32(GetLastError);
       Exit;
     end;
 
     try
-      if (not BCRYPT_SUCCESS(FBCryptGenRandom(LhProv, PUCHAR(AData),
-        ULONG(ALen), 0))) then
+      if not FCryptGenRandom(LProviderHandle, DWORD(ALen), AData) then
       begin
-        result := HResultFromWin32(GetLastError);
+        Result := HResultFromWin32(GetLastError);
         Exit;
       end;
     finally
-      FBCryptCloseAlgorithmProvider(LhProv, 0);
+      FCryptReleaseContext(LProviderHandle, 0);
     end;
   end
   else
   begin
     // should never happen but who knows :)
-    result := S_FALSE;
+    Result := S_FALSE;
     Exit;
   end;
-  result := S_OK;
+  Result := S_OK;
 end;
 
 procedure TWindowsRandomProvider.GetBytes(const AData: TCryptoLibByteArray);
@@ -283,37 +287,40 @@ begin
     Exit;
   end;
 
-{$IFDEF CRYPTOLIB_MSWINDOWS}
   if GenRandomBytesWindows(LCount, PByte(AData)) <> 0 then
   begin
     raise EOSRandomCryptoLibException.CreateRes
-      (@SMSWIndowsCryptographyAPIGenerationError);
+      (@SWindowsCryptoApiGenerationError);
   end;
-{$ELSE}
-  raise EOSRandomCryptoLibException.Create('WindowsRandomProvider is only available on Windows');
-{$ENDIF}
 end;
 
 procedure TWindowsRandomProvider.GetNonZeroBytes(const AData: TCryptoLibByteArray);
+var
+  LI: Int32;
+  LTmp: TCryptoLibByteArray;
 begin
-  repeat
-    GetBytes(AData);
-  until (TArrayUtilities.NoZeroes(AData));
+  GetBytes(AData);
+  System.SetLength(LTmp, 1);
+  for LI := System.Low(AData) to System.High(AData) do
+  begin
+    while AData[LI] = 0 do
+    begin
+      GetBytes(LTmp);
+      AData[LI] := LTmp[0];
+    end;
+  end;
 end;
 
 function TWindowsRandomProvider.GetIsAvailable: Boolean;
 begin
-{$IFDEF CRYPTOLIB_MSWINDOWS}
-  result := FIsRtlGenRandomSupportedOnOS or FIsCryptGenRandomSupportedOnOS or
-    FIsCngBCryptGenRandomSupportedOnOS;
-{$ELSE}
-  result := False;
-{$ENDIF}
+  Result := FHasBCryptGenRandom or FHasRtlGenRandom or FHasCryptGenRandom;
 end;
 
 function TWindowsRandomProvider.GetName: String;
 begin
-  result := 'Windows';
+  Result := 'Windows';
 end;
 
+{$ENDIF}
+
 end.