unit PrecompCrypto;

interface

uses
  Utils,
  PrecompUtils,
  System.SysUtils, System.Classes, System.Math;

var
  Codec: TPrecompressor;

implementation

const
  CryptoCodecs: array of PChar = ['xor', 'aes', 'rc4'];
  CODEC_COUNT = 3;
  XOR_CODEC = 0;
  AES_CODEC = 1;
  RC4_CODEC = 2;

function CryptoInit(Command: PChar; Count: Integer;
  Funcs: PPrecompFuncs): Boolean;
begin
  Result := True;
end;

procedure CryptoFree(Funcs: PPrecompFuncs);
begin
end;

function CryptoParse(Command: PChar; Option: PInteger;
  Funcs: PPrecompFuncs): Boolean;
var
  S: String;
  I: Integer;
begin
  Result := False;
  Option^ := 0;
  I := 0;
  while Funcs^.GetCodec(Command, I, False) <> '' do
  begin
    S := Funcs^.GetCodec(Command, I, False);
    if (CompareText(S, CryptoCodecs[XOR_CODEC]) = 0) then
    begin
      SetBits(Option^, 0, 0, 3);
      Result := True;
    end
    else if (CompareText(S, CryptoCodecs[AES_CODEC]) = 0) then
    begin
      SetBits(Option^, 1, 0, 3);
      Result := True;
    end
    else if (CompareText(S, CryptoCodecs[RC4_CODEC]) = 0) then
    begin
      SetBits(Option^, 2, 0, 3);
      Result := True;
    end;
    Inc(I);
  end;
end;

procedure CryptoScan1(Instance, Depth: Integer; Input: PByte;
  Size, SizeEx: NativeInt; Output: _PrecompOutput; Add: _PrecompAdd;
  Funcs: PPrecompFuncs);
begin

end;

function CryptoScan2(Instance, Depth: Integer; Input: Pointer; Size: NativeInt;
  StreamInfo: PStrInfo2; Offset: PInteger; Output: _PrecompOutput;
  Funcs: PPrecompFuncs): Boolean;
var
  Res: Integer;
begin
  Result := False;
  Res := 0;
  if not Funcs^.GetResource(StreamInfo^.Resource, nil, @Res) then
    exit;
  if (Res > 0) and (StreamInfo^.OldSize > 0) then
  begin
    Output(Instance, Input, StreamInfo^.OldSize);
    StreamInfo^.NewSize := StreamInfo^.OldSize;
    Funcs^.LogScan2(CryptoCodecs[GetBits(StreamInfo^.Option, 0, 3)],
      StreamInfo^.OldSize, -1);
    Result := True;
  end;
end;

function CryptoProcess(Instance, Depth: Integer; OldInput, NewInput: Pointer;
  StreamInfo: PStrInfo2; Output: _PrecompOutput; Funcs: PPrecompFuncs): Boolean;
var
  Buffer: PByte;
  X: Integer;
  Res: Integer;
begin
  Result := False;
  X := GetBits(StreamInfo^.Option, 0, 3);
  Res := 0;
  if not Funcs^.GetResource(StreamInfo^.Resource, nil, @Res) then
    exit;
  Buffer := Funcs^.Allocator(Instance, Res);
  if Funcs^.GetResource(StreamInfo^.Resource, Buffer, @Res) then
  begin
    case X of
      XOR_CODEC:
        Funcs^.Decrypt('xor', NewInput, StreamInfo^.NewSize, Buffer, Res);
      AES_CODEC:
        Funcs^.Decrypt('aes', NewInput, StreamInfo^.NewSize, Buffer, Res);
      RC4_CODEC:
        Funcs^.Decrypt('rc4', NewInput, StreamInfo^.NewSize, Buffer, Res);
    else
      exit;
    end;
    Result := True;
    Funcs^.LogProcess(CryptoCodecs[GetBits(StreamInfo^.Option, 0, 3)], nil,
      StreamInfo^.OldSize, -1, -1, Result);
  end;
end;

function CryptoRestore(Instance, Depth: Integer; Input, InputExt: Pointer;
  StreamInfo: _StrInfo3; Output: _PrecompOutput; Funcs: PPrecompFuncs): Boolean;
var
  Buffer: PByte;
  X: Integer;
  Res: Integer;
begin
  Result := False;
  X := GetBits(StreamInfo.Option, 0, 3);
  Res := 0;
  if not Funcs^.GetResource(StreamInfo.Resource, nil, @Res) then
    exit;
  Buffer := Funcs^.Allocator(Instance, Res);
  if Funcs^.GetResource(StreamInfo.Resource, Buffer, @Res) then
  begin
    case X of
      XOR_CODEC:
        Funcs^.Encrypt('xor', Input, StreamInfo.NewSize, Buffer, Res);
      AES_CODEC:
        Funcs^.Encrypt('aes', Input, StreamInfo.NewSize, Buffer, Res);
      RC4_CODEC:
        Funcs^.Encrypt('rc4', Input, StreamInfo.NewSize, Buffer, Res);
    else
      exit;
    end;
    Output(Instance, Input, StreamInfo.OldSize);
    Result := True;
    Funcs^.LogRestore(CryptoCodecs[GetBits(StreamInfo.Option, 0, 3)], nil,
      StreamInfo.OldSize, -1, -1, Result);
  end;
end;

var
  I: Integer;

initialization

Codec.Names := [];
for I := Low(CryptoCodecs) to High(CryptoCodecs) do
begin
  Codec.Names := Codec.Names + [CryptoCodecs[I]];
  StockMethods.Add(CryptoCodecs[I]);
end;
Codec.Initialised := False;
Codec.Init := @CryptoInit;
Codec.Free := @CryptoFree;
Codec.Parse := @CryptoParse;
Codec.Scan1 := @CryptoScan1;
Codec.Scan2 := @CryptoScan2;
Codec.Process := @CryptoProcess;
Codec.Restore := @CryptoRestore;

end.
