idea.pp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  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 }
  55. TIDEAStream = Class(TOwnerStream)
  56. Private
  57. FKey : TIDEAKey;
  58. FData : TIDEACryptData;
  59. FBufpos : Byte;
  60. FPos : Longint;
  61. Protected
  62. Procedure CreateCryptKey(Const S : String; Var Key : TIDEACryptKey);
  63. Public
  64. Constructor Create(AKey : TIDEAKey; Dest: TStream); overload;
  65. Property Key : TIDEAKey Read FKey;
  66. end;
  67. { TIDEAEncryptStream }
  68. TIDEAEncryptStream = Class(TIDEAStream)
  69. public
  70. Constructor Create(Const AKey : String; Dest: TStream); overload;
  71. Destructor Destroy; override;
  72. function Write(const Buffer; Count: Longint): Longint; override;
  73. function Seek(Offset: Longint; Origin: Word): Longint; override;
  74. procedure Flush;
  75. end;
  76. { TIDEADeCryptStream }
  77. TIDEADeCryptStream = Class(TIDEAStream)
  78. public
  79. Constructor Create(Const AKey : String; Dest: TStream); overload;
  80. function Read(var Buffer; Count: Longint): Longint; override;
  81. function Seek(Offset: Longint; Origin: Word): Longint; override;
  82. end;
  83. Implementation
  84. Const
  85. SNoSeekAllowed = 'Seek not allowed on encryption streams';
  86. SErrEmptyKey = 'String Key may not be empty';
  87. PROCEDURE mul(VAR a:Word; b: Word);
  88. VAR p: LongInt;
  89. BEGIN
  90. IF (a <> 0) THEN BEGIN
  91. IF (b <> 0) THEN BEGIN
  92. p := LongInt(a)*b;
  93. b := p;
  94. a := p SHR 16;
  95. IF (b < a) THEN a := b - a + 1
  96. ELSE a := b - a;
  97. END ELSE a := 1 - a;
  98. END ELSE a := 1-b;
  99. END;
  100. FUNCTION inv(x: word): Word;
  101. VAR t0,t1,q,y: Word;
  102. BEGIN
  103. IF x <= 1 THEN BEGIN
  104. inv := x;
  105. exit;
  106. END;
  107. t1 := 65537 DIV x;
  108. y := 65537 MOD x;
  109. IF y = 1 THEN BEGIN
  110. inv := Word(1-t1);
  111. exit;
  112. END;
  113. t0 := 1;
  114. REPEAT
  115. q := x DIV y;
  116. x := x MOD y;
  117. t0 := t0 + q * t1;
  118. IF x = 1 THEN BEGIN
  119. inv := t0;
  120. exit;
  121. END;
  122. q := y DIV x;
  123. y := y MOD x;
  124. t1 := t1 + q*t0;
  125. UNTIL y = 1;
  126. inv := word(1-t1);
  127. END;
  128. PROCEDURE EnKeyIdea(userkey: ideacryptkey; VAR z: ideakey);
  129. VAR zi,i,j: integer;
  130. BEGIN
  131. FOR j := 0 TO 7 DO z[j] := userkey[j];
  132. zi := 0;
  133. i := 0;
  134. FOR j := 8 TO keylen-1 DO BEGIN
  135. Inc(i);
  136. z[zi+i+7] := (z[zi+(i AND 7)] SHL 9) OR (z[zi+((i+1) AND 7)] SHR 7);
  137. zi := zi + (i AND 8);
  138. i := i AND 7;
  139. END;
  140. FOR i := 0 TO 7 DO userkey[i] := 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: Integer;
  147. iz: Integer;
  148. BEGIN
  149. iz := 0;
  150. ip := keylen;
  151. FOR j := 0 TO keylen - 1 DO p[j] := 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]);
  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. END;
  187. PROCEDURE CipherIdea(input: ideacryptdata; VAR outdata: ideacryptdata; z:IDEAkey);
  188. VAR x1, x2, x3, x4, t1, t2: Word;
  189. r: Integer;
  190. zi: Integer;
  191. BEGIN
  192. zi := 0;
  193. x1 := input[0];
  194. x2 := input[1];
  195. x3 := input[2];
  196. x4 := input[3];
  197. FOR r := 1 TO ROUNDS DO BEGIN
  198. mul(x1,z[zi]); Inc(zi);
  199. x2 := x2 + z[zi]; Inc(zi);
  200. x3 := x3 + z[zi]; Inc(zi);
  201. mul(x4, z[zi]); Inc(zi);
  202. t2 := x1 XOR x3;
  203. mul(t2, z[zi]); Inc(zi);
  204. t1 := t2 + (x2 XOR x4);
  205. mul(t1, z[zi]); Inc(zi);
  206. t2 := t1+t2;
  207. x1 := x1 XOR t1;
  208. x4 := x4 XOR t2;
  209. t2 := t2 XOR x2;
  210. x2 := x3 XOR t1;
  211. x3 := t2;
  212. END;
  213. mul(x1, z[zi]); Inc(zi);
  214. outdata[0] := x1;
  215. outdata[1] := x3 + z[zi]; Inc(zi);
  216. outdata[2] := x2 + z[zi]; Inc(zi);
  217. Mul(x4,z[zi]);
  218. outdata[3] := x4;
  219. FOR r := 0 TO 3 DO input[r] := 0;
  220. FOR r := 0 TO 51 DO z[r] := 0;
  221. END;
  222. { ---------------------------------------------------------------------
  223. TIDEAStream
  224. ---------------------------------------------------------------------}
  225. Constructor TIDEAStream.Create(AKey : TIDEAKey; Dest: TStream);
  226. begin
  227. inherited Create(Dest);
  228. FKey:=AKey;
  229. FBufPos:=0;
  230. Fpos:=0;
  231. end;
  232. procedure TIDEAStream.CreateCryptKey(const S: String; var Key: TIDEACryptKey);
  233. Var
  234. KLen : Integer;
  235. begin
  236. KLen:=Length(S);
  237. If (KLen=0) then
  238. Raise EIDEAError.Create(SErrEmptyKey);
  239. If (Length(S)>SizeOf(Key)) then
  240. KLen:=SizeOf(Key);
  241. Move(S[1],Key,KLen);
  242. end;
  243. { ---------------------------------------------------------------------
  244. TIDEAEncryptStream
  245. ---------------------------------------------------------------------}
  246. constructor TIDEAEncryptStream.Create(Const AKey: String; Dest: TStream);
  247. Var
  248. K : TIdeaCryptKey;
  249. Z : TIDeaKey;
  250. begin
  251. CreateCryptKey(AKey,K);
  252. EnKeyIDEA(K,Z);
  253. Inherited Create(Z,Dest);
  254. end;
  255. Destructor TIDEAEncryptStream.Destroy;
  256. begin
  257. Flush;
  258. Inherited Destroy;
  259. end;
  260. Procedure TIDEAEncryptStream.Flush;
  261. Var
  262. OutData : IdeaCryptData;
  263. begin
  264. If FBufPos>0 then
  265. begin
  266. // Fill with nulls
  267. FillChar(PChar(@FData)[FBufPos],SizeOf(FData)-FBufPos,#0);
  268. CipherIdea(Fdata,OutData,FKey);
  269. Source.Write(OutData,SizeOf(OutData));
  270. // fixed: Manual flush and then free will now work
  271. FBufPos := 0;
  272. end;
  273. end;
  274. function TIDEAEncryptStream.Write(const Buffer; Count: Longint): Longint;
  275. Var
  276. mvsize : Longint;
  277. OutData : IDEAcryptdata;
  278. begin
  279. Result:=0;
  280. While Count>0 do
  281. begin
  282. MVsize:=Count;
  283. If Mvsize>SizeOf(Fdata)-FBufPos then
  284. mvsize:=SizeOf(FData)-FBufPos;
  285. Move(PChar(@Buffer)[Result],PChar(@FData)[FBufPos],MVSize);
  286. If FBufPos+mvSize=Sizeof(FData) then
  287. begin
  288. // Empty buffer.
  289. CipherIdea(Fdata,OutData,FKey);
  290. // this will raise an exception if needed.
  291. Source.Writebuffer(OutData,SizeOf(OutData));
  292. FBufPos:=0;
  293. end
  294. else
  295. inc(FBufPos,mvsize);
  296. Dec(Count,MvSize);
  297. Inc(Result,mvSize);
  298. end;
  299. Inc(FPos,Result);
  300. end;
  301. function TIDEAEncryptStream.Seek(Offset: Longint; Origin: Word): Longint;
  302. begin
  303. if (Offset = 0) and (Origin = soFromCurrent) then
  304. Result := FPos
  305. else
  306. Raise EIDEAError.Create(SNoSeekAllowed);
  307. end;
  308. { ---------------------------------------------------------------------
  309. TIDEADecryptStream
  310. ---------------------------------------------------------------------}
  311. constructor TIDEADeCryptStream.Create(const AKey: String; Dest: TStream);
  312. Var
  313. K : TIdeaCryptKey;
  314. Z1,Z2 : TIDeaKey;
  315. begin
  316. CreateCryptKey(AKey,K);
  317. EnKeyIDEA(K,Z1);
  318. DeKeyIDEA(Z1,Z2);
  319. Inherited Create(Z2,Dest);
  320. end;
  321. function TIDEADeCryptStream.Read(var Buffer; Count: Longint): Longint;
  322. Var
  323. mvsize : Longint;
  324. InData : IDEAcryptdata;
  325. begin
  326. Result:=0;
  327. While Count>0 do
  328. begin
  329. // Empty existing buffer.
  330. If (FBufPos>0) then
  331. begin
  332. mvSize:=FBufPos;
  333. If MvSize>count then
  334. mvsize:=Count;
  335. Move(PChar(@FData)[0],PChar(@Buffer)[Result],MVSize);
  336. If ((Sizeof(FData)-MvSize)>0) then
  337. Move(PChar(@FData)[mvSize],PChar(@FData)[0],Sizeof(FData)-MvSize);
  338. Dec(Count,mvsize);
  339. Inc(Result,mvsize);
  340. FBufPos:=FBufPos-MvSize;
  341. end;
  342. // Fill buffer again if needed.
  343. If (Count>0) then
  344. begin
  345. mvsize:=Source.Read(InData,SizeOf(InData));
  346. If mvsize>0 then
  347. begin
  348. If MvSize<SizeOf(InData) Then
  349. // Fill with nulls
  350. FillChar(PChar(@InData)[mvsize],SizeOf(InData)-mvsize,#0);
  351. CipherIdea(InData,FData,FKey);
  352. FBufPos:=SizeOf(FData);
  353. end
  354. else
  355. Count:=0; // No more data available from stream; st
  356. end;
  357. end;
  358. Inc(FPos,Result);
  359. end;
  360. function TIDEADeCryptStream.Seek(Offset: Longint; Origin: Word): Longint;
  361. Var Buffer : Array[0..1023] of byte;
  362. i : longint;
  363. begin
  364. // Fake seek if possible by reading and discarding bytes.
  365. If ((Offset>=0) and (Origin = soFromCurrent)) or
  366. ((Offset>FPos) and (Origin = soFromBeginning)) then
  367. begin
  368. For I:=1 to (Offset div SizeOf(Buffer)) do
  369. ReadBuffer(Buffer,SizeOf(Buffer));
  370. ReadBuffer(Buffer,Offset mod SizeOf(Buffer));
  371. Result:=FPos;
  372. end
  373. else
  374. Raise EIDEAError.Create(SNoSeekAllowed);
  375. end;
  376. END.