mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-21 11:29:24 +02:00
fcl-hash: rsa encrypt: fixed using non zero padding bytes
This commit is contained in:
parent
864b2ad3f3
commit
8639593574
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user