Przeglądaj źródła

Merge branch 'chacha20'

Martijn Laan 1 rok temu
rodzic
commit
abcf3eb742

+ 248 - 0
Components/ChaCha20.pas

@@ -0,0 +1,248 @@
+unit ChaCha20;
+
+{
+  Inno Setup
+  Copyright (C) 1997-2024 Jordan Russell
+  Portions by Martijn Laan
+  For conditions of distribution and use, see LICENSE.TXT.
+
+  ChaCha20 and XChaCha20 encryption/decryption
+
+  Initially based on https://github.com/Ginurx/chacha20-c/tree/master
+}
+
+interface
+
+type
+  TChaCha20Ctx = array[0..15] of Cardinal;
+
+  TChaCha20Context = record
+    ctx, keystream: TChaCha20Ctx;
+    position: 0..64;
+    count64: Boolean;
+  end;
+
+procedure ChaCha20Init(var Context: TChaCha20Context; const Key;
+ const KeyLength: Cardinal; const Nonce; const NonceLength: Cardinal;
+ const Count: Cardinal);
+procedure ChaCha20Crypt(var Context: TChaCha20Context; const InBuffer;
+  var OutBuffer; const Length: Cardinal);
+
+procedure XChaCha20Init(var Context: TChaCha20Context; const Key;
+ const KeyLength: Cardinal; const Nonce; const NonceLength: Cardinal;
+ const Count: Cardinal);
+procedure XChaCha20Crypt(var Context: TChaCha20Context; const InBuffer;
+  var OutBuffer; const Length: Cardinal);
+
+implementation
+
+uses
+  SysUtils;
+
+{$C+}
+
+procedure ChaCha20InitCtx(var ctx: TChaCha20Ctx; const Key;
+  const KeyLength: Cardinal; const Nonce; const NonceLength: Cardinal;
+  const Count: Cardinal);
+begin
+  Assert(KeyLength = 32);
+  Assert(NonceLength in [0, 8, 12]);
+  {$IFDEF DEBUG}
+  FillChar(ctx[0], SizeOf(ctx), 1);
+  {$ENDIF}
+  ctx[0] := $61707865;
+  ctx[1] := $3320646e;
+  ctx[2] := $79622d32;
+  ctx[3] := $6b206574;
+  Move(Key, ctx[4], KeyLength);
+  ctx[12] := Count;
+  if NonceLength = 12 then
+    Move(Nonce, ctx[13], 12)
+  else if NonceLength = 8 then begin
+    ctx[13] := 0;
+    Move(Nonce, ctx[14], 8)
+  end else
+    FillChar(ctx[13], 12, 0);
+end;
+
+procedure ChaCha20Init(var Context: TChaCha20Context; const Key;
+  const KeyLength: Cardinal; const Nonce; const NonceLength: Cardinal;
+  const Count: Cardinal);
+begin
+  ChaCha20InitCtx(Context.ctx, Key, KeyLength, Nonce, NonceLength, Count);
+  Context.position := 64;
+  Context.count64 := NonceLength <> 12;
+end;
+
+procedure ChaCha20RunRounds(var ctx, keystream: TChaCha20Ctx);
+
+  function ROTL(const x: Cardinal; const n: Byte): Cardinal;
+  begin
+    Result := (x shl n) or (x shr (32 - n));
+  end;
+
+  procedure CHACHA20_QR(var a, b, c, d: Cardinal);
+  begin
+    Inc(a, b); d := d xor a; d := ROTL(d, 16);
+    Inc(c, d); b := b xor c; b := ROTL(b, 12);
+    Inc(a, b); d := d xor a; d := ROTL(d, 8);
+    Inc(c, d); b := b xor c; b := ROTL(b, 7);
+  end;
+
+begin
+  Move(ctx, keystream, SizeOf(ctx));
+
+  for var i := 0 to 9 do begin
+    CHACHA20_QR(keystream[0], keystream[4], keystream[8], keystream[12]);  // column 0
+    CHACHA20_QR(keystream[1], keystream[5], keystream[9], keystream[13]);  // column 1
+    CHACHA20_QR(keystream[2], keystream[6], keystream[10], keystream[14]); // column 2
+    CHACHA20_QR(keystream[3], keystream[7], keystream[11], keystream[15]); // column 3
+    CHACHA20_QR(keystream[0], keystream[5], keystream[10], keystream[15]); // diagonal 1 (main diagonal)
+    CHACHA20_QR(keystream[1], keystream[6], keystream[11], keystream[12]); // diagonal 2
+    CHACHA20_QR(keystream[2], keystream[7], keystream[8], keystream[13]);  // diagonal 3
+    CHACHA20_QR(keystream[3], keystream[4], keystream[9], keystream[14]);  // diagonal 4
+  end;
+end;
+
+procedure ChaCha20Crypt(var Context: TChaCha20Context; const InBuffer;
+  var OutBuffer; const Length: Cardinal);
+
+  procedure ChaCha20BlockNext(var ctx, keystream: TChaCha20Ctx; const count64: Boolean);
+  begin
+    ChaCha20RunRounds(ctx, keystream);
+
+    for var i := 0 to 15 do
+      keystream[i] := keystream[i] + ctx[i];
+
+    if count64 then begin
+      if ctx[12] < High(Cardinal) then
+        ctx[12] := ctx[12] + 1
+      else begin
+        ctx[12] := 0;
+        Assert(ctx[13] < High(Cardinal));
+        ctx[13] := ctx[13] + 1;
+      end;
+    end else begin
+      Assert(ctx[12] < High(Cardinal));
+      ctx[12] := ctx[12] + 1;
+    end;
+  end;
+
+begin
+  if Length = 0 then
+    Exit;
+
+  var InBuf: PByte := @InBuffer;
+  var OutBuf: PByte := @OutBuffer;
+  var KeyStream: PByte := @Context.keystream;
+
+  for var I := 0 to Length-1 do begin
+    if Context.position >= 64 then begin
+      ChaCha20BlockNext(Context.ctx, Context.keystream, Context.count64);
+      Context.position := 0;
+    end;
+    OutBuf[I] := InBuf[I] xor KeyStream[Context.position];
+    Inc(Context.position);
+  end;
+end;
+
+procedure HChaCha20(const Key; const KeyLength: Cardinal; const Nonce;
+  const NonceLength: Cardinal; out SubKey: TBytes);
+begin
+  Assert(NonceLength = 16);
+  var NonceBytes: PByte := @Nonce;
+  var ctx: TChaCha20Ctx;
+  ChaCha20InitCtx(ctx, Key, KeyLength, NonceBytes[4], 12, PCardinal(NonceBytes)^);
+  var keystream: TChaCha20Ctx;
+  ChaCha20RunRounds(ctx, keystream);
+  SetLength(SubKey, 32);
+  Move(keystream[0], SubKey[0], 16);
+  Move(keystream[12], SubKey[16], 16);
+end;
+
+procedure XChaCha20Init(var Context: TChaCha20Context; const Key;
+ const KeyLength: Cardinal; const Nonce; const NonceLength: Cardinal;
+ const Count: Cardinal);
+begin
+  Assert(NonceLength = 24);
+  var SubKey: TBytes;
+  HChaCha20(Key, KeyLength, Nonce, 16, SubKey);
+  var NonceBytes: PByte := @Nonce;
+  ChaCha20Init(Context, SubKey[0], Length(SubKey), NonceBytes[16], 8, Count);
+end;
+
+procedure XChaCha20Crypt(var Context: TChaCha20Context; const InBuffer;
+  var OutBuffer; const Length: Cardinal);
+begin
+  ChaCha20Crypt(Context, InBuffer, OutBuffer, Length);
+end;
+
+{.$DEFINE TEST}
+
+{$IFDEF TEST}
+
+procedure TestChaCha20;
+begin
+  //https://datatracker.ietf.org/doc/html/rfc7539#section-2.4.2
+  var Buf: AnsiString := 'Ladies and Gentlemen of the class of ''99: If I could offer you only one tip for the future, sunscreen would be it.';
+  var BufSize := Length(Buf)*SizeOf(Buf[1]);
+  var Key: TBytes := [$00, $01, $02, $03, $04, $05, $06, $07, $08, $09, $0a, $0b, $0c, $0d, $0e, $0f, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $1a, $1b, $1c, $1d, $1e, $1f];
+  var Nonce: TBytes := [$00, $00, $00, $00, $00, $00, $00, $4a, $00, $00, $00, $00];
+  var Counter := 1;
+  var Ctx: TChaCha20Context;
+
+  ChaCha20Init(Ctx, Key[0], Length(Key), Nonce[0], Length(Nonce), Counter);
+  ChaCha20Crypt(Ctx, Buf[1], Buf[1], 10);
+  ChaCha20Crypt(Ctx, Buf[11], Buf[11], BufSize-10);
+
+  var CipherText: TBytes := [$6e, $2e, $35, $9a, $25, $68, $f9, $80, $41, $ba, $07, $28, $dd, $0d, $69, $81, $e9, $7e, $7a, $ec, $1d, $43, $60, $c2, $0a, $27, $af, $cc, $fd, $9f, $ae, $0b, $f9, $1b, $65, $c5, $52, $47, $33, $ab, $8f, $59, $3d, $ab, $cd, $62, $b3, $57, $16, $39, $d6, $24, $e6, $51, $52, $ab, $8f, $53, $0c, $35, $9f, $08, $61, $d8, $07, $ca, $0d, $bf, $50, $0d, $6a, $61, $56, $a3, $8e, $08, $8a, $22, $b6, $5e, $52, $bc, $51, $4d, $16, $cc, $f8, $06, $81, $8c, $e9, $1a, $b7, $79, $37, $36, $5a, $f9, $0b, $bf, $74, $a3, $5b, $e6, $b4, $0b, $8e, $ed, $f2, $78, $5e, $42, $87, $4d];
+
+  Assert(Length(Buf) = Length(CipherText));
+  for var I := 0 to Length(Buf)-1 do
+    Assert(Byte(Buf[I+1]) = CipherText[I]);
+end;
+
+procedure TestHChaCha20;
+begin
+  //https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-xchacha-03#section-2.2.1
+  var Key: TBytes := [$00, $01, $02, $03, $04, $05, $06, $07, $08, $09, $0a, $0b, $0c, $0d, $0e, $0f, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $1a, $1b, $1c, $1d, $1e, $1f];
+  var Nonce: TBytes := [$00, $00, $00, $09, $00, $00, $00, $4a, $00, $00, $00, $00, $31, $41, $59, $27];
+  var SubKey: TBytes;
+
+  HChaCha20(Key[0], Length(Key), Nonce[0], Length(Nonce), SubKey);
+
+  var ExpectedSubKey: TBytes := [$82, $41, $3b, $42, $27, $b2, $7b, $fe, $d3, $0e, $42, $50, $8a, $87, $7d, $73, $a0, $f9, $e4, $d5, $8a, $74, $a8, $53, $c1, $2e, $c4, $13, $26, $d3, $ec, $dc];
+
+  Assert(Length(SubKey) = Length(ExpectedSubKey));
+  for var I := 0 to Length(SubKey)-1 do
+    Assert(SubKey[I] = ExpectedSubKey[I]);
+end;
+
+procedure TestXChaCha20;
+begin
+  //https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-xchacha-03#appendix-A.2
+  var Buf: AnsiString := 'The dhole (pronounced "dole") is also known as the Asiatic wild dog, red dog, and whistling dog.'+' It is about the size of a German shepherd but looks more like a long-legged fox. This highly elusive and skilled jumper is classified with wolves, coyotes, jackals, and foxes in the taxonomic family Canidae.';
+  var BufSize := Length(Buf)*SizeOf(Buf[1]);
+  var Key: TBytes := [$80, $81, $82, $83, $84, $85, $86, $87, $88, $89, $8a, $8b, $8c, $8d, $8e, $8f, $90, $91, $92, $93, $94, $95, $96, $97, $98, $99, $9a, $9b, $9c, $9d, $9e, $9f];
+  var Nonce: TBytes := [$40, $41, $42, $43, $44, $45, $46, $47, $48, $49, $4a, $4b, $4c, $4d, $4e, $4f, $50, $51, $52, $53, $54, $55, $56, $58];
+  var Counter := 0;
+  var Ctx: TChaCha20Context;
+
+  XChaCha20Init(Ctx, Key[0], Length(Key), Nonce[0], Length(Nonce), Counter);
+  XChaCha20Crypt(Ctx, Buf[1], Buf[1], BufSize);
+
+  var CipherText: TBytes := [$45, $59, $ab, $ba, $4e, $48, $c1, $61, $02, $e8, $bb, $2c, $05, $e6, $94, $7f, $50, $a7, $86, $de, $16, $2f, $9b, $0b, $7e, $59, $2a, $9b, $53, $d0, $d4, $e9, $8d, $8d, $64, $10, $d5, $40, $a1, $a6, $37, $5b, $26, $d8, $0d, $ac, $e4, $fa, $b5, $23, $84, $c7, $31, $ac, $bf, $16, $a5, $92, $3c, $0c, $48, $d3, $57, $5d, $4d, $0d, $2c, $67, $3b, $66, $6f, $aa, $73, $10, $61, $27, $77, $01, $09, $3a, $6b, $f7, $a1, $58, $a8, $86, $42, $92, $a4, $1c, $48, $e3, $a9, $b4, $c0, $da, $ec, $e0, $f8, $d9, $8d, $0d, $7e, $05, $b3, $7a, $30, $7b, $bb, $66, $33, $31, $64, $ec, $9e, $1b, $24, $ea, $0d, $6c, $3f, $fd, $dc, $ec, $4f, $68, $e7, $44, $30, $56, $19, $3a, $03, $c8, $10, $e1, $13, $44, $ca, $06, $d8, $ed, $8a, $2b, $fb, $1e, $8d, $48, $cf, $a6, $bc, $0e, $b4, $e2, $46, $4b, $74, $81, $42, $40, $7c, $9f, $43, $1a, $ee, $76, $99, $60, $e1, $5b, $a8, $b9, $68, $90, $46, $6e, $f2, $45, $75, $99, $85, $23, $85, $c6, $61, $f7, $52, $ce, $20, $f9, $da, $0c, $09, $ab, $6b, $19, $df, $74, $e7, $6a, $95, $96, $74, $46, $f8, $d0, $fd, $41, $5e, $7b, $ee, $2a, $12, $a1, $14, $c2, $0e, $b5, $29, $2a, $e7, $a3, $49, $ae, $57, $78, $20, $d5, $52, $0a, $1f, $3f, $b6, $2a, $17, $ce, $6a, $7e, $68, $fa, $7c, $79, $11, $1d, $88, $60, $92, $0b, $c0, $48, $ef, $43, $fe, $84, $48, $6c, $cb, $87, $c2, $5f, $0a, $e0, $45, $f0, $cc, $e1, $e7, $98, $9a, $9a, $a2, $20, $a2, $8b, $dd, $48, $27, $e7, $51, $a2, $4a, $6d, $5c, $62, $d7, $90, $a6, $63, $93, $b9, $31, $11, $c1, $a5, $5d, $d7, $42, $1a, $10, $18, $49, $74, $c7, $c5];
+
+  Assert(Length(Buf) = Length(CipherText));
+  for var I := 0 to Length(Buf)-1 do
+    Assert(Byte(Buf[I+1]) = CipherText[I]);
+end;
+
+initialization
+  TestChaCha20;
+  TestHChaCha20;
+  TestXChaCha20;
+
+{$ENDIF}
+
+end.

