Browse Source

Replace ArcFour with XChaCha20 which also removes iscrypt.dll use.

Todo:
-Use a single random base nonce for all files
-Remove/replace various iscrypt use in .iss scripts
-Delete iscrypt.dll on updates
-Update help & whatsnew & web
-Rename TSetupSalt/TSetupNonce?
Martijn Laan 1 năm trước cách đây
mục cha
commit
d9d845ab62

+ 1 - 1
Projects/ISCmplr.dpr

@@ -33,7 +33,7 @@ uses
   Compression.bzlib in 'Src\Compression.bzlib.pas',
   Compression.LZMACompressor in 'Src\Compression.LZMACompressor.pas',
   Shared.FileClass in 'Src\Shared.FileClass.pas',
-  Shared.ArcFour in 'Src\Shared.ArcFour.pas',
+  ChaCha20 in '..\Components\ChaCha20.pas',
   Shared.VerInfoFunc in 'Src\Shared.VerInfoFunc.pas',
   PathFunc in '..\Components\PathFunc.pas',
   Shared.CommonFunc in 'Src\Shared.CommonFunc.pas',

+ 1 - 1
Projects/ISCmplr.dproj

@@ -99,7 +99,7 @@
         <DCCReference Include="Src\Compression.bzlib.pas"/>
         <DCCReference Include="Src\Compression.LZMACompressor.pas"/>
         <DCCReference Include="Src\Shared.FileClass.pas"/>
-        <DCCReference Include="Src\Shared.ArcFour.pas"/>
+        <DCCReference Include="..\Components\ChaCha20.pas"/>
         <DCCReference Include="Src\Shared.VerInfoFunc.pas"/>
         <DCCReference Include="..\Components\PathFunc.pas"/>
         <DCCReference Include="Src\Shared.CommonFunc.pas"/>

+ 1 - 1
Projects/Setup.dpr

@@ -51,7 +51,7 @@ uses
   Setup.LoggingFunc in 'Src\Setup.LoggingFunc.pas',
   Setup.DebugClient in 'Src\Setup.DebugClient.pas',
   Shared.DebugStruct in 'Src\Shared.DebugStruct.pas',
-  Shared.ArcFour in 'Src\Shared.ArcFour.pas',
+  ChaCha20 in '..\Components\ChaCha20.pas',
   Setup.Uninstall in 'Src\Setup.Uninstall.pas',
   Setup.UninstallProgressForm in 'Src\Setup.UninstallProgressForm.pas' {UninstallProgressForm},
   Setup.UninstallSharedFileForm in 'Src\Setup.UninstallSharedFileForm.pas' {UninstallSharedFileForm},

+ 1 - 1
Projects/Setup.dproj

@@ -120,7 +120,7 @@
         <DCCReference Include="Src\Setup.LoggingFunc.pas"/>
         <DCCReference Include="Src\Setup.DebugClient.pas"/>
         <DCCReference Include="Src\Shared.DebugStruct.pas"/>
-        <DCCReference Include="Src\Shared.ArcFour.pas"/>
+        <DCCReference Include="..\Components\ChaCha20.pas"/>
         <DCCReference Include="Src\Setup.Uninstall.pas"/>
         <DCCReference Include="Src\Setup.UninstallProgressForm.pas">
             <Form>UninstallProgressForm</Form>

+ 14 - 25
Projects/Src/Compiler.CompressionHandler.pas

@@ -12,7 +12,7 @@ unit Compiler.CompressionHandler;
 interface
 
 uses
-  SHA1, Shared.ArcFour, Shared.Int64Em, Shared.FileClass, Compression.Base,
+  SHA1, ChaCha20, Shared.Int64Em, Shared.FileClass, Compression.Base,
   Compiler.StringLists, Compiler.SetupCompiler;
 
 type
@@ -27,7 +27,7 @@ type
     FChunkFirstSlice: Integer;
     FChunkStarted: Boolean;
     FChunkStartOffset: Longint;
