idea.pp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. {
  2. $Id$
  3. This file is part of the Free Component Library (FCL)
  4. Copyright (c) 1999-2000 by Michael Van Canneyt and Florian Klaempfl
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {$ifdef fpc}
  12. {$mode objfpc}
  13. {$endif}
  14. UNIT IDEA;
  15. {
  16. IDEA encryption routines for pascal
  17. ported from PGP 2.3
  18. IDEA encryption routines for pascal, ported from PGP 2.3
  19. Copyright (C) for this port 1998 Ingo Korb
  20. Copyright (C) for the stream support 1999 Michael Van Canneyt
  21. This library is free software; you can redistribute it and/or
  22. modify it under the terms of the GNU Library General Public
  23. License as published by the Free Software Foundation; either
  24. version 2 of the License, or (at your option) any later version.
  25. This library is distributed in the hope that it will be useful,
  26. but WITHOUT ANY WARRANTY; without even the implied warranty of
  27. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  28. Library General Public License for more details.
  29. You should have received a copy of the GNU Library General Public
  30. License along with this library; if not, write to the Free
  31. Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  32. }
  33. {$R-,Q-}
  34. { Not nice but fast... }
  35. INTERFACE
  36. Uses Sysutils,Classes;
  37. CONST IDEAKEYSIZE = 16;
  38. IDEABLOCKSIZE = 8;
  39. ROUNDS = 8;
  40. KEYLEN = (6*ROUNDS+4);
  41. TYPE IDEAkey = ARRAY[0..keylen-1] OF Word;
  42. ideacryptkey = ARRAY[0..7] OF Word;
  43. ideacryptdata = ARRAY[0..3] OF Word;
  44. PROCEDURE EnKeyIdea(userkey: ideacryptkey; VAR z: ideakey);
  45. PROCEDURE DeKeyIdea(z: IDEAKey; VAR dk: ideakey);
  46. PROCEDURE CipherIdea(input: ideacryptdata; VAR outdata: ideacryptdata; z: IDEAkey);
  47. Type
  48. EIDEAError = Class(EStreamError);
  49. TIDEAEncryptStream = Class(TStream)
  50. private
  51. FDest : TStream;
  52. FKey : IDEAKey;
  53. FData : IDEACryptData;
  54. FBufpos : Byte;
  55. FPos : Longint;
  56. public
  57. constructor Create(AKey : ideakey; Dest: TStream);
  58. destructor Destroy; override;
  59. function Read(var Buffer; Count: Longint): Longint; override;
  60. function Write(const Buffer; Count: Longint): Longint; override;
  61. function Seek(Offset: Longint; Origin: Word): Longint; override;
  62. procedure Flush;
  63. Property Key : IDEAKey Read FKey;
  64. end;
  65. TIDEADeCryptStream = Class(TStream)
  66. private
  67. FSRC : TStream;
  68. FKey : IDEAKey;
  69. FData : IDEACryptData;
  70. FBufpos : Byte;
  71. FPos : Longint;
  72. public
  73. constructor Create(AKey : ideakey; Src: TStream);
  74. destructor Destroy; override;
  75. function Read(var Buffer; Count: Longint): Longint; override;
  76. function Write(const Buffer; Count: Longint): Longint; override;
  77. function Seek(Offset: Longint; Origin: Word): Longint; override;
  78. Property Key : IDEAKey Read FKey;
  79. end;
  80. IMPLEMENTATION
  81. Const
  82. SNoSeekAllowed = 'Seek not allowed on encryption streams';
  83. SNoReadAllowed = 'Reading from encryption stream not allowed';
  84. SNoWriteAllowed = 'Writing to decryption stream not allowed';
  85. {$ifdef fpc}
  86. Type
  87. PChar = ^Byte;
  88. {$endif}
  89. PROCEDURE mul(VAR a:Word; b: Word);
  90. VAR p: LongInt;
  91. BEGIN
  92. IF (a <> 0) THEN BEGIN
  93. IF (b <> 0) THEN BEGIN
  94. p := LongInt(a)*b;
  95. b := p;
  96. a := p SHR 16;
  97. IF (b < a) THEN a := b - a + 1
  98. ELSE a := b - a;
  99. END ELSE a := 1 - a;
  100. END ELSE a := 1-b;
  101. END;
  102. FUNCTION inv(x: word): Word;
  103. VAR t0,t1,q,y: Word;
  104. BEGIN
  105. IF x <= 1 THEN BEGIN
  106. inv := x;
  107. exit;
  108. END;
  109. t1 := 65537 DIV x;
  110. y := 65537 MOD x;
  111. IF y = 1 THEN BEGIN
  112. inv := Word(1-t1);
  113. exit;
  114. END;
  115. t0 := 1;
  116. REPEAT
  117. q := x DIV y;
  118. x := x MOD y;
  119. t0 := t0 + q * t1;
  120. IF x = 1 THEN BEGIN
  121. inv := t0;
  122. exit;
  123. END;
  124. q := y DIV x;
  125. y := y MOD x;
  126. t1 := t1 + q*t0;
  127. UNTIL y = 1;
  128. inv := word(1-t1);
  129. END;
  130. PROCEDURE EnKeyIdea(userkey: ideacryptkey; VAR z: ideakey);
  131. VAR zi,i,j: integer;
  132. BEGIN
  133. FOR j := 0 TO 7 DO z[j] := userkey[j];
  134. zi := 0;
  135. i := 0;
  136. FOR j := 8 TO keylen-1 DO BEGIN
  137. Inc(i);
  138. z[zi+i+7] := (z[zi+(i AND 7)] SHL 9) OR (z[zi+((i+1) AND 7)] SHR 7);
  139. zi := zi + (i AND 8);
  140. i := i AND 7;
  141. END;
  142. FOR i := 0 TO 7 DO userkey[i] := 0;
  143. END;
  144. PROCEDURE DeKeyIdea(z: IDEAKey; VAR dk: ideakey);
  145. VAR j: Integer;
  146. t1,t2,t3: Word;
  147. p: IDEAKey;
  148. ip: Integer;
  149. iz: Integer;
  150. BEGIN
  151. iz := 0;
  152. ip := keylen;
  153. FOR j := 0 TO keylen - 1 DO p[j] := 0;
  154. t1 := inv(z[iz]); Inc(iz);
  155. t2 := not(z[iz])+1; Inc(iz);
  156. t3 := not(z[iz])+1; Inc(iz);
  157. Dec(ip); p[ip] := inv(z[iz]); Inc(iz);
  158. Dec(ip); p[ip] := t3;
  159. Dec(ip); p[ip] := t2;
  160. Dec(ip); p[ip] := t1;
  161. FOR j := 1 TO rounds-1 DO BEGIN
  162. t1 := z[iz]; Inc(iz);
  163. Dec(ip); p[ip] := z[iz]; Inc(iz);
  164. Dec(ip); p[ip] := t1;
  165. t1 := inv(z[iz]); Inc(iz);
  166. t2 := Not(z[iz])+1; Inc(iz);
  167. t3 := Not(z[iz])+1; Inc(iz);
  168. Dec(ip); p[ip] := inv(z[iz]); Inc(iz);
  169. Dec(ip); p[ip] := t2;
  170. Dec(ip); p[ip] := t3;
  171. Dec(ip); p[ip] := t1;
  172. END;
  173. t1 := z[iz]; Inc(iz);
  174. Dec(ip); p[ip] := z[iz]; Inc(iz);
  175. Dec(ip); p[ip] := t1;
  176. t1 := inv(z[iz]); Inc(iz);
  177. t2 := Not(z[iz])+1; Inc(iz);
  178. t3 := Not(z[iz])+1; Inc(iz);
  179. Dec(ip); p[ip] := inv(z[iz]);
  180. Dec(ip); p[ip] := t3;
  181. Dec(ip); p[ip] := t2;
  182. Dec(ip); p[ip] := t1;
  183. FOR j := 0 TO KeyLen-1 DO BEGIN
  184. dk[j] := p[j];
  185. p[j] := 0;
  186. END;
  187. FOR j := 0 TO 51 DO z[j] := 0;
  188. END;
  189. PROCEDURE CipherIdea(input: ideacryptdata; VAR outdata: ideacryptdata; z:IDEAkey);
  190. VAR x1, x2, x3, x4, t1, t2: Word;
  191. r: Integer;
  192. zi: Integer;
  193. BEGIN
  194. zi := 0;
  195. x1 := input[0];
  196. x2 := input[1];
  197. x3 := input[2];
  198. x4 := input[3];
  199. FOR r := 1 TO ROUNDS DO BEGIN
  200. mul(x1,z[zi]); Inc(zi);
  201. x2 := x2 + z[zi]; Inc(zi);
  202. x3 := x3 + z[zi]; Inc(zi);
  203. mul(x4, z[zi]); Inc(zi);
  204. t2 := x1 XOR x3;
  205. mul(t2, z[zi]); Inc(zi);
  206. t1 := t2 + (x2 XOR x4);
  207. mul(t1, z[zi]); Inc(zi);
  208. t2 := t1+t2;
  209. x1 := x1 XOR t1;
  210. x4 := x4 XOR t2;
  211. t2 := t2 XOR x2;
  212. x2 := x3 XOR t1;
  213. x3 := t2;
  214. END;
  215. mul(x1, z[zi]); Inc(zi);
  216. outdata[0] := x1;
  217. outdata[1] := x3 + z[zi]; Inc(zi);
  218. outdata[2] := x2 + z[zi]; Inc(zi);
  219. Mul(x4,z[zi]);
  220. outdata[3] := x4;
  221. FOR r := 0 TO 3 DO input[r] := 0;
  222. FOR r := 0 TO 51 DO z[r] := 0;
  223. END;
  224. constructor TIDEAEncryptStream.Create(AKey : ideakey; Dest: TStream);
  225. begin
  226. inherited Create;
  227. FKey:=AKey;
  228. FDest:=Dest;
  229. FBufPos:=0;
  230. Fpos:=0;
  231. end;
  232. Destructor TIDEAEncryptStream.Destroy;
  233. begin
  234. Flush;
  235. Inherited Destroy;
  236. end;
  237. Procedure TIDEAEncryptStream.Flush;
  238. Var
  239. OutData : IdeaCryptData;
  240. begin
  241. If FBufPos>0 then
  242. begin
  243. // Fill with nulls
  244. FillChar(PChar(@FData)[FBufPos],SizeOf(FData)-FBufPos,#0);
  245. CipherIdea(Fdata,OutData,FKey);
  246. FDest.Write(OutData,SizeOf(OutData));
  247. // fixed: Manual flush and then free will now work
  248. FBufPos := 0;
  249. end;
  250. end;
  251. function TIDEAEncryptStream.Read(var Buffer; Count: Longint): Longint;
  252. begin
  253. Raise EIDEAError.Create(SNoReadAllowed);
  254. end;
  255. function TIDEAEncryptStream.Write(const Buffer; Count: Longint): Longint;
  256. Var
  257. mvsize : Longint;
  258. OutData : IDEAcryptdata;
  259. begin
  260. Result:=0;
  261. While Count>0 do
  262. begin
  263. MVsize:=Count;
  264. If Mvsize>SizeOf(Fdata)-FBufPos then
  265. mvsize:=SizeOf(FData)-FBufPos;
  266. Move(PChar(@Buffer)[Result],PChar(@FData)[FBufPos],MVSize);
  267. If FBufPos+mvSize=Sizeof(FData) then
  268. begin
  269. // Empty buffer.
  270. CipherIdea(Fdata,OutData,FKey);
  271. // this will raise an exception if needed.
  272. FDest.Writebuffer(OutData,SizeOf(OutData));
  273. FBufPos:=0;
  274. end
  275. else
  276. inc(FBufPos,mvsize);
  277. Dec(Count,MvSize);
  278. Inc(Result,mvSize);
  279. end;
  280. Inc(FPos,Result);
  281. end;
  282. function TIDEAEncryptStream.Seek(Offset: Longint; Origin: Word): Longint;
  283. begin
  284. if (Offset = 0) and (Origin = soFromCurrent) then
  285. Result := FPos
  286. else
  287. Raise EIDEAError.Create(SNoSeekAllowed);
  288. end;
  289. constructor TIDEADeCryptStream.Create(AKey : ideakey; Src: TStream);
  290. begin
  291. inherited Create;
  292. FKey:=AKey;
  293. FPos:=0;
  294. FBufPos:=SizeOf(Fdata);
  295. FSrc:=Src;
  296. end;
  297. destructor TIDEADeCryptStream.Destroy;
  298. begin
  299. Inherited destroy;
  300. end;
  301. function TIDEADeCryptStream.Read(var Buffer; Count: Longint): Longint;
  302. Var
  303. mvsize : Longint;
  304. InData : IDEAcryptdata;
  305. begin
  306. Result:=0;
  307. While Count>0 do
  308. begin
  309. // Empty existing buffer.
  310. If FBufPos<SizeOf(FData) then
  311. begin
  312. mvSize:=Sizeof(FData)-FBufPos;
  313. If MvSize>count then
  314. mvsize:=Count;
  315. Move(PChar(@FData)[FBufPos],PChar(@Buffer)[Result],MVSize);
  316. Dec(Count,mvsize);
  317. Inc(Result,mvsize);
  318. inc(fBufPos,mvsize);
  319. end;
  320. // Fill buffer again if needed.
  321. If (FBufPos=SizeOf(FData)) and (Count>0) then
  322. begin
  323. mvsize:=FSrc.Read(InData,SizeOf(InData));
  324. If mvsize>0 then
  325. begin
  326. If MvSize<SizeOf(InData) Then
  327. // Fill with nulls
  328. FillChar(PChar(@InData)[mvsize],SizeOf(InData)-mvsize,#0);
  329. CipherIdea(InData,FData,FKey);
  330. FBufPos:=0;
  331. end
  332. else
  333. Count:=0; // No more data available from stream; st
  334. end;
  335. end;
  336. Inc(FPos,Result);
  337. end;
  338. function TIDEADeCryptStream.Write(const Buffer; Count: Longint): Longint;
  339. begin
  340. Raise EIDEAError.Create(SNoWriteAllowed);
  341. end;
  342. function TIDEADeCryptStream.Seek(Offset: Longint; Origin: Word): Longint;
  343. Var Buffer : Array[0..1023] of byte;
  344. i : longint;
  345. begin
  346. // Fake seek if possible by reading and discarding bytes.
  347. If ((Offset>=0) and (Origin = soFromCurrent)) or
  348. ((Offset>FPos) and (Origin = soFromBeginning)) then
  349. begin
  350. For I:=1 to (Offset div SizeOf(Buffer)) do
  351. ReadBuffer(Buffer,SizeOf(Buffer));
  352. ReadBuffer(Buffer,Offset mod SizeOf(Buffer));
  353. Result:=FPos;
  354. end
  355. else
  356. Raise EIDEAError.Create(SNoSeekAllowed);
  357. end;
  358. END.
  359. {
  360. $Log$
  361. Revision 1.6 2002-09-07 15:15:24 peter
  362. * old logs removed and tabs fixed
  363. }