+ 3 - 4
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; a different hash with a different salt is generated for that.)</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>
 </body>
 </setuptopic>
 
@@ -5437,10 +5437,9 @@ DiskSliceSize=1457664
 <setupvalid><link topic="yesnonotes"><tt>yes</tt> or <tt>no</tt></link></setupvalid>
 <setupdefault><tt>no</tt></setupdefault>
 <body>
-<p>If set to <tt>yes</tt>, files that are compiled into the installation (via [Files] section entries) will be encrypted using ARCFOUR encryption, with a 160-bit key derived from the value of the <link topic="setup_password">Password</link> [Setup] section directive.</p>
-<p>Because of encryption import/export laws in some countries, encryption support is not included in the main Inno Setup installer but downloaded by it instead. See the <extlink href="https://jrsoftware.org/isdl.php">Inno Setup Downloads</extlink> page for more information.</p>
+<p>If set to <tt>yes</tt>, files that are compiled into the installation (via [Files] section entries) will be encrypted using XChaCha20 encryption, with a 256-bit key derived from the value of the <link topic="setup_password">Password</link> [Setup] section directive.</p>
 <p>If encryption is enabled and you call the <link topic="isxfunc_ExtractTemporaryFile">ExtractTemporaryFile</link> function from the [Code] section prior to the user entering the correct password, the function will fail unless the <tt>noencryption</tt> flag is used on the [Files] section entry for the file.</p>
