unit CryptUtils;

interface

uses
  Windows, SysUtils;

procedure Encrypt_Simple(AInput: array of Byte; AInputLength: Integer;
  var AOutput: array of Byte);

procedure Decrypt_Simple(AInput: array of Byte; AInputLength: Integer;
  var AOutput: array of Byte; var AOutputLength: Integer);

procedure Encrypt_BlowFish(AKey: string;
  APInput: Pointer; AInputLength: Integer;
  var APOutput: Pointer; var AOutputLength: Integer);

procedure Decrypt_BlowFish(AKey: string;
  APInput: Pointer; AInputLength: Integer;
  var APOutput: Pointer; var AOutputLength: Integer);

function GetOutputLength(AEncryptData: array of Byte): Integer;

implementation

uses
  BlowUnit, Cryptcon;

const
  // 数据长度信息占用空间大小
  LengthSize: Integer = 4;

function GetOutputLength(AEncryptData: array of Byte): Integer;
var
  I: Integer;
  strHexLength: string;
begin
  strHexLength := '';
  try
    for I := 0 to 3 do
    begin
      strHexLength := strHexLength + IntToHex(Byte(AEncryptData[I]), 2);
    end;
    Result := StrToInt('$' + strHexLength);
  except
    raise Exception.Create('加密数据不正确！');
  end;
end;

procedure Encrypt_Simple(AInput: array of Byte; AInputLength: Integer;
  var AOutput: array of Byte);
var
  I, iTemp: Integer;
  arrBuf: array of Byte;
  strHexLength: string;
begin
  SetLength(arrBuf, AInputLength);
  SetLength(strHexLength, LengthSize * 2);
  ZeroMemory(@arrBuf[0], AInputLength * SizeOf(Byte));
  ZeroMemory(@AOutput[0], (AInputLength + LengthSize) * SizeOf(Byte));
  CopyMemory(@arrBuf[0], @AInput[0], AInputLength * SizeOf(Byte));
  for I := 0 to AInputLength - 1 do
  begin
    AOutput[I] := arrBuf[AInputLength - I - 1];
  end;
  for I := 0 to AInputLength - 1 do
  begin
    arrBuf[I] := $FF - Byte(AOutput[I]);
  end;
  for I := 0 to AInputLength - 1 do
  begin
    if not Odd(I) then
    begin
      if(I + 1 < AInputLength) then
        AOutput[I + LengthSize] := arrBuf[I + 1]
      else
        AOutput[I + LengthSize] := arrBuf[I];
    end
    else
      AOutput[I + LengthSize] := arrBuf[I - 1];
  end;
  strHexLength := IntToHex(AInputLength, 8);
  for I := 0 to LengthSize - 1 do
    AOutput[I] := StrToInt('$' + strHexLength[I * 2 + 1] + strHexLength[I * 2 + 2]);
end;

procedure Decrypt_Simple(AInput: array of Byte; AInputLength: Integer;
  var AOutput: array of Byte; var AOutputLength: Integer);
var
  I, iTemp: Integer;
  arrBuf1: array of Byte;
  arrBuf2: array of Byte;
  strHexLength: string;
begin
  strHexLength := '';
  for I := 0 to 3 do
  begin
    strHexLength := strHexLength + IntToHex(Byte(AInput[I]), 2);
  end;
  AOutputLength := StrToInt('$' + strHexLength);
  SetLength(arrBuf1, AInputLength - LengthSize);
  SetLength(arrBuf2, AOutputLength);
  SetLength(strHexLength, LengthSize * 2);
  ZeroMemory(@arrBuf1[0], (AInputLength - LengthSize) * SizeOf(Byte));
  ZeroMemory(@arrBuf2[0], AOutputLength * SizeOf(Byte));
  ZeroMemory(@AOutput[0], AOutputLength * SizeOf(Byte));
  for I := 0 to AInputLength - LengthSize - 1 do
  begin
    if not Odd(I) then
    begin
      if (I + 1 < AOutputLength) then
        arrBuf1[I] := AInput[I + 1 + LengthSize]
      else
        arrBuf1[I] := AInput[I + LengthSize];
    end
    else
      arrBuf1[I] := AInput[I - 1 + LengthSize];
  end;
  for I := 0 to AOutputLength - 1 do
  begin
    arrBuf2[I] := $FF - Byte(arrBuf1[I]);
  end;
  for I := 0 to AOutputLength - 1 do
  begin
    AOutput[I] := arrBuf2[AOutputLength - I - 1];
  end;
end;

procedure Encrypt_BlowFish(AKey: string;
  APInput: Pointer; AInputLength: Integer;
  var APOutput: Pointer; var AOutputLength: Integer);
var
  BL: TBlowFish;
  arrBuf: array of Byte;
  arrInputBuf: array of Byte;
  arrOutputBuf: array of Byte;
  iOutputLength: Integer;
  strHexLength: string;
  I: Integer;
begin
  BL := TBlowFish.Create(nil);
  try
    BL.CipherMode := ECBMode;
    BL.InputType := SourceByteArray;

    iOutputLength := AInputLength;
    if iOutputLength mod 8 <> 0 then
      iOutputLength :=  8 * (iOutputLength div 8 + 1);

    AOutputLength := (iOutputLength + SizeOf(Integer)) * SizeOf(Byte);
    if not Assigned(APOutput) then
      APOutput := AllocMem(AOutputLength);

    SetLength(arrBuf, iOutputLength);
    SetLength(arrInputBuf, AInputLength);
    SetLength(arrOutputBuf, AOutputLength);
    SetLength(strHexLength, LengthSize * 2);
    ZeroMemory(@arrBuf[0], iOutputLength * SizeOf(Byte));
    ZeroMemory(@arrInputBuf[0], AInputLength * SizeOf(Byte));
    ZeroMemory(@arrOutputBuf[0], AOutputLength * SizeOf(Byte));
    ZeroMemory(APOutput, AOutputLength);

    CopyMemory(@arrInputBuf[0], APInput, AInputLength);

    BL.InputLength := AInputLength;
    BL.pInputArray := @arrInputBuf[0];
    BL.pOutputArray := @arrBuf[0];
    BL.Key := AKey;
    BL.EncipherData(False);

    strHexLength := IntToHex(AInputLength, LengthSize * 2);

    for I := 0 to SizeOf(Integer) - 1 do
      arrOutputBuf[I] := StrToInt('$' + strHexLength[I * 2 + 1] + strHexLength[I * 2 + 2]);
    CopyMemory(@arrOutputBuf[SizeOf(Integer) - 1], @arrBuf[0], Length(arrBuf));

    CopyMemory(APOutput, @arrOutputBuf[0], AOutputLength);
  finally
    BL.Free;
  end;
end;

procedure Decrypt_BlowFish(AKey: string;
  APInput: Pointer; AInputLength: Integer;
  var APOutput: Pointer; var AOutputLength: Integer);
var
  BL: TBlowFish;
  I: Integer;
  arrBuf: array of Byte;
  arrInputBuf: array of Byte;
  arrOutBuf: array of Byte;
  iOutputLength: Integer;
  strHexLength: string;
begin
  BL := TBlowFish.Create(nil);
  try
    SetLength(arrBuf, AInputLength - LengthSize);
    SetLength(arrInputBuf, AInputLength);
    SetLength(strHexLength, LengthSize * 2);

    ZeroMemory(@arrBuf[0], (AInputLength - LengthSize) * Sizeof(Byte));
    ZeroMemory(@arrInputBuf[0], AInputLength * Sizeof(Byte));
    CopyMemory(@arrInputBuf[0], APInput, AInputLength * SizeOf(Byte));
    CopyMemory(@arrBuf[0], @arrInputBuf[4], (AInputLength - LengthSize) * SizeOf(Byte));

    strHexLength := '';
    for I := 0 to 3 do
    begin
      strHexLength := strHexLength + IntToHex(arrInputBuf[I], 2);
    end;
    iOutputLength := StrToInt('$' + strHexLength);
    SetLength(arrOutBuf, iOutputLength);
    ZeroMemory(@arrOutBuf[0], iOutputLength * Sizeof(Byte));

    BL.CipherMode := ECBMode;
    BL.InputType := SourceByteArray;
    BL.InputLength := AInputLength - LengthSize;
    BL.pInputArray := @arrBuf[0];
    BL.pOutputArray := {@arrOutBuf[0];//}@arrOutBuf[0];
    BL.Key := AKey; //'SmartCost2004';
    BL.DecipherData(False);
    if not Assigned(APOutput) then
      APOutput := AllocMem(iOutputLength);
    CopyMemory(APOutput, @arrOutBuf[0], iOutputLength * SizeOf(Byte));
    AOutputLength := iOutputLength;
  finally
    BL.Free;
  end;
end;

end.