-    FCryptContext: TArcFourContext;
+    FCryptContext: TChaCha20Context;
     FCurSlice: Integer;
     FDestFile: TFile;
     FDestFileIsDiskSlice: Boolean;
@@ -61,7 +61,7 @@ type
 implementation
 
 uses
-  SysUtils, Shared.Struct, Compiler.Messages, Compiler.HelperFunc;
+  SysUtils, Hash, Shared.Struct, Compiler.Messages, Compiler.HelperFunc;
 
 constructor TCompressionHandler.Create(ACompiler: TSetupCompiler;
   const InitialSliceFilename: String);
@@ -189,27 +189,16 @@ procedure TCompressionHandler.NewChunk(const ACompressorClass: TCustomCompressor
   end;
 
   procedure InitEncryption;
-  var
-    Salt: TSetupSalt;
-    Context: TSHA1Context;
-    Hash: TSHA1Digest;
   begin
-    { Generate and write a random salt. This salt is hashed into the key to
-      prevent the same key from ever being used twice (theoretically). }
-    GenerateRandomBytes(Salt, SizeOf(Salt));
-    FDestFile.WriteBuffer(Salt, SizeOf(Salt));
-
-    { Create an SHA-1 hash of the salt plus ACryptKey, and use that as the key }
-    SHA1Init(Context);
-    SHA1Update(Context, Salt, SizeOf(Salt));
-    SHA1Update(Context, Pointer(ACryptKey)^, Length(ACryptKey)*SizeOf(ACryptKey[1]));
-    Hash := SHA1Final(Context);
-    ArcFourInit(FCryptContext, Hash, SizeOf(Hash));
-
-    { Discard first 1000 bytes of the output keystream, since according to
-      <http://en.wikipedia.org/wiki/RC4_(cipher)>, "the first few bytes of
-      output keystream are strongly non-random." }
-    ArcFourDiscard(FCryptContext, 1000);
+    { Create an SHA-256 hash of ACryptKey, and use that as the key }
+    var Key := THashSHA2.GetHashBytes(ACryptKey, SHA256);
+
+    { Generate and write a random nonce. }
+    var Nonce: TSetupNonce;
+    GenerateRandomBytes(Nonce, SizeOf(Nonce));
+    FDestFile.WriteBuffer(Nonce, SizeOf(Nonce));
+
+    XChaCha20Init(FCryptContext, Key[0], Length(Key), Nonce[0], Length(Nonce), 0);
   end;
 
 var
@@ -221,7 +210,7 @@ begin
     start a new slice }
   MinBytesLeft := SizeOf(ZLIBID);
   if AUseEncryption then
-    Inc(MinBytesLeft, SizeOf(TSetupSalt));
+    Inc(MinBytesLeft, SizeOf(TSetupNonce));
   Inc(MinBytesLeft);  { for at least one byte of data }
   if FSliceBytesLeft < MinBytesLeft then
     NewSlice('');
@@ -311,7 +300,7 @@ begin
         temporary buffer. }
       GetMem(P2, S);
       try
-        ArcFourCrypt(FCryptContext, P^, P2^, S);
+        XChaCha20Crypt(FCryptContext, P^, P2^, S);
         FDestFile.WriteBuffer(P2^, S)
       finally
         FreeMem(P2);

+ 0 - 3
Projects/Src/Compiler.Messages.pas

@@ -49,7 +49,6 @@ const
   SCompilerStatusCreateSetupFiles = 'Creating setup files';
   SCompilerStatusSkippingCreateSetupFiles = 'Skipping creating setup files, output is disabled';
   SCompilerStatusCreateManifestFile = 'Creating manifest file';
-  SCompilerStatusFilesInitEncryption = '   Initializing encryption';
   SCompilerStatusFilesCompressing = '   Compressing: %s';
   SCompilerStatusFilesCompressingVersion = '   Compressing: %s   (%u.%u.%u.%u)';
   SCompilerStatusFilesStoring = '   Storing: %s';
