UNIT _BFISH5;

 (* ********************************************************************** *)
 (*                         BlowFish Algorithm Unit                        *)
 (*                    Hereby distributed as OPEN SOURCE                   *)
 (*                 Copyrighted by (2001) Dutra de Lacerda                 *)
 (* ********************************************************************** *)
 (*                                                                        *)
 (* This code is Open Source in respect to the similar status of Blowfish  *)
 (* It is Copyrighted by "(2001) Dutra de Lacerda"                         *)
 (* You are allowed to use it with the usual conditions:                   *)
 (*   - Maintain this Copyright notice in the code.                        *)
 (*   - Make reference to this code, and Author, in your application.      *)
 (*   - Graciously communicate the Author your use of this code.           *)
 (*                                                                        *)
 (* ---------------------------------------------------------------------- *)
 (*                                                                        *)
 (*                           Finding the Author                           *)
 (*                           ~~~~~~~~~~~~~~~~~~                           *)
 (*  This units author can be reached via the following E-Mail addresses:  *)
 (*                                                                        *)
 (*      Via InterNet    : dulac@ip.pt                                     *)
 (*            ...and    : dutra.lacerda@mail.telepac.pt                   *)
 (*                                                                        *)
 (* ---------------------------------------------------------------------- *)
 (*                                                                        *)
 (*                          Finding New Versions                          *)
 (*                          ~~~~~~~~~~~~~~~~~~~~                          *)
 (*      My Home Site    : http://planeta.ip.pt/~ip200075                  *)
 (*            ...and    : http://www.factor-h.com                         *)
 (*                                                                        *)
 (*      Net Archives    : ftp://garbo.uwasa.fi/pc/crypt                   *)
 (*                      : ftp://garbo.uwasa.fi/pc/security                *)
 (*                      : ftp://ftp.elf.stuba.sk/pub/pc/security          *)
 (*                                                                        *)
 (* ---------------------------------------------------------------------- *)

 (* ---------------------------------------------------------------------- *)
 (*                               BLOWFISH                                 *)
 (*                               ~~~~~~~~                                 *)
 (*  The original source code in C was published in Dr. Dobb's Journal of  *)
 (*  April 1994...  An improvement to the initialization routine appeared  *)
 (*  on Dr. Dobbs's September 1995 edition...   This code closely follows  *)
 (*  this last definition of the algorithm implementing it using Objects.  *)
 (*                                                                        *)
 (*  This code implements both Standart Blowfish as redefined in Sept/95,  *)
 (*  ALSO implements a variation, BFC15,  made possible by the ingenious   *)
 (*  stucture of the algorithm where it's the arquitecture, not the order  *)
 (*  of the elements (big or little-endian), that gives it's strenght.     *)
 (*  This liberty is not possible in other powerfull algorithms.           *)
 (*                                                                        *)
 (*  The variations in BFC15 are limited to:                               *)
 (*     1 - The inversion of variable use in the F function...             *)
 (*     2 - Initial PArray Encrypted                                       *)
 (*         a) in sequence P[i]=E(P[i-1]) and                              *)
 (*         b) starting with an I.V. of $AAAAAAAA instead of Zero          *)
 (*     3 - Little Endian Code for Performance.                            *)
 (*     4 - Future definition of number of loops greater than 16.          *)
 (*                                                                        *)
 (*  I've choosen this variation by the following reasons:                 *)
 (*     1 - Assumption that a different output MIGHT dificult analysis...  *)
 (*     2 - The original code i was based on.                              *)
 (*     3 - Performance on x86 Processors.                                 *)
 (*                                                                        *)
 (* ---------------------------------------------------------------------- *)
 (*                                                                        *)
 (*  The author of the Blowfish algorithm (not this code) can be reached:  *)
 (*      Via InterNet    : schneier@chinet.com                             *)
 (*                                                                        *)
 (*  The author of this Unit (this code) can be reached:                   *)
 (*      Via InterNet    : dulac@ip.pt                                     *)
 (*                                                                        *)
 (* ---------------------------------------------------------------------- *)

INTERFACE      {========================================================}

uses _Feistel;

const
  st_rounds     = 16;       {  16 is the standart value. MAXIMUM is 111 !!!  }
  my_MaxRounds  = 111;      { Maximum number of rounds... P-Boxes=111+2=113  }
  st_PBox_IV    = 0;        { Standart PBox IV used in PBox Initialization   }
  my_PBox_IV    = $AAAAAAAA;{ My own PBox IV for the PBox Initialization     }

type
    PArray        = Array[0..(my_MaxRounds+2)-1] of Atom32;
    SBox          = Array[0..3, 0..255] of Atom32;

    st_BFish = OBJECT (Crypt_2x32)
        PAtoms  : PArray;
        SBoxes  : SBox;
        Constructor Init ( var PSW :string );
      { Initialization of a key is needed before performing any encryption   }
      { or decryption of data.                                               }
        Procedure   Build ( var PSW :string ); VIRTUAL;
      { These two should speak for themselves                                }
      {     pBuf is a Pointer to the External Buffer                         }
      {     HowMany is the amount of 2x32 Blocks to enCrypt                  }
      { these two are the programmers responsibility for performance sake    }
        Procedure   EnCrypt ( pBuf :pointer; HowMany :integer ); VIRTUAL;
        Procedure   DeCrypt ( pBuf :pointer; HowMany :integer ); VIRTUAL;
      { SetRounds may be used to change the number of rounds or left alone   }
        Procedure   SetRounds( R :byte );
      { Termination is needed in order to free resources and secret Boxes    }
        Destructor  Done; VIRTUAL;
    End;

    BFC_PAS = OBJECT (st_BFish)
        Constructor Init( var PSW :string );
        Procedure   Build ( var PSW :string ); VIRTUAL;
        Procedure   EnCrypt ( pBuf :pointer; HowMany :integer ); VIRTUAL;
        Procedure   DeCrypt ( pBuf :pointer; HowMany :integer ); VIRTUAL;
        Destructor  Done; VIRTUAL;
    End;


{$IFDEF Use_Assembler}

    BFC_ASM = OBJECT (BFC_PAS)
        Constructor Init( var PSW :string );
        Procedure   EnCrypt ( pBuf :pointer; HowMany :integer ); VIRTUAL;
        Procedure   DeCrypt ( pBuf :pointer; HowMany :integer ); VIRTUAL;
        Destructor  Done; VIRTUAL;
    End;

    BFC_ASM16 = OBJECT (BFC_PAS)
        Constructor Init( var PSW :string );
        Procedure   EnCrypt ( pBuf :pointer; HowMany :integer ); VIRTUAL;
        Procedure   DeCrypt ( pBuf :pointer; HowMany :integer ); VIRTUAL;
        Destructor  Done; VIRTUAL;
    End;

    BFC_ASM32 = OBJECT (BFC_PAS)
        Constructor Init( var PSW :string );
        Procedure   EnCrypt ( pBuf :pointer; HowMany :integer ); VIRTUAL;
        Procedure   DeCrypt ( pBuf :pointer; HowMany :integer ); VIRTUAL;
        Destructor  Done; VIRTUAL;
    End;

{$ENDIF}


IMPLEMENTATION {========================================================}

const
  AtomSizeB     = SizeOf(Atom32);   {longint is 4 bytes long}
  BlockSizeA    = 2;                    {in 2x32 Crypts}
  BlockSizeB    = BlockSizeA * AtomSizeB; {each Crypt Block}

  PBoxSizeA     = my_MaxRounds+2;
  PBoxSizeB     = AtomSizeB * PBoxSizeA;
  SBoxSizeA     = 4*256;
  SBoxSizeB     = AtomSizeB * SBoxSizeA;

{
const
  RandomSeed in _PI_DATA.INC
}

{$I _PI_DATA.INC}

  (* ---------------------------------------------------------- *)
  (*                                                            *)
  (*                      _PI_DATA.INC                          *)
  (*                                                            *)
  (*        Contains the following Declarations and data:       *)
  (*                                                            *)
  (*        Type                                                *)
  (*           TSeedBuffer = {Follows Definition}               *)
  (*                                                            *)
  (*        Const                                               *)
  (*           RandomSeed : TSeedBuffer = {Follows Data}        *)
  (*                                                            *)
  (* ---------------------------------------------------------- *)


{*** Blowfish Standart ******************************************}

CONSTRUCTOR st_BFish.Init( var PSW :string );
  begin
  Crypt_2x32.Init( PSW );
  Rounds  := st_rounds;
  Will_Use_CBC(false);
  end;

PROCEDURE st_BFish.Build( var PSW :string );
  var
    i, j, k         : Integer;
    l               : Integer;
    AuxAtom         : Atom32;
    AuxBlock        : Block_2x32;

  begin
  Hold_CBC( True );

  { Initialize first the P-array... }

    for i := 0 to (Rounds+2)-1 do
        PAtoms[i].Atom := RandomSeed.Atoms[i].Atom;

  { ...and then the four S-boxes, in order, with a fixed random string. }
  { This string consists of the hexadecimal digits of Pi.               }

    l := Rounds + 2;
    for i := 0 to 3 do
      begin
        for j := 0 to 255 do SBoxes[i, j].Atom := RandomSeed.Atoms[l+j].Atom;
        l := l+256;
      end;

  { XOR P1 with the first 32 bits of the key, XOR P2 with the second    }
  { 32 bits of the key, and so on for all bits of the key (up to P18).  }
  { Cycle throught the key bits repeatedly until the entire P-array     }
  { has been XORed.                                                     }

    j := 1;
    for i := 0 to (st_rounds+1) do
      begin
        AuxAtom.Atom := st_Pbox_IV;
        for k := 0 to 3 do
          begin
            AuxAtom.byte[ 3-k ] := Ord(PSW[j]); (* This is Little-Endian *)
            Inc(j);
            if j > Length(PSW) then j := 1;
          end;
        PAtoms[i].Atom := PAtoms[i].Atom xor AuxAtom.Atom;
      end;

  { Encrypt the all-zero string using the Blowfish algorithm using     }
  { the subkeys described in steps #1 and #2 and replace the elements  }
  { of the P-array with the output of this process.                    }

    i:=0;
    while (i < st_rounds+1) do              { HERE YOU MAY LOSE COMPAT }
      begin
        AuxBlock[0].Atom := st_PBox_IV;
        AuxBlock[1].Atom := st_PBox_IV;
        EnCrypt( @AuxBlock, 2 );
        PAtoms[i].Atom := AuxBlock[0].Atom;
        Inc(i);
        PAtoms[i].Atom := AuxBlock[1].Atom;
        Inc(i);
      end;

  { Continue the process, replacing the elements of the four S-boxes in }
  { order, with the output of the continuously changing Blowfish Boxes. }

    for j := 0 to 3 do
      begin
        i := 0;
        while i < 255 do                   { HERE YOU MAY LOSE COMPAT }
          begin
            EnCrypt( @SBoxes, SBoxSizeA );
            SBoxes[j, i].Atom := AuxBlock[0].Atom;
            Inc(i);
            SBoxes[j, i].Atom := AuxBlock[1].Atom;
            Inc(i);
          end;
      end;

  { In total, 521 iterations are required to generate all required subkeys. }
  { ...Applications can store the subkeys rather than re-executing all this }
  { derivation on process.                                                  }

  Hold_CBC( False );
  end;

Procedure   st_BFish.EnCrypt ( pBuf :pointer; HowMany :integer );
  begin
  end;

Procedure   st_BFish.DeCrypt ( pBuf :pointer; HowMany :integer );
  begin
  end;

Procedure   st_BFish.SetRounds( R :byte );
  begin
  end;

DESTRUCTOR  st_BFish.Done;
  begin
  end;

{*** BLW-CBC 1.5 ************************************************}

CONSTRUCTOR BFC_PAS.Init( var PSW :string );
  begin
  Crypt_2x32.Init( PSW );
  Rounds := st_Rounds;
  Will_use_CBC(true);
  end;

PROCEDURE BFC_PAS.Build( var PSW :string );
  var
    i, j, k         : Integer;
    l               : Integer;
    AuxAtom         : Atom32;
    AuxBlock        : Block_2x32;

  begin
  Hold_CBC( True );

  { Initialize first the P-array... }

    for i := 0 to (Rounds+2)-1 do
        PAtoms[i].Atom := RandomSeed.Atoms[i].Atom;

  { ...and then the four S-boxes, in order, with a fixed random string. }
  { This string consists of the hexadecimal digits of Pi.               }

    l := Rounds + 2; { L continues i index }
    for i := 0 to 3 do
      begin
        for j := 0 to 255 do
            SBoxes[i, j].Atom := RandomSeed.Atoms[l+j].Atom;
        l := l+256;
      end;

  { XOR P1 with the first 32 bits of the key, XOR P2 with the second    }
  { 32 bits of the key, and so on for all bits of the key (up to P18).  }
  { Cycle throught the key bits repeatedly until the entire P-array     }
  { has been XORed.                                                     }

    j := 1;
    for i := 0 to (st_rounds+1) do
      begin
        AuxAtom.Atom := my_PBox_IV;
        for k := 0 to 3 do
          begin
            AuxAtom.byte[ 3-k ] := Ord(PSW[j]);
            Inc(j);
            if j > Length(PSW) then j := 1;
          end;
        PAtoms[i].Atom := PAtoms[i].Atom xor AuxAtom.Atom;
      end;

  { Encrypt the all-zero string using the Blowfish algorithm using     }
  { the subkeys described in steps #1 and #2 and replace the elements  }
  { of the P-array with the output of this process.                    }

    AuxBlock[0].Atom := my_PBox_IV;
    AuxBlock[1].Atom := my_PBox_IV;
    i:=0;
    while (i <= st_rounds+1) do             { HERE YOU MAY LOSE COMPAT }
      begin
        EnCrypt( @AuxBlock, 2 );
        PAtoms[i].Atom := AuxBlock[0].Atom;
        Inc(i);
        PAtoms[i].Atom := AuxBlock[1].Atom;
        Inc(i);
      end;

  { Continue the process, replacing the elements of the four S-boxes in }
  { order, with the output of the continuously changing Blowfish Boxes. }

    for j := 0 to 3 do
      begin
        i := 0;
        while i < 255 do                   { HERE YOU MAY LOSE COMPAT }
          begin
            EnCrypt( @AuxBlock, 2 );
            SBoxes[j, i].Atom := AuxBlock[0].Atom;
            Inc(i);
            SBoxes[j, i].Atom := AuxBlock[1].Atom;
            Inc(i);
          end;
      end;

  { In total, 521 iterations are required to generate all required subkeys. }
  { ...Applications can store the subkeys rather than re-executing all this }
  { derivation on process.                                                  }

  Hold_CBC( False );
  end;

DESTRUCTOR  BFC_PAS.Done;
  begin
  end;


PROCEDURE BFC_PAS.EnCrypt ( pBuf :pointer; HowMany :integer );
    Function F( AA : Atom32 ) : LongInt;
    BEGIN
         F:= ((Sboxes[0,AA.byte[3]].Atom  +  SBoxes[1,AA.byte[2]].Atom)
                               XOR Sboxes[2,AA.byte[1]].Atom)
                                +  Sboxes[3,AA.byte[0]].Atom;
      { In the original article, in Dr. Dobb's Journal, this function used }
      { the PArray from 0 to 3. I choose to invert it...                   }
      { The reasons for this can be found in this file's Header            }
    END;

    PROCEDURE DOIT ( VAR Bl :Block_2x32 );
     CONST
        Xl = 0;
        Xr = 1;
     VAR
        i  : BYTE;
     BEGIN
       Bl[Xl].Atom := Bl[Xl].Atom xor PAtoms[0].Atom;
       { 16 Rounds to go: Realy 8 Double rounds to avoid swaps }
       i := 1;
       WHILE ( i <= st_rounds ) DO
          BEGIN
          { This is a Readable version ...
          Bl[Xr].Atom:=F(Bl[Xl].Atom) xor Bl[Xr].Atom xor PAtoms[i].Atom;
          Bl[Xl].Atom:=F(Bl[Xr].Atom) xor Bl[Xl].Atom xor PAtoms[i+1].Atom;
          inc(i);
          inc(i);
          ... do not Uncomment! }
          { In the original article in Dr. Dobb's Journal this function }
          { used the PBox from 0 to  3...  I choose to invert it.       }
          { The reasons for this can be found in this file's Header     }

          { Faster First Half Round }
          Bl[Xr].Atom:= Bl[Xr].Atom xor PAtoms[i].Atom xor (((
                 Sboxes[0,Bl[Xl].byte[3]].Atom +
                 SBoxes[1,Bl[Xl].byte[2]].Atom) xor
                 SBoxes[2,Bl[Xl].byte[1]].Atom) +
                 SBoxes[3,Bl[Xl].byte[0]].Atom);
          inc(i);
          { Faster Second Half Round }
          Bl[Xl].Atom:= Bl[Xl].Atom xor PAtoms[i].Atom xor (((
                 Sboxes[0,Bl[Xr].byte[3]].Atom +
                 Sboxes[1,Bl[Xr].byte[2]].Atom) xor
                 Sboxes[2,Bl[Xr].byte[1]].Atom) +
                 Sboxes[3,Bl[Xr].byte[0]].Atom);
          inc(i);
          END;
       Bl[Xr].Atom:=Bl[Xr].Atom XOR PAtoms[(st_rounds+1)].Atom;
     END;


  VAR
    i    : integer;
    CBC  : Boolean;
    Last : Block_2x32;
    pB   : ^Block_2x32;

  Begin
  pB := pBuf;
  i  := HowMany;
  CBC  := CBC_is_ON;
  if CBC Then
    Begin
    Last[0].Atom:= LastBlock[0].Atom;
    Last[1].Atom:= LastBlock[1].Atom;
    While i > 0 do
      begin
        pB^[0].Atom := pB^[0].Atom xor Last[0].Atom;
        pB^[1].Atom := pB^[1].Atom xor Last[1].Atom;

        DOIT( pB^ );

        Last[0].Atom := pB^[0].Atom;
        Last[1].Atom := pB^[1].Atom;

        Dec(i);
        Dec(i);
        Inc(pB);
      end;
    LastBlock[0].Atom :=Last[0].Atom;
    LastBlock[1].Atom :=Last[1].Atom;
    end
  else
    While i > 0 do
      begin
        DOIT( pB^ );
        Dec(i);
        Dec(i);
        Inc(pB);
      end;
  End;

PROCEDURE BFC_PAS.DeCrypt ( pBuf :pointer; HowMany :integer );
    Function F( AA : Atom32 ) : LongInt;
       BEGIN
         F:= ((Sboxes[0,AA.byte[3]].Atom  +  SBoxes[1,AA.byte[2]].Atom)
                               XOR Sboxes[2,AA.byte[1]].Atom)
                                +  Sboxes[3,AA.byte[0]].Atom;
       { In the original article, in Dr. Dobb's Journal, this function used }
       { the PArray from 0 to 3. I choose to invert it...                   }
       { The reasons for this can be found in this file's Header            }
       END;
    PROCEDURE UNDOIT ( VAR Bl :Block_2x32 );
     CONST
        Xl = 0;
        Xr = 1;
     VAR
        i  : BYTE;
     BEGIN
       Bl[Xr].Atom := Bl[Xr].Atom xor PAtoms[st_rounds+1].Atom;
       { 16 Rounds to go: Realy 8 Double rounds to avoid swaps }
       i := st_rounds;
       WHILE ( i > 0 ) DO
          BEGIN
          { This is a Readable version ...
          Bl[Xl].Atom:=F(Bl[Xr].Atom) xor Bl[Xl].Atom xor PAtoms[i].Atom;
          Bl[Xr].Atom:=F(Bl[Xl].Atom) xor Bl[Xr].Atom xor PAtoms[i+1].Atom;
          dec(i);
          dec(i);
          ... do not Uncomment! }
          { In the original article in Dr. Dobb's Journal this function }
          { used the PBox from 0 to  3...  I choose to invert it.       }
          { The reasons for this can be found in this file's Header     }

          { Faster First Half Round }
          Bl[Xl].Atom:= Bl[Xl].Atom xor PAtoms[i].Atom xor (((
                 Sboxes[0,Bl[Xr].byte[3]].Atom +
                 SBoxes[1,Bl[Xr].byte[2]].Atom) xor
                 SBoxes[2,Bl[Xr].byte[1]].Atom) +
                 SBoxes[3,Bl[Xr].byte[0]].Atom);
          dec(i);
          { Faster Second Half Round }
          Bl[Xr].Atom:= Bl[Xr].Atom xor PAtoms[i].Atom xor (((
                 Sboxes[0,Bl[Xl].byte[3]].Atom +
                 Sboxes[1,Bl[Xl].byte[2]].Atom) xor
                 Sboxes[2,Bl[Xl].byte[1]].Atom) +
                 Sboxes[3,Bl[Xl].byte[0]].Atom);
          dec(i);
          END;
       Bl[Xl].Atom:=Bl[Xl].Atom XOR PAtoms[0].Atom;
     END;

  VAR
    i    : integer;
    CBC  : Boolean;
    pB   : ^Block_2x32;
    Last : Block_2x32;
    Aux  : Block_2x32;

  Begin
  pB := pBuf;
  i  := HowMany;
  CBC  := CBC_is_ON;
  if CBC Then
    begin
    Last[0].Atom:= LastBlock[0].Atom;
    Last[1].Atom:= LastBlock[1].Atom;
    While i > 0 do
      begin

        Aux[0].Atom := pB^[0].Atom;
        Aux[1].Atom := pB^[1].Atom;

        UNDOIT( pB^ );

        pB^[0].Atom := pB^[0].Atom xor Last[0].Atom;
        pB^[1].Atom := pB^[1].Atom xor Last[1].Atom;
        Last[0].Atom := Aux[0].Atom;
        Last[1].Atom := Aux[1].Atom;

        Dec(i);
        Dec(i);
        Inc(pB);
      end;
    LastBlock[0].Atom :=Last[0].Atom;
    LastBlock[1].Atom :=Last[1].Atom;
    end
  else
    While i > 0 do
      begin
        UNDOIT( pB^ );
        Dec(i);
        Dec(i);
        Inc(pB);
      end;
  {endif}
  End;

{$IFDEF Use_Assembler}

{$I _BFC_ASM.INC}
{$I _BFC_A16.INC}
{$I _BFC_A32.INC}

{$ENDIF}

begin
end.
