Browse Source

Fix incorrect results in HMAC-MD5/SHA* in system.hash; zero-length key/data are also support now.

Zhan Wang 1 month ago
parent
commit
2734aaebe6

+ 2 - 10
packages/fcl-hash/src/fpsha256.pp

@@ -448,10 +448,6 @@ var
   SHA256, SHA256_: TSHA256;
 begin
   Result:=False;
-  if Key = nil then
-    Exit;
-  if Data = nil then
-    Exit;
   KeyBuffer:=Default(TBuf64);
   SHA256.Init;
   if KeySize > 64 then
@@ -459,7 +455,7 @@ begin
     SHA256.Update(Key, KeySize);
     SHA256.Final;
     System.Move(SHA256.Digest[0], KeyBuffer[0], SizeOf(SHA256.Digest));
-  end else
+  end else if KeySize>0 then
     System.Move(Key^, KeyBuffer[0], KeySize);
   // XOR the key buffer with the iPad value
   for Count := 0 to 63 do
@@ -696,10 +692,6 @@ var
   SHA224, SHA224_: TSHA224;
 begin
   Result:=False;
-  if Key = nil then
-    Exit;
-  if Data = nil then
-    Exit;
   KeyBuffer:=Default(TBuf64);
   SHA224.Init;
   if KeySize > 64 then
@@ -707,7 +699,7 @@ begin
     SHA224.Update(Key, KeySize);
     SHA224.Final;
     System.Move(SHA224.Digest[0], KeyBuffer[0], SizeOf(SHA224.Digest));
-  end else
+  end else if KeySize>0 then
     System.Move(Key^, KeyBuffer[0], KeySize);
   // XOR the key buffer with the iPad value
   for Count := 0 to 63 do

+ 2 - 10
packages/fcl-hash/src/fpsha512.pp

@@ -502,10 +502,6 @@ var
   SHA512, SHA512_: TSHA512;
 begin
   Result:=False;
-  if Key = nil then
-    Exit;
-  if Data = nil then
-    Exit;
   KeyBuffer:=Default(TBuf128);
   SHA512.Init;
   if KeySize > 128 then
@@ -513,7 +509,7 @@ begin
     SHA512.Update(Key, KeySize);
     SHA512.Final;
     System.Move(SHA512.Digest[0], KeyBuffer[0], SizeOf(SHA512.Digest));
-  end else
+  end else if KeySize>0 then
     System.Move(Key^, KeyBuffer[0], KeySize);
   // XOR the key buffer with the iPad value
   for Count := 0 to 127 do
@@ -760,10 +756,6 @@ var
   SHA384, SHA384_: TSHA384;
 begin
   Result:=False;
-  if Key = nil then
-    Exit;
-  if Data = nil then
-    Exit;
   KeyBuffer:=Default(TBuf128);
   SHA384.Init;
   if KeySize > 128 then
@@ -771,7 +763,7 @@ begin
     SHA384.Update(Key, KeySize);
     SHA384.Final;
     System.Move(SHA384.Digest[0], KeyBuffer[0], SizeOf(SHA384.Digest));
-  end else
+  end else if KeySize>0 then
     System.Move(Key^, KeyBuffer[0], KeySize);
   // XOR the key buffer with the iPad value
   for Count := 0 to 127 do

+ 77 - 141
packages/vcl-compat/src/system.hash.pp

@@ -240,18 +240,14 @@ begin
 end;
 
 class function THash.DigestAsString(const aDigest: TBytes; UpperCase: Boolean): UnicodeString;
-
 const
   HexDigitsWL: array[0..15] of widechar = '0123456789abcdef';
-
-
 var
   S : UnicodeString;
   I,Len: Integer;
   H,Res : PWideChar;
   PB : PByte;
   B : Byte;
-
 begin
   S:='';
   if Uppercase then
@@ -275,8 +271,6 @@ begin
 end;
 
 class function THash.DigestAsStringGUID(const aDigest: TBytes): UnicodeString;
