idea.pp 9.8 KB

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