Browse Source

Initial implementation of encryption stream

michael 26 years ago
parent
commit
e1df03febf
5 changed files with 458 additions and 4 deletions
  1. 1 1
      fcl/inc/Makefile.inc
  2. 410 0
      fcl/inc/idea.pp
  3. 5 2
      fcl/tests/Makefile
  4. 2 1
      fcl/tests/README
  5. 40 0
      fcl/tests/tidea.pp

+ 1 - 1
fcl/inc/Makefile.inc

@@ -5,4 +5,4 @@ INCNAMES=classes.inc classesh.inc bits.inc collect.inc compon.inc filer.inc\
          lists.inc parser.inc persist.inc reader.inc streams.inc stringl.inc\
          lists.inc parser.inc persist.inc reader.inc streams.inc stringl.inc\
          writer.inc
          writer.inc
 
 
-INCUNITS=inifiles ezcgi pipes
+INCUNITS=inifiles ezcgi pipes rtfpars idea

+ 410 - 0
fcl/inc/idea.pp

@@ -0,0 +1,410 @@
+UNIT IDEA;
+
+{
+ IDEA encryption routines for pascal
+ ported from PGP 2.3
+
+ IDEA encryption routines for pascal, ported from PGP 2.3
+ Copyright (C) for this port 1998 Ingo Korb
+ Copyright (C) for the stream support 1999 Michael Van Canneyt
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+}
+
+
+{$R-,Q-}
+{ Not nice but fast... }
+
+INTERFACE
+
+Uses Sysutils,Classes;
+
+CONST IDEAKEYSIZE = 16;
+      IDEABLOCKSIZE = 8;
+      ROUNDS = 8;
+      KEYLEN = (6*ROUNDS+4);
+
+TYPE IDEAkey = ARRAY[0..keylen-1] OF Word;
+     ideacryptkey = ARRAY[0..7] OF Word;
+     ideacryptdata = ARRAY[0..3] OF Word;
+
+PROCEDURE EnKeyIdea(userkey: ideacryptkey; VAR z: ideakey);
+PROCEDURE DeKeyIdea(z: IDEAKey; VAR dk: ideakey);
+PROCEDURE CipherIdea(input: ideacryptdata; VAR out: ideacryptdata; z: IDEAkey);
+
+Type  
+
+EIDEAError = Class(Exception);
+
+TIDEAEncryptStream = Class(TStream)
+  private
+    FDest : TStream;
+    FKey : IDEAKey;
+    FData : IDEACryptData;
+    FBufpos : Byte;
+    FPos : Longint;
+  public
+    constructor Create(AKey : ideakey; Dest: TStream);
+    destructor Destroy; override;
+    function Read(var Buffer; Count: Longint): Longint; override;
+    function Write(const Buffer; Count: Longint): Longint; override;
+    function Seek(Offset: Longint; Origin: Word): Longint; override;
+    procedure Flush;
+    Property Key : IDEAKey Read FKey;
+  end;
+
+TIDEADeCryptStream = Class(TStream)
+  private
+    FSRC : TStream;
+    FKey : IDEAKey;
+    FData : IDEACryptData;
+    FBufpos : Byte;
+    FPos : Longint;
+  public
+    constructor Create(AKey : ideakey; Src: TStream);
+    destructor Destroy; override;
+    function Read(var Buffer; Count: Longint): Longint; override;
+    function Write(const Buffer; Count: Longint): Longint; override;
+    function Seek(Offset: Longint; Origin: Word): Longint; override;
+    Property Key : IDEAKey Read FKey;
+  end;
+
+IMPLEMENTATION
+
+Const 
+  SNoSeekAllowed = 'Seek not allowed on encryption streams';
+  SNoReadAllowed = 'Reading from encryption stream not allowed';
+  SNoWriteAllowed = 'Writing to decryption stream not allowed';
+
+Type 
+  PByte = ^Byte;
+
+PROCEDURE mul(VAR a:Word; b: Word);
+VAR p: LongInt;
+BEGIN
+  IF (a <> 0) THEN BEGIN
+    IF (b <> 0) THEN BEGIN
+      p := LongInt(a)*b;
+      b := p;
+      a := p SHR 16;
+      IF (b < a) THEN a := b - a + 1
+                 ELSE a := b - a;
+    END ELSE a := 1 - a;
+  END ELSE a := 1-b;
+END;
+
+FUNCTION inv(x: word): Word;
+VAR t0,t1,q,y: Word;
+BEGIN
+  IF x <= 1 THEN BEGIN
+    inv := x;
+    exit;
+  END;
+  t1 := 65537 DIV x;
+  y := 65537 MOD x;
+  IF y = 1 THEN BEGIN
+    inv := Word(1-t1);
+    exit;
+  END;
+  t0 := 1;
+  REPEAT
+    q := x DIV y;
+    x := x MOD y;
+    t0 := t0 + q * t1;
+    IF x = 1 THEN BEGIN
+      inv := t0;
+      exit;
+    END;
+    q := y DIV x;
+    y := y MOD x;
+    t1 := t1 + q*t0;
+  UNTIL y = 1;
+  inv := word(1-t1);
+END;
+
+PROCEDURE EnKeyIdea(userkey: ideacryptkey; VAR z: ideakey);
+VAR zi,i,j: integer;
+BEGIN
+  FOR j := 0 TO 7 DO z[j] := userkey[j];
+  i := 0;
+  zi := 0;
+  i := 0;
+  FOR j := 8 TO keylen-1 DO BEGIN
+    Inc(i);
+    z[zi+i+7] := (z[zi+(i AND 7)] SHL 9) OR (z[zi+((i+1) AND 7)] SHR 7);
+    zi := zi + (i AND 8);
+    i := i AND 7;
+  END;
+  FOR i := 0 TO 7 DO userkey[i] := 0;
+  zi := 0;
+END;
+
+PROCEDURE DeKeyIdea(z: IDEAKey; VAR dk: ideakey);
+VAR j: Integer;
+    t1,t2,t3: Word;
+    p: IDEAKey;
+    ip,it,idk: Integer;
+    iz: Integer;
+BEGIN
+  iz := 0;
+  ip := keylen;
+  FOR j := 0 TO keylen - 1 DO p[j] := 0;
+  idk := 0;
+  t1 := inv(z[iz]);   Inc(iz);
+  t2 := not(z[iz])+1; Inc(iz);
+  t3 := not(z[iz])+1; Inc(iz);
+  Dec(ip); p[ip] := inv(z[iz]); Inc(iz);
+  Dec(ip); p[ip] := t3;
+  Dec(ip); p[ip] := t2;
+  Dec(ip); p[ip] := t1;
+  FOR j := 1 TO rounds-1 DO BEGIN
+    t1 := z[iz]; Inc(iz);
+    Dec(ip); p[ip] := z[iz]; Inc(iz);
+    Dec(ip); p[ip] := t1;
+    t1 := inv(z[iz]);   Inc(iz);
+    t2 := Not(z[iz])+1; Inc(iz);
+    t3 := Not(z[iz])+1; Inc(iz);
+    Dec(ip); p[ip] := inv(z[iz]); Inc(iz);
+    Dec(ip); p[ip] := t2;
+    Dec(ip); p[ip] := t3;
+    Dec(ip); p[ip] := t1;
+  END;
+  t1 := z[iz]; Inc(iz);
+  Dec(ip); p[ip] := z[iz]; Inc(iz);
+  Dec(ip); p[ip] := t1;
+  t1 := inv(z[iz]);   Inc(iz);
+  t2 := Not(z[iz])+1; Inc(iz);
+  t3 := Not(z[iz])+1; Inc(iz);
+  Dec(ip); p[ip] := inv(z[iz]); Inc(iz);
+  Dec(ip); p[ip] := t3;
+  Dec(ip); p[ip] := t2;
+  Dec(ip); p[ip] := t1;
+  FOR j := 0 TO KeyLen-1 DO BEGIN
+    dk[j] := p[j];
+    p[j] := 0;
+  END;
+  FOR j := 0 TO 51 DO z[j] := 0;
+  t1 := 0;
+  t2 := 0;
+  t3 := 0;
+  ip := 0;
+  it := 0;
+  idk := 0;
+  iz := 0;
+END;
+
+PROCEDURE CipherIdea(input: ideacryptdata; VAR out: ideacryptdata; z:
+IDEAkey);
+VAR x1, x2, x3, x4, t1, t2: Word;
+    r: Integer;
+    zi: Integer;
+BEGIN
+  zi := 0;
+  x1 := input[0];
+  x2 := input[1];
+  x3 := input[2];
+  x4 := input[3];
+  FOR r := 1 TO ROUNDS DO BEGIN
+    mul(x1,z[zi]);    Inc(zi);
+    x2 := x2 + z[zi]; Inc(zi);
+    x3 := x3 + z[zi]; Inc(zi);
+    mul(x4, z[zi]);   Inc(zi);
+    t2 := x1 XOR x3;
+    mul(t2, z[zi]);   Inc(zi);
+    t1 := t2 + (x2 XOR x4);
+    mul(t1, z[zi]);   Inc(zi);
+    t2 := t1+t2;
+    x1 := x1 XOR t1;
+    x4 := x4 XOR t2;
+    t2 := t2 XOR x2;
+    x2 := x3 XOR t1;
+    x3 := t2;
+  END;
+  mul(x1, z[zi]);       Inc(zi);
+  out[0] := x1;
+  out[1] := x3 + z[zi]; Inc(zi);
+  out[2] := x2 + z[zi]; Inc(zi);
+  Mul(x4,z[zi]);
+  out[3] := x4;
+  FOR r := 0 TO 3 DO input[r] := 0;
+  FOR r := 0 TO 51 DO z[r] := 0;
+  x1 := 0;
+  x2 := 0;
+  x3 := 0;
+  x4 := 0;
+  t1 := 0;
+  t2 := 0;
+  zi := 0;
+END;
+
+constructor TIDEAEncryptStream.Create(AKey : ideakey; Dest: TStream);
+
+begin
+  FKey:=Key;
+  FDest:=Dest;
+  FBufPos:=0;
+  Fpos:=0;
+end;
+
+Destructor TIDEAEncryptStream.Destroy; 
+
+
+begin
+  Flush;
+  Inherited Destroy;
+end;
+
+Procedure TIDEAEncryptStream.Flush;
+
+Var
+  OutData : IdeaCryptData;
+  
+begin
+  If FBufPos>0 then
+    begin 
+    // Fill with spaces.
+    FillChar(PByte(@FData)[FBufPos],SizeOf(FData)-FBufPos,' ');
+    CipherIdea(Fdata,OutData,FKey);
+    FDest.Write(OutData,SizeOf(OutData));
+    end;
+end;
+
+function TIDEAEncryptStream.Read(var Buffer; Count: Longint): Longint; 
+
+begin
+  Raise EIDEAError.Create(SNoReadAllowed);
+end;
+
+function TIDEAEncryptStream.Write(const Buffer; Count: Longint): Longint; 
+
+Var 
+  mvsize : Longint;
+  OutData : IDEAcryptdata;
+
+begin
+  Result:=0;
+  While Count>0 do
+    begin
+    MVsize:=Count;
+    If Mvsize>SizeOf(Fdata)-FBufPos then
+      mvsize:=SizeOf(FData)-FBufPos;
+    Move(Pbyte(@Buffer)[Result],PByte(@FData)[FBufPos],MVSize);
+    If FBufPos+mvSize=Sizeof(FData) then
+      begin
+      // Empty buffer.
+      CipherIdea(Fdata,OutData,FKey);
+      // this will raise an exception if needed.
+      FDest.Writebuffer(OutData,SizeOf(OutData));
+      FBufPos:=0;
+      end
+    else
+      inc(FBufPos,mvsize);
+    Dec(Count,MvSize);
+    Inc(Result,mvSize);
+    end;
+  Inc(FPos,Result);
+end;
+
+
+function TIDEAEncryptStream.Seek(Offset: Longint; Origin: Word): Longint; 
+
+begin
+  if (Offset = 0) and (Origin = soFromCurrent) then
+    Result := FPos
+  else
+    Raise EIDEAError.Create(SNoSeekAllowed);
+end;
+
+constructor TIDEADeCryptStream.Create(AKey : ideakey; Src: TStream);
+
+begin
+  inherited Create;
+  FKey:=Key;
+  FPos:=0;
+  FBufPos:=SizeOf(Fdata);
+  FSrc:=Src;
+end;
+
+destructor TIDEADeCryptStream.Destroy; 
+begin
+  Inherited destroy;
+end;
+
+function TIDEADeCryptStream.Read(var Buffer; Count: Longint): Longint; 
+  
+Var 
+  mvsize : Longint;
+  InData : IDEAcryptdata;
+
+begin
+  Result:=0;
+  While Count>0 do
+    begin
+    // Empty existing buffer.
+    If FBufPos<SizeOf(FData) then
+      begin
+      mvSize:=Sizeof(FData)-FBufPos;
+      If MvSize>count then 
+        mvsize:=Count;
+      Move(PByte(@FData)[FBufPos],Pbyte(@Buffer)[Result],MVSize);
+      Dec(Count,mvsize);
+      Inc(Result,mvsize);
+      inc(fBufPos,mvsize);
+      end;
+    // Fill buffer again if needed.  
+    If (FBufPos=SizeOf(FData)) and (Count>0) then
+      begin
+      mvsize:=FSrc.Read(InData,SizeOf(InData));
+      If mvsize>0 then
+        begin
+        If MvSize<SizeOf(InData) Then
+          // Fill with spaces
+          FillChar(PByte(@InData)[mvsize],SizeOf(InData)-mvsize,' ');
+        CipherIdea(InData,FData,FKey);
+        FBufPos:=0;
+        end
+      else
+        Count:=0; // No more data available from stream; st
+      end;
+    end;
+  Inc(FPos,Result);
+end;
+
+function TIDEADeCryptStream.Write(const Buffer; Count: Longint): Longint; 
+begin
+  Raise EIDEAError.Create(SNoReadAllowed);
+end;
+
+function TIDEADeCryptStream.Seek(Offset: Longint; Origin: Word): Longint; 
+
+Var Buffer : Array[0..1023] of byte;
+    i : longint;
+    
+begin
+  // Fake seek if possible by reading and discarding bytes.
+  If ((Offset>=0) and (Origin = soFromCurrent)) or
+    ((Offset>FPos) and (Origin = soFromBeginning)) then
+      begin
+      For I:=1 to (Offset div SizeOf(Buffer)) do
+        ReadBuffer(Buffer,SizeOf(Buffer));
+      ReadBuffer(Buffer,Offset mod SizeOf(Buffer));
+      Result:=FPos;
+      end
+  else             
+    Raise EIDEAError.Create(SNoSeekAllowed);
+end;
+
+END.
+