-<p>The key used for encryption is a 160-bit SHA-1 hash of 64-bit random salt plus the value of <link topic="setup_password">Password</link>.</p>
+<p>The key used for encryption is a 256-bit SHA-256 hash of the value of <link topic="setup_password">Password</link> and the nonce used is a 192-bit random base nonce, appending the index of the first file in the chunk for unique encryption nonces.</p>
 </body>
 </setuptopic>
 

+ 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>

+ 13 - 26
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);
+
+    { Create a unique nonce from the base nonce }
+    var Nonce := FCompiler.GetEncryptionBaseNonce;
+    Nonce.RandomXorStartOffset := Nonce.RandomXorStartOffset xor FChunkStartOffset;
+    Nonce.RandomXorFirstSlice := Nonce.RandomXorFirstSlice xor FChunkFirstSlice;
+
+    XChaCha20Init(FCryptContext, Key[0], Length(Key), Nonce, SizeOf(Nonce), 0);
   end;
 
 var
@@ -220,8 +209,6 @@ begin
   { If there isn't enough room left to start a new chunk on the current slice,
     start a new slice }
   MinBytesLeft := SizeOf(ZLIBID);
-  if AUseEncryption then
-    Inc(MinBytesLeft, SizeOf(TSetupSalt));
   Inc(MinBytesLeft);  { for at least one byte of data }
   if FSliceBytesLeft < MinBytesLeft then
     NewSlice('');
