idea.pp 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  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
  37. IDEAKEYSIZE = 16;
  38. IDEABLOCKSIZE = 8;
  39. ROUNDS = 8;
  40. KEYLEN = (6*ROUNDS+4);
  41. TYPE
  42. TIDEAKey = ARRAY[0..keylen-1] OF Word;
  43. TIdeaCryptKey = ARRAY[0..7] OF Word;
  44. TIdeaCryptData = ARRAY[0..3] OF Word;
  45. { For backward compatibility }
  46. IDEAkey = TIDEAkey;
  47. IdeaCryptKey = TIdeaCryptKey;
  48. IdeaCryptData = TIdeaCryptData;
  49. PROCEDURE EnKeyIdea(UserKey: TIdeacryptkey; VAR z: TIDEAKey);
  50. PROCEDURE DeKeyIdea(z: TIDEAKey; VAR dk: TIDEAKey);
  51. PROCEDURE CipherIdea(Input: TIDEACryptData; VAR outdata: TIDEACryptData; z: TIDEAKey);
  52. Type
  53. EIDEAError = Class(EStreamError);
  54. TIDEAStream = Class(TOwnerStream)
  55. Private
  56. FKey : TIDEAKey;
  57. FData : TIDEACryptData;
  58. FBufpos : Byte;
  59. FPos : Longint;
  60. Public
  61. Constructor Create(AKey : TIDEAKey; Dest: TStream);
  62. Property Key : TIDEAKey Read FKey;
  63. end;
  64. TIDEAEncryptStream = Class(TIDEAStream)
  65. public
  66. Destructor Destroy; override;
  67. function Read(var Buffer; Count: Longint): Longint; override;
  68. function Write(const Buffer; Count: Longint): Longint; override;
  69. function Seek(Offset: Longint; Origin: Word): Longint; override;
  70. procedure Flush;
  71. end;
  72. TIDEADeCryptStream = Class(TIDEAStream)
  73. public
  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. 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. PROCEDURE mul(VAR a:Word; b: Word);
  84. VAR p: LongInt;
  85. BEGIN
  86. IF (a <> 0) THEN BEGIN
  87. IF (b <> 0) THEN BEGIN
  88. p := LongInt(a)*b;
  89. b := p;
  90. a := p SHR 16;
  91. IF (b < a) THEN a := b - a + 1
  92. ELSE a := b - a;
  93. END ELSE a := 1 - a;
  94. END ELSE a := 1-b;
  95. END;
  96. FUNCTION inv(x: word): Word;
  97. VAR t0,t1,q,y: Word;
  98. BEGIN
  99. IF x <= 1 THEN BEGIN
  100. inv := x;
  101. exit;
  102. END;
  103. t1 := 65537 DIV x;
  104. y := 65537 MOD x;
  105. IF y = 1 THEN BEGIN
  106. inv := Word(1-t1);
  107. exit;
  108. END;
  109. t0 := 1;
  110. REPEAT
  111. q := x DIV y;
  112. x := x MOD y;
  113. t0 := t0 + q * t1;
  114. IF x = 1 THEN BEGIN
  115. inv := t0;
  116. exit;
  117. END;
  118. q := y DIV x;
  119. y := y MOD x;
  120. t1 := t1 + q*t0;
  121. UNTIL y = 1;
  122. inv := word(1-t1);
  123. END;
  124. PROCEDURE EnKeyIdea(userkey: ideacryptkey; VAR z: ideakey);
  125. VAR zi,i,j: integer;
  126. BEGIN
  127. FOR j := 0 TO 7 DO z[j] := userkey[j];
  128. zi := 0;
  129. i := 0;
  130. FOR j := 8 TO keylen-1 DO BEGIN
  131. Inc(i);
  132. z[zi+i+7] := (z[zi+(i AND 7)] SHL 9) OR (z[zi+((i+1) AND 7)] SHR 7);
  133. zi := zi + (i AND 8);
  134. i := i AND 7;
  135. END;
  136. FOR i := 0 TO 7 DO userkey[i] := 0;
  137. END;
  138. PROCEDURE DeKeyIdea(z: IDEAKey; VAR dk: ideakey);
  139. VAR j: Integer;
  140. t1,t2,t3: Word;
  141. p: IDEAKey;
  142. ip: Integer;
  143. iz: Integer;
  144. BEGIN
  145. iz := 0;
  146. ip := keylen;
  147. FOR j := 0 TO keylen - 1 DO p[j] := 0;
  148. t1 := inv(z[iz]); Inc(iz);
  149. t2 := not(z[iz])+1; Inc(iz);
  150. t3 := not(z[iz])+1; Inc(iz);
  151. Dec(ip); p[ip] := inv(z[iz]); Inc(iz);
  152. Dec(ip); p[ip] := t3;
  153. Dec(ip); p[ip] := t2;
  154. Dec(ip); p[ip] := t1;
  155. FOR j := 1 TO rounds-1 DO BEGIN
  156. t1 := z[iz]; Inc(iz);
  157. Dec(ip); p[ip] := z[iz]; Inc(iz);
  158. Dec(ip); p[ip] := t1;
  159. t1 := inv(z[iz]); Inc(iz);
  160. t2 := Not(z[iz])+1; Inc(iz);
  161. t3 := Not(z[iz])+1; Inc(iz);
  162. Dec(ip); p[ip] := inv(z[iz]); Inc(iz);
  163. Dec(ip); p[ip] := t2;
  164. Dec(ip); p[ip] := t3;
  165. Dec(ip); p[ip] := t1;
  166. END;
  167. t1 := z[iz]; Inc(iz);
  168. Dec(ip); p[ip] := z[iz]; Inc(iz);
  169. Dec(ip); p[ip] := t1;
  170. t1 := inv(z[iz]); Inc(iz);
  171. t2 := Not(z[iz])+1; Inc(iz);
  172. t3 := Not(z[iz])+1; Inc(iz);
  173. Dec(ip); p[ip] := inv(z[iz]);
  174. Dec(ip); p[ip] := t3;
  175. Dec(ip); p[ip] := t2;
  176. Dec(ip); p[ip] := t1;
  177. FOR j := 0 TO KeyLen-1 DO BEGIN
  178. dk[j] := p[j];
  179. p[j] := 0;
  180. END;
  181. FOR j := 0 TO 51 DO z[j] := 0;
  182. END;
  183. PROCEDURE CipherIdea(input: ideacryptdata; VAR outdata: ideacryptdata; z:IDEAkey);
  184. VAR x1, x2, x3, x4, t1, t2: Word;
  185. r: Integer;
  186. zi: Integer;
  187. BEGIN
  188. zi := 0;
  189. x1 := input[0];
  190. x2 := input[1];
  191. x3 := input[2];
  192. x4 := input[3];
  193. FOR r := 1 TO ROUNDS DO BEGIN
  194. mul(x1,z[zi]); Inc(zi);
  195. x2 := x2 + z[zi]; Inc(zi);
  196. x3 := x3 + z[zi]; Inc(zi);
  197. mul(x4, z[zi]); Inc(zi);
  198. t2 := x1 XOR x3;
  199. mul(t2, z[zi]); Inc(zi);
  200. t1 := t2 + (x2 XOR x4);
  201. mul(t1, z[zi]); Inc(zi);
  202. t2 := t1+t2;
  203. x1 := x1 XOR t1;
  204. x4 := x4 XOR t2;
  205. t2 := t2 XOR x2;
  206. x2 := x3 XOR t1;
  207. x3 := t2;
  208. END;
  209. mul(x1, z[zi]); Inc(zi);
  210. outdata[0] := x1;
  211. outdata[1] := x3 + z[zi]; Inc(zi);
  212. outdata[2] := x2 + z[zi]; Inc(zi);
  213. Mul(x4,z[zi]);
  214. outdata[3] := x4;
  215. FOR r := 0 TO 3 DO input[r] := 0;
  216. FOR r := 0 TO 51 DO z[r] := 0;
  217. END;
  218. { ---------------------------------------------------------------------
  219. TIDEAStream
  220. ---------------------------------------------------------------------}
  221. Constructor TIDEAStream.Create(AKey : ideakey; Dest: TStream);
  222. begin
  223. inherited Create(Dest);
  224. FKey:=AKey;
  225. FBufPos:=0;
  226. Fpos:=0;
  227. end;
  228. { ---------------------------------------------------------------------
  229. TIDEAEncryptStream
  230. ---------------------------------------------------------------------}
  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. Source.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. Source.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. { ---------------------------------------------------------------------
  289. TIDEADecryptStream
  290. ---------------------------------------------------------------------}
  291. function TIDEADeCryptStream.Read(var Buffer; Count: Longint): Longint;
  292. Var
  293. mvsize : Longint;
  294. InData : IDEAcryptdata;
  295. begin
  296. Result:=0;
  297. While Count>0 do
  298. begin
  299. // Empty existing buffer.
  300. If (FBufPos>0) then
  301. begin
  302. mvSize:=FBufPos;
  303. If MvSize>count then
  304. mvsize:=Count;
  305. Move(PChar(@FData)[0],PChar(@Buffer)[Result],MVSize);
  306. If ((Sizeof(FData)-MvSize)>0) then
  307. Move(PChar(@FData)[mvSize],PChar(@FData)[0],Sizeof(FData)-MvSize);
  308. Dec(Count,mvsize);
  309. Inc(Result,mvsize);
  310. FBufPos:=FBufPos-MvSize;
  311. end;
  312. // Fill buffer again if needed.
  313. If (Count>0) then
  314. begin
  315. mvsize:=Source.Read(InData,SizeOf(InData));
  316. If mvsize>0 then
  317. begin
  318. If MvSize<SizeOf(InData) Then
  319. // Fill with nulls
  320. FillChar(PChar(@InData)[mvsize],SizeOf(InData)-mvsize,#0);
  321. CipherIdea(InData,FData,FKey);
  322. FBufPos:=SizeOf(FData);
  323. end
  324. else
  325. Count:=0; // No more data available from stream; st
  326. end;
  327. end;
  328. Inc(FPos,Result);
  329. end;
  330. function TIDEADeCryptStream.Write(const Buffer; Count: Longint): Longint;
  331. begin
  332. Raise EIDEAError.Create(SNoWriteAllowed);
  333. end;
  334. function TIDEADeCryptStream.Seek(Offset: Longint; Origin: Word): Longint;
  335. Var Buffer : Array[0..1023] of byte;
  336. i : longint;
  337. begin
  338. // Fake seek if possible by reading and discarding bytes.
  339. If ((Offset>=0) and (Origin = soFromCurrent)) or
  340. ((Offset>FPos) and (Origin = soFromBeginning)) then
  341. begin
  342. For I:=1 to (Offset div SizeOf(Buffer)) do
  343. ReadBuffer(Buffer,SizeOf(Buffer));
  344. ReadBuffer(Buffer,Offset mod SizeOf(Buffer));
  345. Result:=FPos;
  346. end
  347. else
  348. Raise EIDEAError.Create(SNoSeekAllowed);
  349. end;
  350. END.