Explorar el Código

refactor Rng functionality

Ugochukwu Mmaduekwe hace 2 semanas
padre
commit
3a9424011f

+ 11 - 5
CryptoLib.Tests/Delphi.Tests/CryptoLib.Tests.dpr

@@ -29,7 +29,6 @@ uses
   {$ENDIF }
   {$ENDIF }
   ClpAesEngine in '..\..\CryptoLib\src\Crypto\Engines\ClpAesEngine.pas',
   ClpAesEngine in '..\..\CryptoLib\src\Crypto\Engines\ClpAesEngine.pas',
   ClpAesLightEngine in '..\..\CryptoLib\src\Crypto\Engines\ClpAesLightEngine.pas',
   ClpAesLightEngine in '..\..\CryptoLib\src\Crypto\Engines\ClpAesLightEngine.pas',
-  ClpAESPRNGRandom in '..\..\CryptoLib\src\Rngs\Sources\ClpAESPRNGRandom.pas',
   ClpAgreementUtilities in '..\..\CryptoLib\src\Crypto\Agreements\ClpAgreementUtilities.pas',
   ClpAgreementUtilities in '..\..\CryptoLib\src\Crypto\Agreements\ClpAgreementUtilities.pas',
   ClpAlgorithmIdentifier in '..\..\CryptoLib\src\Asn1\X509\ClpAlgorithmIdentifier.pas',
   ClpAlgorithmIdentifier in '..\..\CryptoLib\src\Asn1\X509\ClpAlgorithmIdentifier.pas',
   ClpArgon2ParametersGenerator in '..\..\CryptoLib\src\Crypto\Generators\ClpArgon2ParametersGenerator.pas',
   ClpArgon2ParametersGenerator in '..\..\CryptoLib\src\Crypto\Generators\ClpArgon2ParametersGenerator.pas',
@@ -309,7 +308,6 @@ uses
   ClpIRandom in '..\..\CryptoLib\src\Interfaces\Crypto\Randoms\ClpIRandom.pas',
   ClpIRandom in '..\..\CryptoLib\src\Interfaces\Crypto\Randoms\ClpIRandom.pas',
   ClpIRandomDsaKCalculator in '..\..\CryptoLib\src\Interfaces\Crypto\Signers\SignerCalculators\ClpIRandomDsaKCalculator.pas',
   ClpIRandomDsaKCalculator in '..\..\CryptoLib\src\Interfaces\Crypto\Signers\SignerCalculators\ClpIRandomDsaKCalculator.pas',
   ClpIRandomGenerator in '..\..\CryptoLib\src\Interfaces\Rngs\ClpIRandomGenerator.pas',
   ClpIRandomGenerator in '..\..\CryptoLib\src\Interfaces\Rngs\ClpIRandomGenerator.pas',
-  ClpIRandomNumberGenerator in '..\..\CryptoLib\src\Interfaces\Rngs\Sources\ClpIRandomNumberGenerator.pas',
   ClpIRawAgreement in '..\..\CryptoLib\src\Interfaces\Crypto\Agreements\ClpIRawAgreement.pas',
   ClpIRawAgreement in '..\..\CryptoLib\src\Interfaces\Crypto\Agreements\ClpIRawAgreement.pas',
   ClpIRijndaelEngine in '..\..\CryptoLib\src\Interfaces\Crypto\Engines\ClpIRijndaelEngine.pas',
   ClpIRijndaelEngine in '..\..\CryptoLib\src\Interfaces\Crypto\Engines\ClpIRijndaelEngine.pas',
   ClpIRsa in '..\..\CryptoLib\src\Interfaces\Crypto\Signers\ClpIRsa.pas',
   ClpIRsa in '..\..\CryptoLib\src\Interfaces\Crypto\Signers\ClpIRsa.pas',
@@ -398,7 +396,6 @@ uses
   ClpOaepEncoding in '..\..\CryptoLib\src\Crypto\Encodings\ClpOaepEncoding.pas',
   ClpOaepEncoding in '..\..\CryptoLib\src\Crypto\Encodings\ClpOaepEncoding.pas',
   ClpOidTokenizer in '..\..\CryptoLib\src\Asn1\ClpOidTokenizer.pas',
   ClpOidTokenizer in '..\..\CryptoLib\src\Asn1\ClpOidTokenizer.pas',
   ClpOiwObjectIdentifiers in '..\..\CryptoLib\src\Asn1\Oiw\ClpOiwObjectIdentifiers.pas',
   ClpOiwObjectIdentifiers in '..\..\CryptoLib\src\Asn1\Oiw\ClpOiwObjectIdentifiers.pas',
-  ClpOSRandom in '..\..\CryptoLib\src\Rngs\Sources\ClpOSRandom.pas',
   ClpPaddedBufferedBlockCipher in '..\..\CryptoLib\src\Crypto\Paddings\ClpPaddedBufferedBlockCipher.pas',
   ClpPaddedBufferedBlockCipher in '..\..\CryptoLib\src\Crypto\Paddings\ClpPaddedBufferedBlockCipher.pas',
   ClpPaddingModes in '..\..\CryptoLib\src\Crypto\Paddings\ClpPaddingModes.pas',
   ClpPaddingModes in '..\..\CryptoLib\src\Crypto\Paddings\ClpPaddingModes.pas',
   ClpParametersWithIV in '..\..\CryptoLib\src\Crypto\Parameters\ClpParametersWithIV.pas',
   ClpParametersWithIV in '..\..\CryptoLib\src\Crypto\Parameters\ClpParametersWithIV.pas',
@@ -421,7 +418,6 @@ uses
   ClpPublicKeyFactory in '..\..\CryptoLib\src\Factories\ClpPublicKeyFactory.pas',
   ClpPublicKeyFactory in '..\..\CryptoLib\src\Factories\ClpPublicKeyFactory.pas',
   ClpRandom in '..\..\CryptoLib\src\Crypto\Randoms\ClpRandom.pas',
   ClpRandom in '..\..\CryptoLib\src\Crypto\Randoms\ClpRandom.pas',
   ClpRandomDsaKCalculator in '..\..\CryptoLib\src\Crypto\Signers\SignerCalculators\ClpRandomDsaKCalculator.pas',
   ClpRandomDsaKCalculator in '..\..\CryptoLib\src\Crypto\Signers\SignerCalculators\ClpRandomDsaKCalculator.pas',
-  ClpRandomNumberGenerator in '..\..\CryptoLib\src\Rngs\Sources\ClpRandomNumberGenerator.pas',
   ClpRfc5280Asn1Utilities in '..\..\CryptoLib\src\Asn1\X509\ClpRfc5280Asn1Utilities.pas',
   ClpRfc5280Asn1Utilities in '..\..\CryptoLib\src\Asn1\X509\ClpRfc5280Asn1Utilities.pas',
   ClpRijndaelEngine in '..\..\CryptoLib\src\Crypto\Engines\ClpRijndaelEngine.pas',
   ClpRijndaelEngine in '..\..\CryptoLib\src\Crypto\Engines\ClpRijndaelEngine.pas',
   ClpRosstandartObjectIdentifiers in '..\..\CryptoLib\src\Asn1\Rosstandart\ClpRosstandartObjectIdentifiers.pas',
   ClpRosstandartObjectIdentifiers in '..\..\CryptoLib\src\Asn1\Rosstandart\ClpRosstandartObjectIdentifiers.pas',
@@ -505,7 +501,17 @@ uses
   ClpX9ObjectIdentifiers in '..\..\CryptoLib\src\Asn1\X9\ClpX9ObjectIdentifiers.pas',
   ClpX9ObjectIdentifiers in '..\..\CryptoLib\src\Asn1\X9\ClpX9ObjectIdentifiers.pas',
   ClpXSalsa20Engine in '..\..\CryptoLib\src\Crypto\Engines\ClpXSalsa20Engine.pas',
   ClpXSalsa20Engine in '..\..\CryptoLib\src\Crypto\Engines\ClpXSalsa20Engine.pas',
   ClpZTauElement in '..\..\CryptoLib\src\Math\EC\Abc\ClpZTauElement.pas',
   ClpZTauElement in '..\..\CryptoLib\src\Math\EC\Abc\ClpZTauElement.pas',
-  //
+  ClpAppleRandomProvider in '..\..\CryptoLib\src\Rngs\Providers\ClpAppleRandomProvider.pas',
+  ClpGenericBSDRandomProvider in '..\..\CryptoLib\src\Rngs\Providers\ClpGenericBSDRandomProvider.pas',
+  ClpLinuxRandomProvider in '..\..\CryptoLib\src\Rngs\Providers\ClpLinuxRandomProvider.pas',
+  ClpSolarisRandomProvider in '..\..\CryptoLib\src\Rngs\Providers\ClpSolarisRandomProvider.pas',
+  ClpUnixRandomProvider in '..\..\CryptoLib\src\Rngs\Providers\ClpUnixRandomProvider.pas',
+  ClpWindowsRandomProvider in '..\..\CryptoLib\src\Rngs\Providers\ClpWindowsRandomProvider.pas',
+  ClpRandomNumberGenerator in '..\..\CryptoLib\src\Rngs\ClpRandomNumberGenerator.pas',
+  ClpIRandomSourceProvider in '..\..\CryptoLib\src\Interfaces\Rngs\Providers\ClpIRandomSourceProvider.pas',
+  ClpOSRandomProvider in '..\..\CryptoLib\src\Rngs\Providers\ClpOSRandomProvider.pas',
+  ClpIRandomNumberGenerator in '..\..\CryptoLib\src\Interfaces\Rngs\ClpIRandomNumberGenerator.pas',
+  ClpAesRandomProvider in '..\..\CryptoLib\src\Rngs\Providers\ClpAesRandomProvider.pas',
   ClpFixedSecureRandom in '..\src\Utils\ClpFixedSecureRandom.pas',
   ClpFixedSecureRandom in '..\src\Utils\ClpFixedSecureRandom.pas',
   ClpIFixedSecureRandom in '..\src\Utils\ClpIFixedSecureRandom.pas',
   ClpIFixedSecureRandom in '..\src\Utils\ClpIFixedSecureRandom.pas',
   ClpIShortenedDigest in '..\src\Utils\ClpIShortenedDigest.pas',
   ClpIShortenedDigest in '..\src\Utils\ClpIShortenedDigest.pas',

+ 15 - 18
CryptoLib.Tests/src/Security/SecureRandomTests.pas

@@ -32,10 +32,12 @@ uses
 {$ELSE}
 {$ELSE}
   TestFramework,
   TestFramework,
 {$ENDIF FPC}
 {$ENDIF FPC}
-  ClpAESPRNGRandom,
+  ClpOSRandomProvider,
+  ClpAesRandomProvider,
   ClpSecureRandom,
   ClpSecureRandom,
   ClpISecureRandom,
   ClpISecureRandom,
   ClpRandomNumberGenerator,
   ClpRandomNumberGenerator,
+  ClpIRandomNumberGenerator,
   ClpCryptoApiRandomGenerator,
   ClpCryptoApiRandomGenerator,
   ClpICryptoApiRandomGenerator,
   ClpICryptoApiRandomGenerator,
   ClpCryptoLibTypes,
   ClpCryptoLibTypes,
@@ -199,8 +201,7 @@ var
   &random: ISecureRandom;
   &random: ISecureRandom;
 begin
 begin
   random := TSecureRandom.Create(TCryptoApiRandomGenerator.Create
   random := TSecureRandom.Create(TCryptoApiRandomGenerator.Create
-    (TRandomNumberGenerator.CreateRNG
-    (TRandomNumberGenerator.TRandomNumberGeneratorMode.rngmOS))
+    (TRandomNumberGenerator.CreateRng(TOSRandomProvider.Instance))
     as ICryptoApiRandomGenerator);
     as ICryptoApiRandomGenerator);
 
 
   CheckSecureRandom(random);
   CheckSecureRandom(random);
@@ -211,8 +212,7 @@ var
   &random: ISecureRandom;
   &random: ISecureRandom;
 begin
 begin
   random := TSecureRandom.Create(TCryptoApiRandomGenerator.Create
   random := TSecureRandom.Create(TCryptoApiRandomGenerator.Create
-    (TRandomNumberGenerator.CreateRNG
-    (TRandomNumberGenerator.TRandomNumberGeneratorMode.rngmAES))
+    (TRandomNumberGenerator.CreateRng(TAesRandomProvider.Instance))
     as ICryptoApiRandomGenerator);
     as ICryptoApiRandomGenerator);
 
 
   CheckSecureRandom(random);
   CheckSecureRandom(random);
@@ -220,34 +220,31 @@ end;
 
 
 procedure TTestSecureRandom.TestAESPRNGRandom;
 procedure TTestSecureRandom.TestAESPRNGRandom;
 var
 var
-  b1, b2, NilBytes: TBytes;
-  a1, a2: IAESPRNGRandom;
+  b1, b2: TBytes;
+  a1, a2: IRandomNumberGenerator;
   Idx: Int32;
   Idx: Int32;
 begin
 begin
   // it is hard to validate randomness - we just test the feature set
   // it is hard to validate randomness - we just test the feature set
   System.SetLength(b1, 16);
   System.SetLength(b1, 16);
   System.SetLength(b2, 16);
   System.SetLength(b2, 16);
-  NilBytes := Nil;
-  TAESPRNGRandom.GetBytes(b1);
-  TAESPRNGRandom.GetBytes(b2);
+  TAesRandomProvider.Instance.GetBytes(b1);
+  TAesRandomProvider.Instance.GetBytes(b2);
 
 
   CheckTrue(not AreEqual(b1, b2));
   CheckTrue(not AreEqual(b1, b2));
 
 
-  a1 := TAESPRNGRandom.Create();
-  a2 := TAESPRNGRandom.Create();
+  a1 := TRandomNumberGenerator.CreateRng(TAesRandomProvider.Instance);
+  a2 := TRandomNumberGenerator.CreateRng(TAesRandomProvider.Instance);
 
 
-  a1.FillBytes(b1);
-  a2.FillBytes(b2);
+  a1.GetBytes(b1);
+  a2.GetBytes(b2);
   CheckTrue(not AreEqual(b1, b2));
   CheckTrue(not AreEqual(b1, b2));
-  a1.FillBytes(NilBytes);
-  CheckEquals(System.Length(NilBytes), 0);
 
 
   for Idx := 1 to 10000 do
   for Idx := 1 to 10000 do
   begin
   begin
     System.SetLength(b1, Idx);
     System.SetLength(b1, Idx);
     System.SetLength(b2, Idx);
     System.SetLength(b2, Idx);
-    a1.FillBytes(b1);
-    a2.FillBytes(b2);
+    a1.GetBytes(b1);
+    a2.GetBytes(b2);
 
 
     CheckTrue(not AreEqual(b1, b2));
     CheckTrue(not AreEqual(b1, b2));
   end;
   end;

+ 70 - 70
CryptoLib/src/Crypto/Randoms/ClpRandom.pas

@@ -53,7 +53,7 @@ type
   public
   public
     /// <summary>Initializes a new instance of the <see cref="T:System.Random" /> class, using a time-dependent default seed value.</summary>
     /// <summary>Initializes a new instance of the <see cref="T:System.Random" /> class, using a time-dependent default seed value.</summary>
     constructor Create(); overload;
     constructor Create(); overload;
-    constructor Create(Seed: Int32); overload;
+    constructor Create(ASeed: Int32); overload;
 
 
     /// <summary>Returns a non-negative random integer.</summary>
     /// <summary>Returns a non-negative random integer.</summary>
     /// <returns>A 32-bit signed integer that is greater than or equal to 0 and less than <see cref="F:System.Int32.MaxValue" />.</returns>
     /// <returns>A 32-bit signed integer that is greater than or equal to 0 and less than <see cref="F:System.Int32.MaxValue" />.</returns>
@@ -61,21 +61,21 @@ type
     function Next(): Int32; overload; virtual;
     function Next(): Int32; overload; virtual;
 
 
     /// <summary>Returns a non-negative random integer that is less than the specified maximum.</summary>
     /// <summary>Returns a non-negative random integer that is less than the specified maximum.</summary>
-    /// <returns>A 32-bit signed integer that is greater than or equal to 0, and less than <paramref name="maxValue" />; that is, the range of return values ordinarily includes 0 but not <paramref name="maxValue" />. However, if <paramref name="maxValue" /> equals 0, <paramref name="maxValue" /> is returned.</returns>
-    /// <param name="maxValue">The exclusive upper bound of the random number to be generated. <paramref name="maxValue" /> must be greater than or equal to 0. </param>
+    /// <returns>A 32-bit signed integer that is greater than or equal to 0, and less than <paramref name="AMaxValue" />; that is, the range of return values ordinarily includes 0 but not <paramref name="AMaxValue" />. However, if <paramref name="AMaxValue" /> equals 0, <paramref name="AMaxValue" /> is returned.</returns>
+    /// <param name="AMaxValue">The exclusive upper bound of the random number to be generated. <paramref name="AMaxValue" /> must be greater than or equal to 0. </param>
     /// <exception cref="EArgumentOutOfRangeCryptoLibException">
     /// <exception cref="EArgumentOutOfRangeCryptoLibException">
-    /// <paramref name="maxValue" /> is less than 0. </exception>
+    /// <paramref name="AMaxValue" /> is less than 0. </exception>
     /// <filterpriority>1</filterpriority>
     /// <filterpriority>1</filterpriority>
-    function Next(maxValue: Int32): Int32; overload; virtual;
+    function Next(AMaxValue: Int32): Int32; overload; virtual;
 
 
     /// <summary>Returns a random integer that is within a specified range.</summary>
     /// <summary>Returns a random integer that is within a specified range.</summary>
