unit 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)

  $jrsoftware: issrc/Projects/ArcFour.pas,v 1.2 2004/04/26 19:11:23 jr Exp $
             modified but updatable

  Rewritten to native Pascal code
}

interface

type
  TArcFourContext = record
    state: array[0..255] of Byte;
    x, y: Byte;
  end;

function ArcFourInitFunctions(Module: HMODULE): Boolean; stdcall;
procedure ArcFourInit(var Context: TArcFourContext; const Key;
  KeyLength: Cardinal); stdcall;
procedure ArcFourCrypt(var Context: TArcFourContext; const InBuffer;
  var OutBuffer; Length: Cardinal); stdcall;
procedure ArcFourDiscard(var Context: TArcFourContext; Bytes: Cardinal); stdcall;

implementation

{$R-}

function ArcFourInitFunctions(Module: HMODULE): Boolean;
begin
  Result:=true;
end;

procedure ArcFourInit(var Context: TArcFourContext; const Key;
  KeyLength: Cardinal);
type
  TPassword = array[0..255] of byte;
var
  i, j, tmp: byte;
begin
  for i := 0 to 255 do
    Context.state[i] := i;
  j := 0;
  for i := 0 to 255 do
  begin
    j := j + Context.state[i] + TPassword(Key)[i mod KeyLength];
    tmp := Context.state[i];
    Context.state[i] := Context.state[j];
    Context.state[j] := tmp;
  end;
  Context.x := 0;
  Context.y := 0;
end;

procedure ArcFourCrypt(var Context: TArcFourContext; const InBuffer;
  var OutBuffer; Length: Cardinal);
var
  i: Cardinal;
  tmp: byte;
  InBuf, OutBuf: ^byte;
begin
  InBuf := @InBuffer;
  OutBuf := @OutBuffer;
  for i := 0 to Pred(Length) do
  begin
    Context.x := Context.x + 1;
    Context.y := Context.y + Context.state[Context.x];
    tmp := Context.state[Context.x];
    Context.state[Context.x] := Context.state[Context.y];
    Context.state[Context.y] := tmp;
    if OutBuf <> nil then
    begin
      OutBuf^ := InBuf^ xor Context.state[(Context.state[Context.x] + Context.state[Context.y]) mod 256];
      Inc(InBuf);
      Inc(OutBuf);
    end;
  end;
end;

procedure ArcFourDiscard(var Context: TArcFourContext; Bytes: Cardinal);
begin
  ArcFourCrypt(Context, Pointer(nil)^, Pointer(nil)^, Bytes);
end;

end.