@@ -311,7 +298,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] }

+ 16 - 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;
@@ -272,6 +271,7 @@ type
     function GetDebugInfo: TMemoryStream;
     function GetDiskSliceSize:Longint;
     function GetDiskSpanning: Boolean;
+    function GetEncryptionBaseNonce: TSetupNonce;
     function GetExeFilename: String;
     function GetLineFilename: String;
     function GetLineNumber: Integer;
@@ -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, Shared.ArcFour, SHA1,
+  Shared.FileClass, Compression.Base, Compression.Zlib, Compression.bzlib, SHA1,
   Shared.LangOptionsSectionDirectives, Shared.ResUpdateFunc, Compiler.ExeUpdateFunc,
 {$IFDEF STATICPREPROC}
   ISPP.Preprocess,
@@ -310,7 +310,7 @@ type
   end;
 
 var
-  ZipInitialized, BzipInitialized, LZMAInitialized, CryptInitialized: Boolean;
+  ZipInitialized, BzipInitialized, LZMAInitialized: Boolean;
   PreprocessorInitialized: Boolean;
   PreprocessScriptProc: TPreprocessScriptProc;
 
@@ -597,6 +597,11 @@ begin
   Result := DiskSpanning;
 end;
 
+function TSetupCompiler.GetEncryptionBaseNonce: TSetupNonce;
+begin
+  Result := SetupHeader.EncryptionBaseNonce;
+end;
+
 function TSetupCompiler.GetExeFilename: String;
 begin
   Result := ExeFilename;