@@ -92,8 +91,6 @@ const
   SCompilerSetup0Mismatch = 'Internal error SC1';
   SCompilerMustUseDiskSpanning = 'Disk spanning must be enabled in order to create an installation larger than %d bytes in size';
   SCompilerCompileCodeError = 'An error occurred while trying to compile the [Code] section:' + SNewLine2 + '%s';
-  SCompilerISCryptMissing = 'Cannot use encryption because ISCrypt.dll is missing.' + SNewLine2 +
-    'Note: This file is not installed with Inno Setup. A link to obtain it can be found on the Inno Setup web site';
   SCompilerFunctionFailedWithCode = '%s failed. Error %d: %s';
 
   { [Setup] }

+ 3 - 36
Projects/Src/Compiler.SetupCompiler.pas

@@ -202,7 +202,6 @@ type
     function FindSignToolIndexByName(const AName: String): Integer;
     function GetLZMAExeFilename(const Allow64Bit: Boolean): String;
     procedure InitBzipDLL;
-    procedure InitCryptDLL;
     procedure InitPreLangData(const APreLangData: TPreLangData);
     procedure InitLanguageEntry(var ALanguageEntry: TSetupLanguageEntry);
     procedure InitLZMADLL;
@@ -291,7 +290,7 @@ implementation
 uses
   Commctrl, TypInfo, AnsiStrings, Math, WideStrUtils,
   PathFunc, Shared.CommonFunc, Compiler.Messages, Shared.SetupEntFunc,
-  Shared.FileClass, Compression.Base, Compression.Zlib, Compression.bzlib, Shared.ArcFour, SHA1,
+  Shared.FileClass, Compression.Base, Compression.Zlib, Compression.bzlib, SHA1,
   Shared.LangOptionsSectionDirectives, Shared.ResUpdateFunc, Compiler.ExeUpdateFunc,
 {$IFDEF STATICPREPROC}
   ISPP.Preprocess,
@@ -310,7 +309,7 @@ type
   end;
 
 var
-  ZipInitialized, BzipInitialized, LZMAInitialized, CryptInitialized: Boolean;
+  ZipInitialized, BzipInitialized, LZMAInitialized: Boolean;
   PreprocessorInitialized: Boolean;
   PreprocessScriptProc: TPreprocessScriptProc;
 
@@ -659,20 +658,6 @@ begin
   Result := SlicesPerDisk;
 end;
 
-procedure TSetupCompiler.InitCryptDLL;
-var
-  M: HMODULE;
-begin
-  if CryptInitialized then
-    Exit;
-  M := SafeLoadLibrary(CompilerDir + 'iscrypt.dll', SEM_NOOPENFILEERRORBOX);
-  if M = 0 then
-    AbortCompileFmt('Failed to load iscrypt.dll (%d)', [GetLastError]);
-  if not ArcFourInitFunctions(M) then
-    AbortCompile('Failed to get address of functions in iscrypt.dll');
-  CryptInitialized := True;
-end;
-
 function TSetupCompiler.FilenameToFileIndex(const AFilename: String): Integer;
 begin
   if not GotPrevFilename or (PathCompare(AFilename, PrevFilename) <> 0) then begin
@@ -6633,7 +6618,7 @@ var
   ExeFile: TFile;
   LicenseText, InfoBeforeText, InfoAfterText: AnsiString;
   WizardImages, WizardSmallImages: TObjectList<TCustomMemoryStream>;
-  DecompressorDLL, DecryptionDLL: TMemoryStream;
+  DecompressorDLL: TMemoryStream;
 
   SetupLdrOffsetTable: TSetupLdrOffsetTable;
   SizeOfExe, SizeOfHeaders: Longint;
