2
0

idea.pp 11 KB

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