Переглянути джерело

fcl-hash: rsa encrypt: fixed using non zero padding bytes

mattias 3 роки тому
батько
коміт
8639593574

+ 1 - 1
packages/fcl-hash/src/fpasn.pp

@@ -852,7 +852,7 @@ begin
     raise Exception.Create(IntToStr(Id));
   if ASNSize<8 then
   begin
-    SetLength(Result,ASNSize);
+    SetLength(Result{%H-},ASNSize);
     Value:=StrToInt64Def(List[ListIndex],0);
     for i:=ASNSize-1 downto 0 do
     begin

+ 24 - 14
packages/fcl-hash/src/fphashutils.pp

@@ -45,7 +45,7 @@ Procedure BytesToHexStrAppend(aBytes : TBytes;var aHexStr : AnsiString);
 procedure BytesEncodeBase64(Source: Tbytes; out Dest: AnsiString; const IsURL, MultiLines, Padding: Boolean);
 Function BytesEncodeBase64(Source: Tbytes; const IsURL, MultiLines, Padding: Boolean) : AnsiString;
 
-function CryptoGetRandomBytes(Buffer: PByte; const Count: Integer): Boolean;
+function CryptoGetRandomBytes(Buffer: PByte; const Count: Integer; ZeroBytesAllowed: boolean = true): Boolean;
 Function ExtractBetween(const ASource,aStart,aEnd : String) : String;
 
 Type
@@ -345,6 +345,7 @@ type
   TLecuyer = record
     rs1, rs2, rs3: UInt32;
     SeedCount: UInt32;
+    ZeroBytesAllowed: boolean;
     procedure Seed;
     function Next: UInt32;
   end;
@@ -372,26 +373,36 @@ end;
 
 function TLecuyer.Next: UInt32;
 begin
-  if SeedCount and $FFFF = 0 then // reseed after 256KB of output
-    Seed
-  else
-    Inc(SeedCount);
-  Result := rs1;
-  rs1 := ((Result and -2) shl 12) xor (((Result shl 13) xor Result) shr 19);
-  Result := rs2;
-  rs2 := ((Result and -8) shl 4) xor (((Result shl 2) xor Result) shr 25);
-  Result := rs3;
-  rs3 := ((Result and -16) shl 17) xor (((Result shl 3) xor Result) shr 11);
-  Result := rs1 xor rs2 xor result;
+  repeat
+    if SeedCount and $FFFF = 0 then // reseed after 256KB of output
+      Seed
+    else
+      Inc(SeedCount);
+    Result := rs1;
+    rs1 := ((Result and -2) shl 12) xor (((Result shl 13) xor Result) shr 19);
+    Result := rs2;
+    rs2 := ((Result and -8) shl 4) xor (((Result shl 2) xor Result) shr 25);
+    Result := rs3;
+    rs3 := ((Result and -16) shl 17) xor (((Result shl 3) xor Result) shr 11);
+    Result := rs1 xor rs2 xor Result;
+    if ZeroBytesAllowed then exit;
+    if ((Result and $ff)<>0)
+        and ((Result and $ff00)<>0)
+        and ((Result and $ff0000)<>0)
+        and ((Result and $ff000000)<>0) then
+      exit;
+  until false;
 end;
 
-function CryptoGetRandomBytes(Buffer: PByte; const Count: Integer): Boolean;
+function CryptoGetRandomBytes(Buffer: PByte; const Count: Integer;
+  ZeroBytesAllowed: boolean): Boolean;
 var
   I, Remainder, Rounds: Integer;
   Lecuyer: TLecuyer;
   R: UInt32;
 begin
   Result := True;
+  Lecuyer.ZeroBytesAllowed:=ZeroBytesAllowed;
   Lecuyer.Seed;
   Rounds := Count div SizeOf(UInt32);
   for I := 0 to Rounds-1 do
@@ -418,7 +429,6 @@ begin
   P2:=Pos(aEnd,ASource,P1);
   if P2<=0 then exit;
   Result:=Copy(aSource,P1,P2-P1);
-
 end;
 
 function IntGetRandomNumber(aBytes : PByte; aCount: Integer): Boolean;

+ 48 - 5
packages/fcl-hash/src/fprsa.pas

@@ -6,6 +6,8 @@ unit fprsa;
 
 interface
 
+{off $DEFINE CRYPTO_DEBUG}
+
 uses
   sysutils, Classes, fpTLSBigInt, fphashutils, fpasn;
 
@@ -317,6 +319,9 @@ var
   Decrypted: PBigInt;
   Encrypted: PBigInt;
   Block: array[0..RSA_MODULUS_BYTES_MAX-1] of Byte;