@@ -6739,8 +6724,6 @@ var
         WriteStream(WizardSmallImages[J], W);
       if SetupHeader.CompressMethod in [cmZip, cmBzip] then
         WriteStream(DecompressorDLL, W);
-      if shEncryptionUsed in SetupHeader.Options then
-        WriteStream(DecryptionDLL, W);
 
       W.Finish;
     finally
@@ -6908,12 +6891,6 @@ var
     ChunkCompressed := False;  { avoid warning }
     CH := TCompressionHandler.Create(Self, FirstDestFile);
     try
-      { If encryption is used, load the encryption DLL }
-      if shEncryptionUsed in SetupHeader.Options then begin
-        AddStatus(SCompilerStatusFilesInitEncryption);
-        InitCryptDLL;
-      end;
-
       if DiskSpanning then begin
         if not CH.ReserveBytesOnSlice(BytesToReserveOnFirstDisk) then
           AbortCompile(SCompilerNotEnoughSpaceOnFirstDisk);
@@ -7356,7 +7333,6 @@ begin
   WizardSmallImages := nil;
   SetupE32 := nil;
   DecompressorDLL := nil;
-  DecryptionDLL := nil;
 
   try
     Finalize(SetupHeader);
@@ -7870,14 +7846,6 @@ begin
         end;
     end;
 
-    { Read decryption DLL }
-    if shEncryptionUsed in SetupHeader.Options then begin
-      AddStatus(Format(SCompilerStatusReadingFile, ['iscrypt.dll']));
-      if not NewFileExists(CompilerDir + 'iscrypt.dll') then
-        AbortCompile(SCompilerISCryptMissing);
-      DecryptionDLL := CreateMemoryStreamFromFile(CompilerDir + 'iscrypt.dll');
-    end;
-
     { Add default types if necessary }
     if (ComponentEntries.Count > 0) and (TypeEntries.Count = 0) then begin
       AddDefaultSetupType(DefaultTypeEntryNames[0], [], ttDefaultFull);
@@ -8057,7 +8025,6 @@ begin
     UsedUserAreas.Clear;
     WarningsList.Clear;
     { Free all the data }
-    DecryptionDLL.Free;
     DecompressorDLL.Free;
     SetupE32.Free;
     WizardSmallImages.Free;

+ 0 - 6
Projects/Src/IDE.HelperFunc.pas

@@ -37,7 +37,6 @@ procedure AddFileToRecentDocs(const Filename: String);
 function GenerateGuid: String;
 function ISPPInstalled: Boolean;
 function IsISPPBuiltins(const Filename: String): Boolean;
-function ISCryptInstalled: Boolean;
 function WindowsVersionAtLeast(const AMajor, AMinor: Byte; const ABuild: Word = 0): Boolean;
 function IsWindows10: Boolean;
 function IsWindows11: Boolean;
@@ -243,11 +242,6 @@ begin
   Result := PathCompare(PathExtractName(Filename), 'ISPPBuiltins.iss') = 0;
 end;
 
-function ISCryptInstalled: Boolean;
-begin
-  Result := NewFileExists(PathExtractPath(NewParamStr(0)) + 'iscrypt.dll');
-end;
-
 var
   WindowsVersion: Cardinal;
 

+ 1 - 2
Projects/Src/IDE.Wizard.WizardForm.pas

@@ -373,7 +373,6 @@ begin
 
   { Compiler }
   OutputBaseFileNameEdit.Text := 'mysetup';
-  EncryptionCheck.Visible := ISCryptInstalled;
   EncryptionCheck.Checked := True;
   EncryptionCheck.Enabled := False;
 
@@ -1053,7 +1052,7 @@ begin
       Setup := Setup + 'SetupIconFile=' + SetupIconFileEdit.Text + SNewLine;
     if PasswordEdit.Text <> '' then begin
       Setup := Setup + 'Password=' + PasswordEdit.Text + SNewLine;
