Browse Source

Add RtlGenRandom support

Ondrej Kelle 6 years ago
parent
commit
09c1c19bf4
1 changed files with 57 additions and 15 deletions
  1. 57 15
      CryptoLib/src/Utils/Randoms/ClpOSRandom.pas

+ 57 - 15
CryptoLib/src/Utils/Randoms/ClpOSRandom.pas

@@ -240,6 +240,21 @@ type
       : Int32; static;
       : Int32; static;
     class property IsCngBCryptGenRandomSupportedOnOS: Boolean
     class property IsCngBCryptGenRandomSupportedOnOS: Boolean
       read GetIsCngBCryptGenRandomSupportedOnOS;
       read GetIsCngBCryptGenRandomSupportedOnOS;
+
+  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;
 {$ENDIF}
 {$ENDIF}
 
 
     // ================================================================//
     // ================================================================//
@@ -336,6 +351,7 @@ implementation
 class procedure TOSRandom.Boot;
 class procedure TOSRandom.Boot;
 begin
 begin
 {$IFDEF CRYPTOLIB_MSWINDOWS}
 {$IFDEF CRYPTOLIB_MSWINDOWS}
+  FIsRtlGenRandomSupportedOnOS := IsRtlGenRandomAvailable();
   FIsCngBCryptGenRandomSupportedOnOS := IsCngBCryptGenRandomAvailable();
   FIsCngBCryptGenRandomSupportedOnOS := IsCngBCryptGenRandomAvailable();
 {$ENDIF}
 {$ENDIF}
 {$IFDEF CRYPTOLIB_HAS_GETRANDOM}
 {$IFDEF CRYPTOLIB_HAS_GETRANDOM}
@@ -355,22 +371,39 @@ begin
   result := FIsCngBCryptGenRandomSupportedOnOS;
   result := FIsCngBCryptGenRandomSupportedOnOS;
 end;
 end;
 
 
-class function TOSRandom.IsCngBCryptGenRandomAvailable(): Boolean;
-const
-  BCRYPT = 'bcrypt.dll';
+class function TOSRandom.GetIsRtlGenRandomSupportedOnOS(): Boolean;
+begin
+  result := FIsRtlGenRandomSupportedOnOS;
+end;
+
+function 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.IsRtlGenRandomAvailable(): Boolean;
 var
 var
   ModuleHandle: THandle;
   ModuleHandle: THandle;
-
-  function GetProcedureAddress(const AProcedureName: String;
-    var AFunctionFound: Boolean): Pointer;
+begin
+  result := False;
+  ModuleHandle := SafeLoadLibrary(ADVAPI32, SEM_FAILCRITICALERRORS);
+  if ModuleHandle <> 0 then
   begin
   begin
-    result := GetProcAddress(ModuleHandle, PChar(AProcedureName));
-    if result = Nil then
-    begin
-      AFunctionFound := False;
-    end;
+    result := True;
+    FRtlGenRandom := GetProcedureAddress(ModuleHandle, 'SystemFunction036', result);
   end;
   end;
+end;
 
 
+class function TOSRandom.IsCngBCryptGenRandomAvailable(): Boolean;
+const
+  BCRYPT = 'bcrypt.dll';
+var
+  ModuleHandle: THandle;
 begin
 begin
   result := False;
   result := False;
   ModuleHandle := SafeLoadLibrary(PChar(BCRYPT), SEM_FAILCRITICALERRORS);
   ModuleHandle := SafeLoadLibrary(PChar(BCRYPT), SEM_FAILCRITICALERRORS);
@@ -378,10 +411,10 @@ begin
   begin
   begin
     result := True;
     result := True;
     FBCryptOpenAlgorithmProvider :=
     FBCryptOpenAlgorithmProvider :=
-      GetProcedureAddress('BCryptOpenAlgorithmProvider', result);
+      GetProcedureAddress(ModuleHandle, 'BCryptOpenAlgorithmProvider', result);
     FBCryptCloseAlgorithmProvider :=
     FBCryptCloseAlgorithmProvider :=
-      GetProcedureAddress('BCryptCloseAlgorithmProvider', result);
-    FBCryptGenRandom := GetProcedureAddress('BCryptGenRandom', result);
+      GetProcedureAddress(ModuleHandle, 'BCryptCloseAlgorithmProvider', result);
+    FBCryptGenRandom := GetProcedureAddress(ModuleHandle, 'BCryptGenRandom', result);
   end;
   end;
 end;
 end;
 
 
@@ -402,7 +435,16 @@ const
   BCRYPT_RNG_ALGORITHM: WideString = 'RNG';
   BCRYPT_RNG_ALGORITHM: WideString = 'RNG';
 
 
 begin
 begin
-  if IsCngBCryptGenRandomSupportedOnOS then
+  if IsRtlGenRandomSupportedOnOS then
+  begin
+    // Windows XP / Server 2003 and Above
+    if not FRtlGenRandom(data, ULONG(len)) then
+    begin
+      result := HResultFromWin32(GetLastError);
+      Exit;
+    end;
+  end
+  else if IsCngBCryptGenRandomSupportedOnOS then
   begin
   begin
     // Windows Vista and Above
     // Windows Vista and Above
     if (not BCRYPT_SUCCESS(FBCryptOpenAlgorithmProvider(@hProv,
     if (not BCRYPT_SUCCESS(FBCryptOpenAlgorithmProvider(@hProv,