idea.pp 9.3 KB

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