-      if ISCryptInstalled and EncryptionCheck.Checked then
+      if EncryptionCheck.Checked then
         Setup := Setup + 'Encryption=yes' + SNewLine;
     end;
 

+ 13 - 22
Projects/Src/Setup.FileExtractor.pas

@@ -13,7 +13,7 @@ interface
 
 uses
   Windows, SysUtils, Shared.Int64Em, Shared.FileClass, Compression.Base,
-  Shared.Struct, Shared.ArcFour;
+  Shared.Struct, ChaCha20;
 
 type
   TExtractorProgressProc = procedure(Bytes: Cardinal);
@@ -27,7 +27,7 @@ type
     FChunkBytesLeft, FChunkDecompressedBytesRead: Integer64;
     FNeedReset: Boolean;
     FChunkCompressed, FChunkEncrypted: Boolean;
-    FCryptContext: TArcFourContext;
+    FCryptContext: TChaCha20Context;
     FCryptKey: String;
     FEntered: Integer;
     procedure DecompressBytes(var Buffer; Count: Cardinal);
@@ -50,8 +50,8 @@ procedure FreeFileExtractor;
 implementation
 
 uses
-  PathFunc, Shared.CommonFunc, Setup.MainFunc, SetupLdrAndSetup.Messages, Shared.SetupMessageIDs,
-  Setup.InstFunc, Compression.Zlib, Compression.bzlib,
+  Hash, PathFunc, Shared.CommonFunc, Setup.MainFunc, SetupLdrAndSetup.Messages,
+  Shared.SetupMessageIDs, Setup.InstFunc, Compression.Zlib, Compression.bzlib,
   Compression.LZMADecompressor, SHA1, Setup.LoggingFunc, Setup.NewDiskForm;
 
 var
@@ -189,25 +189,16 @@ procedure TFileExtractor.SeekTo(const FL: TSetupFileLocationEntry;
   const ProgressProc: TExtractorProgressProc);
 
   procedure InitDecryption;
-  var
-    Salt: TSetupSalt;
-    Context: TSHA1Context;
-    Hash: TSHA1Digest;
   begin
-    { Read the salt }
-    if FSourceF.Read(Salt, SizeOf(Salt)) <> SizeOf(Salt) then
-      SourceIsCorrupted('Failed to read salt');
+    { Read the nonce }
+    var Nonce: TSetupNonce;
+    if FSourceF.Read(Nonce, SizeOf(Nonce)) <> SizeOf(Nonce) then
+      SourceIsCorrupted('Failed to read nonce');
 
-    { Initialize the key, which is the SHA-1 hash of the salt plus FCryptKey }
-    SHA1Init(Context);
-    SHA1Update(Context, Salt, SizeOf(Salt));
-    SHA1Update(Context, Pointer(FCryptKey)^, Length(FCryptKey)*SizeOf(FCryptKey[1]));
-    Hash := SHA1Final(Context);
-    ArcFourInit(FCryptContext, Hash, SizeOf(Hash));
-
-    { The compiler discards the first 1000 bytes for extra security,
-      so we must as well }
-    ArcFourDiscard(FCryptContext, 1000);
+    { Initialize the key, which is the SHA-256 hash of FCryptKey }
+    var Key := THashSHA2.GetHashBytes(FCryptKey, SHA256);
+
+    XChaCha20Init(FCryptContext, Key[0], Length(Key), Nonce[0], Length(Nonce), 0);
   end;
 
   procedure Discard(Count: Integer64);
@@ -302,7 +293,7 @@ begin
 
     { Decrypt the data after reading from the file }
     if FChunkEncrypted then
-      ArcFourCrypt(FCryptContext, Buffer^, Buffer^, Res);
+      ChaCha20Crypt(FCryptContext, Buffer^, Buffer^, Res);
 
     if Left = Res then
       Break

+ 3 - 29
Projects/Src/Setup.MainFunc.pas

