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