@@ -659,20 +664,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
@@ -2377,6 +2368,11 @@ var
     Hash := SHA1Final(Context);
   end;
 
+  procedure GenerateEncryptionBaseNonce(var Nonce: TSetupNonce);
+  begin
+    GenerateRandomBytes(Nonce, SizeOf(Nonce));
+  end;
+
   procedure StrToTouchDate(const S: String);
   var
     P: PChar;
@@ -2820,6 +2816,8 @@ begin
     ssEncryption:
       begin
         SetSetupHeaderOption(shEncryptionUsed);
+        if shEncryptionUsed in SetupHeader.Options then
+          GenerateEncryptionBaseNonce(SetupHeader.EncryptionBaseNonce);
       end;
     ssExtraDiskSpaceRequired: begin
         if not StrToInteger64(Value, SetupHeader.ExtraDiskSpaceRequired) then
@@ -6633,7 +6631,7 @@ var
   ExeFile: TFile;
   LicenseText, InfoBeforeText, InfoAfterText: AnsiString;
   WizardImages, WizardSmallImages: TObjectList<TCustomMemoryStream>;
-  DecompressorDLL, DecryptionDLL: TMemoryStream;
+  DecompressorDLL: TMemoryStream;
 
   SetupLdrOffsetTable: TSetupLdrOffsetTable;
   SizeOfExe, SizeOfHeaders: Longint;