-
-
 begin
   With TGUID.Create(aDigest,TEndian.Little) do
     begin
@@ -292,11 +286,9 @@ begin
 end;
 
 class function THash.GetRandomString(const aLen: Integer): UnicodeString;
-
 var
   I : Integer;
   Res: PWideChar;
-
 begin
   Result:='';
   SetLength(Result,aLen);
@@ -327,7 +319,6 @@ begin
 end;
 
 class function THashMD5.GetHashBytes(const aData: UnicodeString): TBytes;
-
 begin
   With THashMD5.Create do
     begin
@@ -337,7 +328,6 @@ begin
 end;
 
 class function THashMD5.GetHashString(const aData: UnicodeString): UnicodeString;
-
 begin
   With THashMD5.Create do
     begin
@@ -347,11 +337,9 @@ begin
 end;
 
 class function THashMD5.GetHashBytes(const aStream: TStream): TBytes;
-
 var
   Buf: TBytes;
   Len,Count: Longint;
-
 begin
   Buf:=Default(TBytes);
   Len:=HashReadBufferSize;
@@ -416,59 +404,49 @@ begin
 end;
 
 class function THashMD5.GetHMACAsBytes(const aData, aKey: TBytes): TBytes;
-
 var
-  I: Byte;
-  MD5_BLOCK_SIZE : Integer;
-  VLength: PtrUInt;
-  PKey, POPad, PIPad: PByte;
-  VKey, VOPad, VIPad: TBytes;
-  MD5  : THashMD5;
-
+  Count: UInt32;
+  KeySize,DataSize,BufSize : Integer;
+  aDigest,KeyBuffer, PadBuffer: TBytes;
+  MD5: THashMD5;
 begin
-  VKey:=Default(TBytes);
-  VOPad:=Default(TBytes);
-  VIPad:=Default(TBytes);
+  Result:=[];
+  KeySize:=Length(akey);
+  DataSize:=Length(aData);
   MD5:=THashMD5.Create;
