idea.pp 9.7 KB

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