@@ -241,7 +241,7 @@ uses
   SetupLdrAndSetup.Messages, Shared.SetupMessageIDs, Setup.Install, SetupLdrAndSetup.InstFunc,
   Setup.InstFunc, SetupLdrAndSetup.RedirFunc, PathFunc,
   Compression.Base, Compression.Zlib, Compression.bzlib, Compression.LZMADecompressor,
-  Shared.ArcFour, Shared.SetupEntFunc, Setup.SelectLanguageForm,
+  Shared.SetupEntFunc, Setup.SelectLanguageForm,
   Setup.WizardForm, Setup.DebugClient, Shared.VerInfoFunc, Setup.FileExtractor,
   Shared.FileClass, Setup.LoggingFunc, SHA1, ActiveX,
   SimpleExpression, Setup.Helper, Setup.SpawnClient, Setup.SpawnServer,
@@ -2543,7 +2543,7 @@ procedure InitializeSetup;
 { Initializes various vars used by the setup. This is called in the project
   source. }
 var
-  DecompressorDLL, DecryptDLL: TMemoryStream;
+  DecompressorDLL: TMemoryStream;
 
   function ExtractLongWord(var S: String): LongWord;
   var
@@ -2635,20 +2635,6 @@ var
     end;
   end;
 
-  procedure LoadDecryptDLL;
-  var
-    Filename: String;
-  begin
-    Filename := AddBackslash(TempInstallDir) + '_isetup\_iscrypt.dll';
-    SaveStreamToTempFile(DecryptDLL, Filename);
-    FreeAndNil(DecryptDLL);
-    DecryptDLLHandle := SafeLoadLibrary(Filename, SEM_NOOPENFILEERRORBOX);
-    if DecryptDLLHandle = 0 then
-      InternalError(Format('Failed to load DLL "%s"', [Filename]));
-    if not ArcFourInitFunctions(DecryptDLLHandle) then
-      InternalError('ISCryptInitFunctions failed');
-  end;
-
 var
   Reader: TCompressedBlockReader;
 
@@ -3161,9 +3147,7 @@ begin
         ReadEntries(seUninstallRun, SetupHeader.NumUninstallRunEntries, SizeOf(TSetupRunEntry),
           Integer(@PSetupRunEntry(nil).MinVersion),
           Integer(@PSetupRunEntry(nil).OnlyBelowVersion));
-
-        { Wizard image }
-
+        { Wizard images }
         Reader.Read(N, SizeOf(LongInt));
         for I := 0 to N-1 do
           WizardImages.Add(ReadWizardImage(Reader));
@@ -3176,12 +3160,6 @@ begin
           DecompressorDLL := TMemoryStream.Create;
           ReadFileIntoStream(DecompressorDLL, Reader);
         end;
-        { Decryption DLL }
-        DecryptDLL := nil;
-        if shEncryptionUsed in SetupHeader.Options then begin
-          DecryptDLL := TMemoryStream.Create;
-          ReadFileIntoStream(DecryptDLL, Reader);
-        end;
       finally
         Reader.Free;
       end;
@@ -3265,10 +3243,6 @@ begin
   if SetupHeader.CompressMethod in [cmZip, cmBzip] then
     LoadDecompressorDLL;
 
-  { Extract "_iscrypt.dll" to TempInstallDir, and load it }
-  if shEncryptionUsed in SetupHeader.Options then
-    LoadDecryptDLL;
-
   { Start RestartManager session }
   if InitCloseApplications or
      ((shCloseApplications in SetupHeader.Options) and not InitNoCloseApplications) then begin

+ 0 - 74
Projects/Src/Shared.ArcFour.pas