-    /// <returns>A 32-bit signed integer greater than or equal to <paramref name="minValue" /> and less than <paramref name="maxValue" />; that is, the range of return values includes <paramref name="minValue" /> but not <paramref name="maxValue" />. If <paramref name="minValue" /> equals <paramref name="maxValue" />, <paramref name="minValue" /> is returned.</returns>
-    /// <param name="minValue">The inclusive lower bound of the random number returned. </param>
-    /// <param name="maxValue">The exclusive upper bound of the random number returned. <paramref name="maxValue" /> must be greater than or equal to <paramref name="minValue" />. </param>
+    /// <returns>A 32-bit signed integer greater than or equal to <paramref name="AMinValue" /> and less than <paramref name="AMaxValue" />; that is, the range of return values includes <paramref name="AMinValue" /> but not <paramref name="AMaxValue" />. If <paramref name="AMinValue" /> equals <paramref name="AMaxValue" />, <paramref name="AMinValue" /> is returned.</returns>
+    /// <param name="AMinValue">The inclusive lower bound of the random number returned. </param>
+    /// <param name="AMaxValue">The exclusive upper bound of the random number returned. <paramref name="AMaxValue" /> must be greater than or equal to <paramref name="AMinValue" />. </param>
     /// <exception cref="EArgumentOutOfRangeCryptoLibException">
     /// <exception cref="EArgumentOutOfRangeCryptoLibException">
-    /// <paramref name="minValue" /> is greater than <paramref name="maxValue" />. </exception>
+    /// <paramref name="AMinValue" /> is greater than <paramref name="AMaxValue" />. </exception>
     /// <filterpriority>1</filterpriority>
     /// <filterpriority>1</filterpriority>
-    function Next(minValue, maxValue: Int32): Int32; overload; virtual;
+    function Next(AMinValue, AMaxValue: Int32): Int32; overload; virtual;
 
 
     /// <summary>Returns a random floating-point number that is greater than or equal to 0.0, and less than 1.0.</summary>
     /// <summary>Returns a random floating-point number that is greater than or equal to 0.0, and less than 1.0.</summary>
     /// <returns>A double-precision floating point number that is greater than or equal to 0.0, and less than 1.0.</returns>
     /// <returns>A double-precision floating point number that is greater than or equal to 0.0, and less than 1.0.</returns>
@@ -85,14 +85,14 @@ type
     /// <summary>
     /// <summary>
     /// Fills the elements of a specified array of bytes with random numbers.
     /// Fills the elements of a specified array of bytes with random numbers.
     /// </summary>
     /// </summary>
-    /// <param name="buffer">
+    /// <param name="ABuf">
     /// An array of bytes to contain random numbers.
     /// An array of bytes to contain random numbers.
     /// </param>
     /// </param>
     /// <exception cref="EArgumentNilCryptoLibException">
     /// <exception cref="EArgumentNilCryptoLibException">
-    /// <paramref name="buffer" /> is nil.
+    /// <paramref name="ABuf" /> is nil.
     /// </exception>
     /// </exception>
     /// <filterpriority>1</filterpriority>
     /// <filterpriority>1</filterpriority>
-    procedure NextBytes(const buf: TCryptoLibByteArray); overload; virtual;
+    procedure NextBytes(const ABuf: TCryptoLibByteArray); overload; virtual;
 
 
   end;
   end;
 
 
@@ -109,34 +109,34 @@ begin
 {$ENDIF FPC}
 {$ENDIF FPC}
 end;
 end;
 
 
-constructor TRandom.Create(Seed: Int32);
+constructor TRandom.Create(ASeed: Int32);
 var
 var
-  num1, num2, index1, index2: Int32;
+  LNum1, LNum2, LIndex1, LIndex2: Int32;
 begin
 begin
-  num1 := FMSEED - Abs(Seed);
-  FSeedArray[55] := num1;
-  num2 := 1;
-  for index1 := 1 to System.Pred(55) do
+  LNum1 := FMSEED - Abs(ASeed);
+  FSeedArray[55] := LNum1;
+  LNum2 := 1;
+  for LIndex1 := 1 to System.Pred(55) do
   begin
   begin
-    index2 := 21 * index1 mod 55;
-    FSeedArray[index2] := num2;
-    num2 := num1 - num2;
-    if (num2 < 0) then
-      num2 := num2 + System.High(Int32);
-    num1 := FSeedArray[index2];
+    LIndex2 := 21 * LIndex1 mod 55;
+    FSeedArray[LIndex2] := LNum2;
+    LNum2 := LNum1 - LNum2;
+    if (LNum2 < 0) then
+      LNum2 := LNum2 + System.High(Int32);
+    LNum1 := FSeedArray[LIndex2];
   end;
   end;
 
 
-  index1 := 1;
-  while index1 < 5 do
+  LIndex1 := 1;
+  while LIndex1 < 5 do
   begin
   begin
-    for index2 := 1 to System.Pred(56) do
+    for LIndex2 := 1 to System.Pred(56) do
     begin
     begin
-      FSeedArray[index2] := FSeedArray[index2] - FSeedArray
-        [1 + (index2 + 30) mod 55];
-      if (FSeedArray[index2] < 0) then
-        FSeedArray[index2] := FSeedArray[index2] + System.High(Int32);
+      FSeedArray[LIndex2] := FSeedArray[LIndex2] - FSeedArray
+        [1 + (LIndex2 + 30) mod 55];
+      if (FSeedArray[LIndex2] < 0) then
+        FSeedArray[LIndex2] := FSeedArray[LIndex2] + System.High(Int32);
     end;
     end;
-    System.Inc(index1);
+    System.Inc(LIndex1);
   end;
   end;
 
 
   Finext := 0;
   Finext := 0;
@@ -145,61 +145,61 @@ end;
 
 
 function TRandom.InternalSample: Int32;
 function TRandom.InternalSample: Int32;
 var
 var
-  inext, inextp, index1, index2, num: Int32;
+  LInext, LInextp, LIndex1, LIndex2, LNum: Int32;
 begin
 begin
-  inext := Finext;
-  inextp := Finextp;
-  index1 := inext + 1;
-  if ((index1) >= 56) then
-    index1 := 1;
-
-  index2 := inextp + 1;
-  if ((index2) >= 56) then
-    index2 := 1;
-  num := FSeedArray[index1] - FSeedArray[index2];
-  if (num < 0) then
-    num := num + System.High(Int32);
-  FSeedArray[index1] := num;
-  Finext := index1;
-  Finextp := index2;
-  Result := num;
+  LInext := Finext;
+  LInextp := Finextp;
+  LIndex1 := LInext + 1;
+  if ((LIndex1) >= 56) then
+    LIndex1 := 1;
+
+  LIndex2 := LInextp + 1;
+  if ((LIndex2) >= 56) then
+    LIndex2 := 1;
+  LNum := FSeedArray[LIndex1] - FSeedArray[LIndex2];
+  if (LNum < 0) then
+    LNum := LNum + System.High(Int32);
+  FSeedArray[LIndex1] := LNum;
+  Finext := LIndex1;
+  Finextp := LIndex2;
+  Result := LNum;
 end;
 end;
 
 
 function TRandom.GetSampleForLargeRange: Double;
 function TRandom.GetSampleForLargeRange: Double;
 var
 var
-  num: Int32;
+  LNum: Int32;
 begin
 begin
-  num := InternalSample();
+  LNum := InternalSample();
   if (InternalSample() mod 2 = 0) then
   if (InternalSample() mod 2 = 0) then
-    num := -num;
-  Result := (num + 2147483646.0) / 4294967293.0;
+    LNum := -LNum;
+  Result := (LNum + 2147483646.0) / 4294967293.0;
 end;
 end;
 
 
-function TRandom.Next(minValue, maxValue: Int32): Int32;
+function TRandom.Next(AMinValue, AMaxValue: Int32): Int32;
 var
 var
-  num: Int64;
+  LNum: Int64;
 begin
 begin
-  if (minValue > maxValue) then
+  if (AMinValue > AMaxValue) then
   begin
   begin
     raise EArgumentOutOfRangeCryptoLibException.CreateRes(@SInvalidMinValue);
     raise EArgumentOutOfRangeCryptoLibException.CreateRes(@SInvalidMinValue);
   end;
   end;
-  num := Int64(maxValue) - Int64(minValue);
-  if (num <= Int64(System.High(Int32))) then
+  LNum := Int64(AMaxValue) - Int64(AMinValue);
+  if (LNum <= Int64(System.High(Int32))) then
   begin
   begin
-    Result := Int32(Trunc(Sample()) * num) + minValue;
+    Result := Int32(Trunc(Sample()) * LNum) + AMinValue;
     Exit;
     Exit;
   end;
   end;
-  Result := Int32(Int64(Trunc(GetSampleForLargeRange()) * num) +
-    Int64(minValue));
+  Result := Int32(Int64(Trunc(GetSampleForLargeRange()) * LNum) +
+    Int64(AMinValue));
 end;
 end;
 
 
-function TRandom.Next(maxValue: Int32): Int32;
+function TRandom.Next(AMaxValue: Int32): Int32;
 begin
 begin
-  if (maxValue < 0) then
+  if (AMaxValue < 0) then
   begin
   begin
     raise EArgumentOutOfRangeCryptoLibException.CreateRes(@SMaxValueNegative);
     raise EArgumentOutOfRangeCryptoLibException.CreateRes(@SMaxValueNegative);
   end;
   end;
-  Result := Int32(Trunc(Sample() * maxValue));
+  Result := Int32(Trunc(Sample() * AMaxValue));
 end;
 end;
 
 
 function TRandom.Next: Int32;
 function TRandom.Next: Int32;
@@ -207,16 +207,16 @@ begin
   Result := InternalSample();
   Result := InternalSample();
 end;
 end;
 
 
-procedure TRandom.NextBytes(const buf: TCryptoLibByteArray);
+procedure TRandom.NextBytes(const ABuf: TCryptoLibByteArray);
 var
 var
-  i: Int32;
+  LI: Int32;
 begin
 begin
-  if (buf = Nil) then
+  if (ABuf = nil) then
     raise EArgumentNilCryptoLibException.CreateRes(@SBufferNil);
     raise EArgumentNilCryptoLibException.CreateRes(@SBufferNil);
 
 
-  for i := System.Low(buf) to System.High(buf) do
+  for LI := System.Low(ABuf) to System.High(ABuf) do
   begin
   begin
-    buf[i] := Byte(InternalSample() mod (255 + 1));
+    ABuf[LI] := Byte(InternalSample() mod (255 + 1));
   end;
   end;
 
 
 end;
 end;

+ 110 - 111
CryptoLib/src/Crypto/Randoms/ClpSecureRandom.pas

@@ -32,13 +32,14 @@ uses
   ClpIDigest,
   ClpIDigest,
   ClpIRandomGenerator,
   ClpIRandomGenerator,
   ClpRandom,
   ClpRandom,
-  ClpOSRandom,
+  ClpOSRandomProvider,
   ClpDigestUtilities,
   ClpDigestUtilities,
   ClpCryptoApiRandomGenerator,
   ClpCryptoApiRandomGenerator,
   ClpICryptoApiRandomGenerator,
   ClpICryptoApiRandomGenerator,
   ClpDigestRandomGenerator,
   ClpDigestRandomGenerator,
   ClpIDigestRandomGenerator,
   ClpIDigestRandomGenerator,
-  ClpISecureRandom;
+  ClpISecureRandom,
+  ClpPlatform;
 
 
 resourcestring
 resourcestring
   SUnRecognisedPRNGAlgorithm = 'Unrecognised PRNG Algorithm: %s "algorithm"';
   SUnRecognisedPRNGAlgorithm = 'Unrecognised PRNG Algorithm: %s "algorithm"';
@@ -59,8 +60,7 @@ type
 
 
     class function NextCounterValue(): Int64; static; inline;
     class function NextCounterValue(): Int64; static; inline;
 
 
-    class function CreatePrng(const digestName: String; autoSeed: Boolean)
-      : IDigestRandomGenerator; static; inline;
+    class function CreatePrng(const ADigestName: String; AAutoSeed: Boolean): IDigestRandomGenerator; static; inline;
 
 
     class property Master: ISecureRandom read GetMaster;
     class property Master: ISecureRandom read GetMaster;
 
 
@@ -79,16 +79,16 @@ type
     /// proper seed material as necessary/appropriate for the given <c>IRandomGenerator</c>
     /// proper seed material as necessary/appropriate for the given <c>IRandomGenerator</c>
     /// implementation.
     /// implementation.
     /// </remarks>
     /// </remarks>
-    /// <param name="generator">The source to generate all random bytes from.</param>
-    constructor Create(const generator: IRandomGenerator); overload;
+    /// <param name="AGenerator">The source to generate all random bytes from.</param>
+    constructor Create(const AGenerator: IRandomGenerator); overload;
     constructor Create(); overload;
     constructor Create(); overload;
 
 
-    function GenerateSeed(length: Int32): TCryptoLibByteArray; virtual;
-    procedure SetSeed(const seed: TCryptoLibByteArray); overload; virtual;
-    procedure SetSeed(seed: Int64); overload; virtual;
+    function GenerateSeed(ALength: Int32): TCryptoLibByteArray; virtual;
+    procedure SetSeed(const ASeed: TCryptoLibByteArray); overload; virtual;
+    procedure SetSeed(ASeed: Int64); overload; virtual;
 
 
-    procedure NextBytes(const buf: TCryptoLibByteArray); overload; override;
-    procedure NextBytes(const buf: TCryptoLibByteArray; off, len: Int32);
+    procedure NextBytes(const ABuf: TCryptoLibByteArray); overload; override;
+    procedure NextBytes(const ABuf: TCryptoLibByteArray; AOff, ALen: Int32);
       overload; virtual;
       overload; virtual;
     function NextInt32(): Int32; virtual;
     function NextInt32(): Int32; virtual;
     function NextInt64(): Int64; virtual;
     function NextInt64(): Int64; virtual;
@@ -96,26 +96,24 @@ type
     function NextDouble(): Double; override;
     function NextDouble(): Double; override;
 
 
     function Next(): Int32; overload; override;
     function Next(): Int32; overload; override;
-    function Next(maxValue: Int32): Int32; overload; override;
-    function Next(minValue, maxValue: Int32): Int32; overload; override;
+    function Next(AMaxValue: Int32): Int32; overload; override;
+    function Next(AMinValue, AMaxValue: Int32): Int32; overload; override;
 
 
-    class function GetNextBytes(const SecureRandom: ISecureRandom;
-      length: Int32): TCryptoLibByteArray; static;
+    class function GetNextBytes(const ASecureRandom: ISecureRandom;
+      ALength: Int32): TCryptoLibByteArray; static;
 
 
     /// <summary>
     /// <summary>
     /// Create and auto-seed an instance based on the given algorithm.
     /// Create and auto-seed an instance based on the given algorithm.
     /// </summary>
     /// </summary>
-    /// <remarks>Equivalent to GetInstance(algorithm, true)</remarks>
-    /// <param name="algorithm">e.g. "SHA256PRNG"</param>
-    class function GetInstance(const algorithm: String): ISecureRandom;
-      overload; static; inline;
+    /// <remarks>Equivalent to GetInstance(AAlgorithm, true)</remarks>
+    /// <param name="AAlgorithm">e.g. "SHA256PRNG"</param>
+    class function GetInstance(const AAlgorithm: String): ISecureRandom; overload; static; inline;
     /// <summary>
     /// <summary>
     /// Create an instance based on the given algorithm, with optional auto-seeding
     /// Create an instance based on the given algorithm, with optional auto-seeding
     /// </summary>
     /// </summary>
-    /// <param name="algorithm">e.g. "SHA256PRNG"</param>
-    /// <param name="autoSeed">If true, the instance will be auto-seeded.</param>
-    class function GetInstance(const algorithm: String; autoSeed: Boolean)
-      : ISecureRandom; overload; static;
+    /// <param name="AAlgorithm">e.g. "SHA256PRNG"</param>
+    /// <param name="AAutoSeed">If true, the instance will be auto-seeded.</param>
+    class function GetInstance(const AAlgorithm: String; AAutoSeed: Boolean): ISecureRandom; overload; static;
 
 
     class procedure Boot(); static;
     class procedure Boot(); static;
 
 
@@ -125,10 +123,10 @@ implementation
 
 
 { TSecureRandom }
 { TSecureRandom }
 
 
-constructor TSecureRandom.Create(const generator: IRandomGenerator);
+constructor TSecureRandom.Create(const AGenerator: IRandomGenerator);
 begin
 begin
-  Inherited Create(0);
-  Fgenerator := generator;
+  inherited Create(0);
+  Fgenerator := AGenerator;
 end;
 end;
 
 
 class function TSecureRandom.GetMaster: ISecureRandom;
 class function TSecureRandom.GetMaster: ISecureRandom;
@@ -136,20 +134,20 @@ begin
   Result := Fmaster;
   Result := Fmaster;
 end;
 end;
 
 
-class function TSecureRandom.GetNextBytes(const SecureRandom: ISecureRandom;
-  length: Int32): TCryptoLibByteArray;
+class function TSecureRandom.GetNextBytes(const ASecureRandom: ISecureRandom;
+  ALength: Int32): TCryptoLibByteArray;
 begin
 begin
-  System.SetLength(Result, length);
-  SecureRandom.NextBytes(Result);
+  System.SetLength(Result, ALength);
+  ASecureRandom.NextBytes(Result);
 end;
 end;
 
 
-function TSecureRandom.Next(maxValue: Int32): Int32;
+function TSecureRandom.Next(AMaxValue: Int32): Int32;
 var
 var
-  bits: Int32;
+  LBits: Int32;
 begin
 begin
-  if (maxValue < 2) then
+  if (AMaxValue < 2) then
   begin
   begin
-    if (maxValue < 0) then
+    if (AMaxValue < 0) then
     begin
     begin
       raise EArgumentOutOfRangeCryptoLibException.CreateRes(@SCannotBeNegative);
       raise EArgumentOutOfRangeCryptoLibException.CreateRes(@SCannotBeNegative);
     end;
     end;
@@ -158,52 +156,52 @@ begin
     Exit;
     Exit;
   end;
   end;
 
 
-  // Test whether maxValue is a power of 2
-  if ((maxValue and (maxValue - 1)) = 0) then
+  // Test whether AMaxValue is a power of 2
+  if ((AMaxValue and (AMaxValue - 1)) = 0) then
   begin
   begin
-    bits := NextInt32() and System.High(Int32);
-    Result := Int32(TBits.Asr64((Int64(bits) * maxValue), 31));
+    LBits := NextInt32() and System.High(Int32);
+    Result := Int32(TBits.Asr64((Int64(LBits) * AMaxValue), 31));
     Exit;
     Exit;
   end;
   end;
 
 
   repeat
   repeat
