Browse Source

Cleanup remaining MD5, SHA1 and Hash unit use.

Martijn Laan 11 months ago
parent
commit
58b27f351b

+ 1 - 1
Examples/CodeDlg.iss

@@ -153,7 +153,7 @@ begin
     finally
       ProgressPage.Hide;
     end;
-    if GetSHA1OfString('codedlg' + KeyPage.Values[0]) = '8013f310d340dab18a0d0cda2b5b115d2dcd97e4' then
+    if GetSHA256OfString('codedlg' + KeyPage.Values[0]) = '4c06e466ec3a2c977ac902a6cf4c602457f701b59309fc4282d9cb2234b7559b' then
       Result := True
     else begin
       MsgBox('You must enter a valid registration key. (Hint: The key is "inno".)', mbError, MB_OK);

+ 1 - 1
ISHelp/isetup.xml

@@ -5030,7 +5030,7 @@ DiskSliceSize=1457664
 <body>
 <p>Specifies a password you want to prompt the user for at the beginning of the installation.</p>
 <p>When using a password, you might consider setting <link topic="setup_encryption">Encryption</link> to <tt>yes</tt> as well, otherwise files will be stored as plain text and it would not be exceedingly difficult for someone to gain access to them through reverse engineering.</p>
-<p>The password itself is not stored as clear text; it's stored as a 160-bit SHA-1 hash, salted with a 64-bit random number. (Note: When encryption is enabled, this stored hash is <i>not</i> used for the encryption key.)</p>
+<p>The password itself is not stored as clear text; it's stored as a SHA-256 hash, salted with a 64-bit random number. (Note: When encryption is enabled, this stored hash is <i>not</i> used for the encryption key.)</p>
 </body>
 </setuptopic>
 

+ 1 - 1
ISHelp/isx.xml

@@ -196,7 +196,7 @@
 <dt><tt>function <a name="CheckPassword">CheckPassword</a>(Password: String): Boolean;</tt></dt>
 <dd>
 <p>If Setup finds the <tt>CheckPassword</tt> event function in the Pascal script, it automatically displays the <i>Password</i> page and calls <tt>CheckPassword</tt> to check passwords. Return True to accept the password and False to reject it.</p>
-<p>To avoid storing the actual password inside the compiled [Code] section which is stored inside Setup, you should use comparisons by hash only: calculate the SHA-1 hash of your salted password yourself and then compare that to <tt><link topic="isxfunc_GetSHA1OfString">GetSHA1OfString</link>(Password)</tt>. This way the actual value of the password remains protected.</p>
+<p>To avoid storing the actual password inside the compiled [Code] section which is stored inside Setup, you should use comparisons by hash only: calculate the SHA-256 hash of your salted password yourself and then compare that to <tt><link topic="isxfunc_GetSHA256OfString">GetSHA256OfString</link>(Password)</tt>. This way the actual value of the password is better protected.</p>
 <p>Note: If Setup is run with a /PASSWORD= <link topic="setupcmdline" anchor="PASSWORD">command line parameter</link>, your <tt>CheckPassword</tt> function will be called <i>before</i> any other event function is called, including <tt><anchorlink name="InitializeSetup">InitializeSetup</anchorlink></tt>.</p>
 </dd>
 

+ 9 - 9
Projects/Src/Compiler.CompressionHandler.pas

@@ -12,7 +12,7 @@ unit Compiler.CompressionHandler;
 interface
 
 uses
-  SHA1, ChaCha20, Shared.Int64Em, Shared.FileClass, Compression.Base,
+  SHA256, ChaCha20, Shared.Int64Em, Shared.FileClass, Compression.Base,
   Compiler.StringLists, Compiler.SetupCompiler;
 
 type