@@ -6739,8 +6737,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 +6904,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 +7346,6 @@ begin
   WizardSmallImages := nil;
   SetupE32 := nil;
   DecompressorDLL := nil;
-  DecryptionDLL := nil;
 
   try
     Finalize(SetupHeader);
@@ -7870,14 +7859,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 +8038,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;
 

+ 16 - 24
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');
+    { Initialize the key, which is the SHA-256 hash of FCryptKey }
+    var Key := THashSHA2.GetHashBytes(FCryptKey, SHA256);
 
-    { 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);
+    { Recreate the unique nonce from the base nonce }
+    var Nonce := SetupHeader.EncryptionBaseNonce;
+    Nonce.RandomXorStartOffset := Nonce.RandomXorStartOffset xor FChunkStartOffset;
+    Nonce.RandomXorFirstSlice := Nonce.RandomXorFirstSlice xor FChunkFirstSlice;
+
+    XChaCha20Init(FCryptContext, Key[0], Length(Key), Nonce, SizeOf(Nonce), 0);
   end;
 
   procedure Discard(Count: Integer64);
@@ -262,8 +253,6 @@ begin
         SourceIsCorrupted('Failed to read CompID');
       if Longint(TestCompID) <> Longint(ZLIBID) then
         SourceIsCorrupted('Invalid CompID');
-      if foChunkEncrypted in FL.Flags then
-        InitDecryption;
 
       FChunkFirstSlice := FL.FirstSlice;
       FChunkLastSlice := FL.LastSlice;
@@ -273,6 +262,9 @@ begin
       FChunkDecompressedBytesRead.Lo := 0;
       FChunkCompressed := foChunkCompressed in FL.Flags;
       FChunkEncrypted := foChunkEncrypted in FL.Flags;
+
+      if foChunkEncrypted in FL.Flags then
+        InitDecryption;
     end;
 
     { Need to seek forward in the chunk? }
@@ -302,7 +294,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 - 34
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,
@@ -257,7 +257,6 @@ var
     var ppszPath: PWideChar): HRESULT; stdcall;
 
   DecompressorDLLHandle: HMODULE;
-  DecryptDLLHandle: HMODULE;
 
 type
   TDummyClass = class
@@ -2543,7 +2542,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 +2634,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 +3146,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 +3159,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 +3242,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
@@ -3516,10 +3489,6 @@ begin
   if RmSessionStarted then
     RmEndSession(RmSessionHandle);
 
-  { Free the _iscrypt.dll handle }
-  if DecryptDLLHandle <> 0 then
-    FreeLibrary(DecryptDLLHandle);
-
   { Free the _isdecmp.dll handle }
   if DecompressorDLLHandle <> 0 then
     FreeLibrary(DecompressorDLLHandle);

+ 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.

+ 7 - 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,11 @@ type
   TSetupLanguageDetectionMethod = (ldUILanguage, ldLocale, ldNone);
   TSetupCompressMethod = (cmStored, cmZip, cmBzip, cmLZMA, cmLZMA2);
   TSetupSalt = array[0..7] of Byte;
+  TSetupNonce = record
+    RandomXorStartOffset: Int64;
+    RandomXorFirstSlice: Int32;
+    RemainingRandom: array[0..2] of Int32;
+  end;
   TSetupProcessorArchitecture = (paUnknown, paX86, paX64, paArm32, paArm64);
   TSetupProcessorArchitectures = set of TSetupProcessorArchitecture;
   TSetupDisablePage = (dpAuto, dpNo, dpYes);
@@ -106,6 +111,7 @@ type
     WizardImageAlphaFormat: (afIgnored, afDefined, afPremultiplied); // Must be same as Graphics.TAlphaFormat
     PasswordHash: TSHA1Digest;
     PasswordSalt: TSetupSalt;
