123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421 |
- {
- $Id$
- This file is part of the Free Component Library (FCL)
- Copyright (c) 1999-2000 by Michael Van Canneyt and Florian Klaempfl
- See the file COPYING.FPC, included in this distribution,
- for details about the copyright.
- This program 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.
- **********************************************************************}
- {$ifdef fpc}
- {$mode objfpc}
- {$endif}
- 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 outdata: ideacryptdata; z: IDEAkey);
- Type
- EIDEAError = Class(EStreamError);
- 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';
- {$ifdef fpc}
- Type
- PChar = ^Byte;
- {$endif}
- 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];
- 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;
- END;
- PROCEDURE DeKeyIdea(z: IDEAKey; VAR dk: ideakey);
- VAR j: Integer;
- t1,t2,t3: Word;
- p: IDEAKey;
- ip: Integer;
- iz: Integer;
- BEGIN
- iz := 0;
- ip := keylen;
- FOR j := 0 TO keylen - 1 DO p[j] := 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]);
- 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;
- END;
- PROCEDURE CipherIdea(input: ideacryptdata; VAR outdata: 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);
- outdata[0] := x1;
- outdata[1] := x3 + z[zi]; Inc(zi);
- outdata[2] := x2 + z[zi]; Inc(zi);
- Mul(x4,z[zi]);
- outdata[3] := x4;
- FOR r := 0 TO 3 DO input[r] := 0;
- FOR r := 0 TO 51 DO z[r] := 0;
- END;
- constructor TIDEAEncryptStream.Create(AKey : ideakey; Dest: TStream);
- begin
- inherited Create;
- FKey:=AKey;
- 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 nulls
- FillChar(PChar(@FData)[FBufPos],SizeOf(FData)-FBufPos,#0);
- CipherIdea(Fdata,OutData,FKey);
- FDest.Write(OutData,SizeOf(OutData));
- // fixed: Manual flush and then free will now work
- FBufPos := 0;
- 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(PChar(@Buffer)[Result],PChar(@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:=AKey;
- 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(PChar(@FData)[FBufPos],PChar(@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 nulls
- FillChar(PChar(@InData)[mvsize],SizeOf(InData)-mvsize,#0);
- 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(SNoWriteAllowed);
- 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.
- {
- $Log$
- Revision 1.6 2002-09-07 15:15:24 peter
- * old logs removed and tabs fixed
- }
|