@@ -1,74 +0,0 @@
-unit Shared.ArcFour;
-
-{
-  Inno Setup
-  Copyright (C) 1997-2004 Jordan Russell
-  Portions by Martijn Laan
-  For conditions of distribution and use, see LICENSE.TXT.
-
-  Interface to ISCrypt.dll (ARCFOUR encryption/decryption)
-}
-
-interface
-
-uses
-  Windows;
-
-type
-  TArcFourContext = record
-    state: array[0..255] of Byte;
-    x, y: Byte;
-  end;
-
-function ArcFourInitFunctions(Module: HMODULE): Boolean;
-procedure ArcFourInit(var Context: TArcFourContext; const Key;
-  KeyLength: Cardinal);
-procedure ArcFourCrypt(var Context: TArcFourContext; const InBuffer;
-  var OutBuffer; Length: Cardinal);
-procedure ArcFourDiscard(var Context: TArcFourContext; Bytes: Cardinal);
-
-implementation
-
-var
-  _ISCryptGetVersion: function: Integer; stdcall;
-  _ArcFourInit: procedure(var context: TArcFourContext; const key;
-    key_length: Cardinal); stdcall;
-  _ArcFourCrypt: procedure(var context: TArcFourContext; const in_buffer;
-    var out_buffer; length: Cardinal); stdcall;
-
-function ArcFourInitFunctions(Module: HMODULE): Boolean;
-begin
-  _ISCryptGetVersion := GetProcAddress(Module, 'ISCryptGetVersion');
-  _ArcFourInit := GetProcAddress(Module, 'ArcFourInit');
-  _ArcFourCrypt := GetProcAddress(Module, 'ArcFourCrypt');
-  if Assigned(_ISCryptGetVersion) and Assigned(_ArcFourInit) and
-     Assigned(_ArcFourCrypt) then begin
-    { Verify that the DLL's version is what we expect }
-    Result := (_ISCryptGetVersion = 1);
-  end
-  else begin
-    Result := False;
-    _ISCryptGetVersion := nil;
-    _ArcFourInit := nil;
-    _ArcFourCrypt := nil;
-  end
-end;
-
-procedure ArcFourInit(var Context: TArcFourContext; const Key;
-  KeyLength: Cardinal);
-begin
-  _ArcFourInit(Context, Key, KeyLength);
-end;
-
-procedure ArcFourCrypt(var Context: TArcFourContext; const InBuffer;
-  var OutBuffer; Length: Cardinal);
-begin
-  _ArcFourCrypt(Context, InBuffer, OutBuffer, Length);
-end;
-
-procedure ArcFourDiscard(var Context: TArcFourContext; Bytes: Cardinal);
-begin
-  _ArcFourCrypt(Context, Pointer(nil)^, Pointer(nil)^, Bytes);
-end;
-
-end.

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

@@ -33,7 +33,7 @@ const
     this file it's recommended you change SetupID. Any change will do (like
     changing the letters or numbers), as long as your format is
     unrecognizable by the standard Inno Setup. }
-  SetupID: TSetupID = 'Inno Setup Setup Data (6.3.0)';
+  SetupID: TSetupID = 'Inno Setup Setup Data (6.4.0)';
   UninstallLogID: array[Boolean] of TUninstallLogID =
     ('Inno Setup Uninstall Log (b)', 'Inno Setup Uninstall Log (b) 64-bit');
   MessagesHdrID: TMessagesHdrID = 'Inno Setup Messages (6.0.0) (u)';
@@ -69,6 +69,7 @@ type
   TSetupLanguageDetectionMethod = (ldUILanguage, ldLocale, ldNone);
   TSetupCompressMethod = (cmStored, cmZip, cmBzip, cmLZMA, cmLZMA2);
   TSetupSalt = array[0..7] of Byte;
+  TSetupNonce = array[0..23] of Byte;
   TSetupProcessorArchitecture = (paUnknown, paX86, paX64, paArm32, paArm64);
   TSetupProcessorArchitectures = set of TSetupProcessorArchitecture;
   TSetupDisablePage = (dpAuto, dpNo, dpYes);