+  {$IFDEF CRYPTO_DEBUG}
+  i: integer;
+  {$ENDIF}
 begin
   Result := -1;
   if Input = nil then
@@ -352,8 +357,13 @@ begin
       Imported[1]:=2;
 
       // Pad with random non-zero bytes
-      if not CryptoGetRandomBytes(@Imported[2], Padding) then
+      if not CryptoGetRandomBytes(@Imported[2], Padding, false) then
         Exit;
+      {$IFDEF CRYPTO_DEBUG}
+      for i:=0 to Padding-1 do
+        if Imported[2+i]=0 then
+          raise Exception.Create('20220429000653');
+      {$ENDIF}
     end;
 
     // Trailing zero after padding bytes
@@ -363,7 +373,7 @@ begin
     System.Move(Input^,Imported[3 + Padding],Len);
 
     {$IFDEF CRYPTO_DEBUG}
-    writeln('RSAEncryptSign - Imported Size = ' + IntToStr(Size) + ' Imported = ',Imported,Size);
+    writeln('RSAEncryptSign - Imported Size = ' + IntToStr(Size) + ' Len = ',Len);
     {$ENDIF}
 
     // Encrypt the Block
@@ -381,7 +391,7 @@ begin
     BIExport(RSA.Context,Encrypted,Output,Size); // this releases Encrypted
 
     {$IFDEF CRYPTO_DEBUG}
-    writeln('RSAEncryptSign - Output Size = ' + IntToStr(Size) + ' Output = ',Output,Size);
+    writeln('RSAEncryptSign - Output Size = ' + IntToStr(Size) + ' Len = ',Len);
     {$ENDIF}
 
     // Return Result
@@ -425,23 +435,38 @@ begin
     // Decrypt with Private Key
     Decrypted := BICRT(RSA.Context,Encrypted,RSA.DP,RSA.DQ,RSA.P,RSA.Q,RSA.QInv);
   end;
-  Exported := @Block;
+  Exported := @Block[0];
   if Size > RSA_MODULUS_BYTES_MAX then
   begin
     Exported := GetMem(Size);
     if Exported = nil then
+    begin
+      {$IFDEF CRYPTO_DEBUG}
+      writeln('RSADecryptVerify GetMem failed');
+      {$ENDIF}
       Exit;
+    end;
   end;
   try
     BIExport(RSA.Context, Decrypted, Exported, Size);
     if Exported[Count] <> 0 then
+    begin
+      {$IFDEF CRYPTO_DEBUG}
+      writeln('RSADecryptVerify leading zero missing');
+      {$ENDIF}
       Exit; // Check Leading Zero
+    end;
     Inc(Count);
     if Verify then
     begin
       // Check Block Type 1
       if Exported[Count] <> 1 then
+      begin
+        {$IFDEF CRYPTO_DEBUG}
+        writeln('RSADecryptVerify Verify Blockt Type<>1');
+        {$ENDIF}
         Exit;
+      end;
       Inc(Count);
       while (Exported[Count] = $FF) and (Count < Size) do
       begin
@@ -453,7 +478,12 @@ begin
     begin
       // Check Block Type 2
       if Exported[Count] <> 2 then
+      begin
+        {$IFDEF CRYPTO_DEBUG}
+        writeln('RSADecryptVerify Decrypt Blockt Type<>2');
+        {$ENDIF}
         Exit;
+      end;
       Inc(Count);
       while (Exported[Count] <> 0) and (Count < Size) do
       begin
@@ -464,13 +494,26 @@ begin
     end;
     // Check trailing zero byte and padding size
     if (Count = Size) or (Padding < 8) then
+    begin
+      {$IFDEF CRYPTO_DEBUG}
+      writeln('RSADecryptVerify invalid padding');
+      {$ENDIF}
       Exit;
+    end;
     if Exported[Count] <> 0 then
+    begin
+      {$IFDEF CRYPTO_DEBUG}
+      writeln('RSADecryptVerify after padding zero missing');
+      {$ENDIF}
       Exit;
+    end;
     Inc(Count);
     Result := Size-Count;
     if Len < Result then
     begin
+      {$IFDEF CRYPTO_DEBUG}
+      writeln('RSADecryptVerify Output too small');
+      {$ENDIF}
       Result := -1;
       Exit;
     end;
@@ -526,7 +569,7 @@ begin
       Exit;
     if not ASNFetchOID(DataP, DataEnd, OID) then  // OID: Algorithm
       Exit;
-    if not ASNFetch(DataP, DataEnd, ASNType, ASNSize) then  // ASN1_NULL OctetString: Digest
+    if not ASNFetch(DataP, DataEnd, ASNType, ASNSize) then  // ASN1_NULL
       Exit;
     if ASNType = ASN1_NULL then
     begin