diff --git a/packages/fcl-hash/src/fprsa.pas b/packages/fcl-hash/src/fprsa.pas index 066c2a8283..7a51dcd6a7 100644 --- a/packages/fcl-hash/src/fprsa.pas +++ b/packages/fcl-hash/src/fprsa.pas @@ -873,7 +873,7 @@ begin // Note: directly into ZeroesHashSalt // "3. If emLen < hLen + sLen + 2, error" - if EncodedLen < HashLen + SaltLen + 2 then + if EncodedLen < HashLen + DWord(SaltLen) + 2 then exit(20220501221837); // "4. Generate a random octet string salt of length sLen; if sLen = 0, @@ -883,7 +883,7 @@ begin // "5. Let M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt; // M' is an octet string of length 8 + hLen + sLen with eight // initial zero octets." - SetLength(ZeroesHashSalt{%H-},8+HashLen+SaltLen); + SetLength(ZeroesHashSalt{%H-},8+HashLen+DWord(SaltLen)); FillByte(ZeroesHashSalt[0],8,0); MsgHashP:=@ZeroesHashSalt[8]; HashFunc^.Func(Input,InLen,MsgHashP); @@ -935,8 +935,7 @@ function EMSA_PSS_Verify(Msg: PByte; MsgLen: DWord; EncodedMsg: PByte; EncodedBits: DWord; HashFunc: PRSAHashFuncInfo; SaltLen: integer): int64; // RFC 3447 9.1.2 Verification operation var - HashLen: Word; - EncodedLen, DBLen, i, Padding: DWord; + HashLen, EncodedLen, DBLen, i, Padding: DWord; MaskedDB, HashP, SaltP: PByte; MsgHash, DBMask, Msg2, Hash2, DB: TBytes; begin @@ -966,7 +965,7 @@ begin begin if EncodedLen < HashLen + 2 then exit(20220502222313); - end else if EncodedLen < HashLen + SaltLen + 2 then + end else if EncodedLen < HashLen + DWord(SaltLen) + 2 then exit(20220502205834); // "4. If the rightmost octet of EM does not have hexadecimal value 0xbc, error." @@ -1024,7 +1023,7 @@ begin // "12. Let M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt ; // M' is an octet string of length 8 + hLen + sLen with eight // initial zero octets. - SetLength(Msg2{%H-},8 + HashLen + SaltLen); + SetLength(Msg2{%H-},8 + HashLen + DWord(SaltLen)); FillByte(Msg2[0],8,0); System.Move(MsgHash[0],Msg2[8],HashLen); System.Move(SaltP^,Msg2[8+HashLen],SaltLen); diff --git a/packages/fcl-hash/src/fptlsbigint.pas b/packages/fcl-hash/src/fptlsbigint.pas index f9d1fbfd7d..9078731d31 100644 --- a/packages/fcl-hash/src/fptlsbigint.pas +++ b/packages/fcl-hash/src/fptlsbigint.pas @@ -8,14 +8,17 @@ {$h+} {$MODESWITCH advancedrecords} {$R-} +{$Q-} unit fpTLSBigInt; +{$WARN 6058 off : Call to subroutine "$1" marked as inline is not inlined} + interface uses SysUtils; -{ $DEFINE BIGINT_DEBUG} // Enable debug output/functions for BitInt unit +{off $DEFINE BIGINT_DEBUG} // Enable debug output/functions for BitInt unit const // Maintain a number of precomputed variables when doing reduction @@ -108,7 +111,10 @@ function BISquare(var Context: TBigIntContext; BI: PBigInt): PBigInt; inline; function BICRT(var Context: TBigIntContext; BI, DP, DQ, P, Q, QInv: PBigInt): PBigInt; -procedure BItoString(BI: PBigInt; out S: AnsiString); +// Convert a bigint to a string of hex characters @Result[BI.Size*2] +function BIToString(BI: PBigInt): AnsiString; overload; +function BIToDbgString(BI: PBigInt): AnsiString; overload; +procedure BIToString(BI: PBigInt; out S: AnsiString); overload; function StringToBI(var Context: TBigIntContext; const Value: AnsiString): PBigInt; implementation @@ -260,10 +266,10 @@ begin Result := BIAllocate(Context, N + 1); R := Result^.Components; A := BIA^.Components; - FillChar(R^, (N+1) * BIGINT_COMP_BYTE_SIZE, 0); + FillByte(R^, (N+1) * BIGINT_COMP_BYTE_SIZE, 0); repeat - Tmp := R^ + TBILongComponent(A[J]) * B + Carry; // Avoid overflow - R^ := Tmp; // Downsize + Tmp := TBILongComponent(R^) + TBILongComponent(A[J]) * B + Carry; // Avoid overflow + R^ := DWord(Tmp and $ffffffff); // Downsize Inc(R); Carry := Tmp shr BIGINT_COMP_BIT_SIZE; Inc(J); @@ -287,7 +293,7 @@ begin R := 0; repeat R := (R shl BIGINT_COMP_BIT_SIZE) + BIR^.Components[I]; - BIR^.Components[I] := R div Denom; + BIR^.Components[I] := DWord((R div Denom) and $ffffffff); R := R mod Denom; Dec(I); until I < 0; @@ -391,8 +397,8 @@ begin repeat if (InnerPartial > 0) and (RIndex >= InnerPartial) then Break; - Tmp := SR[RIndex] + TBILongComponent(SA[J]) * SB[I] + Carry; // Avoid overflow - SR[RIndex] := Tmp; // Downsize + Tmp := TBILongComponent(SR[RIndex]) + TBILongComponent(SA[J]) * SB[I] + Carry; // Avoid overflow + SR[RIndex] := TBIComponent(Tmp and $ffffffff); // Downsize Inc(RIndex); Carry := Tmp shr BIGINT_COMP_BIT_SIZE; Inc(J); @@ -424,7 +430,7 @@ begin FillChar(W^,BIR^.Size * BIGINT_COMP_BYTE_SIZE,0); repeat Tmp := W[2*I] + TBILongComponent(X[I]) * X[I]; // Avoid overflow - W[2 * I] := Tmp; + W[2 * I] := DWord(Tmp and $ffffffff); Carry := Tmp shr BIGINT_COMP_BIT_SIZE; J := I+1; while J < T do @@ -440,14 +446,14 @@ begin if BIGINT_COMP_MAX-Tmp < Carry then C := 1; Tmp := Tmp + Carry; - W[I + J] := Tmp; + W[I + J] := DWord(Tmp and $ffffffff); Carry := Tmp shr BIGINT_COMP_BIT_SIZE; if C > 0 then Carry := Carry + BIGINT_COMP_RADIX; Inc(J); end; Tmp := W[I+T]+Carry; - W[I+T] := Tmp; + W[I+T] := DWord(Tmp and $ffffffff); W[I+T+1] := Tmp shr BIGINT_COMP_BIT_SIZE; Inc(I); until I >= T; @@ -658,7 +664,7 @@ end; function BIImport(var Context: TBigIntContext; const Data: AnsiString): PBigInt; overload; begin - Result:=BIImport(Context,TEncoding.UTF8.GetAnsiBytes(Data)); + Result:=BIImport(Context,@Data[1],length(Data)); end; @@ -783,7 +789,7 @@ end; // @IsMod: Determines if this is a normal division (False) or a reduction (True)} function BIDivide(var Context: TBigIntContext; U, V: PBigInt; IsMod: Boolean): PBigInt; - function BIDivide_V1(V:PBigInt):TBIComponent; inline; + function BIDivide_V1(V: PBigInt): TBIComponent; inline; begin // V1 for division Result := V^.Components[V^.Size-1]; end; @@ -828,7 +834,7 @@ begin TmpU := BIAllocate(Context, N+1); BITrim(V); // Make sure we have no leading 0's D := BIGINT_COMP_RADIX div (TBILongComponent(BIDivide_V1(V)) + 1); - FillChar(Quotient^.Components^, Quotient^.Size * BIGINT_COMP_BYTE_SIZE, 0); + FillByte(Quotient^.Components^, Quotient^.Size * BIGINT_COMP_BYTE_SIZE, 0); if D > 1 then begin // Normalize U := BIIntMultiply(Context,U,D); @@ -852,8 +858,11 @@ begin if (V^.Size > 1) and (BIDivide_V2(V) > 0) then begin // We are implementing the following: if (V2*q_dash > (((U(0)*COMP_RADIX + U(1) - q_dash*V1)*COMP_RADIX) + U(2))) ... - Inner := BIGINT_COMP_RADIX * BIDivide_U(TmpU, 0) + BIDivide_U(TmpU, 1) - TBILongComponent(QDash) * BIDivide_V1(V); {Avoid overflow} - if (TBILongComponent(BIDivide_V2(V)) * QDash) > (TBILongComponent(Inner) * BIGINT_COMP_RADIX + BIDivide_U(TmpU, 2)) then {Avoid overflow} + Inner := (BIGINT_COMP_RADIX * BIDivide_U(TmpU, 0) + BIDivide_U(TmpU, 1) + - TBILongComponent(QDash) * BIDivide_V1(V)) + and $ffffffff; {Avoid overflow} + if (TBILongComponent(BIDivide_V2(V)) * QDash) > + (TBILongComponent(Inner) * BIGINT_COMP_RADIX + BIDivide_U(TmpU, 2)) then {Avoid overflow} Dec(QDash); end; end; @@ -882,7 +891,7 @@ begin BIRelease(Context, V); if IsMod then begin // Get the remainder - BIRelease(Context, Quotient);; + BIRelease(Context, Quotient); BITrim(U); Result := BIIntDivide(U, D); end else @@ -1165,33 +1174,48 @@ begin Result := BIAdd(Context, M2, BIMultiply(Context, Q, H)); end; -// Convert a bigint to a string of hex characters -// @Result[BI.Size*2] -procedure BItoString(BI: PBigInt; out S: AnsiString); +function BIToString(BI: PBigInt): AnsiString; const Digits: Array[0..15] of char = ('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'); var I,J,K: Integer; Num: TBIComponent; - Mask: TBIComponent; begin - S:=''; + Result:=''; if BI = nil then Exit; - SetLength(S,BI^.Size*BIGINT_COMP_NUM_NIBBLES); + SetLength(Result,BI^.Size*BIGINT_COMP_NUM_NIBBLES); K:=1; for I := BI^.Size-1 downto 0 do begin for J := BIGINT_COMP_NUM_NIBBLES-1 downto 0 do begin - Mask := $0F shl (J*4); - Num := (BI^.Components[I] and Mask) shr (J*4); - S[K]:=Digits[Num and $F]; + Num := (BI^.Components[I] shr (J*4)) and $F; + Result[K]:=Digits[Num]; inc(K); end; end; end; +function BIToDbgString(BI: PBigInt): AnsiString; +var + Num, I, J: Integer; +begin + Result:=''; + if BI=nil then + exit; + Num:=0; + for I := BI^.Size-1 downto 0 do + for J := BIGINT_COMP_NUM_NIBBLES-1 downto 0 do + inc(Num, (BI^.Components[I] shr (J*4)) and $F); + Result:='{'+IntToStr(Num)+'}'+BIToString(BI); +end; + +procedure BIToString(BI: PBigInt; out S: AnsiString); +begin + S:=BIToString(BI); +end; + // Convert a string of hex characters to a bigint function StringToBI(var Context: TBigIntContext; const Value: AnsiString): PBigInt; const