-  MD5_BLOCK_SIZE:=MD5.GetBlockSize;
-  VLength:=Length(aKey);
-  if VLength > MD5_BLOCK_SIZE then
-    begin
-    SetLength(VKey,MD5_BLOCK_SIZE);
-    FillChar(VKey[0],MD5_BLOCK_SIZE, #0);
+  BufSize:=MD5.GetBlockSize;
+  SetLength(KeyBuffer,BufSize);
+  SetLength(PadBuffer,BufSize);
+  if KeySize>BufSize then
+  begin
     MD5.Update(aKey);
-    VKey:=Concat(MD5.GetDigest,VKey);
-    end
-  else
-    begin
-    SetLength(VKey,MD5_BLOCK_SIZE-VLength);
-    FillChar(VKey[0],MD5_BLOCK_SIZE-VLength, #0);
-    VKey:=Concat(aKey,VKey);
-    end;
-  SetLength(VOPad,MD5_BLOCK_SIZE);
-  POPad:=PByte(VOPad);
-  FillChar(POPad^, MD5_BLOCK_SIZE, $5c);
-  SetLength(VIPad, MD5_BLOCK_SIZE);
-  PIPad := PByte(VIPad);
-  FillChar(PIPad^, MD5_BLOCK_SIZE, $36);
-  PKey := PByte(VKey);
-  for I:=1 to VLength do
-    begin
-    POPad^:=(POPad^ xor PKey^);
-    PIPad^:=(PIPad^ xor PKey^);
-    Inc(POPad);
-    Inc(PIPad);
-    Inc(PKey);
-    end;
-  VIPad:=Concat(VIPad,aData);
+    aDigest:=MD5.GetDigest;
+    System.Move(aDigest[0],KeyBuffer[0],MD5.GetHashSize);
+  end else
+    if KeySize>0 then
+      System.Move(aKey[0], KeyBuffer[0], KeySize);
+  // XOR the key buffer with the iPad value
+  for Count := 0 to BufSize -1 do
+    PadBuffer[Count] := KeyBuffer[Count] xor $36;
   MD5.Reset;
-  MD5.Update(VIPad);
-  Result:=Concat(VOPad,MD5.GetDigest);
+  MD5.Update(PadBuffer);
+  MD5.Update(aData);
+  aDigest:=MD5.GetDigest;
+  // XOR the key buffer with the oPad value
+  for Count := 0 to BufSize -1 do
+    PadBuffer[Count] := KeyBuffer[Count] xor $5C;
+  // MD5 the key buffer and the result of the inner MD5 (Outer)
+  MD5.Reset;
+  MD5.Update(PadBuffer);
+  MD5.Update(aDigest);
+  Result:=MD5.GetDigest;
 end;
 
 procedure THashMD5.Reset;
 begin
   MD5Init(_MD5);
+  FillChar(_Digest, sizeof(TMD5Digest), 0);
+  _DidFinal:=False;
 end;
 
 procedure THashMD5.Update(var aData; aLength: Cardinal);
@@ -489,7 +467,6 @@ begin
 end;
 
 function THashMD5.GetDigest: TBytes;
-
 begin
   Result:=[];
   if not _DidFinal then
@@ -516,6 +493,8 @@ end;
 procedure THashSHA1.Reset;
 begin
   SHA1Init(_SHA1);
+  FillChar(_Digest, sizeof(TSHA1Digest), 0);
+  _DidFinal:=False;
 end;
 
 class function THashSHA1.Create: THashSHA1;
@@ -525,7 +504,6 @@ begin
 end;
 
 procedure THashSHA1.Update(var aData; aLength: Cardinal);
-
 begin
   SHA1Update(_SHA1,aData,aLength);
 end;
@@ -581,11 +559,9 @@ begin
 end;
 
 class function THashSHA1.GetHashBytes(const aStream: TStream): TBytes;
-
 var
   Buf: TBytes;
   Len,Count: Longint;
-
 begin
   Buf:=Default(TBytes);
   Len:=HashReadBufferSize;
@@ -608,10 +584,8 @@ begin
 end;
 
 class function THashSHA1.GetHashBytesFromFile(const aFileName: TFileName): TBytes;
-
 var
   F: TFileStream;
-
 begin
   F:=TFileStream.Create(aFileName,fmOpenRead or fmShareDenyWrite);
   try
@@ -650,58 +624,45 @@ begin
 end;
 
 class function THashSHA1.GetHMACAsBytes(const aData, aKey: TBytes): TBytes;
-
 var
-  I: Byte;
-  SHA1_BLOCK_SIZE : Integer;
-  VLength: PtrUInt;
-  PKey, POPad, PIPad: PByte;
-  VKey, VOPad, VIPad: TBytes;
-  Sha1  : THashSha1;
-
-begin
-  VKey:=Default(TBytes);
-  VOPad:=Default(TBytes);
-  VIPad:=Default(TBytes);
-  Sha1:=THashSha1.Create;
-  SHA1_BLOCK_SIZE:=Sha1.GetBlockSize;
-  VLength:=Length(aKey);
-  if VLength > SHA1_BLOCK_SIZE then
-    begin
-    SetLength(VKey,SHA1_BLOCK_SIZE);
-    FillChar(VKey[0],SHA1_BLOCK_SIZE, #0);
-    Sha1.Update(aKey);
-    VKey:=Concat(Sha1.GetDigest,VKey);
-    end
-  else
-    begin
-    SetLength(VKey,SHA1_BLOCK_SIZE-VLength);
-    FillChar(VKey[0],SHA1_BLOCK_SIZE-VLength, #0);
-    VKey:=Concat(aKey,VKey);
-    end;
-  SetLength(VOPad,SHA1_BLOCK_SIZE);
-  POPad:=PByte(VOPad);
-  FillChar(POPad^, SHA1_BLOCK_SIZE, $5c);
-  SetLength(VIPad, SHA1_BLOCK_SIZE);
-  PIPad := PByte(VIPad);
-  FillChar(PIPad^, SHA1_BLOCK_SIZE, $36);
-  PKey := PByte(VKey);
-  for I:=1 to VLength do
-    begin
-    POPad^:=(POPad^ xor PKey^);
-    PIPad^:=(PIPad^ xor PKey^);
-    Inc(POPad);
-    Inc(PIPad);
-    Inc(PKey);
-    end;
-  VIPad:=Concat(VIPad,aData);
-  Sha1.Reset;
-  Sha1.Update(VIPad);
-  Result:=Concat(VOPad,Sha1.GetDigest);
+  Count: UInt32;
+  KeySize,DataSize,BufSize : Integer;
+  aDigest,KeyBuffer, PadBuffer: TBytes;
+  SHA1: THashSHA1;
+begin
+  Result:=[];
+  KeySize:=Length(akey);
+  DataSize:=Length(aData);
+  SHA1:=THashSHA1.Create;
+  BufSize:=SHA1.GetBlockSize;
+  SetLength(KeyBuffer,BufSize);
+  SetLength(PadBuffer,BufSize);
+  if KeySize>BufSize then
+  begin
+    SHA1.Update(aKey);
+    aDigest:=SHA1.GetDigest;
+    System.Move(aDigest[0],KeyBuffer[0],SHA1.GetHashSize);
+  end else   
+    if KeySize>0 then
+      System.Move(aKey[0], KeyBuffer[0], KeySize);
+  // XOR the key buffer with the iPad value
+  for Count := 0 to BufSize -1 do
+    PadBuffer[Count] := KeyBuffer[Count] xor $36;
+  SHA1.Reset;
+  SHA1.Update(PadBuffer);
+  SHA1.Update(aData);
+  aDigest:=SHA1.GetDigest;
+  // XOR the key buffer with the oPad value
+  for Count := 0 to BufSize -1 do
+    PadBuffer[Count] := KeyBuffer[Count] xor $5C;
+  // SHA1 the key buffer and the result of the inner SHA1 (Outer)
+  SHA1.Reset;
+  SHA1.Update(PadBuffer);
+  SHA1.Update(aDigest);
+  Result:=SHA1.GetDigest;
 end;
 
 function THashSHA1.GetDigest: TBytes;
-
 begin
   Result:=[];
   if not _DidFinal then
@@ -717,17 +678,14 @@ end;
 { THashSHA2 }
 
 Procedure NotSupportedVersion(aHashVersion : THashSHA2.TSHA2Version);
-
 var
   S : String;
-
 begin
   WriteStr(S,aHashversion);
   Raise EHashException.CreateFmt('SHA2 - %s not yet supported',[S]);
 end;
 
 class function THashSHA2.Create(aHashVersion: TSHA2Version): THashSHA2;
-
 begin
   if aHashVersion in [SHA512_224, SHA512_256] then
     NotSupportedVersion(aHashVersion);
@@ -736,10 +694,8 @@ begin
 end;
 
 class function THashSHA2.GetHashBytes(const aData: UnicodeString; aHashVersion: TSHA2Version): TBytes;
-
 var
   H : THashSHA2;
-
 begin
   H:=THashSHA2.Create(aHashVersion);
   H.Update(AData);
@@ -747,10 +703,8 @@ begin
 end;
 
 class function THashSHA2.GetHashString(const aData: UnicodeString; aHashVersion: TSHA2Version): UnicodeString;
-
 var
   H: THashSHA2;
-
 begin
   H:=THashSHA2.Create(aHashVersion);
   H.Update(aData);
@@ -758,11 +712,9 @@ begin
 end;
 
 class function THashSHA2.GetHashBytes(const aStream: TStream; aHashVersion: TSHA2Version): TBytes;
-
 var
   Buf: TBytes;
   Len,Count: Longint;
-
 begin
   Buf:=Default(TBytes);
   Len:=HashReadBufferSize;
@@ -785,10 +737,8 @@ begin
 end;
 
 class function THashSHA2.GetHashBytesFromFile(const aFileName: TFileName; aHashVersion: TSHA2Version): TBytes;
-
 var
   F: TFileStream;
-
 begin
   F:=TFileStream.Create(aFileName,fmOpenRead or fmShareDenyWrite);
   try
@@ -827,21 +777,15 @@ begin
 end;
 
 class function THashSHA2.GetHMACAsBytes(const aData, aKey: TBytes; aHashVersion: TSHA2Version): TBytes;
-
 var
   Count: UInt32;
   KeySize,DataSize,BufSize : Integer;
   aDigest,KeyBuffer, PadBuffer: TBytes;
-  SHA2 : THashSHA2;
-
+  SHA2: THashSHA2;
 begin
   Result:=[];
   KeySize:=Length(akey);
   DataSize:=Length(aData);
-  if aKey = nil then
-    Exit;
-  if aData = nil then
-    Exit;
   SHA2:=THashSHA2.Create(aHashversion);
   BufSize:=SHA2.GetBlockSize;
   SetLength(KeyBuffer,BufSize);
@@ -851,19 +795,20 @@ begin
     SHA2.Update(aKey);
     aDigest:=SHA2.GetDigest;
     System.Move(aDigest[0],KeyBuffer[0],SHA2.GetHashSize);
-  end else
-    System.Move(aKey[0], KeyBuffer[0], KeySize);
+  end else  
+    if KeySize>0 then
+      System.Move(aKey[0], KeyBuffer[0], KeySize);
   // XOR the key buffer with the iPad value
-  for Count := 0 to BufSize do
+  for Count := 0 to BufSize -1 do
     PadBuffer[Count] := KeyBuffer[Count] xor $36;
   SHA2.Reset;
   SHA2.Update(PadBuffer);
   SHA2.Update(aData);
   aDigest:=SHA2.GetDigest;
   // XOR the key buffer with the oPad value
-  for Count := 0 to 63 do
+  for Count := 0 to BufSize -1 do
     PadBuffer[Count] := KeyBuffer[Count] xor $5C;
-  // SHA256 the key buffer and the result of the inner SHA256 (Outer)
+  // SHA2 the key buffer and the result of the inner SHA2 (Outer)
   SHA2.Reset;
   SHA2.Update(PadBuffer);
   SHA2.Update(aDigest);
@@ -914,7 +859,6 @@ begin
 end;
 
 procedure THashSHA2.DoFinal;
-
 begin
   case FHashVersion of
     Sha224 : _S224.Final;
@@ -926,12 +870,9 @@ begin
 end;
 
 function THashSHA2.GetDigest: TBytes;
-
 Var
   P : PByte;
   L : Integer;
-
-
 begin
   if Not FDidFinal then
     DoFinal;
@@ -956,7 +897,6 @@ begin
 end;
 
 function THashSHA2.GetHashSize: Integer;
-
 Const
   Sizes : Array[TSHA2Version] of integer
         = (28,32,48,64,28,32);
@@ -1076,10 +1016,8 @@ begin
 end;
 
 class function THashFNV1a32.GetHashBytes(const aData: UnicodeString): TBytes;
-
 var
   C : Cardinal;
-
 begin
   Result:=Default(TBytes);
   SetLength(Result,SizeOf(Fnv32_t));
@@ -1098,10 +1036,8 @@ begin
 end;
 
 class function THashFNV1a32.GetHashValue(const aData: UnicodeString): Integer;
-
 var
   C : Cardinal;
-
 begin
   C:=FNV1_32a(PByte(aData),Length(aData)*SizeOf(UnicodeChar),FNV_SEED);
   Result:=Integer(C);