idea.pp 9.9 KB

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