-    bits := NextInt32() and System.High(Int32);
-    Result := bits mod maxValue;
+    LBits := NextInt32() and System.High(Int32);
+    Result := LBits mod AMaxValue;
     // Ignore results near overflow
     // Ignore results near overflow
-  until (not((bits - (Result + (maxValue - 1))) < 0));
+  until (not((LBits - (Result + (AMaxValue - 1))) < 0));
 
 
 end;
 end;
 
 
-function TSecureRandom.Next(minValue, maxValue: Int32): Int32;
+function TSecureRandom.Next(AMinValue, AMaxValue: Int32): Int32;
 var
 var
-  diff, i: Int32;
+  LDiff, LI: Int32;
 begin
 begin
-  if (maxValue <= minValue) then
+  if (AMaxValue <= AMinValue) then
   begin
   begin
-    if (maxValue = minValue) then
+    if (AMaxValue = AMinValue) then
     begin
     begin
-      Result := minValue;
+      Result := AMinValue;
       Exit;
       Exit;
     end;
     end;
 
 
     raise EArgumentCryptoLibException.CreateRes(@SInvalidMaxValue);
     raise EArgumentCryptoLibException.CreateRes(@SInvalidMaxValue);
   end;
   end;
 
 
-  diff := maxValue - minValue;
-  if (diff > 0) then
+  LDiff := AMaxValue - AMinValue;
+  if (LDiff > 0) then
   begin
   begin
-    Result := minValue + Next(diff);
+    Result := AMinValue + Next(LDiff);
     Exit;
     Exit;
   end;
   end;
 
 
   while True do
   while True do
 
 
   begin
   begin
-    i := NextInt32();
+    LI := NextInt32();
 
 
-    if ((i >= minValue) and (i < maxValue)) then
+    if ((LI >= AMinValue) and (LI < AMaxValue)) then
     begin
     begin
-      Result := i;
+      Result := LI;
       Exit;
       Exit;
     end;
     end;
   end;
   end;
@@ -217,16 +215,15 @@ begin
   Result := NextInt32() and System.High(Int32);
   Result := NextInt32() and System.High(Int32);
 end;
 end;
 
 
-procedure TSecureRandom.NextBytes(const buf: TCryptoLibByteArray);
+procedure TSecureRandom.NextBytes(const ABuf: TCryptoLibByteArray);
 begin
 begin
-  Fgenerator.NextBytes(buf);
+  Fgenerator.NextBytes(ABuf);
 
 
 end;
 end;
 
 
-procedure TSecureRandom.NextBytes(const buf: TCryptoLibByteArray;
-  off, len: Int32);
+procedure TSecureRandom.NextBytes(const ABuf: TCryptoLibByteArray; AOff, ALen: Int32);
 begin
 begin
-  Fgenerator.NextBytes(buf, off, len);
+  Fgenerator.NextBytes(ABuf, AOff, ALen);
 end;
 end;
 
 
 class function TSecureRandom.NextCounterValue: Int64;
 class function TSecureRandom.NextCounterValue: Int64;
@@ -253,20 +250,20 @@ end;
 
 
 function TSecureRandom.NextInt32: Int32;
 function TSecureRandom.NextInt32: Int32;
 var
 var
-  tempRes: UInt32;
-  bytes: TCryptoLibByteArray;
+  LTempRes: UInt32;
+  LBytes: TCryptoLibByteArray;
 begin
 begin
-  System.SetLength(bytes, 4);
-  NextBytes(bytes);
-
-  tempRes := bytes[0];
-  tempRes := tempRes shl 8;
-  tempRes := tempRes or bytes[1];
-  tempRes := tempRes shl 8;
-  tempRes := tempRes or bytes[2];
-  tempRes := tempRes shl 8;
-  tempRes := tempRes or bytes[3];
-  Result := Int32(tempRes);
+  System.SetLength(LBytes, 4);
+  NextBytes(LBytes);
+
+  LTempRes := LBytes[0];
+  LTempRes := LTempRes shl 8;
+  LTempRes := LTempRes or LBytes[1];
+  LTempRes := LTempRes shl 8;
+  LTempRes := LTempRes or LBytes[2];
+  LTempRes := LTempRes shl 8;
+  LTempRes := LTempRes or LBytes[3];
+  Result := Int32(LTempRes);
 end;
 end;
 
 
 function TSecureRandom.NextInt64: Int64;
 function TSecureRandom.NextInt64: Int64;
@@ -284,50 +281,50 @@ begin
   FLock.Free;
   FLock.Free;
 end;
 end;
 
 
-procedure TSecureRandom.SetSeed(seed: Int64);
+procedure TSecureRandom.SetSeed(ASeed: Int64);
 begin
 begin
-  Fgenerator.AddSeedMaterial(seed);
+  Fgenerator.AddSeedMaterial(ASeed);
 end;
 end;
 
 
-procedure TSecureRandom.SetSeed(const seed: TCryptoLibByteArray);
+procedure TSecureRandom.SetSeed(const ASeed: TCryptoLibByteArray);
 begin
 begin
-  Fgenerator.AddSeedMaterial(seed);
+  Fgenerator.AddSeedMaterial(ASeed);
 end;
 end;
 
 
-class function TSecureRandom.CreatePrng(const digestName: String;
-  autoSeed: Boolean): IDigestRandomGenerator;
+class function TSecureRandom.CreatePrng(const ADigestName: String;
+  AAutoSeed: Boolean): IDigestRandomGenerator;
 var
 var
-  digest: IDigest;
-  prng: IDigestRandomGenerator;
-  seedLength: Int32;
+  LDigest: IDigest;
+  LPrng: IDigestRandomGenerator;
+  LSeedLength: Int32;
 begin
 begin
-  digest := TDigestUtilities.GetDigest(digestName);
-  if (digest = Nil) then
+  LDigest := TDigestUtilities.GetDigest(ADigestName);
+  if (LDigest = nil) then
   begin
   begin
-    Result := Nil;
+    Result := nil;
     Exit;
     Exit;
   end;
   end;
 
 
-  prng := TDigestRandomGenerator.Create(digest);
-  if (autoSeed) then
+  LPrng := TDigestRandomGenerator.Create(LDigest);
+  if (AAutoSeed) then
   begin
   begin
-    seedLength := 2 * digest.GetDigestSize;
-    prng.AddSeedMaterial(NextCounterValue());
-    prng.AddSeedMaterial(GetNextBytes(Master, seedLength));
+    LSeedLength := 2 * LDigest.GetDigestSize;
+    LPrng.AddSeedMaterial(NextCounterValue());
+    LPrng.AddSeedMaterial(GetNextBytes(Master, LSeedLength));
   end;
   end;
-  Result := prng;
+  Result := LPrng;
 end;
 end;
 
 
 class procedure TSecureRandom.Boot;
 class procedure TSecureRandom.Boot;
 begin
 begin
-  if FLock = Nil then
+  if FLock = nil then
   begin
   begin
     FLock := TCriticalSection.Create;
     FLock := TCriticalSection.Create;
     FCounter := TTimes.NanoTime();
     FCounter := TTimes.NanoTime();
     Fmaster := TSecureRandom.Create(TCryptoApiRandomGenerator.Create()
     Fmaster := TSecureRandom.Create(TCryptoApiRandomGenerator.Create()
       as ICryptoApiRandomGenerator);
       as ICryptoApiRandomGenerator);
     FDoubleScale := Power(2.0, 64.0);
     FDoubleScale := Power(2.0, 64.0);
-    TOSRandom.Boot;
+    TOSRandomProvider.Boot;
   end;
   end;
 end;
 end;
 
 
@@ -336,45 +333,47 @@ begin
   Create(CreatePrng('SHA256', True));
   Create(CreatePrng('SHA256', True));
 end;
 end;
 
 
-class function TSecureRandom.GetInstance(const algorithm: String;
-  autoSeed: Boolean): ISecureRandom;
+class function TSecureRandom.GetInstance(const AAlgorithm: String; AAutoSeed: Boolean): ISecureRandom;
 var
 var
-  upper, digestName: String;
-  prng: IDigestRandomGenerator;
-  LowPoint, HighPoint: Int32;
+  LUpper, LDigestName: String;
+  LPrng: IDigestRandomGenerator;
+  LPrngIndex: Int32;
 begin
 begin
-  upper := UpperCase(algorithm);
+  LUpper := TPlatform.ToUpperInvariant(AAlgorithm);
 
 
-  LowPoint := 1;
-  HighPoint := System.length(upper);
-
-  if AnsiEndsStr('PRNG', upper) then
+  if TPlatform.EndsWith(LUpper, 'PRNG', True) then
   begin
   begin
-    digestName := System.Copy(upper, LowPoint,
-      HighPoint - System.length('PRNG'));
+    LPrngIndex := TPlatform.LastIndexOf(LUpper, 'PRNG');
+    if LPrngIndex > 0 then
+    begin
+      LDigestName := TPlatform.Substring(LUpper, 1, LPrngIndex - 1);
+    end
+    else
+    begin
+      LDigestName := '';
+    end;
 
 
-    prng := CreatePrng(digestName, autoSeed);
-    if (prng <> Nil) then
+    LPrng := CreatePrng(LDigestName, AAutoSeed);
+    if (LPrng <> nil) then
     begin
     begin
-      Result := TSecureRandom.Create(prng);
+      Result := TSecureRandom.Create(LPrng);
       Exit;
       Exit;
     end;
     end;
   end;
   end;
 
 
   raise EArgumentCryptoLibException.CreateResFmt(@SUnRecognisedPRNGAlgorithm,
   raise EArgumentCryptoLibException.CreateResFmt(@SUnRecognisedPRNGAlgorithm,
-    [algorithm]);
+    [AAlgorithm]);
 
 
 end;
 end;
 
 
-class function TSecureRandom.GetInstance(const algorithm: String)
-  : ISecureRandom;
+class function TSecureRandom.GetInstance(const AAlgorithm: String) : ISecureRandom;
 begin
 begin
-  Result := GetInstance(algorithm, True);
+  Result := GetInstance(AAlgorithm, True);
 end;
 end;
 
 
-function TSecureRandom.GenerateSeed(length: Int32): TCryptoLibByteArray;
+function TSecureRandom.GenerateSeed(ALength: Int32): TCryptoLibByteArray;
 begin
 begin
-  Result := GetNextBytes(Master, length);
+  Result := GetNextBytes(Master, ALength);
 end;
 end;
 
 
 end.
 end.

+ 3 - 3
CryptoLib/src/Interfaces/Crypto/Randoms/ClpIRandom.pas

@@ -29,13 +29,13 @@ type
   IRandom = interface(IInterface)
   IRandom = interface(IInterface)
     ['{509F9F51-2FC4-40E6-8E4A-68B59808BF5A}']
     ['{509F9F51-2FC4-40E6-8E4A-68B59808BF5A}']
 
 
-    procedure NextBytes(const buf: TCryptoLibByteArray); overload;
+    procedure NextBytes(const ABuf: TCryptoLibByteArray); overload;
 
 
     function NextDouble(): Double;
     function NextDouble(): Double;
 
 
     function Next(): Int32; overload;
     function Next(): Int32; overload;
-    function Next(maxValue: Int32): Int32; overload;
-    function Next(minValue, maxValue: Int32): Int32; overload;
+    function Next(AMaxValue: Int32): Int32; overload;
+    function Next(AMinValue, AMaxValue: Int32): Int32; overload;
 
 
   end;
   end;
 
 

+ 5 - 5
CryptoLib/src/Interfaces/Crypto/Randoms/ClpISecureRandom.pas

@@ -30,12 +30,12 @@ type
   ISecureRandom = interface(IRandom)
   ISecureRandom = interface(IRandom)
     ['{BF2E135B-E889-4B2F-837E-6B2049213C83}']
     ['{BF2E135B-E889-4B2F-837E-6B2049213C83}']
 
 
-    function GenerateSeed(length: Int32): TCryptoLibByteArray;
-    procedure SetSeed(const seed: TCryptoLibByteArray); overload;
-    procedure SetSeed(seed: Int64); overload;
+    function GenerateSeed(ALength: Int32): TCryptoLibByteArray;
+    procedure SetSeed(const ASeed: TCryptoLibByteArray); overload;
+    procedure SetSeed(ASeed: Int64); overload;
 
 
-    procedure NextBytes(const buf: TCryptoLibByteArray;
-      off, len: Int32); overload;
+    procedure NextBytes(const ABuf: TCryptoLibByteArray;
+      AOff, ALen: Int32); overload;
     function NextInt32(): Int32;
     function NextInt32(): Int32;
     function NextInt64(): Int64;
     function NextInt64(): Int64;
 
 

+ 3 - 21
CryptoLib/src/Interfaces/Rngs/Sources/ClpIRandomNumberGenerator.pas → CryptoLib/src/Interfaces/Rngs/ClpIRandomNumberGenerator.pas

@@ -17,7 +17,7 @@
 
 
 unit ClpIRandomNumberGenerator;
 unit ClpIRandomNumberGenerator;
 
 
-{$I ..\..\..\Include\CryptoLib.inc}
+{$I ..\..\Include\CryptoLib.inc}
 
 
 interface
 interface
 
 
@@ -28,27 +28,9 @@ type
   IRandomNumberGenerator = interface(IInterface)
   IRandomNumberGenerator = interface(IInterface)
     ['{48F39DBB-8BE4-4167-8CE9-265F9B3B785E}']
     ['{48F39DBB-8BE4-4167-8CE9-265F9B3B785E}']
 
 
-    procedure GetBytes(const data: TCryptoLibByteArray);
+    procedure GetBytes(const AData: TCryptoLibByteArray);
 
 
-    procedure GetNonZeroBytes(const data: TCryptoLibByteArray);
-
-  end;
-
-type
-  IOSRandomNumberGenerator = interface(IRandomNumberGenerator)
-    ['{EF52111D-1E69-42D7-99E0-D1C733D17995}']
-
-  end;
-
-type
-  IPCGRandomNumberGenerator = interface(IRandomNumberGenerator)
-    ['{49D3C867-E4F0-4EA3-BD81-0BCD6C0F08A8}']
-
-  end;
-
-type
-  IAESPRNGRandomNumberGenerator = interface(IRandomNumberGenerator)
-    ['{9E0D8D8F-D9D4-42D6-9D55-36271293B59E}']
+    procedure GetNonZeroBytes(const AData: TCryptoLibByteArray);
 
 
   end;
   end;
 
 

+ 52 - 0
CryptoLib/src/Interfaces/Rngs/Providers/ClpIRandomSourceProvider.pas