@@ -40,7 +40,7 @@ type
     constructor Create(ACompiler: TSetupCompiler; const InitialSliceFilename: String);
     destructor Destroy; override;
     procedure CompressFile(const SourceFile: TFile; Bytes: Integer64;
-      const CallOptimize: Boolean; var SHA1Sum: TSHA1Digest);
+      const CallOptimize: Boolean; var SHA256Sum: TSHA256Digest);
     procedure EndChunk;
     procedure Finish;
     procedure NewChunk(const ACompressorClass: TCustomCompressorClass;
@@ -61,7 +61,7 @@ type
 implementation
 
 uses
-  SysUtils, Hash, Shared.Struct, Compiler.Messages, Compiler.HelperFunc;
+  SysUtils, Shared.Struct, Compiler.Messages, Compiler.HelperFunc;
 
 constructor TCompressionHandler.Create(ACompiler: TSetupCompiler;
   const InitialSliceFilename: String);
@@ -191,7 +191,7 @@ procedure TCompressionHandler.NewChunk(const ACompressorClass: TCustomCompressor
   procedure InitEncryption;
   begin
     { Create an SHA-256 hash of ACryptKey, and use that as the key }
-    var Key := THashSHA2.GetHashBytes(ACryptKey, SHA256);
+    var Key := SHA256Buf(Pointer(ACryptKey)^, Length(ACryptKey)*SizeOf(ACryptKey[1]));
 
     { Create a unique nonce from the base nonce }
     var Nonce := FCompiler.GetEncryptionBaseNonce;
@@ -246,16 +246,16 @@ begin
 end;
 
 procedure TCompressionHandler.CompressFile(const SourceFile: TFile;
-  Bytes: Integer64; const CallOptimize: Boolean; var SHA1Sum: TSHA1Digest);
+  Bytes: Integer64; const CallOptimize: Boolean; var SHA256Sum: TSHA256Digest);
 var
-  Context: TSHA1Context;
+  Context: TSHA256Context;
   AddrOffset: LongWord;
   BufSize: Cardinal;
   Buf: array[0..65535] of Byte;
   { ^ *must* be the same buffer size used in Setup (TFileExtractor), otherwise
     the TransformCallInstructions call will break }
 begin
-  SHA1Init(Context);
+  SHA256Init(Context);
   AddrOffset := 0;
   while True do begin
     BufSize := SizeOf(Buf);
@@ -267,14 +267,14 @@ begin
     SourceFile.ReadBuffer(Buf, BufSize);
     Inc64(FChunkBytesRead, BufSize);
     Dec64(Bytes, BufSize);
-    SHA1Update(Context, Buf, BufSize);
+    SHA256Update(Context, Buf, BufSize);
     if CallOptimize then begin
       TransformCallInstructions(Buf, BufSize, True, AddrOffset);
       Inc(AddrOffset, BufSize);  { may wrap, but OK }
     end;
     FCompressor.Compress(Buf, BufSize);
   end;
-  SHA1Sum := SHA1Final(Context);
+  SHA256Sum := SHA256Final(Context);
 end;
 
 procedure TCompressionHandler.WriteProc(const Buf; BufSize: Longint);

+ 5 - 5
Projects/Src/Compiler.SetupCompiler.pas

@@ -291,7 +291,7 @@ implementation
 uses
   Commctrl, TypInfo, AnsiStrings, Math, WideStrUtils,
   PathFunc, Shared.CommonFunc, Compiler.Messages, Shared.SetupEntFunc,
-  Shared.FileClass, Compression.Base, Compression.Zlib, Compression.bzlib, SHA1,
+  Shared.FileClass, Compression.Base, Compression.Zlib, Compression.bzlib,
   Shared.LangOptionsSectionDirectives, Shared.ResUpdateFunc, Compiler.ExeUpdateFunc,
 {$IFDEF STATICPREPROC}
   ISPP.Preprocess,
@@ -6999,7 +6999,7 @@ var
             Include(FL.Flags, foCallInstructionOptimized);
 
           CH.CompressFile(SourceFile, FL.OriginalSize,
-            foCallInstructionOptimized in FL.Flags, FL.SHA1Sum);
+            foCallInstructionOptimized in FL.Flags, FL.SHA256Sum);
         finally
           SourceFile.Free;
         end;
@@ -7125,7 +7125,7 @@ var
       end;
     end else begin
       Filename := SignedUninstallerDir + Format('uninst-%s-%s.e32', [SetupVersion,
-        Copy(SHA1DigestToString(SHA1Buf(UnsignedFile.Memory^, UnsignedFileSize)), 1, 10)]);
+        Copy(SHA256DigestToString(SHA256Buf(UnsignedFile.Memory^, UnsignedFileSize)), 1, 10)]);
 
       if not NewFileExists(Filename) then begin
         { Create new signed uninstaller file }
@@ -7272,7 +7272,7 @@ var
       fdCreateAlways, faWrite, fsRead);
     try
       S := 'Index' + #9 + 'SourceFilename' + #9 + 'TimeStamp' + #9 +
-        'Version' + #9 + 'SHA1Sum' + #9 + 'OriginalSize' + #9 +
+        'Version' + #9 + 'SHA256Sum' + #9 + 'OriginalSize' + #9 +
         'FirstSlice' + #9 + 'LastSlice' + #9 + 'StartOffset' + #9 +
         'ChunkSuboffset' + #9 + 'ChunkCompressedSize' + #9 + 'Encrypted';
       F.WriteLine(S);
@@ -7285,7 +7285,7 @@ var
           S := S + Format('%u.%u.%u.%u', [FL.FileVersionMS shr 16,
             FL.FileVersionMS and $FFFF, FL.FileVersionLS shr 16,
             FL.FileVersionLS and $FFFF]);
-        S := S + #9 + SHA1DigestToString(FL.SHA1Sum) + #9 +
+        S := S + #9 + SHA256DigestToString(FL.SHA256Sum) + #9 +
           Integer64ToStr(FL.OriginalSize) + #9 +
           SliceToString(FL.FirstSlice) + #9 +
           SliceToString(FL.LastSlice) + #9 +

+ 5 - 5
Projects/Src/IDE.IDEScintEdit.pas

@@ -171,7 +171,7 @@ type
 implementation
 
 uses
-  SysUtils, MD5, ScintInt.InnoSetup;
+  SysUtils, SHA256, ScintInt.InnoSetup;
   
 { TIDEScintEdit }
 