+ 5 - 2
fcl/tests/Makefile

@@ -36,7 +36,7 @@ NEEDOPT=-S2
 
 
 UNITOBJECTS=
 UNITOBJECTS=
 EXEOBJECTS=stringl dparser fstream mstream list threads testrtf\
 EXEOBJECTS=stringl dparser fstream mstream list threads testrtf\
-           cfgtest testz testz2 xmldump htdump testcgi
+           cfgtest testz testz2 xmldump htdump testcgi tidea
 
 
 
 
 #####################################################################
 #####################################################################
@@ -113,7 +113,10 @@ endif
 
 
 #
 #
 # $Log$
 # $Log$
-# Revision 1.8  1999-07-15 12:05:55  michael
+# Revision 1.9  1999-07-25 14:30:39  michael
+# Initial implementation of encryption stream
+#
+# Revision 1.8  1999/07/15 12:05:55  michael
 # + Added testcgi program
 # + Added testcgi program
 #
 #
 # Revision 1.7  1999/07/11 22:43:23  michael
 # Revision 1.7  1999/07/11 22:43:23  michael

+ 2 - 1
fcl/tests/README

@@ -26,4 +26,5 @@ testrtf.pp   TRTFParser object from rtfpars (MVC)
 cfgtest.pp   Example for using XML read/write as cfg file (SG)
 cfgtest.pp   Example for using XML read/write as cfg file (SG)
 xmldump.pp   xml dump program (SG)
 xmldump.pp   xml dump program (SG)
 htdump.pp    htdump dumps XL IDL definition as ObjectPascal classes (MVC)
 htdump.pp    htdump dumps XL IDL definition as ObjectPascal classes (MVC)