+    EncryptionBaseNonce: TSetupNonce;
     ExtraDiskSpaceRequired: Integer64;
     SlicesPerDisk: Integer;
     UninstallLogMode: (lmAppend, lmNew, lmOverwrite);

BIN
iscrypt.ico


+ 0 - 141
iscrypt.iss

@@ -1,141 +0,0 @@
-// -- IsCrypt.iss --
-// Include file with support functions to download encryption support
-// Must be included before adding [Files] entries
-//
-#if FileExists('iscrypt-custom.ico')
-  #define iscryptico      'iscrypt-custom.ico'
-  #define iscrypticosizes '[32, 48, 64]'
-#else
-  #define iscryptico      'iscrypt.ico'
-  #define iscrypticosizes '[32]'
-#endif
-//
-[Files]
-Source: "{#iscryptico}"; DestName: "iscrypt.ico"; Flags: dontcopy
-Source: "{tmp}\ISCrypt.dll"; DestDir: "{app}"; Flags: ignoreversion external skipifsourcedoesntexist touch
-
-[Code]
-const
-  ISCryptHash = '2f6294f9aa09f59a574b5dcd33be54e16b39377984f3d5658cda44950fa0f8fc';
-
-var
-  ISCryptPage: TWizardPage;
-  ISCryptCheckBox: TCheckBox;
-
-procedure CreateCustomOption(Page: TWizardPage; ACheckCaption: String; var CheckBox: TCheckBox; PreviousControl: TControl);
-begin
-  CheckBox := TCheckBox.Create(Page);
-  with CheckBox do begin
-    Top := PreviousControl.Top + PreviousControl.Height + ScaleY(12);
-    Width := Page.SurfaceWidth;
-    Height := ScaleY(Height);
-    Anchors := [akLeft, akTop, akRight];
-    Caption := ACheckCaption;
-    Parent := Page.Surface;
-  end;
-end;
-
-function CreateCustomOptionPage(AAfterId: Integer; ACaption, ASubCaption, AIconFileName, ALabel1Caption, ALabel2Caption,
-  ACheckCaption: String; var CheckBox: TCheckBox): TWizardPage;
-var
-  Page: TWizardPage;
-  BitmapImage: TBitmapImage;
-  Label1, Label2: TNewStaticText;
-begin
-  Page := CreateCustomPage(AAfterID, ACaption, ASubCaption);
-  
-  AIconFileName := ExpandConstant('{tmp}\' + AIconFileName);
-  if not FileExists(AIconFileName) then
-    ExtractTemporaryFile(ExtractFileName(AIconFileName));
-
-  BitmapImage := TBitmapImage.Create(Page);
-  with BitmapImage do begin
-    Width := ScaleX(34);
-    Height := ScaleY(34);
-    Parent := Page.Surface;
-  end;
-  
-  InitializeBitmapImageFromIcon(BitmapImage, AIconFileName, Page.SurfaceColor, {#iscrypticosizes});
-
-  Label1 := TNewStaticText.Create(Page);
-  with Label1 do begin
-    AutoSize := False;
-    Left := WizardForm.SelectDirLabel.Left;
-    Width := Page.SurfaceWidth - Left;
-    Anchors := [akLeft, akTop, akRight];
-    WordWrap := True;
-    Caption := ALabel1Caption;
-    Parent := Page.Surface;
-    AdjustHeight;
-  end;
-
-  Label2 := TNewStaticText.Create(Page);
-  with Label2 do begin
-    AutoSize := False;
-    Top := Label1.Top + Label1.Height + ScaleY(12);
-    Width := Page.SurfaceWidth;
-    Anchors := [akLeft, akTop, akRight];
-    WordWrap := True;
-    Caption := ALabel2Caption;
-    Parent := Page.Surface;
-    AdjustHeight;
-  end;
-  
-  CreateCustomOption(Page, ACheckCaption, CheckBox, Label2);
-
-  Result := Page;
-end;
-
-<event('InitializeWizard')>
-procedure IsCryptInitializeWizard;
-var
-  ExistingFileName, Caption, SubCaption1, IconFileName, Label1Caption, Label2Caption, CheckCaption: String;
-begin
-  if WizardForm.PrevAppDir <> '' then begin
-    ExistingFileName := AddBackslash(WizardForm.PrevAppDir) + 'ISCrypt.dll';
-    try
-      if GetSHA256OfFile(ExistingFileName) = ISCryptHash then
-        Exit;
-    except
-    end;
-  end;
-
-  Caption := 'Encryption Support';
-  SubCaption1 := 'Would you like to download encryption support?';
-  IconFileName := 'iscrypt.ico';
-  Label1Caption :=
-    'Inno Setup supports encryption. However, because of encryption import/export laws in some countries, encryption support is not included in the main' +
-    ' Inno Setup installer. Instead, it can be downloaded from a server located in the Netherlands now.';
-  Label2Caption := 'Select whether you would like to download and install encryption support, then click Next.';
-  CheckCaption := '&Download and install encryption support';
-
-  ISCryptPage := CreateCustomOptionPage(wpSelectProgramGroup, Caption, SubCaption1, IconFileName, Label1Caption, Label2Caption, CheckCaption, ISCryptCheckBox);
-  
-  ISCryptCheckBox.Checked := ExpandConstant('{param:downloadiscrypt|0}') = '1';
-end;
-
-<event('NextButtonClick')>
-function IsCryptNextButtonClick(CurPageID: Integer): Boolean;
-var
-  DownloadPage: TDownloadWizardPage;
-begin
-  Result := True;
-  if (CurPageID = wpReady) and (ISCryptCheckBox <> nil) and ISCryptCheckBox.Checked then begin
-    DownloadPage := CreateDownloadPage(SetupMessage(msgWizardPreparing), SetupMessage(msgPreparingDesc), nil);
-    DownloadPage.Clear;
-    DownloadPage.Add('https://jrsoftware.org/download.php/iscrypt.dll', 'ISCrypt.dll', ISCryptHash);
-    DownloadPage.Show;
-    try
-      try
-        DownloadPage.Download;
-      except
-        if DownloadPage.AbortedByUser then
-          Log('Aborted by user.')
-        else
-          SuppressibleMsgBox(AddPeriod(GetExceptionMessage), mbCriticalError, MB_OK, IDOK);
-      end;
-    finally
-      DownloadPage.Hide;
-    end;
-  end;
-end;

+ 2 - 2
isdonateandmail.iss

@@ -2,8 +2,8 @@
 // Include file which adds donate and subscribe buttons to Setup
 //
 [Files]
-Source: "isdonate.bmp"; Flags: dontcopy
-Source: "ismail.bmp"; Flags: dontcopy
+Source: "isdonate.bmp"; Flags: dontcopy noencryption
+Source: "ismail.bmp"; Flags: dontcopy noencryption
 
 [CustomMessages]
 ; No need to localize: The IS website is in English only

+ 3 - 3
setup.iss

@@ -6,8 +6,6 @@
 ; Portions Copyright (C) 2000-2024 Martijn Laan. All rights reserved.
 ; For conditions of distribution and use, see LICENSE.TXT.
 
-#include "iscrypt.iss"
-
 #include "isdonateandmail.iss"
 
 #include "isportable.iss"
@@ -77,7 +75,7 @@ Name: english; MessagesFile: "files\Default.isl"
 #expr FindFiles("files\Languages\")
 
 [Messages]
-HelpTextNote=/PORTABLE=1%nEnable portable mode.%n/DOWNLOADISCRYPT=1%nEnable ISCrypt.dll download.
+HelpTextNote=/PORTABLE=1%nEnable portable mode.
 ; Two "Setup" on the same line looks weird, so put a line break in between
 english.WelcomeLabel1=Welcome to the Inno Setup%nSetup Wizard
 
@@ -111,6 +109,8 @@ Type: files; Name: "{app}\WizModernImage.bmp"
 Type: files; Name: "{app}\WizModernImage-IS.bmp"
 Type: files; Name: "{app}\WizModernSmallImage.bmp"
 Type: files; Name: "{app}\WizModernSmallImage-IS.bmp"
+; Remove old ISCrypt.dll
+Type: files; Name: "{app}\ISCrypt.dll"
 
 [Files]
 Source: "license.txt"; DestDir: "{app}"; Flags: ignoreversion touch

+ 1 - 0
whatsnew.htm

@@ -82,6 +82,7 @@ For conditions of distribution and use, see <a href="files/is/license.txt">LICEN
 <p><span class="head2">Other changes</span></p>
 <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>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: