[UNIT] BlowFish Encription

Iniciado por Expermicid, Junio 11, 2013, 09:39:39 PM

Tema anterior - Siguiente tema

0 Miembros y 1 Visitante están viendo este tema.

Código: delphi
unit Blowfish;
{
  (c) 1998, 1999, 2000 Budi Sukmawan
  mailto:budskman [at] yahoo [dot] com
  [url]http://www.bimacipta.com/[/url]

  1998.04.17 written by Budi Sukmawan <[email protected]>
  1999.03.25 Add ECB, CBC, CTS, CFB, OFB routine.
  1999.11.06 Change Setup key routine.
             Fix CBC, CBC CTS, CFB, OFB routine.
  1999.12.03 change type casting at endian conversion
             small performance adv. [-12 clock/round)
  2000.04.21 Simplify routine for publication
             CBC mode only
}
interface

uses Windows, SysUtils;

const
  BF_BLOCKSIZE = 8;    { Blowfish block size }
  BF_SBOX_SIZE = 256;  { Number of S-box entries }
  BF_SBOX_SIZE_BYTES = ( BF_SBOX_SIZE * 4 );
  BF_PARRAY_SIZE = 18; { Number of P-array entries }
  BF_NO_ROUNDS = 16;
  IVSIZE = BF_BLOCKSIZE;

type
{$ifndef VER80}{$ifndef VER90}{$ifndef VER93}
{$ifndef VER100}{$ifndef VER110}
{$define D4UP}
{$endif}{$endif}{$endif}{$endif}{$endif}

{$ifndef D4UP}
  LongWord = LongInt;
{$endif}

  TSBox = array [0..BF_SBOX_SIZE-1] of LongWord;
  TPArr = array [0..BF_PARRAY_SIZE-1] of LongWord;
  TBFBlock = array [0..BF_BLOCKSIZE-1] of Byte;
  TIV = array [0..IVSIZE-1] of Byte;
  PBA = PByteArray;
  PLA = ^TLongArray;
  TLongArray = array[0..(4*1024)-1] of LongWord;

{$I BF_Init.Inc}

type
  PBlowFishKey = ^TBlowFishKey;
  TBlowFishKey = record
    P: TPArr;                { P-array }
    S1, S2, S3, S4: TSBox;   { S-boxes }
  end;

  TCryptCtx = record
    { User encryption key }
    key: TBlowFishKey; { kunci Blowfish }
    IV,                { Initial IV }
    currentIV: TIV;    { IV }
  end;

  procedure bfEncrypt(const key: TBlowFishKey;const inBlock;var outBlock);
  procedure bfDecrypt(const key: TBlowFishKey;const inBlock;var outBlock);
  procedure bfKeySetup(var key: TBlowFishKey;const pUserKey;
                       userKeyLen: Integer );
  function bfSelfTest: Integer;
  procedure bfEncryptCBC(var cryptCtx: TCryptCtx; var pBuffer; bufLen: Integer);
  procedure bfDecryptCBC(var cryptCtx: TCryptCtx; var pBuffer; bufLen: Integer);
  procedure bfResetContext(var cryptCtx: TCryptCtx);
  function bfModeSelfTest: Integer;

implementation

procedure bfEncrypt(const key: TBlowFishKey;const inBlock;var outBlock);
var
  L, R, i: LongWord;

begin
  { get data  }
  L := (LongWord(TByteArray(inBlock)[0]) shl 24) or
       (LongWord(TByteArray(inBlock)[1]) shl 16) or
       (LongWord(TByteArray(inBlock)[2]) shl 8) or
        LongWord(TByteArray(inBlock)[3]);
  R := (LongWord(TByteArray(inBlock)[4]) shl 24) or
       (LongWord(TByteArray(inBlock)[5]) shl 16) or
       (LongWord(TByteArray(inBlock)[6]) shl 8) or
        LongWord(TByteArray(inBlock)[7]);
  { Perform 16 rounds of encryption }
  with key do
  begin
    i := 1;
    L := L xor P[0];
    while i <= BF_NO_ROUNDS do
    begin
      R := R xor P[i] xor
           (((S1[L shr 24] + S2[Byte(L shr 16)]) xor
              S3[Byte(L shr 8)]) + S4[Byte(L)]);
      inc(i);
      L := L xor P[i] xor
           (((S1[R shr 24] + S2[Byte(R shr 16)]) xor
              S3[Byte(R shr 8)]) + S4[Byte(R)]);
      inc(i);
    end;
    R := R xor P[BF_NO_ROUNDS + 1];
  end;
  { put data back }
  TByteArray(outBlock)[0] := R shr 24;
  TByteArray(outBlock)[1] := Byte(R shr 16);
  TByteArray(outBlock)[2] := Byte(R shr  8);
  TByteArray(outBlock)[3] := Byte(R);
  TByteArray(outBlock)[4] := L shr 24;
  TByteArray(outBlock)[5] := Byte(L shr 16);
  TByteArray(outBlock)[6] := Byte(L shr  8);
  TByteArray(outBlock)[7] := Byte(L);
end;

procedure bfDecrypt(const key: TBlowFishKey;const inBlock;var outBlock);
var
  L, R, i: LongWord;

begin
  { get data }
  R := (LongWord(TByteArray(inBlock)[0]) shl 24) or
       (LongWord(TByteArray(inBlock)[1]) shl 16) or
       (LongWord(TByteArray(inBlock)[2]) shl 8) or
        LongWord(TByteArray(inBlock)[3]);
  L := (LongWord(TByteArray(inBlock)[4]) shl 24) or
       (LongWord(TByteArray(inBlock)[5]) shl 16) or
       (LongWord(TByteArray(inBlock)[6]) shl 8) or
        LongWord(TByteArray(inBlock)[7]);
  { Perform 16 rounds of decryption }
  with key do
  begin
    i := BF_NO_ROUNDS;
    R := R xor P[BF_NO_ROUNDS + 1];
    while i >= 1 do
    begin
      L := L xor P[i] xor
           (((S1[R shr 24] + S2[Byte(R shr 16)]) xor
              S3[Byte(R shr 8)]) + S4[Byte(R)]);
      dec(i);
      R := R xor P[i] xor
           (((S1[L shr 24] + S2[Byte(L shr 16)]) xor
              S3[Byte(L shr 8)]) + S4[Byte(L)]);
      dec(i);
    end;
    L := L xor P[0];
  end;
  { put data back }
  TByteArray(outBlock)[0] := L shr 24;
  TByteArray(outBlock)[1] := Byte(L shr 16);
  TByteArray(outBlock)[2] := Byte(L shr  8);
  TByteArray(outBlock)[3] := Byte(L);
  TByteArray(outBlock)[4] := R shr 24;
  TByteArray(outBlock)[5] := Byte(R shr 16);
  TByteArray(outBlock)[6] := Byte(R shr  8);
  TByteArray(outBlock)[7] := Byte(R);
end;

{These only for key setup, no endian conversion needed}
procedure bfInitEncrypt(const key: TBlowFishKey;var data1, data2: LongWord);
var
  L, R, i: LongWord;
begin
  L := data1;
  R := data2;
  with key do
  begin
    i := 1;
    L := L xor P[0];
    while i <= BF_NO_ROUNDS do
    begin
      R := R xor P[i] xor
           (((S1[L shr 24] + S2[Byte(L shr 16)]) xor
              S3[Byte(L shr 8)]) + S4[Byte(L)]);
      inc(i);
      L := L xor P[i] xor
           (((S1[R shr 24] + S2[Byte(R shr 16)]) xor
              S3[Byte(R shr 8)]) + S4[Byte(R)]);
      inc(i);
    end;
    R := R xor P[BF_NO_ROUNDS + 1];
  end;
  data1 := R;
  data2 := L;
end;

procedure bfKeySetup(var key: TBlowFishKey;const pUserKey; userKeyLen: Integer);
var
  userKey: PByte;
  keyIndex, i, j, byteIndex: Integer;
  data1, data2: LongWord;
  sBox: PLA;
begin
  userKey := @pUserKey;
  for i := 0 to (BF_NO_ROUNDS + 2) - 1 do
    key.P[i] := initialParray[i];
  for i := 0 to BF_SBOX_SIZE-1 do
  begin
    key.S1[i] := initialSbox1[i];
    key.S2[i] := initialSbox2[i];
    key.S3[i] := initialSbox3[i];
    key.S4[i] := initialSbox4[i];
  end;
  keyIndex := 0;
  for i := 0 to (BF_NO_ROUNDS + 2) - 1 do
  begin
    data1 := 0;
    for byteIndex := 0 to 3 do
    begin
      data1 := data1 shl 8;
      data1 := data1 or LongWord(PByteArray(userKey)[keyIndex]);
      inc(keyIndex);
      keyIndex := keyIndex mod userKeyLen;
    end;
    key.P[i] := key.P[i] xor data1;
  end;
  data1 := 0;
  data2 := 0;
  i := 0 ;
  while i < (BF_NO_ROUNDS + 2) do
  begin
    bfInitEncrypt(key, data1, data2);
    key.P[i] := data1;
    key.P[i+1] := data2;
    inc(i,2);
  end;
  sBox := nil;
  for j := 0 to 3 do
  begin
    case j of
     0: sBox := @key.S1;
     1: sBox := @key.S2;
     2: sBox := @key.S3;
     3: sBox := @key.S4;
    end;
    i := 0;
    while i < BF_SBOX_SIZE do
    begin
      bfInitEncrypt(key, data1, data2);
      sBox[i] := data1;
      sBox[i+1] := data2;
      Inc(i, 2);
    end;
  end;
end;

(***************************************************************
*                 Blowfish Mode of Operation                  *
***************************************************************)

procedure bfResetContext(var cryptCtx: TCryptCtx);
begin
  Move(cryptCtx.IV, cryptCtx.currentIV, IVSIZE);
end;

{ Encrypt data in CBC (Cipher Block Chaining) Mode}
procedure bfEncryptCBC(var cryptCtx: TCryptCtx; var pBuffer; bufLen: Integer);
var
  buffer, currentIV: PByte;
begin
  assert( ( bufLen mod BF_BLOCKSIZE ) = 0,
         'Data length is must be multiple of the block size');
  buffer := @pBuffer;
  currentIV := @cryptCtx.currentIV;
  while bufLen >= BF_BLOCKSIZE do
  begin
    PLA(buffer)^[0] := PLA(buffer)^[0] xor PLA(currentIV)^[0];
    PLA(buffer)^[1] := PLA(buffer)^[1] xor PLA(currentIV)^[1];
    bfEncrypt(cryptCtx.key, buffer^, buffer^);
    currentIV := buffer;
    Inc(buffer, BF_BLOCKSIZE);
    Dec(bufLen, BF_BLOCKSIZE);
  end;
  {Move(currentIV^, cryptCtx.currentIV, BF_BLOCKSIZE);}
  PLA(@cryptCtx.currentIV)^[0] := PLA(currentIV)^[0];
  PLA(@cryptCtx.currentIV)^[1] := PLA(currentIV)^[1];
end;

{ Decrypt data in CBC mode }
procedure bfDecryptCBC(var cryptCtx: TCryptCtx; var pBuffer; bufLen: Integer);
var
  buffer: PByte;
  temp: TbfBlock;
begin
  assert( ( bufLen mod BF_BLOCKSIZE ) = 0,
         'Data length is must be multiple of the block size');
  buffer := @pBuffer;
  while bufLen >= BF_BLOCKSIZE do
  begin
    {Move(buffer^, temp, BF_BLOCKSIZE);}
    PLA(@temp)^[0] := PLA(buffer)^[0];
    PLA(@temp)^[1] := PLA(buffer)^[1];
    bfDecrypt(cryptCtx.key, buffer^, buffer^);
    PLA(buffer)^[0] := PLA(buffer)^[0] xor PLA(@cryptCtx.currentIV)^[0];
    PLA(buffer)^[1] := PLA(buffer)^[1] xor PLA(@cryptCtx.currentIV)^[1];
    {Move(temp, cryptCtx.currentIV, BF_BLOCKSIZE);}
    PLA(@cryptCtx.currentIV)^[0] := PLA(@temp)^[0];
    PLA(@cryptCtx.currentIV)^[1] := PLA(@temp)^[1];
    Inc(buffer, BF_BLOCKSIZE);
    Dec(bufLen, BF_BLOCKSIZE);
  end;
end;

(***************************************************************
*                      Blowfish Self Test                     *
***************************************************************)
type
  TBlock64 = array [0..7] of byte;
  TBfTest = record
    key: TBlock64;
    pt: TBlock64;
    ct: TBlock64;
  end;

const
  plain1: PChar = 'BLOWFISH';
  key1: PChar = 'abcdefghijklmnopqrstuvwxyz';
  cipher1: TBFBlock = ($32,$4E,$D0,$FE,$F4,$13,$A2,$03);

  plain2: TBFBlock = ($FE,$DC,$BA,$98,$76,$54,$32,$10);
  key2: PChar = 'Who is John Galt?';
  cipher2: TBFBlock = ($CC,$91,$73,$2B,$80,$22,$F6,$84);

  plain3: TBFBlock = ($FE, $DC, $BA, $98, $76, $54, $32, $10);
  key3: TBFBlock = ($41, $79, $6E, $A0, $52, $61, $6E, $E4);
  cipher3: TBFBlock = ($E1, $13, $F4, $10, $2C, $FC, $CE, $43);

  bfTest : array[0..33] of TBfTest = (
    (key : ($00, $00, $00, $00, $00, $00, $00, $00);
     pt  : ($00, $00, $00, $00, $00, $00, $00, $00);
     ct  : ($4E, $F9, $97, $45, $61, $98, $DD, $78)),
    (key : ($FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF);
     pt  : ($FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF);
     ct  : ($51, $86, $6F, $D5, $B8, $5E, $CB, $8A)),
    (key : ($30, $00, $00, $00, $00, $00, $00, $00);
     pt  : ($10, $00, $00, $00, $00, $00, $00, $01);
     ct  : ($7D, $85, $6F, $9A, $61, $30, $63, $F2)),
    (key : ($11, $11, $11, $11, $11, $11, $11, $11);
     pt  : ($11, $11, $11, $11, $11, $11, $11, $11);
     ct  : ($24, $66, $DD, $87, $8B, $96, $3C, $9D)),
    (key : ($01, $23, $45, $67, $89, $AB, $CD, $EF);
     pt  : ($11, $11, $11, $11, $11, $11, $11, $11);
     ct  : ($61, $F9, $C3, $80, $22, $81, $B0, $96)),
    (key : ($11, $11, $11, $11, $11, $11, $11, $11);
     pt  : ($01, $23, $45, $67, $89, $AB, $CD, $EF);
     ct  : ($7D, $0C, $C6, $30, $AF, $DA, $1E, $C7)),
    (key : ($00, $00, $00, $00, $00, $00, $00, $00);
     pt  : ($00, $00, $00, $00, $00, $00, $00, $00);
     ct  : ($4E, $F9, $97, $45, $61, $98, $DD, $78)),
    (key : ($FE, $DC, $BA, $98, $76, $54, $32, $10);
     pt  : ($01, $23, $45, $67, $89, $AB, $CD, $EF);
     ct  : ($0A, $CE, $AB, $0F, $C6, $A0, $A2, $8D)),
    (key : ($7C, $A1, $10, $45, $4A, $1A, $6E, $57);
     pt  : ($01, $A1, $D6, $D0, $39, $77, $67, $42);
     ct  : ($59, $C6, $82, $45, $EB, $05, $28, $2B)),
    (key : ($01, $31, $D9, $61, $9D, $C1, $37, $6E);
     pt  : ($5C, $D5, $4C, $A8, $3D, $EF, $57, $DA);
     ct  : ($B1, $B8, $CC, $0B, $25, $0F, $09, $A0)),
    (key : ($07, $A1, $13, $3E, $4A, $0B, $26, $86);
     pt  : ($02, $48, $D4, $38, $06, $F6, $71, $72);
     ct  : ($17, $30, $E5, $77, $8B, $EA, $1D, $A4)),
    (key : ($38, $49, $67, $4C, $26, $02, $31, $9E);
     pt  : ($51, $45, $4B, $58, $2D, $DF, $44, $0A);
     ct  : ($A2, $5E, $78, $56, $CF, $26, $51, $EB)),
    (key : ($04, $B9, $15, $BA, $43, $FE, $B5, $B6);
     pt  : ($42, $FD, $44, $30, $59, $57, $7F, $A2);
     ct  : ($35, $38, $82, $B1, $09, $CE, $8F, $1A)),
    (key : ($01, $13, $B9, $70, $FD, $34, $F2, $CE);
     pt  : ($05, $9B, $5E, $08, $51, $CF, $14, $3A);
     ct  : ($48, $F4, $D0, $88, $4C, $37, $99, $18)),
    (key : ($01, $70, $F1, $75, $46, $8F, $B5, $E6);
     pt  : ($07, $56, $D8, $E0, $77, $47, $61, $D2);
     ct  : ($43, $21, $93, $B7, $89, $51, $FC, $98)),
    (key : ($43, $29, $7F, $AD, $38, $E3, $73, $FE);
     pt  : ($76, $25, $14, $B8, $29, $BF, $48, $6A);
     ct  : ($13, $F0, $41, $54, $D6, $9D, $1A, $E5)),
    (key : ($07, $A7, $13, $70, $45, $DA, $2A, $16);
     pt  : ($3B, $DD, $11, $90, $49, $37, $28, $02);
     ct  : ($2E, $ED, $DA, $93, $FF, $D3, $9C, $79)),
    (key : ($04, $68, $91, $04, $C2, $FD, $3B, $2F);
     pt  : ($26, $95, $5F, $68, $35, $AF, $60, $9A);
     ct  : ($D8, $87, $E0, $39, $3C, $2D, $A6, $E3)),
    (key : ($37, $D0, $6B, $B5, $16, $CB, $75, $46);
     pt  : ($16, $4D, $5E, $40, $4F, $27, $52, $32);
     ct  : ($5F, $99, $D0, $4F, $5B, $16, $39, $69)),
    (key : ($1F, $08, $26, $0D, $1A, $C2, $46, $5E);
     pt  : ($6B, $05, $6E, $18, $75, $9F, $5C, $CA);
     ct  : ($4A, $05, $7A, $3B, $24, $D3, $97, $7B)),
    (key : ($58, $40, $23, $64, $1A, $BA, $61, $76);
     pt  : ($00, $4B, $D6, $EF, $09, $17, $60, $62);
     ct  : ($45, $20, $31, $C1, $E4, $FA, $DA, $8E)),
    (key : ($02, $58, $16, $16, $46, $29, $B0, $07);
     pt  : ($48, $0D, $39, $00, $6E, $E7, $62, $F2);
     ct  : ($75, $55, $AE, $39, $F5, $9B, $87, $BD)),
    (key : ($49, $79, $3E, $BC, $79, $B3, $25, $8F);
     pt  : ($43, $75, $40, $C8, $69, $8F, $3C, $FA);
     ct  : ($53, $C5, $5F, $9C, $B4, $9F, $C0, $19)),
    (key : ($4F, $B0, $5E, $15, $15, $AB, $73, $A7);
     pt  : ($07, $2D, $43, $A0, $77, $07, $52, $92);
     ct  : ($7A, $8E, $7B, $FA, $93, $7E, $89, $A3)),
    (key : ($49, $E9, $5D, $6D, $4C, $A2, $29, $BF);
     pt  : ($02, $FE, $55, $77, $81, $17, $F1, $2A);
     ct  : ($CF, $9C, $5D, $7A, $49, $86, $AD, $B5)),
    (key : ($01, $83, $10, $DC, $40, $9B, $26, $D6);
     pt  : ($1D, $9D, $5C, $50, $18, $F7, $28, $C2);
     ct  : ($D1, $AB, $B2, $90, $65, $8B, $C7, $78)),
    (key : ($1C, $58, $7F, $1C, $13, $92, $4F, $EF);
     pt  : ($30, $55, $32, $28, $6D, $6F, $29, $5A);
     ct  : ($55, $CB, $37, $74, $D1, $3E, $F2, $01)),
    (key : ($01, $01, $01, $01, $01, $01, $01, $01);
     pt  : ($01, $23, $45, $67, $89, $AB, $CD, $EF);
     ct  : ($FA, $34, $EC, $48, $47, $B2, $68, $B2)),
    (key : ($1F, $1F, $1F, $1F, $0E, $0E, $0E, $0E);
     pt  : ($01, $23, $45, $67, $89, $AB, $CD, $EF);
     ct  : ($A7, $90, $79, $51, $08, $EA, $3C, $AE)),
    (key : ($E0, $FE, $E0, $FE, $F1, $FE, $F1, $FE);
     pt  : ($01, $23, $45, $67, $89, $AB, $CD, $EF);
     ct  : ($C3, $9E, $07, $2D, $9F, $AC, $63, $1D)),
    (key : ($00, $00, $00, $00, $00, $00, $00, $00);
     pt  : ($FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF);
     ct  : ($01, $49, $33, $E0, $CD, $AF, $F6, $E4)),
    (key : ($FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF);
     pt  : ($00, $00, $00, $00, $00, $00, $00, $00);
     ct  : ($F2, $1E, $9A, $77, $B7, $1C, $49, $BC)),
    (key : ($01, $23, $45, $67, $89, $AB, $CD, $EF);
     pt  : ($00, $00, $00, $00, $00, $00, $00, $00);
     ct  : ($24, $59, $46, $88, $57, $54, $36, $9A)),
    (key : ($FE, $DC, $BA, $98, $76, $54, $32, $10);
     pt  : ($FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF);
     ct  : ($6B, $5C, $5A, $9C, $5D, $9E, $0A, $5A))
  );

function bfSelfTest: Integer;
var
  bfKey: TBlowFishKey;
  buffer: TBlock64;
  i: Integer;
begin
  { Test #1 }
  Move(plain1^, buffer, 8 );
  bfKeySetup(bfKey, key1^, StrLen(key1));
  bfEncrypt(bfKey, buffer, buffer);
  if not (CompareMem(@buffer[0], @cipher1[0], 8 )) then
  begin
    Result := -11;
    exit;
  end;
  bfDecrypt(bfKey, buffer, buffer);
  if not (CompareMem(@buffer[0], @plain1^, 8 )) then
  begin
    Result := -21;
    exit;
  end;
  { Test #2 }
  Move(plain2, buffer, 8 );
  bfKeySetup(bfKey, key2^, StrLen(key2));
  bfEncrypt(bfKey, buffer, buffer);
  if not (CompareMem(@buffer[0], @cipher2[0], 8 )) then
  begin
    Result := -12;
    exit;
  end;
  bfDecrypt(bfKey, buffer, buffer);
  if not (CompareMem(@buffer[0], @plain2, 8 )) then
  begin
    Result := -22;
    exit;
  end;
  { Test #3 }
  Move(plain3, buffer, 8);
  bfKeySetup(bfKey, key3, SizeOf(key3));
  bfEncrypt(bfKey, buffer, buffer);
  if not (CompareMem(@buffer[0], @cipher3[0], 8 )) then
  begin
    Result := -13;
    exit;
  end;
  bfDecrypt(bfKey, buffer, buffer);
  if not (CompareMem(@buffer[0], @plain3, 8 )) then
  begin
    Result := -23;
    exit;
  end;
  { Test #4 }
  for i := 0 to (SizeOf(bfTest) div SizeOf(TBfTest))-1 do
  begin
    bfKeySetup(bfKey, bfTest[i].key, SizeOf(bfTest[i].key));
    Move(bfTest[i].pt, buffer, SizeOf(TBlock64));
    bfEncrypt(bfKey, buffer, buffer);
    if not CompareMem(@buffer, @bfTest[i].ct, SizeOf(TBlock64)) then
    begin
      Result := -100 - i ;
      Exit;
    end;
    bfDecrypt(bfKey, buffer, buffer);
    if not CompareMem(@buffer, @bfTest[i].pt, SizeOf(TBlock64)) then
    begin
      Result := -200 - i ;
      Exit;
    end;
  end;
  Result := 0;
end;

function bfModeSelfTest: Integer;
var
  data: PByte;
  retval: Integer;
  CryptCtx: TCryptCtx;
begin
  retval := 0;
  GetMem(data, SizeOf(bfTest));
  try
    Move(bfTest, data^, SizeOf(bfTest));
    {Init.}
    FillChar(CryptCtx, SizeOf(TCryptCtx), 0);
    bfKeySetup(CryptCtx.key, key1^, StrLen(key1));
    {Encrypt}
    bfResetContext(cryptCtx);
    bfEncryptCBC(cryptCtx, data^, SizeOf(bfTest));
    {Decrypt}
    bfResetContext(cryptCtx);
    bfDecryptCBC(cryptCtx, data^, SizeOf(bfTest));
    if not CompareMem(data, @bfTest, SizeOf(bfTest)) then
      retval := -300
  finally
    FreeMem(data, SizeOf(bfTest));
  end;
  Result := retval;
end;

end.


Saludos