-testcgi.pp   test program or ezcgi class (MH)
+testcgi.pp   test program for ezcgi class (MH)
+tidea.pp     test program for IDEA encryption/decryption streams (MVC)

+ 40 - 0
fcl/tests/tidea.pp

@@ -0,0 +1,40 @@
+Program tidea;
+
+Uses Classes,Idea;
+
+Type
+   PByte = ^Byte;
+
+Var M : TMemorystream;
+    ES : TIDeaEncryptStream;
+    DS : TIdeaDecryptStream;
+    StartKey : ideacryptkey;
+    EnKey,DeKey : ideakey;
+    I,J : longint;
+    
+begin
+  M:=TMemoryStream.create;
+  // generate some phoney key;
+  For I:=0 to SizeOf(StartKey)-1 do
+   PByte(@StartKey)[I]:=I;
+  // Get encryption key
+  EnKeyIdea(StartKey,enKey);
+  ES:=TIDeaEncryptStream.Create(EnKey,M);
+  For I:=1 to 65 do
+    ES.Write(I,SizeOf(I));
+  Writeln ('Position after Write : ',ES.Position);  
+  ES.Flush;
+  Writeln ('Size of memory stream : ',M.Size);
+  M.Seek(0,soFromBeginning);
+  // Get decryption key
+  DeKeyIdea(EnKey,DeKey);
+  DS:=TIDeaDecryptStream.Create(DEKey,M);
+  For I:=1 to 65 do
+    begin
+    DS.Read(J,SizeOf(J));
+    If J<>I then 
+      Writeln ('Error; Read : ',J);
+    end;
+  Writeln ('Position after Reading : ',DS.Position);  
+  DS.destroy;
+end.