@@ -0,0 +1,52 @@
+{ *********************************************************************************** }
+{ *                              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 ClpIRandomSourceProvider;
+
+{$I ..\..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  ClpCryptoLibTypes;
+
+type
+  /// <summary>
+  /// Interface for random source providers.
+  /// </summary>
+  IRandomSourceProvider = interface(IInterface)
+    ['{A1B2C3D4-E5F6-7890-ABCD-EF0123456789}']
+
+    /// <summary>Fill byte array with random bytes from implementing source.</summary>
+    procedure GetBytes(const AData: TCryptoLibByteArray);
+
+    /// <summary>Fill byte array with non-zero random bytes from implementing source.</summary>
+    procedure GetNonZeroBytes(const AData: TCryptoLibByteArray);
+
+    /// <summary>Returns true if this implementing random implementation is available.</summary>
+    function GetIsAvailable: Boolean;
+
+    /// <summary>Returns the name of this random source provider.</summary>
+    function GetName: String;
+
+    property IsAvailable: Boolean read GetIsAvailable;
+    property Name: String read GetName;
+  end;
+
+implementation
+
+end.

+ 32 - 33
CryptoLib/src/Rngs/ClpCryptoApiRandomGenerator.pas

@@ -34,10 +34,9 @@ resourcestring
 
 
 type
 type
   /// <summary>
   /// <summary>
-  /// Uses TRandomNumberGenerator.Create() to Get randomness generator
+  /// Uses TRandomNumberGenerator.CreateRng() to Get randomness generator
   /// </summary>
   /// </summary>
-  TCryptoApiRandomGenerator = class(TInterfacedObject,
-    ICryptoApiRandomGenerator, IRandomGenerator)
+  TCryptoApiRandomGenerator = class(TInterfacedObject, ICryptoApiRandomGenerator, IRandomGenerator)
 
 
   strict private
   strict private
   var
   var
@@ -45,29 +44,29 @@ type
 
 
   public
   public
     /// <summary>
     /// <summary>
-    /// Uses TRandomNumberGenerator.CreateRNG() to Get randomness generator
+    /// Uses TRandomNumberGenerator.Create() to Get randomness generator
     /// </summary>
     /// </summary>
     constructor Create(); overload;
     constructor Create(); overload;
-    constructor Create(const rng: IRandomNumberGenerator); overload;
+    constructor Create(const ARng: IRandomNumberGenerator); overload;
 
 
     /// <summary>Add more seed material to the generator.</summary>
     /// <summary>Add more seed material to the generator.</summary>
-    /// <param name="seed">A byte array to be mixed into the generator's state.</param>
-    procedure AddSeedMaterial(const seed: TCryptoLibByteArray);
+    /// <param name="ASeed">A byte array to be mixed into the generator's state.</param>
+    procedure AddSeedMaterial(const ASeed: TCryptoLibByteArray);
       overload; virtual;
       overload; virtual;
 
 
     /// <summary>Add more seed material to the generator.</summary>
     /// <summary>Add more seed material to the generator.</summary>
-    /// <param name="seed">A long value to be mixed into the generator's state.</param>
-    procedure AddSeedMaterial(seed: Int64); overload; virtual;
+    /// <param name="ASeed">A long value to be mixed into the generator's state.</param>
+    procedure AddSeedMaterial(ASeed: Int64); overload; virtual;
 
 
     /// <summary>Fill byte array with random values.</summary>
     /// <summary>Fill byte array with random values.</summary>
-    /// <param name="bytes">Array to be filled.</param>
-    procedure NextBytes(const bytes: TCryptoLibByteArray); overload; virtual;
+    /// <param name="ABytes">Array to be filled.</param>
+    procedure NextBytes(const ABytes: TCryptoLibByteArray); overload; virtual;
 
 
     /// <summary>Fill byte array with random values.</summary>
     /// <summary>Fill byte array with random values.</summary>
-    /// <param name="bytes">Array to receive bytes.</param>
-    /// <param name="start">Index to start filling at.</param>
-    /// <param name="len">Length of segment to fill.</param>
-    procedure NextBytes(const bytes: TCryptoLibByteArray; start, len: Int32);
+    /// <param name="ABytes">Array to receive bytes.</param>
+    /// <param name="AStart">Index to start filling at.</param>
+    /// <param name="ALen">Length of segment to fill.</param>
+    procedure NextBytes(const ABytes: TCryptoLibByteArray; AStart, ALen: Int32);
       overload; virtual;
       overload; virtual;
 
 
   end;
   end;
@@ -76,58 +75,58 @@ implementation
 
 
 { TCryptoApiRandomGenerator }
 { TCryptoApiRandomGenerator }
 
 
-procedure TCryptoApiRandomGenerator.AddSeedMaterial(seed: Int64);
+procedure TCryptoApiRandomGenerator.AddSeedMaterial(ASeed: Int64);
 begin
 begin
   // We don't care about the seed
   // We don't care about the seed
 end;
 end;
 
 
 procedure TCryptoApiRandomGenerator.AddSeedMaterial
 procedure TCryptoApiRandomGenerator.AddSeedMaterial
-  (const seed: TCryptoLibByteArray);
+  (const ASeed: TCryptoLibByteArray);
 begin
 begin
   // We don't care about the seed
   // We don't care about the seed
 end;
 end;
 
 
-constructor TCryptoApiRandomGenerator.Create(const rng: IRandomNumberGenerator);
+constructor TCryptoApiRandomGenerator.Create(const ARng: IRandomNumberGenerator);
 begin
 begin
-  Inherited Create();
-  FrndProv := rng;
+  inherited Create();
+  FRndProv := ARng;
 end;
 end;
 
 
 constructor TCryptoApiRandomGenerator.Create;
 constructor TCryptoApiRandomGenerator.Create;
 begin
 begin
-  Create(TRandomNumberGenerator.CreateRNG());
+  Create(TRandomNumberGenerator.CreateRng());
 end;
 end;
 
 
-procedure TCryptoApiRandomGenerator.NextBytes(const bytes: TCryptoLibByteArray);
+procedure TCryptoApiRandomGenerator.NextBytes(const ABytes: TCryptoLibByteArray);
 begin
 begin
-  FrndProv.GetBytes(bytes);
+  FRndProv.GetBytes(ABytes);
 end;
 end;
 
 
-procedure TCryptoApiRandomGenerator.NextBytes(const bytes: TCryptoLibByteArray;
-  start, len: Int32);
+procedure TCryptoApiRandomGenerator.NextBytes(const ABytes: TCryptoLibByteArray;
+  AStart, ALen: Int32);
 var
 var
-  tmpBuf: TCryptoLibByteArray;
+  LTmpBuf: TCryptoLibByteArray;
 begin
 begin
-  if (start < 0) then
+  if (AStart < 0) then
   begin
   begin
     raise EArgumentCryptoLibException.CreateRes(@SNegativeOffset);
     raise EArgumentCryptoLibException.CreateRes(@SNegativeOffset);
   end;
   end;
-  if (System.Length(bytes) < (start + len)) then
+  if (System.Length(ABytes) < (AStart + ALen)) then
   begin
   begin
     raise EArgumentCryptoLibException.CreateRes(@SArrayTooSmall);
     raise EArgumentCryptoLibException.CreateRes(@SArrayTooSmall);
 
 
   end;
   end;
 
 
-  if ((System.Length(bytes) = len) and (start = 0)) then
+  if ((System.Length(ABytes) = ALen) and (AStart = 0)) then
   begin
   begin
-    NextBytes(bytes);
+    NextBytes(ABytes);
   end
   end
   else
   else
   begin
   begin
-    System.SetLength(tmpBuf, len);
-    NextBytes(tmpBuf);
+    System.SetLength(LTmpBuf, ALen);
+    NextBytes(LTmpBuf);
 
 
-    System.Move(tmpBuf[0], bytes[start], len * System.SizeOf(Byte));
+    System.Move(LTmpBuf[0], ABytes[AStart], ALen * System.SizeOf(Byte));
 
 
   end;
   end;
 end;
 end;

+ 58 - 59
CryptoLib/src/Rngs/ClpDigestRandomGenerator.pas

@@ -37,12 +37,11 @@ type
   // * Internal access to the digest is synchronized so a single one of these can be shared.
   // * Internal access to the digest is synchronized so a single one of these can be shared.
   // * </p>
   // * </p>
   // */
   // */
-  TDigestRandomGenerator = class sealed(TInterfacedObject,
-    IDigestRandomGenerator, IRandomGenerator)
+  TDigestRandomGenerator = class sealed(TInterfacedObject, IDigestRandomGenerator, IRandomGenerator)
 
 
   strict private
   strict private
   const
   const
-    CYCLE_COUNT = Int64(10);
+    CycleCount = Int64(10);
 
 
   var
   var
     FLock: TCriticalSection;
     FLock: TCriticalSection;
@@ -52,20 +51,20 @@ type
 
 
     procedure CycleSeed(); inline;
     procedure CycleSeed(); inline;
     procedure GenerateState(); inline;
     procedure GenerateState(); inline;
-    procedure DigestAddCounter(seedVal: Int64); inline;
-    procedure DigestUpdate(const inSeed: TCryptoLibByteArray); inline;
-    procedure DigestDoFinal(const result: TCryptoLibByteArray); inline;
+    procedure DigestAddCounter(ASeedVal: Int64); inline;
+    procedure DigestUpdate(const AInSeed: TCryptoLibByteArray); inline;
+    procedure DigestDoFinal(const AResult: TCryptoLibByteArray); inline;
 
 
   public
   public
 
 
-    constructor Create(const digest: IDigest);
+    constructor Create(const ADigest: IDigest);
     destructor Destroy; override;
     destructor Destroy; override;
-    procedure AddSeedMaterial(const inSeed: TCryptoLibByteArray);
+    procedure AddSeedMaterial(const AInSeed: TCryptoLibByteArray);
       overload; inline;
       overload; inline;
-    procedure AddSeedMaterial(rSeed: Int64); overload; inline;
-    procedure NextBytes(const bytes: TCryptoLibByteArray); overload; inline;
-    procedure NextBytes(const bytes: TCryptoLibByteArray;
-      start, len: Int32); overload;
+    procedure AddSeedMaterial(ARSeed: Int64); overload; inline;
+    procedure NextBytes(const ABytes: TCryptoLibByteArray); overload; inline;
+    procedure NextBytes(const ABytes: TCryptoLibByteArray;
+      AStart, ALen: Int32); overload;
 
 
   end;
   end;
 
 
@@ -73,69 +72,69 @@ implementation
 
 
 { TDigestRandomGenerator }
 { TDigestRandomGenerator }
 
 
-procedure TDigestRandomGenerator.DigestAddCounter(seedVal: Int64);
+procedure TDigestRandomGenerator.DigestAddCounter(ASeedVal: Int64);
 var
 var
-  bytes: TCryptoLibByteArray;
+  LBytes: TCryptoLibByteArray;
 begin
 begin
-  System.SetLength(bytes, 8);
-  bytes := TConverters.ReadUInt64AsBytesLE(UInt64(seedVal));
-  Fdigest.BlockUpdate(bytes, 0, System.Length(bytes));
+  System.SetLength(LBytes, 8);
+  LBytes := TConverters.ReadUInt64AsBytesLE(UInt64(ASeedVal));
+  FDigest.BlockUpdate(LBytes, 0, System.Length(LBytes));
 end;
 end;
 
 
-procedure TDigestRandomGenerator.DigestUpdate(const inSeed
+procedure TDigestRandomGenerator.DigestUpdate(const AInSeed
   : TCryptoLibByteArray);
   : TCryptoLibByteArray);
 begin
 begin
-  Fdigest.BlockUpdate(inSeed, 0, System.Length(inSeed));
+  FDigest.BlockUpdate(AInSeed, 0, System.Length(AInSeed));
 end;
 end;
 
 
-procedure TDigestRandomGenerator.DigestDoFinal(const result
+procedure TDigestRandomGenerator.DigestDoFinal(const AResult
   : TCryptoLibByteArray);
   : TCryptoLibByteArray);
 begin
 begin
-  Fdigest.DoFinal(result, 0);
+  FDigest.DoFinal(AResult, 0);
 end;
 end;
 
 
-procedure TDigestRandomGenerator.AddSeedMaterial(rSeed: Int64);
+procedure TDigestRandomGenerator.AddSeedMaterial(ARSeed: Int64);
 begin
 begin
   FLock.Acquire;
   FLock.Acquire;
   try
   try
-    DigestAddCounter(rSeed);
-    DigestUpdate(Fseed);
-    DigestDoFinal(Fseed);
+    DigestAddCounter(ARSeed);
+    DigestUpdate(FSeed);
+    DigestDoFinal(FSeed);
   finally
   finally
     FLock.Release;
     FLock.Release;
   end;
   end;
 end;
 end;
 
 
-procedure TDigestRandomGenerator.AddSeedMaterial(const inSeed
+procedure TDigestRandomGenerator.AddSeedMaterial(const AInSeed
   : TCryptoLibByteArray);
   : TCryptoLibByteArray);
 begin
 begin
   FLock.Acquire;
   FLock.Acquire;
   try
   try
-    DigestUpdate(inSeed);
-    DigestUpdate(Fseed);
-    DigestDoFinal(Fseed);
+    DigestUpdate(AInSeed);
+    DigestUpdate(FSeed);
+    DigestDoFinal(FSeed);
   finally
   finally
     FLock.Release;
     FLock.Release;
   end;
   end;
 end;
 end;
 
 
-constructor TDigestRandomGenerator.Create(const digest: IDigest);
+constructor TDigestRandomGenerator.Create(const ADigest: IDigest);
 begin
 begin
-  Inherited Create();
+  inherited Create();
   FLock := TCriticalSection.Create;
   FLock := TCriticalSection.Create;
-  Fdigest := digest;
-  System.SetLength(Fseed, digest.GetDigestSize);
-  FseedCounter := 1;
-  System.SetLength(Fstate, digest.GetDigestSize);
-  FstateCounter := 1;
+  FDigest := ADigest;
+  System.SetLength(FSeed, ADigest.GetDigestSize);
+  FSeedCounter := 1;
+  System.SetLength(FState, ADigest.GetDigestSize);
+  FStateCounter := 1;
 end;
 end;
 
 
 procedure TDigestRandomGenerator.CycleSeed;
 procedure TDigestRandomGenerator.CycleSeed;
 begin
 begin
-  DigestUpdate(Fseed);
-  DigestAddCounter(FseedCounter);
-  System.Inc(FseedCounter);
-  DigestDoFinal(Fseed);
+  DigestUpdate(FSeed);
+  DigestAddCounter(FSeedCounter);
+  System.Inc(FSeedCounter);
+  DigestDoFinal(FSeed);
 end;
 end;
 
 
 destructor TDigestRandomGenerator.Destroy;
 destructor TDigestRandomGenerator.Destroy;
@@ -146,44 +145,44 @@ end;
 
 
 procedure TDigestRandomGenerator.GenerateState;
 procedure TDigestRandomGenerator.GenerateState;
 begin
 begin
-  DigestAddCounter(FstateCounter);
-  System.Inc(FstateCounter);
-  DigestUpdate(Fstate);
-  DigestUpdate(Fseed);
-  DigestDoFinal(Fstate);
+  DigestAddCounter(FStateCounter);
+  System.Inc(FStateCounter);
+  DigestUpdate(FState);
+  DigestUpdate(FSeed);
+  DigestDoFinal(FState);
 
 
-  if ((FstateCounter mod CYCLE_COUNT) = 0) then
+  if ((FStateCounter mod CycleCount) = 0) then
   begin
   begin
     CycleSeed();
     CycleSeed();
   end;
   end;
 end;
 end;
 
 
-procedure TDigestRandomGenerator.NextBytes(const bytes: TCryptoLibByteArray);
+procedure TDigestRandomGenerator.NextBytes(const ABytes: TCryptoLibByteArray);
 begin
 begin
-  NextBytes(bytes, 0, System.Length(bytes));
+  NextBytes(ABytes, 0, System.Length(ABytes));
 end;
 end;
 
 
-procedure TDigestRandomGenerator.NextBytes(const bytes: TCryptoLibByteArray;
-  start, len: Int32);
+procedure TDigestRandomGenerator.NextBytes(const ABytes: TCryptoLibByteArray;
+  AStart, ALen: Int32);
 var
 var
-  stateOff, endPoint: Int32;
-  I: Int32;
+  LStateOff, LEndPoint: Int32;
+  LI: Int32;
 begin
 begin
   FLock.Acquire;
   FLock.Acquire;
   try
   try
-    stateOff := 0;
+    LStateOff := 0;
     GenerateState();
     GenerateState();
-    endPoint := start + len;
+    LEndPoint := AStart + ALen;
 
 
-    for I := start to System.Pred(endPoint) do
+    for LI := AStart to System.Pred(LEndPoint) do
     begin
     begin
-      if (stateOff = System.Length(Fstate)) then
+      if (LStateOff = System.Length(FState)) then
       begin
       begin
         GenerateState();
         GenerateState();
-        stateOff := 0;
+        LStateOff := 0;
       end;
       end;
-      bytes[I] := Fstate[stateOff];
-      System.Inc(stateOff);
+      ABytes[LI] := FState[LStateOff];
+      System.Inc(LStateOff);
     end;
     end;
 
 
   finally
   finally

+ 126 - 0
CryptoLib/src/Rngs/ClpRandomNumberGenerator.pas

@@ -0,0 +1,126 @@
+{ *********************************************************************************** }
+{ *                              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 ClpRandomNumberGenerator;
+
+{$I ..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  ClpCryptoLibTypes,
+  ClpOSRandomProvider,
+  ClpAesRandomProvider,
+  ClpIRandomNumberGenerator,
+  ClpIRandomSourceProvider;
+
+resourcestring
+  SRandomNumberGeneratorOutputBufferNil =
+    'Random Number Generator Output Buffer Cannot Be Nil';
+  SRandomSourceProviderNil =
+    'Random Source Provider Cannot Be Nil';
+
+type
+  TRandomNumberGenerator = class abstract(TInterfacedObject, IRandomNumberGenerator)
+
+  strict protected
+    class procedure ValidateOutputBufferNotNull(const ABuffer
+      : TCryptoLibByteArray); static; inline;
+
+  public
+
+    class function CreateRng(): IRandomNumberGenerator; overload; static;
+
+    class function CreateRng(const ARandomSource: IRandomSourceProvider)
+      : IRandomNumberGenerator; overload; static;
+
+    procedure GetBytes(const AData: TCryptoLibByteArray); virtual; abstract;
+
+    procedure GetNonZeroBytes(const AData: TCryptoLibByteArray); virtual; abstract;
+
+  end;
+
+
+implementation
+
+type
+  TDefaultRandomNumberGenerator = class sealed(TRandomNumberGenerator,
+    IRandomNumberGenerator)
+
+  strict private
+    FRandomSource: IRandomSourceProvider;
+
+  public
+    constructor Create(const ARandomSource: IRandomSourceProvider);
+
+    procedure GetBytes(const AData: TCryptoLibByteArray); override;
+
+    procedure GetNonZeroBytes(const AData: TCryptoLibByteArray); override;
+
+  end;
+
+{ TRandomNumberGenerator }
+
+class procedure TRandomNumberGenerator.ValidateOutputBufferNotNull
+  (const ABuffer: TCryptoLibByteArray);
+begin
+  if ABuffer = nil then
+  begin
+    raise EArgumentNilCryptoLibException.CreateRes
+      (@SRandomNumberGeneratorOutputBufferNil);
+  end;
+end;
+
+class function TRandomNumberGenerator.CreateRng: IRandomNumberGenerator;
+begin
+  result := TDefaultRandomNumberGenerator.Create(TOSRandomProvider.Instance);
+end;
+
+class function TRandomNumberGenerator.CreateRng(const ARandomSource
+  : IRandomSourceProvider): IRandomNumberGenerator;
+begin
+  if ARandomSource = nil then
+  begin
+    raise EArgumentNilCryptoLibException.CreateRes(@SRandomSourceProviderNil);
+  end;
+  result := TDefaultRandomNumberGenerator.Create(ARandomSource);
+end;
+
+{ TDefaultRandomNumberGenerator }
+
+constructor TDefaultRandomNumberGenerator.Create
+  (const ARandomSource: IRandomSourceProvider);
+begin
+  inherited Create;
+  FRandomSource := ARandomSource;
+end;
+
+procedure TDefaultRandomNumberGenerator.GetBytes
+  (const AData: TCryptoLibByteArray);
+begin
+  TRandomNumberGenerator.ValidateOutputBufferNotNull(AData);
+  FRandomSource.GetBytes(AData);
+end;
+
+procedure TDefaultRandomNumberGenerator.GetNonZeroBytes
+  (const AData: TCryptoLibByteArray);
+begin
+  TRandomNumberGenerator.ValidateOutputBufferNotNull(AData);
+  FRandomSource.GetNonZeroBytes(AData);
+end;
+
+end.

+ 89 - 76
CryptoLib/src/Rngs/Sources/ClpAESPRNGRandom.pas → CryptoLib/src/Rngs/Providers/ClpAesRandomProvider.pas

@@ -15,7 +15,7 @@
 
 
 (* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
 (* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
 
 
-unit ClpAESPRNGRandom;
+unit ClpAesRandomProvider;
 
 
 {$I ..\..\Include\CryptoLib.inc}
 {$I ..\..\Include\CryptoLib.inc}
 
 
@@ -32,7 +32,8 @@ uses
   ClpIBufferedBlockCipher,
   ClpIBufferedBlockCipher,
   ClpBufferedBlockCipher,
   ClpBufferedBlockCipher,
   ClpArrayUtils,
   ClpArrayUtils,
-  ClpOSRandom,
+  ClpOSRandomProvider,
+  ClpIRandomSourceProvider,
   ClpCryptoLibTypes;
   ClpCryptoLibTypes;
 
 
 resourcestring
 resourcestring
@@ -40,74 +41,84 @@ resourcestring
     'AES RNG Seed Length must be either one of these "128/192/256 bits".';
     'AES RNG Seed Length must be either one of these "128/192/256 bits".';
 
 
 type
 type
-  IAESPRNGRandom = interface(IInterface)
-    ['{DE2F9387-CD63-475F-AD4B-EA0692790FB2}']
-
-    procedure FillBytes(const data: TCryptoLibByteArray);
-    procedure FillNonZeroBytes(const data: TCryptoLibByteArray);
-
-  end;
-
-type
-  TAESPRNGRandom = class sealed(TInterfacedObject, IAESPRNGRandom)
+  /// <summary>
+  /// AES-based random source provider.
+  /// Implements counter-based AES PRNG with automatic reseeding.
+  /// </summary>
+  TAesRandomProvider = class sealed(TInterfacedObject, IRandomSourceProvider)
 
 
   strict private
   strict private
   const
   const
-    COUNTER_SIZE = Int32(16);
-    class var
-
-      FDefaultInstance: IAESPRNGRandom;
+    CounterSize = Int32(16);
+  class var
+    FInstance: IRandomSourceProvider;
+    FLock: TCriticalSection;
 
 
   var
   var
-    FLock: TCriticalSection;
+    FInternalLock: TCriticalSection;
     FCounter: TCryptoLibByteArray;
     FCounter: TCryptoLibByteArray;
     FAESRNGSeedLength, FBytesSinceSeed, FReseedAfterBytes: Int32;
     FAESRNGSeedLength, FBytesSinceSeed, FReseedAfterBytes: Int32;
     FCipher: IBufferedCipher;
     FCipher: IBufferedCipher;
 
 
-    class function GetDefaultInstance: IAESPRNGRandom; static; inline;
+    class function GetInstance: IRandomSourceProvider; static;
+    class function CreateProvider: IRandomSourceProvider; static;
 
 
     class procedure GetRawEntropy(const AEntropy: TCryptoLibByteArray); inline;
     class procedure GetRawEntropy(const AEntropy: TCryptoLibByteArray); inline;
 
 
     class procedure Boot(); static;
     class procedure Boot(); static;
-    class constructor CreateAESPRNGRandom();
-    class destructor DestroyAESPRNGRandom();
+    class constructor Create();
+    class destructor Destroy();
 
 
     class procedure ValidateAESRNGSeedLength(ASeedLength: Int32);
     class procedure ValidateAESRNGSeedLength(ASeedLength: Int32);
 
 
-    constructor Create(const AAESRNGSeed: TCryptoLibByteArray;
-      AReseedAfterBytes: Int32); overload;
+    constructor Create(const AAesRngSeed: TCryptoLibByteArray; AReseedAfterBytes: Int32); overload;
 
 
     procedure DoIncrementCounter();
     procedure DoIncrementCounter();
 
 
     procedure DoSeed(const AAESRNGSeed: TCryptoLibByteArray);
     procedure DoSeed(const AAESRNGSeed: TCryptoLibByteArray);
 
 
   public
   public
-    constructor Create(AAESRNGSeedLength: Int32 = 32;
-      AReseedAfterBytes: Int32 = 1024 * 1024); overload;
+    constructor Create(AAesRngSeedLength: Int32 = 32; AReseedAfterBytes: Int32 = 1024 * 1024); overload;
 
 
     destructor Destroy; override;
     destructor Destroy; override;
 
 
-    procedure FillBytes(const data: TCryptoLibByteArray); overload;
-    procedure FillNonZeroBytes(const data: TCryptoLibByteArray); overload;
+    function GetIsAvailable: Boolean;
+    function GetName: String;
 
 
-    class procedure GetBytes(const data: TCryptoLibByteArray); overload; static;
-    class procedure GetNonZeroBytes(const data: TCryptoLibByteArray);
-      overload; static;
+    procedure GetBytes(const AData: TCryptoLibByteArray);
+    procedure GetNonZeroBytes(const AData: TCryptoLibByteArray);
 
 
-    class property DefaultInstance: IAESPRNGRandom read GetDefaultInstance;
+    class property Instance: IRandomSourceProvider read GetInstance;
 
 
   end;
   end;
 
 
 implementation
 implementation
 
 
-{ TAESPRNGRandom }
+{ TAesRandomProvider }
+
+class function TAesRandomProvider.GetInstance: IRandomSourceProvider;
+begin
+  if FInstance = nil then
+  begin
+    FLock.Enter;
+    try
+      if FInstance = nil then
+      begin
+        FInstance := CreateProvider();
+      end;
+    finally
+      FLock.Leave;
+    end;
+  end;
+  Result := FInstance;
+end;
 
 
-class function TAESPRNGRandom.GetDefaultInstance: IAESPRNGRandom;
+class function TAesRandomProvider.CreateProvider: IRandomSourceProvider;
 begin
 begin
-  result := FDefaultInstance;
+  Result := TAesRandomProvider.Create();
 end;
 end;
 
 
-class procedure TAESPRNGRandom.ValidateAESRNGSeedLength(ASeedLength: Int32);
+class procedure TAesRandomProvider.ValidateAESRNGSeedLength(ASeedLength: Int32);
 begin
 begin
   if ((ASeedLength < 16) or (ASeedLength > 32) or ((ASeedLength and 7) <> 0))
   if ((ASeedLength < 16) or (ASeedLength > 32) or ((ASeedLength and 7) <> 0))
   then
   then
@@ -116,21 +127,34 @@ begin
   end;
   end;
 end;
 end;
 
 
-class procedure TAESPRNGRandom.GetRawEntropy(const AEntropy
+class procedure TAesRandomProvider.GetRawEntropy(const AEntropy
   : TCryptoLibByteArray);
   : TCryptoLibByteArray);
 begin
 begin
-  TOSRandom.GetBytes(AEntropy);
+  TOSRandomProvider.Instance.GetBytes(AEntropy);
 end;
 end;
 
 
-class procedure TAESPRNGRandom.Boot;
+class procedure TAesRandomProvider.Boot;
 begin
 begin
-  if FDefaultInstance = Nil then
+  if FLock = nil then
   begin
   begin
-    FDefaultInstance := TAESPRNGRandom.Create();
+    FLock := TCriticalSection.Create;
   end;
   end;
+  // Trigger instance creation
+  GetInstance;
 end;
 end;
 
 
-procedure TAESPRNGRandom.DoIncrementCounter;
+class constructor TAesRandomProvider.Create();
+begin
+  Boot();
+end;
+
+class destructor TAesRandomProvider.Destroy();
+begin
+  FLock.Free;
+  FInstance := nil;
+end;
+
+procedure TAesRandomProvider.DoIncrementCounter;
 var
 var
   i: Int32;
   i: Int32;
 begin
 begin
@@ -145,35 +169,34 @@ begin
   end;
   end;
 end;
 end;
 
 
-procedure TAESPRNGRandom.DoSeed(const AAESRNGSeed: TCryptoLibByteArray);
+procedure TAesRandomProvider.DoSeed(const AAESRNGSeed: TCryptoLibByteArray);
 var
 var
   LKeyParameter: IKeyParameter;
   LKeyParameter: IKeyParameter;
 begin
 begin
   LKeyParameter := TKeyParameter.Create(AAESRNGSeed);
   LKeyParameter := TKeyParameter.Create(AAESRNGSeed);
-  FLock.Acquire;
+  FInternalLock.Acquire;
   try
   try
     FCipher.Init(True, LKeyParameter);
     FCipher.Init(True, LKeyParameter);
     FBytesSinceSeed := 0;
     FBytesSinceSeed := 0;
   finally
   finally
-    FLock.Release;
+    FInternalLock.Release;
   end;
   end;
 end;
 end;
 
 
-constructor TAESPRNGRandom.Create(const AAESRNGSeed: TCryptoLibByteArray;
-  AReseedAfterBytes: Int32);
+constructor TAesRandomProvider.Create(const AAesRngSeed: TCryptoLibByteArray; AReseedAfterBytes: Int32);
 var
 var
   LAesEngine: IAesEngine;
   LAesEngine: IAesEngine;
   LBlockCipher: IBlockCipher;
   LBlockCipher: IBlockCipher;
   LAESRNGSeed: TCryptoLibByteArray;
   LAESRNGSeed: TCryptoLibByteArray;
 begin
 begin
-  Inherited Create();
-  LAESRNGSeed := System.Copy(AAESRNGSeed);
-  FLock := TCriticalSection.Create;
+  inherited Create();
+  LAESRNGSeed := System.Copy(AAesRngSeed);
+  FInternalLock := TCriticalSection.Create;
   // Set up engine
   // Set up engine
   LAesEngine := TAesEngine.Create();
   LAesEngine := TAesEngine.Create();
   LBlockCipher := LAesEngine as IBlockCipher; // ECB no padding
   LBlockCipher := LAesEngine as IBlockCipher; // ECB no padding
   FCipher := TBufferedBlockCipher.Create(LBlockCipher) as IBufferedBlockCipher;
   FCipher := TBufferedBlockCipher.Create(LBlockCipher) as IBufferedBlockCipher;
-  System.SetLength(FCounter, COUNTER_SIZE);
+  System.SetLength(FCounter, CounterSize);
   FAESRNGSeedLength := System.Length(LAESRNGSeed);
   FAESRNGSeedLength := System.Length(LAESRNGSeed);
   FReseedAfterBytes := AReseedAfterBytes;
   FReseedAfterBytes := AReseedAfterBytes;
   ValidateAESRNGSeedLength(FAESRNGSeedLength);
   ValidateAESRNGSeedLength(FAESRNGSeedLength);
@@ -181,28 +204,28 @@ begin
   TArrayUtils.ZeroFill(LAESRNGSeed); // clear key from memory
   TArrayUtils.ZeroFill(LAESRNGSeed); // clear key from memory
 end;
 end;
 
 
-constructor TAESPRNGRandom.Create(AAESRNGSeedLength, AReseedAfterBytes: Int32);
+constructor TAesRandomProvider.Create(AAesRngSeedLength, AReseedAfterBytes: Int32);
 var
 var
   LSeed: TCryptoLibByteArray;
   LSeed: TCryptoLibByteArray;
 begin
 begin
-  System.SetLength(LSeed, AAESRNGSeedLength);
+  System.SetLength(LSeed, AAesRngSeedLength);
   GetRawEntropy(LSeed); // pure entropy from OS
   GetRawEntropy(LSeed); // pure entropy from OS
   Create(LSeed, AReseedAfterBytes);
   Create(LSeed, AReseedAfterBytes);
   TArrayUtils.ZeroFill(LSeed); // clear seed from memory
   TArrayUtils.ZeroFill(LSeed); // clear seed from memory
 end;
 end;
 
 
-destructor TAESPRNGRandom.Destroy;
+destructor TAesRandomProvider.Destroy;
 begin
 begin
-  FLock.Free;
+  FInternalLock.Free;
   inherited Destroy;
   inherited Destroy;
 end;
 end;
 
 
-procedure TAESPRNGRandom.FillBytes(const data: TCryptoLibByteArray);
+procedure TAesRandomProvider.GetBytes(const AData: TCryptoLibByteArray);
 var
 var
   LDataLength, LDatum, LResultLength: Int32;
   LDataLength, LDatum, LResultLength: Int32;
   LSeed, LResult: TCryptoLibByteArray;
   LSeed, LResult: TCryptoLibByteArray;
 begin
 begin
-  LDataLength := System.Length(data);
+  LDataLength := System.Length(AData);
   if LDataLength <= 0 then
   if LDataLength <= 0 then
   begin
   begin
     Exit;
     Exit;
@@ -218,12 +241,12 @@ begin
 
 
   LDatum := 0;
   LDatum := 0;
 
 
-  FLock.Acquire;
+  FInternalLock.Acquire;
   try
   try
     while (LDataLength shr 4) > 0 do
     while (LDataLength shr 4) > 0 do
     begin
     begin
       DoIncrementCounter;
       DoIncrementCounter;
-      LResultLength := FCipher.DoFinal(FCounter, data, LDatum);
+      LResultLength := FCipher.DoFinal(FCounter, AData, LDatum);
 
 
       System.Inc(LDatum, LResultLength);
       System.Inc(LDatum, LResultLength);
       System.Inc(FBytesSinceSeed, LResultLength);
       System.Inc(FBytesSinceSeed, LResultLength);
@@ -234,40 +257,30 @@ begin
     begin
     begin
       DoIncrementCounter;
       DoIncrementCounter;
       LResult := FCipher.DoFinal(FCounter);
       LResult := FCipher.DoFinal(FCounter);
-      System.Move(LResult[0], data[LDatum], LDataLength * System.SizeOf(Byte));
+      System.Move(LResult[0], AData[LDatum], LDataLength * System.SizeOf(Byte));
       System.Inc(FBytesSinceSeed, LDataLength);
       System.Inc(FBytesSinceSeed, LDataLength);
     end;
     end;
 
 
   finally
   finally
-    FLock.Release;
+    FInternalLock.Release;
   end;
   end;
 end;
 end;
 
 
-procedure TAESPRNGRandom.FillNonZeroBytes(const data: TCryptoLibByteArray);
+procedure TAesRandomProvider.GetNonZeroBytes(const AData: TCryptoLibByteArray);
 begin
 begin
   repeat
   repeat
-    FillBytes(data);
-  until (TArrayUtils.NoZeroes(data));
-end;
-
-class constructor TAESPRNGRandom.CreateAESPRNGRandom;
-begin
-  TAESPRNGRandom.Boot();
-end;
-
-class destructor TAESPRNGRandom.DestroyAESPRNGRandom;
-begin
-  FDefaultInstance := Nil;
+    GetBytes(AData);
+  until (TArrayUtils.NoZeroes(AData));
 end;
 end;
 
 
-class procedure TAESPRNGRandom.GetBytes(const data: TCryptoLibByteArray);
+function TAesRandomProvider.GetIsAvailable: Boolean;
 begin
 begin
-  DefaultInstance.FillBytes(data);
+  Result := True; // AES PRNG is always available
 end;
 end;
 
 
-class procedure TAESPRNGRandom.GetNonZeroBytes(const data: TCryptoLibByteArray);
+function TAesRandomProvider.GetName: String;
 begin
 begin
-  DefaultInstance.FillNonZeroBytes(data);
+  Result := 'AES';
 end;
 end;
 
 
 end.
 end.

+ 265 - 0
CryptoLib/src/Rngs/Providers/ClpAppleRandomProvider.pas

@@ -0,0 +1,265 @@
+{ *********************************************************************************** }
+{ *                              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 ClpAppleRandomProvider;
+
+{$I ..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+{$IFDEF CRYPTOLIB_APPLE}
+{$IFDEF FPC}
+{$LINKFRAMEWORK Security}
+{$IFDEF CRYPTOLIB_MACOS}
+  CocoaAll,
+{$ENDIF}
+{$ELSE}
+  Macapi.ObjCRuntime,
+{$IFDEF CRYPTOLIB_IOS}
+  iOSapi.Foundation,
+{$ENDIF}
+{$IFDEF CRYPTOLIB_MACOS}
+  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.';
+
+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;
+
+  // 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;
+
+{$ELSE}
+
+type
+  SecRandomRef = Pointer;
+
+const
+  libSecurity = '/System/Library/Frameworks/Security.framework/Security';
+
+function SecRandomCopyBytes(rnd: SecRandomRef; count: LongWord; bytes: PByte)
+  : Int32; cdecl; external libSecurity Name _PU + 'SecRandomCopyBytes';
+
+{$ENDIF}
+{$ENDIF}
+
+  /// <summary>
+  /// Apple OS random source provider.
+  /// Implements Apple SecRandomCopyBytes and /dev/urandom fallback
+  /// </summary>
+  TAppleRandomProvider = 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 GenRandomBytesApple(ALen: Int32; AData: PByte): Int32;
+
+  public
+    constructor Create();
+
+    procedure GetBytes(const AData: TCryptoLibByteArray);
+    procedure GetNonZeroBytes(const AData: TCryptoLibByteArray);
+    function GetIsAvailable: Boolean;
+    function GetName: String;
+
+  end;
+
+implementation
+
+uses
+  ClpArrayUtils;
+
+{ TAppleRandomProvider }
+
+constructor TAppleRandomProvider.Create;
+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;
+{$ELSE}
+    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
+  begin
+    result := SecRandomCopyBytes(kSecRandomDefault, LongWord(ALen), AData);
+  end
+  else
+  begin
+    // fallback for when SecRandomCopyBytes API is not available
+    result := DevRandomDeviceRead(ALen, AData);
+  end;
+{$ELSE}
+  result := SecRandomCopyBytes(kSecRandomDefault, LongWord(ALen), AData);
+{$IFEND}
+{$ELSE}
+  result := -1;
+{$ENDIF}
+end;
+
+procedure TAppleRandomProvider.GetBytes(const AData: TCryptoLibByteArray);
+var
+  LCount: Int32;
+begin
+  LCount := System.Length(AData);
+
+  if LCount <= 0 then
+  begin
+    Exit;
+  end;
+
+{$IFDEF CRYPTOLIB_APPLE}
+  if GenRandomBytesApple(LCount, PByte(AData)) <> 0 then
+  begin
+    raise EOSRandomCryptoLibException.CreateRes
+      (@SAppleSecRandomCopyBytesGenerationError);
+  end;
+{$ELSE}
+  raise EOSRandomCryptoLibException.Create('AppleRandomProvider is only available on Apple platforms');
+{$ENDIF}
+end;
+
+procedure TAppleRandomProvider.GetNonZeroBytes(const AData: TCryptoLibByteArray);
+begin
+  repeat
+    GetBytes(AData);
+  until (TArrayUtils.NoZeroes(AData));
+end;
+
+function TAppleRandomProvider.GetIsAvailable: Boolean;
+begin
+{$IFDEF CRYPTOLIB_APPLE}
+  result := True;
+{$ELSE}
+  result := False;
+{$ENDIF}
+end;
+
+function TAppleRandomProvider.GetName: String;
+begin
+  result := 'Apple';
+end;
+
+end.

+ 123 - 0
CryptoLib/src/Rngs/Providers/ClpGenericBSDRandomProvider.pas

@@ -0,0 +1,123 @@
+{ *********************************************************************************** }
+{ *                              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 ClpGenericBSDRandomProvider;
+
+{$I ..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  SysUtils,
+  ClpCryptoLibTypes,
+  ClpIRandomSourceProvider;
+
+resourcestring
+  SArc4RandomBufGenerationError =
+    'An Error Occured while generating random data using arc4random_buf API.';
+
+type
+{$IFDEF CRYPTOLIB_GENERIC_BSD}
+procedure arc4random_buf(bytes: PByte; count: LongWord); cdecl;
+  external 'c' name 'arc4random_buf';
+{$ENDIF}
+
+  /// <summary>
+  /// Generic BSD OS random source provider.
+  /// Implements BSD variants using arc4random_buf
+  /// </summary>
+  TGenericBSDRandomProvider = class sealed(TInterfacedObject, IRandomSourceProvider)
+
+  strict private
+    function GenRandomBytesGenericBSD(ALen: Int32; AData: PByte): Int32;
+
+  public
+    constructor Create();
+
+    procedure GetBytes(const AData: TCryptoLibByteArray);
+    procedure GetNonZeroBytes(const AData: TCryptoLibByteArray);
+    function GetIsAvailable: Boolean;
+    function GetName: String;
+
+  end;
+
+implementation
+
+uses
+  ClpArrayUtils;
+
+{ TGenericBSDRandomProvider }
+
+constructor TGenericBSDRandomProvider.Create;
+begin
+  inherited Create();
+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}
+end;
+
+procedure TGenericBSDRandomProvider.GetBytes(const AData: TCryptoLibByteArray);
+var
+  LCount: Int32;
+begin
+  LCount := System.Length(AData);
+
+  if LCount <= 0 then
+  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);
+begin
+  repeat
+    GetBytes(AData);
+  until (TArrayUtils.NoZeroes(AData));
+end;
+
+function TGenericBSDRandomProvider.GetIsAvailable: Boolean;
+begin
+{$IFDEF CRYPTOLIB_GENERIC_BSD}
+  result := True;
+{$ELSE}
+  result := False;
+{$ENDIF}
+end;
+
+function TGenericBSDRandomProvider.GetName: String;
+begin
+  result := 'GenericBSD';
+end;
+
+end.

+ 274 - 0
CryptoLib/src/Rngs/Providers/ClpLinuxRandomProvider.pas

@@ -0,0 +1,274 @@
+{ *********************************************************************************** }
+{ *                              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 ClpLinuxRandomProvider;
+
+{$I ..\..\Include\CryptoLib.inc}
+
+interface
+
+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,
+  ClpIRandomSourceProvider;
+
+resourcestring
+  SLinuxGetRandomError =
+    'An Error Occured while generating random data using getRandom API';
+
+type
+{$IFDEF CRYPTOLIB_HAS_GETRANDOM}
+{$IFDEF CRYPTOLIB_LINUX}
+{$IFDEF CRYPTOLIB_ANDROID}
+const
+  LIBC_SO = 'libc.so';
+{$ELSE}
+const
+  LIBC_SO = 'libc.so.6';
+{$ENDIF}
+{$ENDIF}
+
+type
+  TGetRandom = function(pbBuffer: PByte; buflen: LongWord; flags: UInt32)
+    : Int32; cdecl;
+{$ENDIF}
+
+  /// <summary>
+  /// Linux OS random source provider.
+  /// Implements Linux getrandom and /dev/urandom fallback
+  /// </summary>
+  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;
+    FGetRandom: TGetRandom;
+
+    function IsGetRandomAvailable(): Boolean;
+{$ENDIF}
+    function GenRandomBytesLinux(ALen: Int32; AData: PByte): Int32;
+
+  public
+    constructor Create();
+
+    procedure GetBytes(const AData: TCryptoLibByteArray);
+    procedure GetNonZeroBytes(const AData: TCryptoLibByteArray);
+    function GetIsAvailable: Boolean;
+    function GetName: String;
+
+  end;
+
+implementation
+
+uses
+  ClpArrayUtils;
+
+{ TLinuxRandomProvider }
+
+constructor TLinuxRandomProvider.Create;
+begin
+  inherited Create();
+{$IFDEF CRYPTOLIB_HAS_GETRANDOM}
+  FIsGetRandomSupportedOnOS := 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};
+begin
+  FGetRandom := nil;
+  LLib := {$IFDEF FPC}PtrInt{$ENDIF}(dlopen(LIBC_SO, RTLD_NOW));
+  if LLib <> 0 then
+  begin
+    FGetRandom := dlsym(LLib, 'getrandom');
+    dlclose(LLib);
+  end;
+  result := System.Assigned(FGetRandom);
+end;
+
+{$ENDIF}
+
+function TLinuxRandomProvider.GenRandomBytesLinux(ALen: Int32;
+  AData: PByte): Int32;
+var
+  LGot: Int32;
+begin
+{$IFDEF CRYPTOLIB_LINUX}
+{$IFDEF CRYPTOLIB_HAS_GETRANDOM}
+  if FIsGetRandomSupportedOnOS then
+  begin
+    while (ALen > 0) do
+    begin
+      LGot := FGetRandom(AData, LongWord(ALen), GRND_DEFAULT);
+
+      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;
+  end
+  else
+  begin
+    // fallback for when getrandom API is not available
+    result := DevRandomDeviceRead(ALen, AData);
+  end;
+{$ELSE}
+  result := DevRandomDeviceRead(ALen, AData);
+{$ENDIF}
+{$ELSE}
+  result := -1;
+{$ENDIF}
+end;
+
+procedure TLinuxRandomProvider.GetBytes(const AData: TCryptoLibByteArray);
+var
+  LCount: Int32;
+begin
+  LCount := System.Length(AData);
+
+  if LCount <= 0 then
+  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);
+begin
+  repeat
+    GetBytes(AData);
+  until (TArrayUtils.NoZeroes(AData));
+end;
+
+function TLinuxRandomProvider.GetIsAvailable: Boolean;
+begin
+{$IFDEF CRYPTOLIB_LINUX}
+  result := True;
+{$ELSE}
+  result := False;
+{$ENDIF}
+end;
+
+function TLinuxRandomProvider.GetName: String;
+begin
+  result := 'Linux';
+end;
+
+end.

+ 135 - 0
CryptoLib/src/Rngs/Providers/ClpOSRandomProvider.pas

@@ -0,0 +1,135 @@
+{ *********************************************************************************** }
+{ *                              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 ClpOSRandomProvider;
+
+{$I ..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  SyncObjs,
+  ClpIRandomSourceProvider
+{$IFDEF CRYPTOLIB_MSWINDOWS}
+  , ClpWindowsRandomProvider
+{$ENDIF}
+{$IFDEF CRYPTOLIB_APPLE}
+  , ClpAppleRandomProvider
+{$ENDIF}
+{$IFDEF CRYPTOLIB_LINUX}
+  , ClpLinuxRandomProvider
+{$ENDIF}
+{$IFDEF CRYPTOLIB_SOLARIS}
+  , ClpSolarisRandomProvider
+{$ENDIF}
+{$IFDEF CRYPTOLIB_GENERIC_BSD}
+  , ClpGenericBSDRandomProvider
+{$ENDIF}
+{$IFDEF CRYPTOLIB_UNIX}
+  , ClpUnixRandomProvider
+{$ENDIF}
+  ;
+
+type
+  /// <summary>
+  /// Factory class for OS-specific random source providers.
+  /// Provides a singleton instance of the appropriate platform-specific implementation.
+  /// </summary>
+  TOSRandomProvider = class sealed(TObject)
+
+  strict private
+  class var
+    FInstance: IRandomSourceProvider;
+    FLock: TCriticalSection;
+
+    class function GetInstance: IRandomSourceProvider; static;
+    class function CreateProvider: IRandomSourceProvider; static;
+
+  public
+    class property Instance: IRandomSourceProvider read GetInstance;
+
+    class procedure Boot(); static;
+
+    class constructor Create();
+
+    class destructor Destroy();
+
+  end;
+
+implementation
+
+{ TOSRandomProvider }
+
+class constructor TOSRandomProvider.Create();
+begin
+  Boot();
+end;
+
+class destructor TOSRandomProvider.Destroy();
+begin
+  FLock.Free;
+  FInstance := nil;
+end;
+
+class function TOSRandomProvider.CreateProvider: IRandomSourceProvider;
+begin
+{$IF DEFINED(CRYPTOLIB_MSWINDOWS)}
+  Result := TWindowsRandomProvider.Create();
+{$ELSEIF DEFINED(CRYPTOLIB_APPLE)}
+  Result := TAppleRandomProvider.Create();
+{$ELSEIF DEFINED(CRYPTOLIB_LINUX)}
+  Result := TLinuxRandomProvider.Create();
+{$ELSEIF DEFINED(CRYPTOLIB_SOLARIS)}
+  Result := TSolarisRandomProvider.Create();
+{$ELSEIF DEFINED(CRYPTOLIB_GENERIC_BSD)}
+  Result := TGenericBSDRandomProvider.Create();
+{$ELSEIF DEFINED(CRYPTOLIB_UNIX)}
+  Result := TUnixRandomProvider.Create();
+{$ELSE}
+{$MESSAGE ERROR 'UNSUPPORTED TARGET.'}
+  Result := nil;
+{$IFEND}
+end;
+
+class function TOSRandomProvider.GetInstance: IRandomSourceProvider;
+begin
+  if FInstance = nil then
+  begin
+    FLock.Enter;
+    try
+      if FInstance = nil then
+      begin
+        FInstance := CreateProvider();
+      end;
+    finally
+      FLock.Leave;
+    end;
+  end;
+  result := FInstance;
+end;
+
+class procedure TOSRandomProvider.Boot;
+begin
+  if FLock = nil then
+  begin
+    FLock := TCriticalSection.Create;
+  end;
+  // Trigger instance creation
+  GetInstance;
+end;
+
+end.

+ 277 - 0
CryptoLib/src/Rngs/Providers/ClpSolarisRandomProvider.pas

@@ -0,0 +1,277 @@
+{ *********************************************************************************** }
+{ *                              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 ClpSolarisRandomProvider;
+
+{$I ..\..\Include\CryptoLib.inc}
+
+interface
+
+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,
+  ClpIRandomSourceProvider;
+
+resourcestring
+  SSolarisGetRandomError =
+    'An Error Occured while generating random data using getRandom API';
+
+type
+{$IFDEF CRYPTOLIB_HAS_GETRANDOM}
+{$IFDEF CRYPTOLIB_SOLARIS}
+const
+  LIBC_SO = 'libc.so.1';
+{$ENDIF}
+
+type
+  TGetRandom = function(pbBuffer: PByte; buflen: LongWord; flags: UInt32)
+    : Int32; cdecl;
+{$ENDIF}
+
+  /// <summary>
+  /// Solaris OS random source provider.
+  /// Implements Solaris getrandom and /dev/urandom fallback
+  /// </summary>
+  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;
+    FGetRandom: TGetRandom;
+
+    function IsGetRandomAvailable(): Boolean;
+{$ENDIF}
+    function GenRandomBytesSolaris(ALen: Int32; AData: PByte): Int32;
+
+  public
+    constructor Create();
+
+    procedure GetBytes(const AData: TCryptoLibByteArray);
+    procedure GetNonZeroBytes(const AData: TCryptoLibByteArray);
+    function GetIsAvailable: Boolean;
+    function GetName: String;
+
+  end;
+
+implementation
+
+uses
+  ClpArrayUtils;
+
+{ TSolarisRandomProvider }
+
+constructor TSolarisRandomProvider.Create;
+begin
+  inherited Create();
+{$IFDEF CRYPTOLIB_HAS_GETRANDOM}
+  FIsGetRandomSupportedOnOS := 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};
+begin
+  FGetRandom := nil;
+  LLib := {$IFDEF FPC}PtrInt{$ENDIF}(dlopen(LIBC_SO, RTLD_NOW));
+  if LLib <> 0 then
+  begin
+    FGetRandom := dlsym(LLib, 'getrandom');
+    dlclose(LLib);
+  end;
+  result := System.Assigned(FGetRandom);
+end;
+
+{$ENDIF}
+
+function TSolarisRandomProvider.GenRandomBytesSolaris(ALen: Int32;
+  AData: PByte): Int32;
+var
+  LGot, LMaxChunkSize: Int32;
+begin
+  LMaxChunkSize := 256; // 256 bytes
+
+{$IFDEF CRYPTOLIB_SOLARIS}
+{$IFDEF CRYPTOLIB_HAS_GETRANDOM}
+  if FIsGetRandomSupportedOnOS then
+  begin
+    while (ALen > 0) do
+    begin
+      if ALen <= LMaxChunkSize then
+      begin
+        LMaxChunkSize := ALen;
+      end;
+
+      LGot := FGetRandom(AData, LongWord(LMaxChunkSize), GRND_DEFAULT);
+
+      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;
+  end
+  else
+  begin
+    // fallback for when getrandom API is not available
+    result := DevRandomDeviceRead(ALen, AData);
+  end;
+{$ELSE}
+  result := DevRandomDeviceRead(ALen, AData);
+{$ENDIF}
+{$ELSE}
+  result := -1;
+{$ENDIF}
+end;
+
+procedure TSolarisRandomProvider.GetBytes(const AData: TCryptoLibByteArray);
+var
+  LCount: Int32;
+begin
+  LCount := System.Length(AData);
+
+  if LCount <= 0 then
+  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);
+begin
+  repeat
+    GetBytes(AData);
+  until (TArrayUtils.NoZeroes(AData));
+end;
+
+function TSolarisRandomProvider.GetIsAvailable: Boolean;
+begin
+{$IFDEF CRYPTOLIB_SOLARIS}
+  result := True;
+{$ELSE}
+  result := False;
+{$ENDIF}
+end;
+
+function TSolarisRandomProvider.GetName: String;
+begin
+  result := 'Solaris';
+end;
+
+end.

+ 183 - 0
CryptoLib/src/Rngs/Providers/ClpUnixRandomProvider.pas

@@ -0,0 +1,183 @@
+{ *********************************************************************************** }
+{ *                              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 ClpUnixRandomProvider;
+
+{$I ..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+{$IFDEF CRYPTOLIB_UNIX}
+  Classes,
+{$IFDEF FPC}
+  BaseUnix,
+{$ELSE}
+  Posix.Errno,
+{$ENDIF}
+{$ENDIF}
+  SysUtils,
+  ClpCryptoLibTypes,
+  ClpIRandomSourceProvider;
+
+resourcestring
+  SRandomDeviceReadError =
+    'An Error Occured while reading random data from random device (file)';
+
+type
+  /// <summary>
+  /// Unix OS random source provider (fallback for other Unix systems).
+  /// Implements /dev/urandom fallback
+  /// </summary>
+  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}
+
+  public
+    constructor Create();
+
+    procedure GetBytes(const AData: TCryptoLibByteArray);
+    procedure GetNonZeroBytes(const AData: TCryptoLibByteArray);
+    function GetIsAvailable: Boolean;
+    function GetName: String;
+
+  end;
+
+implementation
+
+uses
+  ClpArrayUtils;
+
+{ TUnixRandomProvider }
+
+constructor TUnixRandomProvider.Create;
+begin
+  inherited Create();
+end;
+
+{$IFDEF CRYPTOLIB_UNIX}
+
+function TUnixRandomProvider.ErrorNo: Int32;
+begin
+  result := Errno;
+end;
+
+function TUnixRandomProvider.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}
+
+procedure TUnixRandomProvider.GetBytes(const AData: TCryptoLibByteArray);
+var
+  LCount: Int32;
+begin
+  LCount := System.Length(AData);
+
+  if LCount <= 0 then
+  begin
+    Exit;
+  end;
+
+{$IFDEF CRYPTOLIB_UNIX}
+  if DevRandomDeviceRead(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);
+begin
+  repeat
+    GetBytes(AData);
+  until (TArrayUtils.NoZeroes(AData));
+end;
+
+function TUnixRandomProvider.GetIsAvailable: Boolean;
+begin
+{$IFDEF CRYPTOLIB_UNIX}
+  result := True;
+{$ELSE}
+  result := False;
+{$ENDIF}
+end;
+
+function TUnixRandomProvider.GetName: String;
+begin
+  result := 'Unix';
+end;
+
+end.

+ 319 - 0
CryptoLib/src/Rngs/Providers/ClpWindowsRandomProvider.pas

@@ -0,0 +1,319 @@
+{ *********************************************************************************** }
+{ *                              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 ClpWindowsRandomProvider;
+
+{$I ..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+{$IFDEF CRYPTOLIB_MSWINDOWS}
+  Windows,
+{$ENDIF}
+  SysUtils,
+  ClpCryptoLibTypes,
+  ClpIRandomSourceProvider;
+
+resourcestring
+  SMSWIndowsCryptographyAPIGenerationError =
+    'An Error Occured 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
+  /// </summary>
+  TWindowsRandomProvider = class sealed(TInterfacedObject, IRandomSourceProvider)
+
+  strict private
+  const
+    BCRYPT = 'bcrypt.dll';
+    ADVAPI32 = 'advapi32.dll';
+
+  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;
+
+    TCryptGenRandom = function(hProv: THandle; dwLen: DWORD; pbBuffer: PByte)
+      : BOOL; stdcall;
+
+    TCryptAcquireContextW = function(phProv: Pointer; pszContainer: LPCWSTR;
+      pszProvider: LPCWSTR; dwProvType: DWORD; dwFlags: DWORD): BOOL; stdcall;
+
+    TCryptReleaseContext = function(hProv: THandle; dwFlags: DWORD)
+      : BOOL; stdcall;
+
+    TRtlGenRandom = function(RandomBuffer: PVOID; RandomBufferLength: ULONG)
+      : Boolean; stdcall;
+
+  var
+    FIsCngBCryptGenRandomSupportedOnOS: Boolean;
+    FIsCryptGenRandomSupportedOnOS: Boolean;
+    FIsRtlGenRandomSupportedOnOS: Boolean;
+    FBCryptGenRandom: TBCryptGenRandom;
+    FBCryptOpenAlgorithmProvider: TBCryptOpenAlgorithmProvider;
+    FBCryptCloseAlgorithmProvider: TBCryptCloseAlgorithmProvider;
+    FCryptGenRandom: TCryptGenRandom;
+    FCryptAcquireContextW: TCryptAcquireContextW;
+    FCryptReleaseContext: TCryptReleaseContext;
+    FRtlGenRandom: TRtlGenRandom;
+
+    function GetProcedureAddress(AModuleHandle: THandle;
+      const AProcedureName: String; var AFunctionFound: Boolean): Pointer;
+
+    function IsCngBCryptGenRandomAvailable(): Boolean;
+    function IsCryptGenRandomAvailable(): Boolean;
+    function IsRtlGenRandomAvailable(): Boolean;
+
+    function GenRandomBytesWindows(ALen: Int32; AData: PByte): Int32;
+
+  public
+    constructor Create();
+
+    procedure GetBytes(const AData: TCryptoLibByteArray);
+    procedure GetNonZeroBytes(const AData: TCryptoLibByteArray);
+    function GetIsAvailable: Boolean;
+    function GetName: String;
+
+  end;
+
+implementation
+
+uses
+  ClpArrayUtils;
+
+{ TWindowsRandomProvider }
+
+constructor TWindowsRandomProvider.Create;
+begin
+  inherited Create();
+  FIsCngBCryptGenRandomSupportedOnOS := IsCngBCryptGenRandomAvailable();
+  FIsCryptGenRandomSupportedOnOS := IsCryptGenRandomAvailable();
+  FIsRtlGenRandomSupportedOnOS := IsRtlGenRandomAvailable();
+end;
+
+function TWindowsRandomProvider.GetProcedureAddress(AModuleHandle: THandle;
+  const AProcedureName: String; var AFunctionFound: Boolean): Pointer;
+begin
+  result := GetProcAddress(AModuleHandle, PChar(AProcedureName));
+  if result = nil then
+  begin
+    AFunctionFound := False;
+  end;
+end;
+
+function TWindowsRandomProvider.IsCngBCryptGenRandomAvailable(): Boolean;
+var
+  LModuleHandle: THandle;
+  LFunctionFound: Boolean;
+begin
+  result := False;
+  LModuleHandle := SafeLoadLibrary(BCRYPT, SEM_FAILCRITICALERRORS);
+  if LModuleHandle <> 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,
+      'BCryptGenRandom', LFunctionFound);
+    result := result and LFunctionFound;
+  end;
+end;
+
+function TWindowsRandomProvider.IsCryptGenRandomAvailable(): Boolean;
+var
+  LModuleHandle: THandle;
+  LFunctionFound: Boolean;
+begin
+  result := False;
+  LModuleHandle := SafeLoadLibrary(ADVAPI32, SEM_FAILCRITICALERRORS);
+  if LModuleHandle <> 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;
+  end;
+end;
+
+function TWindowsRandomProvider.IsRtlGenRandomAvailable(): Boolean;
+var
+  LModuleHandle: THandle;
+  LFunctionFound: Boolean;
+begin
+  result := False;
+  LModuleHandle := SafeLoadLibrary(ADVAPI32, SEM_FAILCRITICALERRORS);
+  if LModuleHandle <> 0 then
+  begin
+    result := True;
+    LFunctionFound := True;
+    FRtlGenRandom := GetProcedureAddress(LModuleHandle,
+      'SystemFunction036', 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;
+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
+  begin
+    // Availability: Windows XP / Server 2003 and Above
+    if not FRtlGenRandom(AData, ULONG(ALen)) then
+    begin
+      result := HResultFromWin32(GetLastError);
+      Exit;
+    end;
+  end
+  else if FIsCryptGenRandomSupportedOnOS then
+  begin
+    // Availability: Windows XP / Server 2003 and Above
+    if not FCryptAcquireContextW(@LhProv, nil, nil, PROV_RSA_FULL,
+      CRYPT_VERIFYCONTEXT or CRYPT_SILENT) then
+    begin
+      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
+  begin
+    // Availability: Windows Vista / Server 2008 and Above
+    if (not BCRYPT_SUCCESS(FBCryptOpenAlgorithmProvider(@LhProv,
+      PWideChar(BCRYPT_RNG_ALGORITHM), nil, 0))) then
+    begin
+      result := HResultFromWin32(GetLastError);
+      Exit;
+    end;
+
+    try
+      if (not BCRYPT_SUCCESS(FBCryptGenRandom(LhProv, PUCHAR(AData),
+        ULONG(ALen), 0))) then
+      begin
+        result := HResultFromWin32(GetLastError);
+        Exit;
+      end;
+    finally
+      FBCryptCloseAlgorithmProvider(LhProv, 0);
+    end;
+  end
+  else
+  begin
+    // should never happen but who knows :)
+    result := S_FALSE;
+    Exit;
+  end;
+  result := S_OK;
+end;
+
+procedure TWindowsRandomProvider.GetBytes(const AData: TCryptoLibByteArray);
+var
+  LCount: Int32;
+begin
+  LCount := System.Length(AData);
+
+  if LCount <= 0 then
+  begin
+    Exit;
+  end;
+
+{$IFDEF CRYPTOLIB_MSWINDOWS}
+  if GenRandomBytesWindows(LCount, PByte(AData)) <> 0 then
+  begin
+    raise EOSRandomCryptoLibException.CreateRes
+      (@SMSWIndowsCryptographyAPIGenerationError);
+  end;
+{$ELSE}
+  raise EOSRandomCryptoLibException.Create('WindowsRandomProvider is only available on Windows');
+{$ENDIF}
+end;
+
+procedure TWindowsRandomProvider.GetNonZeroBytes(const AData: TCryptoLibByteArray);
+begin
+  repeat
+    GetBytes(AData);
+  until (TArrayUtils.NoZeroes(AData));
+end;
+
+function TWindowsRandomProvider.GetIsAvailable: Boolean;
+begin
+{$IFDEF CRYPTOLIB_MSWINDOWS}
+  result := FIsRtlGenRandomSupportedOnOS or FIsCryptGenRandomSupportedOnOS or
+    FIsCngBCryptGenRandomSupportedOnOS;
+{$ELSE}
+  result := False;
+{$ENDIF}
+end;
+
+function TWindowsRandomProvider.GetName: String;
+begin
+  result := 'Windows';
+end;
+
+end.

+ 0 - 807
CryptoLib/src/Rngs/Sources/ClpOSRandom.pas

@@ -1,807 +0,0 @@
-{ *********************************************************************************** }
-{ *                              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 ClpOSRandom;
-
-{$I ..\..\Include\CryptoLib.inc}
-
-interface
-
-uses
-{$IFDEF CRYPTOLIB_MSWINDOWS}
-  Windows,
-{$ENDIF} // ENDIF CRYPTOLIB_MSWINDOWS
-{$IFDEF CRYPTOLIB_APPLE}
-{$IFDEF FPC}
-{$LINKFRAMEWORK Security}
-{$IFDEF CRYPTOLIB_MACOS}
-  CocoaAll,
-{$ENDIF} // ENDIF CRYPTOLIB_MACOS
-{$ELSE}
-  // Macapi.Dispatch, or
-  Macapi.ObjCRuntime,
-{$IFDEF CRYPTOLIB_IOS}
-  iOSapi.Foundation,
-{$ENDIF} // ENDIF CRYPTOLIB_IOS
-{$IFDEF CRYPTOLIB_MACOS}
-  Macapi.AppKit,
-  Macapi.Foundation,
-{$ENDIF} // ENDIF CRYPTOLIB_MACOS
-{$ENDIF}  // ENDIF FPC
-{$ENDIF}   // ENDIF CRYPTOLIB_APPLE
-{$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}  // ENDIF CRYPTOLIB_UNIX
-{$IFDEF CRYPTOLIB_GENERIC_BSD}
-  // GenericBSD (NetBSD, FreeBSD, OpenBSD, DragonFlyBSD)
-{$ENDIF}  // ENDIF CRYPTOLIB_GENERIC_BSD
-{$IF DEFINED(CRYPTOLIB_MSWINDOWS) OR DEFINED(CRYPTOLIB_UNIX)}
-  SysUtils,
-{$IFEND}  // ENDIF CRYPTOLIB_MSWINDOWS OR CRYPTOLIB_UNIX
-  ClpArrayUtils,
-  ClpCryptoLibTypes;
-
-resourcestring
-{$IFDEF CRYPTOLIB_MSWINDOWS}
-  SMSWIndowsCryptographyAPIGenerationError =
-    'An Error Occured while generating random data using MS Windows Cryptography API.';
-{$ENDIF}
-{$IFDEF CRYPTOLIB_APPLE}
-  SAppleSecRandomCopyBytesGenerationError =
-    'An Error Occured while generating random data using SecRandomCopyBytes API.';
-{$ENDIF}
-{$IFDEF CRYPTOLIB_LINUX}
-  SLinuxGetRandomError =
-    'An Error Occured while generating random data using getRandom API';
-{$ENDIF}
-{$IFDEF CRYPTOLIB_SOLARIS}
-  SSolarisGetRandomError =
-    'An Error Occured while generating random data using getRandom API';
-{$ENDIF}
-{$IFDEF CRYPTOLIB_GENERIC_BSD}
-  SArc4RandomBufGenerationError =
-    'An Error Occured while generating random data using arc4random_buf API.';
-{$ENDIF}
-  // {$IFDEF CRYPTOLIB_UNIX}
-  // SRandomDeviceReadError =
-  // 'An Error Occured while reading random data from random device (file)';
-  // {$ENDIF}
-
-type
-
-  /// <summary>
-  /// <para>
-  /// TOSRandom Number Class.
-  /// </para>
-  /// <para>
-  /// This class returns random bytes from an OS-specific randomness
-  /// source. The returned data should be unpredictable enough for
-  /// 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>Solaris</term>
-  /// <description><see href="https://docs.oracle.com/cd/E88353_01/html/E37841/getrandom-2.html">
-  /// getrandom</see> system call if available, otherwise ( <see href="https://docs.oracle.com/cd/E86824_01/html/E54777/random-7d.html">
-  /// /dev/urandom or /dev/random</see>) (which ever is
-  /// available)</description>
-  /// </item>
-  /// <item>
-  /// <term>Windows</term>
-  /// <description>Checks availability in this order, <see href="https://docs.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-rtlgenrandom">
-  /// RtlGenRandom</see> =&gt; <see href="https://docs.microsoft.com/en-us/windows/desktop/api/wincrypt/nf-wincrypt-cryptgenrandom">
-  /// CryptGenRandom</see> =&gt; <see href="https://docs.microsoft.com/en-us/windows/desktop/api/bcrypt/nf-bcrypt-bcryptgenrandom">
-  /// BCryptGenRandom</see></description>
-  /// </item>
-  /// <item>
-  /// <term>Mac OS X</term>
-  /// <description><see href="https://developer.apple.com/documentation/security/1399291-secrandomcopybytes?language=objc">
-  /// SecRandomCopyBytes</see> for <b>10.7+,</b> ( /dev/urandom
-  /// or /dev/random) (which ever is available) for &lt; <b>10.7</b><br /></description>
-  /// </item>
-  /// <item>
-  /// <term>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>
-  /// <item>
-  /// <term>DragonFlyBSD</term>
-  /// <description><see href="https://www.dragonflybsd.org/cgi/web-man?command=arc4random&amp;section=3">
-  /// arc4random_buf</see></description>
-  /// </item>
-  /// </list>
-  /// </summary>
-  TOSRandom = class sealed(TObject)
-
-  strict private
-
-    // ================================================================//
-
-{$IFDEF CRYPTOLIB_UNIX}
-  const
-    EINTR = {$IFDEF FPC}ESysEINTR {$ELSE}Posix.Errno.EINTR{$ENDIF};
-
-    class function ErrorNo: Int32; static; inline;
-
-{$IFDEF CRYPTOLIB_HAS_GETRANDOM}
-
-  const
-    GRND_DEFAULT: Int32 = $0000;
-
-{$IFDEF CRYPTOLIB_LINUX}
-{$IFDEF CRYPTOLIB_ANDROID}
-    LIBC_SO = 'libc.so';
-{$ELSE}
-    LIBC_SO = 'libc.so.6';
-{$ENDIF}
-{$ENDIF}
-{$IFDEF CRYPTOLIB_SOLARIS}
-    LIBC_SO = 'libc.so.1';
-{$ENDIF}
-
-  type
-    TGetRandom = function(pbBuffer: PByte; buflen: LongWord; flags: UInt32)
-      : Int32; cdecl;
-
-  class var
-
-    FIsGetRandomSupportedOnOS: Boolean;
-    FGetRandom: TGetRandom;
-
-    class function GetIsGetRandomSupportedOnOS(): Boolean; static; inline;
-
-    class function IsGetRandomAvailable(): Boolean; static;
-
-    class property IsGetRandomSupportedOnOS: Boolean
-      read GetIsGetRandomSupportedOnOS;
-
-{$ENDIF}
-{$ENDIF}
-    // ================================================================//
-
-{$IFDEF CRYPTOLIB_MSWINDOWS}
-
-  const
-    BCRYPT = 'bcrypt.dll';
-    ADVAPI32 = 'advapi32.dll';
-
-  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;
-
-  class var
-
-    FIsCngBCryptGenRandomSupportedOnOS: Boolean;
-    FBCryptGenRandom: TBCryptGenRandom;
-    FBCryptOpenAlgorithmProvider: TBCryptOpenAlgorithmProvider;
-    FBCryptCloseAlgorithmProvider: TBCryptCloseAlgorithmProvider;
-
-    class function GetIsCngBCryptGenRandomSupportedOnOS(): Boolean;
-      static; inline;
-
-    class function IsCngBCryptGenRandomAvailable(): Boolean; static;
-
-    class property IsCngBCryptGenRandomSupportedOnOS: Boolean
-      read GetIsCngBCryptGenRandomSupportedOnOS;
-
-  type
-
-    TCryptGenRandom = function(hProv: THandle; dwLen: DWORD; pbBuffer: PByte)
-      : BOOL; stdcall;
-
-    TCryptAcquireContextW = function(phProv: Pointer; pszContainer: LPCWSTR;
-      pszProvider: LPCWSTR; dwProvType: DWORD; dwFlags: DWORD): BOOL; stdcall;
-
-    TCryptReleaseContext = function(hProv: THandle; dwFlags: DWORD)
-      : BOOL; stdcall;
-
-  class var
-
-    FIsCryptGenRandomSupportedOnOS: Boolean;
-    FCryptGenRandom: TCryptGenRandom;
-    FCryptAcquireContextW: TCryptAcquireContextW;
-    FCryptReleaseContext: TCryptReleaseContext;
-
-    class function GetIsCryptGenRandomSupportedOnOS(): Boolean; static; inline;
-
-    class function IsCryptGenRandomAvailable(): Boolean; static;
-
-    class property IsCryptGenRandomSupportedOnOS: Boolean
-      read GetIsCryptGenRandomSupportedOnOS;
-
-  type
-    TRtlGenRandom = function(RandomBuffer: PVOID; RandomBufferLength: ULONG)
-      : Boolean; stdcall;
-
-  class var
-    FIsRtlGenRandomSupportedOnOS: Boolean;
-    FRtlGenRandom: TRtlGenRandom;
-
-    class function GetIsRtlGenRandomSupportedOnOS(): Boolean; static; inline;
-
-    class function IsRtlGenRandomAvailable(): Boolean; static;
-
-    class property IsRtlGenRandomSupportedOnOS: Boolean
-      read GetIsRtlGenRandomSupportedOnOS;
-
-    class function GetProcedureAddress(ModuleHandle: THandle;
-      const AProcedureName: String; var AFunctionFound: Boolean)
-      : Pointer; static;
-
-    class function GenRandomBytesWindows(len: Int32; data: PByte)
-      : Int32; static;
-{$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_SOLARIS}
-    class function GenRandomBytesSolaris(len: Int32; data: PByte)
-      : Int32; static;
-{$ENDIF}
-    // ================================================================//
-{$IFDEF CRYPTOLIB_GENERIC_BSD}
-    class function GenRandomBytesGenericBSD(len: Int32; data: PByte)
-      : Int32; static;
-{$ENDIF}
-    // ================================================================//
-{$IFDEF CRYPTOLIB_UNIX}
-    class function dev_random_device_read(len: Int32; data: PByte)
-      : Int32; static;
-{$ENDIF}
-    // ================================================================//
-    class constructor OSRandom();
-
-  public
-    class procedure Boot(); static;
-    class procedure GetBytes(const data: TCryptoLibByteArray); static;
-    class procedure GetNonZeroBytes(const data: TCryptoLibByteArray); static;
-
-  end;
-
-  // ************************************************************************//
-{$IFDEF CRYPTOLIB_APPLE}
-{$IFDEF FPC}
-
-type
-  // 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;
-
-  // 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;
-
-{$ELSE}
-
-type
-  SecRandomRef = Pointer;
-
-const
-  libSecurity = '/System/Library/Frameworks/Security.framework/Security';
-
-function SecRandomCopyBytes(rnd: SecRandomRef; count: LongWord; bytes: PByte)
-  : Int32; cdecl; external libSecurity Name _PU + 'SecRandomCopyBytes';
-
-{$ENDIF}
-{$ENDIF}
-// ************************************************************************//
-{$IFDEF CRYPTOLIB_GENERIC_BSD}
-procedure arc4random_buf(bytes: PByte; count: LongWord); cdecl;
-  external 'c' name 'arc4random_buf';
-{$ENDIF}
-
-implementation
-
-class procedure TOSRandom.Boot;
-begin
-{$IFDEF CRYPTOLIB_MSWINDOWS}
-  FIsCngBCryptGenRandomSupportedOnOS := IsCngBCryptGenRandomAvailable();
-  FIsCryptGenRandomSupportedOnOS := IsCryptGenRandomAvailable();
-  FIsRtlGenRandomSupportedOnOS := IsRtlGenRandomAvailable();
-{$ENDIF}
-{$IFDEF CRYPTOLIB_HAS_GETRANDOM}
-  FIsGetRandomSupportedOnOS := IsGetRandomAvailable();
-{$ENDIF}
-end;
-
-class constructor TOSRandom.OSRandom;
-begin
-  TOSRandom.Boot();
-end;
-
-{$IFDEF CRYPTOLIB_MSWINDOWS}
-
-class function TOSRandom.GetProcedureAddress(ModuleHandle: THandle;
-  const AProcedureName: String; var AFunctionFound: Boolean): Pointer;
-begin
-  result := GetProcAddress(ModuleHandle, PChar(AProcedureName));
-  if result = Nil then
-  begin
-    AFunctionFound := False;
-  end;
-end;
-
-class function TOSRandom.GetIsCngBCryptGenRandomSupportedOnOS(): Boolean;
-begin
-  result := FIsCngBCryptGenRandomSupportedOnOS;
-end;
-
-class function TOSRandom.GetIsCryptGenRandomSupportedOnOS(): Boolean;
-begin
-  result := FIsCryptGenRandomSupportedOnOS;
-end;
-
-class function TOSRandom.GetIsRtlGenRandomSupportedOnOS(): Boolean;
-begin
-  result := FIsRtlGenRandomSupportedOnOS;
-end;
-
-class function TOSRandom.IsCngBCryptGenRandomAvailable(): Boolean;
-var
-  ModuleHandle: THandle;
-begin
-  result := False;
-  ModuleHandle := SafeLoadLibrary(BCRYPT, SEM_FAILCRITICALERRORS);
-  if ModuleHandle <> 0 then
-  begin
-    result := True;
-    FBCryptOpenAlgorithmProvider := GetProcedureAddress(ModuleHandle,
-      'BCryptOpenAlgorithmProvider', result);
-    FBCryptCloseAlgorithmProvider := GetProcedureAddress(ModuleHandle,
-      'BCryptCloseAlgorithmProvider', result);
-    FBCryptGenRandom := GetProcedureAddress(ModuleHandle,
-      'BCryptGenRandom', result);
-  end;
-end;
-
-class function TOSRandom.IsCryptGenRandomAvailable(): Boolean;
-var
-  ModuleHandle: THandle;
-begin
-  result := False;
-  ModuleHandle := SafeLoadLibrary(ADVAPI32, SEM_FAILCRITICALERRORS);
-  if ModuleHandle <> 0 then
-  begin
-    result := True;
-    FCryptAcquireContextW := GetProcedureAddress(ModuleHandle,
-      'CryptAcquireContextW', result);
-    FCryptReleaseContext := GetProcedureAddress(ModuleHandle,
-      'CryptReleaseContext', result);
-    FCryptGenRandom := GetProcedureAddress(ModuleHandle,
-      'CryptGenRandom', result);
-  end;
-end;
-
-class function TOSRandom.IsRtlGenRandomAvailable(): Boolean;
-var
-  ModuleHandle: THandle;
-begin
-  result := False;
-  ModuleHandle := SafeLoadLibrary(ADVAPI32, SEM_FAILCRITICALERRORS);
-  if ModuleHandle <> 0 then
-  begin
-    result := True;
-    FRtlGenRandom := GetProcedureAddress(ModuleHandle,
-      'SystemFunction036', result);
-  end;
-end;
-
-class function TOSRandom.GenRandomBytesWindows(len: Int32; data: PByte): Int32;
-
-  function BCRYPT_SUCCESS(AStatus: NTStatus): Boolean; inline;
-  begin
-    result := AStatus >= 0;
-  end;
-
-var
-  hProv: 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 IsRtlGenRandomSupportedOnOS then
-  begin
-    // Availability: Windows XP / Server 2003 and Above
-    if not FRtlGenRandom(data, ULONG(len)) then
-    begin
-      result := HResultFromWin32(GetLastError);
-      Exit;
-    end;
-  end
-  else if IsCryptGenRandomSupportedOnOS then
-  begin
-    // Availability: Windows XP / Server 2003 and Above
-    if not FCryptAcquireContextW(@hProv, nil, nil, PROV_RSA_FULL,
-      CRYPT_VERIFYCONTEXT or CRYPT_SILENT) then
-    begin
-      result := HResultFromWin32(GetLastError);
-      Exit;
-    end;
-
-    try
-      if not FCryptGenRandom(hProv, DWORD(len), data) then
-      begin
-        result := HResultFromWin32(GetLastError);
-        Exit;
-      end;
-    finally
-      FCryptReleaseContext(hProv, 0);
-    end;
-  end
-  else if IsCngBCryptGenRandomSupportedOnOS then
-  begin
-    // Availability: Windows Vista / Server 2008 and Above
-    if (not BCRYPT_SUCCESS(FBCryptOpenAlgorithmProvider(@hProv,
-      PWideChar(BCRYPT_RNG_ALGORITHM), nil, 0))) then
-    begin
-      result := HResultFromWin32(GetLastError);
-      Exit;
-    end;
-
-    try
-      if (not BCRYPT_SUCCESS(FBCryptGenRandom(hProv, PUCHAR(data),
-        ULONG(len), 0))) then
-      begin
-        result := HResultFromWin32(GetLastError);
-        Exit;
-      end;
-    finally
-      FBCryptCloseAlgorithmProvider(hProv, 0);
-    end;
-  end
-  else
-  begin
-    // should never happen but who knows :)
-    result := S_FALSE;
-    Exit;
-  end;
-  result := S_OK;
-end;
-
-{$ENDIF}
-{$IFDEF CRYPTOLIB_APPLE}
-
-class function TOSRandom.GenRandomBytesApple(len: Int32; data: PByte): Int32;
-
-  function kSecRandomDefault: SecRandomRef;
-  begin
-{$IFDEF FPC}
-    result := Nil;
-{$ELSE}
-    result := CocoaPointerConst(libSecurity, 'kSecRandomDefault');
-{$ENDIF}
-  end;
-
-begin
-{$IF DEFINED(CRYPTOLIB_MACOS)}
-  // >= (Mac OS X 10.7+)
-  if NSAppKitVersionNumber >= 1138 then // NSAppKitVersionNumber10_7
-  begin
-    result := SecRandomCopyBytes(kSecRandomDefault, LongWord(len), data);
-  end
-  else
-  begin
-    // fallback for when SecRandomCopyBytes API is not available
-    result := dev_random_device_read(len, data);
-  end;
-{$ELSE}
-  result := SecRandomCopyBytes(kSecRandomDefault, LongWord(len), data);
-{$IFEND}
-end;
-
-{$ENDIF}
-{$IFDEF CRYPTOLIB_UNIX}
-
-class function TOSRandom.dev_random_device_read(len: Int32; data: PByte): Int32;
-var
-  LStream: TFileStream;
-  RandGen: String;
-  got, MaxChunkSize: Int32;
-begin
-  MaxChunkSize := len;
-  RandGen := '/dev/urandom';
-{$IFDEF CRYPTOLIB_SOLARIS}
-  MaxChunkSize := 128 * 1040; // 128 * 1040 bytes
-{$ENDIF}
-  if not FileExists(RandGen) then
-  begin
-{$IFDEF CRYPTOLIB_SOLARIS}
-    MaxChunkSize := 1040; // 1040 bytes
-{$ENDIF}
-    RandGen := '/dev/random';
-
-    if not FileExists(RandGen) then
-    begin
-      result := -1;
-      Exit;
-    end;
-  end;
-
-  LStream := TFileStream.Create(RandGen, fmOpenRead);
-
-  try
-    while (len > 0) do
-    begin
-      if len <= MaxChunkSize then
-      begin
-        MaxChunkSize := len;
-      end;
-
-      got := LStream.Read(data^, MaxChunkSize);
-
-      if (got = 0) then
-      begin
-        if ErrorNo = EINTR then
-        begin
-          continue;
-        end;
-
-        result := -1;
-        Exit;
-      end;
-
-      System.Inc(data, got);
-      System.Dec(len, got);
-    end;
-    result := 0;
-  finally
-    LStream.Free;
-  end;
-end;
-{$ENDIF}
-{$IFDEF CRYPTOLIB_UNIX}
-
-class function TOSRandom.ErrorNo: Int32;
-begin
-  result := Errno;
-end;
-{$ENDIF}
-{$IFDEF CRYPTOLIB_HAS_GETRANDOM}
-
-class function TOSRandom.GetIsGetRandomSupportedOnOS(): Boolean;
-begin
-  result := FIsGetRandomSupportedOnOS;
-end;
-
-class function TOSRandom.IsGetRandomAvailable(): Boolean;
-var
-  Lib: {$IFDEF FPC} PtrInt {$ELSE} NativeUInt {$ENDIF};
-begin
-  FGetRandom := Nil;
-  Lib := {$IFDEF FPC}PtrInt{$ENDIF}(dlopen(LIBC_SO, RTLD_NOW));
-  if Lib <> 0 then
-  begin
-    FGetRandom := dlsym(Lib, 'getrandom');
-    dlclose(Lib);
-  end;
-  result := System.Assigned(FGetRandom);
-end;
-
-{$ENDIF}
-{$IFDEF CRYPTOLIB_LINUX}
-
-class function TOSRandom.GenRandomBytesLinux(len: Int32; data: PByte): Int32;
-var
-  got: Int32;
-begin
-
-  if IsGetRandomSupportedOnOS then
-  begin
-    while (len > 0) do
-    begin
-
-      got := FGetRandom(data, LongWord(len), GRND_DEFAULT);
-
-      if (got < 0) then
-      begin
-        if ErrorNo = EINTR then
-        begin
-          continue;
-        end;
-        result := -1;
-        Exit;
-      end;
-      System.Inc(data, got);
-      System.Dec(len, got);
-    end;
-    result := 0;
-  end
-  else
-  begin
-    // fallback for when getrandom API is not available
-    result := dev_random_device_read(len, data);
-  end;
-end;
-{$ENDIF}
-{$IFDEF CRYPTOLIB_SOLARIS}
-
-class function TOSRandom.GenRandomBytesSolaris(len: Int32; data: PByte): Int32;
-var
-  got, MaxChunkSize: Int32;
-begin
-  MaxChunkSize := 256; // 256 bytes
-
-  if IsGetRandomSupportedOnOS then
-  begin
-    while (len > 0) do
-    begin
-      if len <= MaxChunkSize then
-      begin
-        MaxChunkSize := len;
-      end;
-
-      got := FGetRandom(data, LongWord(MaxChunkSize), GRND_DEFAULT);
-
-      if (got = 0) then
-      begin
-        if ErrorNo = EINTR then
-        begin
-          continue;
-        end;
-        result := -1;
-        Exit;
-      end;
-      System.Inc(data, got);
-      System.Dec(len, got);
-    end;
-    result := 0;
-  end
-  else
-  begin
-    // fallback for when getrandom API is not available
-    result := dev_random_device_read(len, data);
-  end;
-end;
-{$ENDIF}
-{$IFDEF CRYPTOLIB_GENERIC_BSD}
-
-class function TOSRandom.GenRandomBytesGenericBSD(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 count <= 0 then
-  begin
-    Exit;
-  end;
-
-{$IF DEFINED(CRYPTOLIB_MSWINDOWS)}
-  if GenRandomBytesWindows(count, PByte(data)) <> 0 then
-  begin
-    raise EOSRandomCryptoLibException.CreateRes
-      (@SMSWIndowsCryptographyAPIGenerationError);
-  end;
-
-{$ELSEIF DEFINED(CRYPTOLIB_APPLE)}
-  if GenRandomBytesApple(count, PByte(data)) <> 0 then
-  begin
-    raise EOSRandomCryptoLibException.CreateRes
-      (@SAppleSecRandomCopyBytesGenerationError);
-  end;
-
-{$ELSEIF DEFINED(CRYPTOLIB_LINUX)}
-  if GenRandomBytesLinux(count, PByte(data)) <> 0 then
-  begin
-    raise EOSRandomCryptoLibException.CreateRes(@SLinuxGetRandomError);
-  end;
-
-{$ELSEIF DEFINED(CRYPTOLIB_SOLARIS)}
-  if GenRandomBytesSolaris(count, PByte(data)) <> 0 then
-  begin
-    raise EOSRandomCryptoLibException.CreateRes(@SSolarisGetRandomError);
-  end;
-
-{$ELSEIF DEFINED(CRYPTOLIB_GENERIC_BSD)}
-  if GenRandomBytesGenericBSD(count, PByte(data)) <> 0 then
-  begin
-    raise EOSRandomCryptoLibException.CreateRes(@SArc4RandomBufGenerationError);
-  end;
-  // {$ELSEIF DEFINED(CRYPTOLIB_UNDEFINED_UNIX_VARIANTS)}
-  // // fallback option for other Undefined Unix OSes
-  // if dev_random_device_read(count, PByte(data)) <> 0 then
-  // begin
-  // raise EOSRandomCryptoLibException.CreateRes(@SRandomDeviceReadError);
-  // end;
-{$ELSE}
-{$MESSAGE ERROR 'UNSUPPORTED TARGET.'}
-{$IFEND}
-end;
-
-class procedure TOSRandom.GetNonZeroBytes(const data: TCryptoLibByteArray);
-begin
-  repeat
-    TOSRandom.GetBytes(data);
-  until (TArrayUtils.NoZeroes(data));
-end;
-
-end.

+ 0 - 172
CryptoLib/src/Rngs/Sources/ClpRandomNumberGenerator.pas

@@ -1,172 +0,0 @@
-{ *********************************************************************************** }
-{ *                              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 ClpRandomNumberGenerator;
-
-{$I ..\..\Include\CryptoLib.inc}
-
-interface
-
-uses
-  ClpCryptoLibTypes,
-  ClpOSRandom,
-  ClpAESPRNGRandom,
-  ClpIRandomNumberGenerator;
-
-resourcestring
-  SUnknownAlgorithm = 'Unknown Random Generation Algorithm Requested';
-  SRandomNumberGeneratorOutputBufferNil =
-    'Random Number Generator Output Buffer Cannot Be Nil';
-
-type
-  TRandomNumberGenerator = class abstract(TInterfacedObject,
-    IRandomNumberGenerator)
-
-  strict protected
-    class procedure ValidateOutputBufferNotNull(const ABuffer
-      : TCryptoLibByteArray); static; inline;
-
-  public
-
-    type
-{$SCOPEDENUMS ON}
-    TRandomNumberGeneratorMode = (rngmOS = 0, rngmAES = 1);
-{$SCOPEDENUMS OFF}
-  class function CreateRNG(): IRandomNumberGenerator; overload; static;
-
-  class function CreateRNG(rngMode: TRandomNumberGeneratorMode)
-    : IRandomNumberGenerator; overload; static;
-
-  procedure GetBytes(const data: TCryptoLibByteArray); virtual; abstract;
-
-  procedure GetNonZeroBytes(const data: TCryptoLibByteArray); virtual; abstract;
-
-  end;
-
-type
-  TOSRandomNumberGenerator = class sealed(TRandomNumberGenerator,
-    IOSRandomNumberGenerator)
-
-  public
-    constructor Create();
-
-    procedure GetBytes(const data: TCryptoLibByteArray); override;
-
-    procedure GetNonZeroBytes(const data: TCryptoLibByteArray); override;
-
-  end;
-
-type
-  TAESPRNGRandomNumberGenerator = class sealed(TRandomNumberGenerator,
-    IAESPRNGRandomNumberGenerator)
-
-  public
-    constructor Create();
-
-    procedure GetBytes(const data: TCryptoLibByteArray); override;
-
-    procedure GetNonZeroBytes(const data: TCryptoLibByteArray); override;
-
-  end;
-
-implementation
-
-{ TRandomNumberGenerator }
-
-class procedure TRandomNumberGenerator.ValidateOutputBufferNotNull
-  (const ABuffer: TCryptoLibByteArray);
-begin
-  if ABuffer = Nil then
-  begin
-    raise EArgumentNilCryptoLibException.CreateRes
-      (@SRandomNumberGeneratorOutputBufferNil);
-  end;
-end;
-
-class function TRandomNumberGenerator.CreateRNG: IRandomNumberGenerator;
-begin
-  result := TRandomNumberGenerator.CreateRNG(TRandomNumberGeneratorMode.rngmOS);
-end;
-
-class function TRandomNumberGenerator.CreateRNG
-  (rngMode: TRandomNumberGeneratorMode): IRandomNumberGenerator;
-begin
-
-  case rngMode of
-    TRandomNumberGeneratorMode.rngmOS:
-      begin
-        result := TOSRandomNumberGenerator.Create();
-        Exit;
-      end;
-
-    TRandomNumberGeneratorMode.rngmAES:
-      begin
-        result := TAESPRNGRandomNumberGenerator.Create();
-        Exit;
-      end
-
-  else
-    begin
-      raise EArgumentCryptoLibException.CreateRes(@SUnknownAlgorithm);
-    end;
-
-  end;
-
-end;
-
-{ TOSRandomNumberGenerator }
-
-constructor TOSRandomNumberGenerator.Create;
-begin
-  inherited Create();
-end;
-
-procedure TOSRandomNumberGenerator.GetBytes(const data: TCryptoLibByteArray);
-begin
-  ValidateOutputBufferNotNull(data);
-  TOSRandom.GetBytes(data);
-end;
-
-procedure TOSRandomNumberGenerator.GetNonZeroBytes
-  (const data: TCryptoLibByteArray);
-begin
-  ValidateOutputBufferNotNull(data);
-  TOSRandom.GetNonZeroBytes(data);
-end;
-
-{ TAESPRNGRandomNumberGenerator }
-
-constructor TAESPRNGRandomNumberGenerator.Create;
-begin
-  inherited Create();
-end;
-
-procedure TAESPRNGRandomNumberGenerator.GetBytes
-  (const data: TCryptoLibByteArray);
-begin
-  ValidateOutputBufferNotNull(data);
-  TAESPRNGRandom.GetBytes(data);
-end;
-
-procedure TAESPRNGRandomNumberGenerator.GetNonZeroBytes
-  (const data: TCryptoLibByteArray);
-begin
-  ValidateOutputBufferNotNull(data);
-  TAESPRNGRandom.GetNonZeroBytes(data);
-end;
-
-end.