@@ -401,11 +401,11 @@ procedure TIDEScintEdit.UpdateIndicators(const Ranges: TScintRangeList;
   function HashRanges(const Ranges: TScintRangeList): String;
   begin
     if Ranges.Count > 0 then begin
-      var Context: TMD5Context;
-      MD5Init(Context);
+      var Context: TSHA256Context;
+      SHA256Init(Context);
       for var Range in Ranges do
-        MD5Update(Context, Range, SizeOf(Range));
-      Result := MD5DigestToString(MD5Final(Context));
+        SHA256Update(Context, Range, SizeOf(Range));
+      Result := SHA256DigestToString(SHA256Final(Context));
     end else
       Result := '';
   end;

+ 20 - 19
Projects/Src/ISPP.Funcs.pas

@@ -21,8 +21,8 @@ implementation
 
 uses
   SysUtils, IniFiles, Registry, Math, ISPP.Consts, ISPP.Base, ISPP.IdentMan,
-  ISPP.Sessions, DateUtils, Shared.FileClass, MD5, SHA1, PathFunc, Shared.CommonFunc,
-  Shared.Int64Em, Hash;
+  ISPP.Sessions, DateUtils, Shared.FileClass, MD5, SHA1, SHA256, PathFunc, Shared.CommonFunc,
+  Shared.Int64Em;
   
 var
   IsWin64: Boolean;
@@ -1802,12 +1802,27 @@ end;
 
 function GetSHA256OfFile(Ext: Longint; const Params: IIsppFuncParams;
   const FuncResult: IIsppFuncResult): TIsppFuncResult; stdcall;
+var
+  Buf: array[0..65535] of Byte;
 begin
   if CheckParams(Params, [evStr], 1, Result) then
   try
     with IInternalFuncParams(Params) do
     begin
-      MakeStr(ResPtr^, THashSHA2.GetHashStringFromFile(Get(0).AsStr, SHA256));
+      var Context: TSHA256Context;
+      SHA256Init(Context);
+      var F := TFile.Create(PrependPath(Ext, Get(0).AsStr), fdOpenExisting, faRead, fsReadWrite);
+      try
+        while True do begin
+          var NumRead := F.Read(Buf, SizeOf(Buf));
+          if NumRead = 0 then
+            Break;
+          SHA256Update(Context, Buf, NumRead);
+        end;
+      finally
+        F.Free;
+      end;
+      MakeStr(ResPtr^, SHA256DigestToString(SHA256Final(Context)));
     end;
   except
     on E: Exception do
@@ -1826,14 +1841,7 @@ begin
     with IInternalFuncParams(Params) do
     begin
       var S := AnsiString(Get(0).AsStr);
-      var M := TMemoryStream.Create;
-      try
-        M.Write(Pointer(S)^, Length(S)*SizeOf(S[1]));
-        M.Seek(0, soFromBeginning);
-        MakeStr(ResPtr^, THashSHA2.GetHashString(M, SHA256));
-      finally
-        M.Free;
-      end;
+      MakeStr(ResPtr^, SHA256DigestToString(SHA256Buf(Pointer(S)^, Length(S)*SizeOf(S[1]))));
     end;
   except
     on E: Exception do
@@ -1852,14 +1860,7 @@ begin
     with IInternalFuncParams(Params) do
     begin
       var S := Get(0).AsStr;
-      var M := TMemoryStream.Create;
-      try
-        M.Write(Pointer(S)^, Length(S)*SizeOf(S[1]));
-        M.Seek(0, soFromBeginning);
-        MakeStr(ResPtr^, THashSHA2.GetHashString(M, SHA256));
-      finally
-        M.Free;
-      end;
+      MakeStr(ResPtr^, SHA256DigestToString(SHA256Buf(Pointer(S)^, Length(S)*SizeOf(S[1]))));
     end;
   except
     on E: Exception do

+ 8 - 8
Projects/Src/Setup.FileExtractor.pas

@@ -50,9 +50,9 @@ procedure FreeFileExtractor;
 implementation
 
 uses
-  Hash, PathFunc, Shared.CommonFunc, Setup.MainFunc, SetupLdrAndSetup.Messages,
+  PathFunc, Shared.CommonFunc, Setup.MainFunc, SetupLdrAndSetup.Messages,
   Shared.SetupMessageIDs, Setup.InstFunc, Compression.Zlib, Compression.bzlib,
-  Compression.LZMADecompressor, SHA1, Setup.LoggingFunc, Setup.NewDiskForm;
+  Compression.LZMADecompressor, SHA256, Setup.LoggingFunc, Setup.NewDiskForm;
 
 var
   FFileExtractor: TFileExtractor;
@@ -191,7 +191,7 @@ procedure TFileExtractor.SeekTo(const FL: TSetupFileLocationEntry;
   procedure InitDecryption;
   begin
     { Initialize the key, which is the SHA-256 hash of FCryptKey }
-    var Key := THashSHA2.GetHashBytes(FCryptKey, SHA256);
+    var Key := SHA256Buf(Pointer(FCryptKey)^, Length(FCryptKey)*SizeOf(FCryptKey[1]));
 
     { Recreate the unique nonce from the base nonce }
     var Nonce := SetupHeader.EncryptionBaseNonce;
@@ -315,7 +315,7 @@ procedure TFileExtractor.DecompressFile(const FL: TSetupFileLocationEntry;
   const VerifyChecksum: Boolean);
 var
   BytesLeft: Integer64;
-  Context: TSHA1Context;
+  Context: TSHA256Context;
   AddrOffset: LongWord;
   BufSize: Cardinal;
   Buf: array[0..65535] of Byte;
@@ -334,7 +334,7 @@ begin
     DestF.Truncate;
     DestF.Seek(0);
 
-    SHA1Init(Context);
+    SHA256Init(Context);
 
     try
       AddrOffset := 0;
@@ -351,7 +351,7 @@ begin
           Inc(AddrOffset, BufSize);  { may wrap, but OK }
         end;
         Dec64(BytesLeft, BufSize);
-        SHA1Update(Context, Buf, BufSize);
+        SHA256Update(Context, Buf, BufSize);
         DestF.WriteBuffer(Buf, BufSize);
 
         if Assigned(ProgressProc) then
@@ -362,8 +362,8 @@ begin
         SourceIsCorrupted(E.Message);
     end;
 
-    if VerifyChecksum and not SHA1DigestsEqual(SHA1Final(Context), FL.SHA1Sum) then
-      SourceIsCorrupted('SHA-1 hash mismatch');
+    if VerifyChecksum and not SHA256DigestsEqual(SHA256Final(Context), FL.SHA256Sum) then
+      SourceIsCorrupted('SHA-256 hash mismatch');
   finally
     Dec(FEntered);
   end;

+ 22 - 102
Projects/Src/Setup.InstFunc.pas

@@ -12,7 +12,7 @@ unit Setup.InstFunc;
 interface
 
 uses
-  Windows, SysUtils, Shared.Int64Em, MD5, SHA1, Shared.CommonFunc;
+  Windows, SysUtils, Shared.Int64Em, SHA256, Shared.CommonFunc;
 
 type
   PSimpleStringListArray = ^TSimpleStringListArray;
@@ -58,15 +58,9 @@ function GenerateNonRandomUniqueTempDir(const LimitCurrentUserSidAccess: Boolean
 function GetComputerNameString: String;
 function GetFileDateTime(const DisableFsRedir: Boolean; const Filename: String;
   var DateTime: TFileTime): Boolean;
-function GetMD5OfFile(const DisableFsRedir: Boolean; const Filename: String): TMD5Digest;
-function GetMD5OfAnsiString(const S: AnsiString): TMD5Digest;
-function GetMD5OfUnicodeString(const S: UnicodeString): TMD5Digest;
-function GetSHA1OfFile(const DisableFsRedir: Boolean; const Filename: String): TSHA1Digest;
-function GetSHA1OfAnsiString(const S: AnsiString): TSHA1Digest;
-function GetSHA1OfUnicodeString(const S: UnicodeString): TSHA1Digest;
-function GetSHA256OfFile(const DisableFsRedir: Boolean; const Filename: String): String;
-function GetSHA256OfAnsiString(const S: AnsiString): String;
-function GetSHA256OfUnicodeString(const S: UnicodeString): String;
+function GetSHA256OfFile(const DisableFsRedir: Boolean; const Filename: String): TSHA256Digest;
+function GetSHA256OfAnsiString(const S: AnsiString): TSHA256Digest;
+function GetSHA256OfUnicodeString(const S: UnicodeString): TSHA256Digest;
 function GetRegRootKeyName(const RootKey: HKEY): String;
 function GetSpaceOnDisk(const DisableFsRedir: Boolean; const DriveRoot: String;
   var FreeBytes, TotalBytes: Integer64): Boolean;
@@ -87,7 +81,7 @@ procedure InternalErrorFmt(const S: String; const Args: array of const);
 function IsDirEmpty(const DisableFsRedir: Boolean; const Dir: String): Boolean;
 function IsProtectedSystemFile(const DisableFsRedir: Boolean;
   const Filename: String): Boolean;
-function MakePendingFileRenameOperationsChecksum: TMD5Digest;
+function MakePendingFileRenameOperationsChecksum: TSHA256Digest;
 function ModifyPifFile(const Filename: String; const CloseOnExit: Boolean): Boolean;
 procedure RaiseFunctionFailedError(const FunctionName: String);
 procedure RaiseOleError(const FunctionName: String; const ResultCode: HRESULT);
@@ -106,7 +100,7 @@ implementation
 uses
   Messages, ShellApi, PathFunc, SetupLdrAndSetup.InstFunc, SetupLdrAndSetup.Messages,
   Shared.SetupMessageIDs, Shared.FileClass, SetupLdrAndSetup.RedirFunc, Shared.SetupTypes,
-  Hash, Classes, RegStr, Math;
+  Classes, RegStr, Math;
 
 procedure InternalError(const Id: String);
 begin
@@ -556,110 +550,36 @@ begin
   DateTime.dwHighDateTime := 0;
 end;
 
-function GetMD5OfFile(const DisableFsRedir: Boolean; const Filename: String): TMD5Digest;
-{ Gets MD5 sum of the file Filename. An exception will be raised upon
-  failure. }
-var
-  Buf: array[0..65535] of Byte;
-begin
-  var Context: TMD5Context;
-  MD5Init(Context);
-  var F := TFileRedir.Create(DisableFsRedir, Filename, fdOpenExisting, faRead, fsReadWrite);
-  try
-    while True do begin
-      var NumRead := F.Read(Buf, SizeOf(Buf));
-      if NumRead = 0 then
-        Break;
-      MD5Update(Context, Buf, NumRead);
-    end;
-  finally
-    F.Free;
-  end;
-  Result := MD5Final(Context);
-end;
-
-function GetSHA1OfFile(const DisableFsRedir: Boolean; const Filename: String): TSHA1Digest;
-{ Gets SHA-1 sum of the file Filename. An exception will be raised upon
+function GetSHA256OfFile(const DisableFsRedir: Boolean; const Filename: String): TSHA256Digest;
+{ Gets SHA-256 sum as a string of the file Filename. An exception will be raised upon
   failure. }
 var
   Buf: array[0..65535] of Byte;
 begin
-  var Context: TSHA1Context;
-  SHA1Init(Context);
+  var Context: TSHA256Context;
+  SHA256Init(Context);
   var F := TFileRedir.Create(DisableFsRedir, Filename, fdOpenExisting, faRead, fsReadWrite);
   try
     while True do begin
       var NumRead := F.Read(Buf, SizeOf(Buf));
       if NumRead = 0 then
         Break;
-      SHA1Update(Context, Buf, NumRead);
+      SHA256Update(Context, Buf, NumRead);
     end;
   finally
     F.Free;
   end;
-  Result := SHA1Final(Context);
-end;
-
-function GetSHA256OfFile(const DisableFsRedir: Boolean; const Filename: String): String;
-{ Gets SHA-256 sum as a string of the file Filename. An exception will be raised upon
-  failure. }
-begin
-  var PrevState: TPreviousFsRedirectionState;
-  if not DisableFsRedirectionIf(DisableFsRedir, PrevState) then
-    InternalError('GetSHA256OfFile: DisableFsRedirectionIf failed.');
-  try
-    Result := THashSHA2.GetHashStringFromFile(Filename, SHA256);
-  finally
-    RestoreFsRedirection(PrevState);
-  end;
-end;
-
-function GetMD5OfAnsiString(const S: AnsiString): TMD5Digest;
-begin
-  Result := MD5Buf(Pointer(S)^, Length(S)*SizeOf(S[1]));
+  Result := SHA256Final(Context);
 end;
 
-function GetMD5OfUnicodeString(const S: UnicodeString): TMD5Digest;
+function GetSHA256OfAnsiString(const S: AnsiString): TSHA256Digest;
 begin
-  Result := MD5Buf(Pointer(S)^, Length(S)*SizeOf(S[1]));
+  Result := SHA256Buf(Pointer(S)^, Length(S)*SizeOf(S[1]));
 end;
 
-function GetSHA1OfAnsiString(const S: AnsiString): TSHA1Digest;
+function GetSHA256OfUnicodeString(const S: UnicodeString): TSHA256Digest;
 begin
-  Result := SHA1Buf(Pointer(S)^, Length(S)*SizeOf(S[1]));
-end;
-
-function GetSHA1OfUnicodeString(const S: UnicodeString): TSHA1Digest;
-begin
-  Result := SHA1Buf(Pointer(S)^, Length(S)*SizeOf(S[1]));
-end;
-
-function GetSHA256OfAnsiString(const S: AnsiString): String;
-var
-  M: TMemoryStream;
-begin
-  M := TMemoryStream.Create;
-  try
-    M.Write(Pointer(S)^, Length(S)*SizeOf(S[1]));
-    M.Seek(0, soFromBeginning);
-    Result := THashSHA2.GetHashString(M, SHA256);
-  finally
-    M.Free;
-  end;
-end;
-
-function GetSHA256OfUnicodeString(const S: UnicodeString): String;
-var
-  M: TMemoryStream;
-begin
-  M := TMemoryStream.Create;
-  try
-    M.Write(Pointer(S)^, Length(S)*SizeOf(S[1]));
-    M.Seek(0, soFromBeginning);
-    Result := THashSHA2.GetHashString(M, SHA256);
-  finally
-    M.Free;
-  end;
+  Result := SHA256Buf(Pointer(S)^, Length(S)*SizeOf(S[1]));
 end;
 
 var
@@ -940,31 +860,31 @@ begin
     Result := '';
 end;
 
-function MakePendingFileRenameOperationsChecksum: TMD5Digest;
+function MakePendingFileRenameOperationsChecksum: TSHA256Digest;
 { Calculates a checksum of the current PendingFileRenameOperations registry
   value The caller can use this checksum to determine if
   PendingFileRenameOperations was changed (perhaps by another program). }
 var
-  Context: TMD5Context;
+  Context: TSHA256Context;
   K: HKEY;
   S: String;
 begin
-  MD5Init(Context);
+  SHA256Init(Context);
   try
     if RegOpenKeyExView(rvDefault, HKEY_LOCAL_MACHINE, 'SYSTEM\CurrentControlSet\Control\Session Manager',
        0, KEY_QUERY_VALUE, K) = ERROR_SUCCESS then begin
       if RegQueryMultiStringValue(K, 'PendingFileRenameOperations', S) then
-        MD5Update(Context, S[1], Length(S)*SizeOf(S[1]));
+        SHA256Update(Context, S[1], Length(S)*SizeOf(S[1]));
       { When "PendingFileRenameOperations" is full, it spills over into
         "PendingFileRenameOperations2" }
       if RegQueryMultiStringValue(K, 'PendingFileRenameOperations2', S) then
-        MD5Update(Context, S[1], Length(S)*SizeOf(S[1]));
+        SHA256Update(Context, S[1], Length(S)*SizeOf(S[1]));
       RegCloseKey(K);
     end;
   except
     { don't propagate exceptions }
   end;
-  Result := MD5Final(Context);
+  Result := SHA256Final(Context);
 end;
 
 procedure EnumFileReplaceOperationsFilenames(const EnumFunc: TEnumFROFilenamesProc;

+ 23 - 22
Projects/Src/Setup.Install.pas

@@ -31,7 +31,7 @@ uses
   Windows, SysUtils, Messages, Classes, Forms, ShlObj, Shared.Struct, Setup.UninstallLog, Shared.SetupTypes,
   SetupLdrAndSetup.InstFunc, Setup.InstFunc, Setup.InstFunc.Ole, Setup.SecurityFunc, SetupLdrAndSetup.Messages,
   Setup.MainFunc, Setup.LoggingFunc, Setup.FileExtractor, Shared.FileClass,
-  Compression.Base, SHA1, PathFunc, Shared.CommonFunc.Vcl, Shared.CommonFunc, SetupLdrAndSetup.RedirFunc, Shared.Int64Em, Shared.SetupMessageIDs,
+  Compression.Base, SHA256, PathFunc, Shared.CommonFunc.Vcl, Shared.CommonFunc, SetupLdrAndSetup.RedirFunc, Shared.Int64Em, Shared.SetupMessageIDs,
   Setup.WizardForm, Shared.DebugStruct, Setup.DebugClient, Shared.VerInfoFunc, Setup.ScriptRunner, Setup.RegDLL, Setup.Helper,
   Shared.ResUpdateFunc, Setup.DotNetFunc, TaskbarProgressFunc, NewProgressBar, RestartManager,
   Net.HTTPClient, Net.URLClient, NetEncoding, RegStr;
@@ -237,12 +237,12 @@ begin
     Result := '(invalid)';
 end;
 
-function TryToGetSHA1OfFile(const DisableFsRedir: Boolean; const Filename: String;
-  var Sum: TSHA1Digest): Boolean;
-{ Like GetSHA1OfFile but traps exceptions locally. Returns True if successful. }
+function TryToGetSHA256OfFile(const DisableFsRedir: Boolean; const Filename: String;
+  var Sum: TSHA256Digest): Boolean;
+{ Like GetSHA256OfFile but traps exceptions locally. Returns True if successful. }
 begin
   try
-    Sum := GetSHA1OfFile(DisableFsRedir, Filename);
+    Sum := GetSHA256OfFile(DisableFsRedir, Filename);
     Result := True;
   except
     Result := False;
@@ -877,17 +877,17 @@ var
 
   procedure BindUninstallMsgDataToExe(const F: TFile);
   var
-    UniqueValue: TSHA1Digest;
+    UniqueValue: TSHA256Digest;
     UninstallerMsgTail: TUninstallerMsgTail;
   begin
     F.SeekToEnd;
 
     { First append the hash of AppId so that unins*.exe files from different
-      applications won't have the same MD5 sum. This is done to combat broken
-      anti-spyware programs that catch all unins*.exe files with certain MD5
+      applications won't have the same file hash. This is done to combat broken
+      anti-spyware programs that catch all unins*.exe files with certain hash
       sums just because some piece of spyware was deployed with Inno Setup and
       had the unins*.exe file in its directory. }
-    UniqueValue := GetSHA1OfUnicodeString(ExpandedAppId);
+    UniqueValue := GetSHA256OfUnicodeString(ExpandedAppId);
     F.WriteBuffer(UniqueValue, SizeOf(UniqueValue));
 
     UninstallerMsgTail.ID := UninstallerMsgTailID;
@@ -1080,7 +1080,7 @@ var
     CurFileVersionInfoValid: Boolean;
     CurFileVersionInfo, ExistingVersionInfo: TFileVersionNumbers;
     CurFileDateValid, ExistingFileDateValid: Boolean;
-    CurFileHash, ExistingFileHash: TSHA1Digest;
+    CurFileHash, ExistingFileHash: TSHA256Digest;
     IsProtectedFile, AllowTimeStampComparison: Boolean;
     DeleteFlags: Longint;
     CurFileDate, ExistingFileDate: TFileTime;
@@ -1254,27 +1254,27 @@ var
                    (ExistingVersionInfo.LS = CurFileVersionInfo.LS) and
                    not(foOverwriteSameVersion in CurFile^.Options) then begin
                   if foReplaceSameVersionIfContentsDiffer in CurFile^.Options then begin
-                    { Get the two files' SHA-1 hashes and compare them }
-                    if TryToGetSHA1OfFile(DisableFsRedir, DestFile, ExistingFileHash) then begin
+                    { Get the two files' SHA-256 hashes and compare them }
+                    if TryToGetSHA256OfFile(DisableFsRedir, DestFile, ExistingFileHash) then begin
                       if Assigned(CurFileLocation) then
-                        CurFileHash := CurFileLocation^.SHA1Sum
+                        CurFileHash := CurFileLocation^.SHA256Sum
                       else begin
                         LastOperation := SetupMessages[msgErrorReadingSource];
-                        { This GetSHA1OfFile call could raise an exception, but
+                        { This GetSHA256OfFile call could raise an exception, but
                           it's very unlikely since we were already able to
                           successfully read the file's version info. }
-                        CurFileHash := GetSHA1OfFile(DisableFsRedir, ASourceFile);
+                        CurFileHash := GetSHA256OfFile(DisableFsRedir, ASourceFile);
                         LastOperation := SetupMessages[msgErrorReadingExistingDest];
                       end;
-                      { If the two files' SHA-1 hashes are equal, skip the file }
-                      if SHA1DigestsEqual(ExistingFileHash, CurFileHash) then begin
-                        Log('Existing file''s SHA-1 hash matches our file. Skipping.');
+                      { If the two files' SHA-256 hashes are equal, skip the file }
+                      if SHA256DigestsEqual(ExistingFileHash, CurFileHash) then begin
+                        Log('Existing file''s SHA-256 hash matches our file. Skipping.');
                         goto Skip;
                       end;
-                      Log('Existing file''s SHA-1 hash is different from our file. Proceeding.');
+                      Log('Existing file''s SHA-256 hash is different from our file. Proceeding.');
                     end
                     else
-                      Log('Failed to read existing file''s SHA-1 hash. Proceeding.');
+                      Log('Failed to read existing file''s SHA-256 hash. Proceeding.');
                   end
                   else begin
                     { Skip the file or fall back to time stamp comparison }
@@ -3511,7 +3511,8 @@ begin
 
   { Prepare directory }
   if FileExists(DestFile) then begin
-    if (RequiredSHA256OfFile <> '') and (RequiredSHA256OfFile = GetSHA256OfFile(DisableFsRedir, DestFile)) then begin
+    if (RequiredSHA256OfFile <> '') and
+       (RequiredSHA256OfFile = SHA256DigestToString(GetSHA256OfFile(DisableFsRedir, DestFile))) then begin
       Log('  File already downloaded.');
       Result := 0;
       Exit;
@@ -3574,7 +3575,7 @@ begin
       { Check hash if specified, otherwise check everything else we can check }
       if RequiredSHA256OfFile <> '' then begin
         try
-          SHA256OfFile := GetSHA256OfFile(DisableFsRedir, TempFile);
+          SHA256OfFile := SHA256DigestToString(GetSHA256OfFile(DisableFsRedir, TempFile));
         except on E: Exception do
           raise Exception.Create(FmtSetupMessage(msgErrorFileHash1, [E.Message]));
         end;

+ 3 - 3
Projects/Src/Setup.MainForm.pas

@@ -49,7 +49,7 @@ var
 implementation
 
 uses
-  Forms, Graphics, ShlObj, MD5, RestartManager,
+  Forms, Graphics, ShlObj, SHA256, RestartManager,
   Shared.CommonFunc, Shared.CommonFunc.Vcl, Shared.SetupMessageIDs,
   SetupLdrAndSetup.Messages, SetupLdrAndSetup.RedirFunc, Setup.Install,
   Setup.InstFunc, Setup.WizardForm, Setup.LoggingFunc;
@@ -328,7 +328,7 @@ function TMainForm.Install: Boolean;
   procedure ProcessRunEntries;
   var
     CheckIfRestartNeeded: Boolean;
-    ChecksumBefore, ChecksumAfter: TMD5Digest;
+    ChecksumBefore, ChecksumAfter: TSHA256Digest;
     WindowDisabler: TWindowDisabler;
     I: Integer;
     RunEntry: PSetupRunEntry;
@@ -388,7 +388,7 @@ function TMainForm.Install: Boolean;
         WindowDisabler.Free;
         if CheckIfRestartNeeded then begin
           ChecksumAfter := MakePendingFileRenameOperationsChecksum;
-          if not MD5DigestsEqual(ChecksumBefore, ChecksumAfter) then
+          if not SHA256DigestsEqual(ChecksumBefore, ChecksumAfter) then
             NeedsRestart := True;
         end;
       end;

+ 70 - 5
Projects/Src/Setup.ScriptFunc.pas

@@ -25,7 +25,7 @@ uses
   Shared.CommonFunc, Shared.FileClass, SetupLdrAndSetup.RedirFunc,
   Setup.Install, SetupLdrAndSetup.InstFunc, Setup.InstFunc, Setup.InstFunc.Ole, SetupLdrAndSetup.Messages,
   Shared.SetupMessageIDs, Setup.NewDiskForm, BrowseFunc, Setup.WizardForm, Shared.VerInfoFunc,
-  Shared.SetupTypes, Shared.Int64Em, MD5, SHA1, Setup.LoggingFunc, Setup.SetupForm, Setup.RegDLL, Setup.Helper,
+  Shared.SetupTypes, Shared.Int64Em, MD5, SHA1, SHA256, Setup.LoggingFunc, Setup.SetupForm, Setup.RegDLL, Setup.Helper,
   Setup.SpawnClient, Setup.UninstallProgressForm, ASMInline, Setup.DotNetFunc,
   Shared.DotNetVersion, Setup.MsiFunc, BitmapImage;
 
@@ -849,6 +849,71 @@ begin
 end;
 
 function InstFuncProc(Caller: TPSExec; Proc: TPSExternalProcRec; Global, Stack: TPSStack): Boolean;
+
+  function GetMD5OfFile(const DisableFsRedir: Boolean; const Filename: String): TMD5Digest;
+  { Gets MD5 sum of the file Filename. An exception will be raised upon
+    failure. }
+  var
+    Buf: array[0..65535] of Byte;
+  begin
+    var Context: TMD5Context;
+    MD5Init(Context);
+    var F := TFileRedir.Create(DisableFsRedir, Filename, fdOpenExisting, faRead, fsReadWrite);
+    try
+      while True do begin
+        var NumRead := F.Read(Buf, SizeOf(Buf));
+        if NumRead = 0 then
+          Break;
+        MD5Update(Context, Buf, NumRead);
+      end;
+    finally
+      F.Free;
+    end;
+    Result := MD5Final(Context);
+  end;
+
+  function GetSHA1OfFile(const DisableFsRedir: Boolean; const Filename: String): TSHA1Digest;
+  { Gets SHA-1 sum of the file Filename. An exception will be raised upon
+    failure. }
+  var
+    Buf: array[0..65535] of Byte;
+  begin
+    var Context: TSHA1Context;
+    SHA1Init(Context);
+    var F := TFileRedir.Create(DisableFsRedir, Filename, fdOpenExisting, faRead, fsReadWrite);
+    try
+      while True do begin
+        var NumRead := F.Read(Buf, SizeOf(Buf));
+        if NumRead = 0 then
+          Break;
+        SHA1Update(Context, Buf, NumRead);
+      end;
+    finally
+      F.Free;
+    end;
+    Result := SHA1Final(Context);
+  end;
+
+  function GetMD5OfAnsiString(const S: AnsiString): TMD5Digest;
+  begin
+    Result := MD5Buf(Pointer(S)^, Length(S)*SizeOf(S[1]));
+  end;
+
+  function GetMD5OfUnicodeString(const S: UnicodeString): TMD5Digest;
+  begin
+    Result := MD5Buf(Pointer(S)^, Length(S)*SizeOf(S[1]));
+  end;
+
+  function GetSHA1OfAnsiString(const S: AnsiString): TSHA1Digest;
+  begin
+    Result := SHA1Buf(Pointer(S)^, Length(S)*SizeOf(S[1]));
+  end;
+
+  function GetSHA1OfUnicodeString(const S: UnicodeString): TSHA1Digest;
+  begin
+    Result := SHA1Buf(Pointer(S)^, Length(S)*SizeOf(S[1]));
+end;
+
 var
   PStart: Cardinal;
   Filename: String;
@@ -890,11 +955,11 @@ begin
   end else if Proc.Name = 'GETSHA1OFUNICODESTRING' then begin
     Stack.SetString(PStart, SHA1DigestToString(GetSHA1OfUnicodeString(Stack.GetString(PStart-1))));
   end else if Proc.Name = 'GETSHA256OFFILE' then begin
-    Stack.SetString(PStart, GetSHA256OfFile(ScriptFuncDisableFsRedir, Stack.GetString(PStart-1)));
+    Stack.SetString(PStart, SHA256DigestToString(GetSHA256OfFile(ScriptFuncDisableFsRedir, Stack.GetString(PStart-1))));
   end else if Proc.Name = 'GETSHA256OFSTRING' then begin
-    Stack.SetString(PStart, GetSHA256OfAnsiString(StackGetAnsiString(Stack, PStart-1)));
+    Stack.SetString(PStart, SHA256DigestToString(GetSHA256OfAnsiString(StackGetAnsiString(Stack, PStart-1))));
   end else if Proc.Name = 'GETSHA256OFUNICODESTRING' then begin
-    Stack.SetString(PStart, GetSHA256OfUnicodeString(Stack.GetString(PStart-1)));
+    Stack.SetString(PStart, SHA256DigestToString(GetSHA256OfUnicodeString(Stack.GetString(PStart-1))));
   end else if Proc.Name = 'GETSPACEONDISK' then begin
     if GetSpaceOnDisk(ScriptFuncDisableFsRedir, Stack.GetString(PStart-1), FreeBytes, TotalBytes) then begin
       if Stack.GetBool(PStart-2) then begin
@@ -999,7 +1064,7 @@ begin
   end else if Proc.Name = 'ISPROTECTEDSYSTEMFILE' then begin
     Stack.SetBool(PStart, IsProtectedSystemFile(ScriptFuncDisableFsRedir, Stack.GetString(PStart-1)));
   end else if Proc.Name = 'MAKEPENDINGFILERENAMEOPERATIONSCHECKSUM' then begin
-    Stack.SetString(PStart, MD5DigestToString(MakePendingFileRenameOperationsChecksum));
+    Stack.SetString(PStart, SHA256DigestToString(MakePendingFileRenameOperationsChecksum));
   end else if Proc.Name = 'MODIFYPIFFILE' then begin
     Stack.SetBool(PStart, ModifyPifFile(Stack.GetString(PStart-1), Stack.GetBool(PStart-2)));
   end else if Proc.Name = 'REGISTERSERVER' then begin

+ 1 - 1
Projects/Src/Setup.WizardForm.pas

@@ -343,7 +343,7 @@ implementation
 
 uses
   ShellApi, ShlObj, Types, SetupLdrAndSetup.Messages, Setup.MainForm, Setup.MainFunc, PathFunc, Shared.CommonFunc.Vcl, Shared.CommonFunc,
-  MD5, Setup.InstFunc, Setup.SelectFolderForm, Setup.FileExtractor, Setup.LoggingFunc, RestartManager, Setup.ScriptRunner;
+  Setup.InstFunc, Setup.SelectFolderForm, Setup.FileExtractor, Setup.LoggingFunc, RestartManager, Setup.ScriptRunner;
 
 {$R *.DFM}
 

+ 2 - 2
Projects/Src/Shared.Struct.pas

@@ -13,7 +13,7 @@ unit Shared.Struct;
 interface
 
 uses
-  Windows, Shared.Int64Em, SHA1, SHA256;
+  Windows, Shared.Int64Em, SHA256;
 
 const
   SetupTitle = 'Inno Setup';
@@ -255,7 +255,7 @@ type
     ChunkSuboffset: Integer64;
     OriginalSize: Integer64;
     ChunkCompressedSize: Integer64;
-    SHA1Sum: TSHA1Digest;
+    SHA256Sum: TSHA256Digest;
     SourceTimeStamp: TFileTime;
     FileVersionMS, FileVersionLS: DWORD;
     Flags: set of (foVersionInfoValid, foVersionInfoNotValid, foTimeStampInUTC,

+ 1 - 0
whatsnew.htm

@@ -83,6 +83,7 @@ For conditions of distribution and use, see <a href="files/is/license.txt">LICEN
 <ul>
   <li>Updated the LZMA SDK used by Inno Setup to the latest version, increasing the speed of LZMA and LZMA2 compression and decompression (respectively by 21% and 11% in a test with default settings) without changing the compression ratio. Compression memory requirements have increased by about 4%.</li>
   <li>Updated the encryption algorithm used by Inno Setup to XChaCha20 for extra security. This code is built-in: the separate ISCrypt.dll "encryption module" is no longer used and will be automatically deleted when you update.</li>
+  <li>Replaced all remaining use of MD5 and SHA-1 hashes with SHA-256 hashes, without removing the MD5 and SHA-1 Pascal Scripting and ISPP support functions.</li>
   <li>Merged the Inno Setup Preprocessor documentation into the main documentation instead of being separate.</li>
   <li>Added a dark mode version of the documentation, automatically used by the Compiler IDE if a dark theme is chosen.</li>
   <li>Pascal Scripting changes: