md5.pp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. {
  2. $Id$
  3. This file is part of the Free Pascal packages.
  4. Copyright (c) 1999-2000 by the Free Pascal development team
  5. Implements a MD5 digest algorithm.
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. {
  13. Implements a MD5 digest algorithm (RFC 1321)
  14. }
  15. unit md5;
  16. {$mode objfpc}
  17. {$h+}
  18. Interface
  19. type
  20. PCardinal = ^Cardinal;
  21. TMD5Count = array[0..1] of Cardinal;
  22. TMD5State = array[0..3] of Cardinal;
  23. TMD5Block = array[0..15] of Cardinal;
  24. TMD5CBits = array[0..7] of byte;
  25. TMD5Digest = array[0..15] of byte;
  26. TMD5Buffer = array[0..63] of byte;
  27. TMD5Context = packed record
  28. State: TMD5State;
  29. Count: TMD5Count;
  30. Buffer: TMD5Buffer;
  31. end;
  32. Const
  33. DefBufSize : Cardinal = 1024;
  34. { Raw methods }
  35. procedure MD5Init(var Context: TMD5Context);
  36. procedure MD5Update(var Context: TMD5Context; Var Buf; BufLen: cardinal);
  37. procedure MD5Final(var Context: TMD5Context; var Digest: TMD5Digest);
  38. { Auxiliary methods }
  39. function MD5String(M: string): TMD5Digest;
  40. function MD5File(N: string): TMD5Digest;
  41. function MD5File(N: string; Bufsize : Cardinal): TMD5Digest;
  42. function MD5Print(D: TMD5Digest): String;
  43. // based on an implementation by Matthias Fichtner
  44. function MD5Match(D1, D2: TMD5Digest): boolean;
  45. Implementation
  46. Var
  47. PADDING: TMD5Buffer;
  48. { Transformations. }
  49. function F(x,y,z: Cardinal): Cardinal;
  50. begin
  51. Result:=(x and y) or ((not x) and z);
  52. end;
  53. function G(x,y,z: Cardinal): Cardinal;
  54. begin
  55. Result:=(x and z) or (y and (not z));
  56. end;
  57. function H(x,y,z: Cardinal): Cardinal;
  58. begin
  59. Result:=x xor y xor z;
  60. end;
  61. function I(x,y,z: Cardinal): Cardinal;
  62. begin
  63. Result:=y xor (x or (not z));
  64. end;
  65. procedure rot(var x: Cardinal; n: Byte);
  66. begin
  67. x:=(x shl n) or (x shr (32 - n));
  68. end;
  69. procedure FF(var a: Cardinal;b,c,d,x: Cardinal; s: Byte; ac: Cardinal);
  70. begin
  71. inc(a,F(b,c,d)+x+ac);
  72. rot(a,s);
  73. inc(a,b);
  74. end;
  75. procedure GG(var a: Cardinal;b,c,d,x: Cardinal;s: Byte;ac: Cardinal);
  76. begin
  77. inc(a,G(b,c,d)+x+ac);
  78. rot(a,s);
  79. inc(a,b);
  80. end;
  81. procedure HH(var a: Cardinal;b,c,d,x: Cardinal;s: Byte;ac: Cardinal);
  82. begin
  83. inc(a,H(b,c,d)+x+ac);
  84. rot(a,s);
  85. inc(a,b);
  86. end;
  87. procedure II(var a: Cardinal;b,c,d,x: Cardinal;s: Byte;ac: Cardinal);
  88. begin
  89. inc(a,I(b,c,d)+x+ac);
  90. rot(a,s);
  91. inc(a,b);
  92. end;
  93. // inverts the bytes of (Count div) 4 cardinals from source to target.
  94. procedure Invert(Source,Target: pointer; Count: cardinal);
  95. var
  96. S: PByte;
  97. T: PCardinal;
  98. I: cardinal;
  99. begin
  100. S := Source;
  101. T := Target;
  102. for I := 1 to (Count div 4) do
  103. begin
  104. T^:=S[0] or (S[1] shl 8) or (S[2] shl 16) or (S[3] shl 24);
  105. inc(S,4);
  106. inc(T);
  107. end;
  108. end;
  109. procedure Transform(Buffer: pointer; var State: TMD5State);
  110. var
  111. a, b, c, d: Cardinal;
  112. Block: TMD5Block;
  113. begin
  114. Invert(Buffer, @Block, 64);
  115. a:=State[0];
  116. b:=State[1];
  117. c:=State[2];
  118. d:=State[3];
  119. FF(a,b,c,d,Block[0] , 7,$d76aa478);
  120. FF(d,a,b,c,Block[1] ,12,$e8c7b756);
  121. FF(c,d,a,b,Block[2] ,17,$242070db);
  122. FF(b,c,d,a,Block[3] ,22,$c1bdceee);
  123. FF(a,b,c,d,Block[4] , 7,$f57c0faf);
  124. FF(d,a,b,c,Block[5] ,12,$4787c62a);
  125. FF(c,d,a,b,Block[6] ,17,$a8304613);
  126. FF(b,c,d,a,Block[7] ,22,$fd469501);
  127. FF(a,b,c,d,Block[8] , 7,$698098d8);
  128. FF(d,a,b,c,Block[9] ,12,$8b44f7af);
  129. FF(c,d,a,b,Block[10],17,$ffff5bb1);
  130. FF(b,c,d,a,Block[11],22,$895cd7be);
  131. FF(a,b,c,d,Block[12], 7,$6b901122);
  132. FF(d,a,b,c,Block[13],12,$fd987193);
  133. FF(c,d,a,b,Block[14],17,$a679438e);
  134. FF(b,c,d,a,Block[15],22,$49b40821);
  135. GG(a,b,c,d,Block[1] , 5,$f61e2562);
  136. GG(d,a,b,c,Block[6] , 9,$c040b340);
  137. GG(c,d,a,b,Block[11],14,$265e5a51);
  138. GG(b,c,d,a,Block[0] ,20,$e9b6c7aa);
  139. GG(a,b,c,d,Block[5] , 5,$d62f105d);
  140. GG(d,a,b,c,Block[10], 9,$02441453);
  141. GG(c,d,a,b,Block[15],14,$d8a1e681);
  142. GG(b,c,d,a,Block[4] ,20,$e7d3fbc8);
  143. GG(a,b,c,d,Block[9] , 5,$21e1cde6);
  144. GG(d,a,b,c,Block[14], 9,$c33707d6);
  145. GG(c,d,a,b,Block[3] ,14,$f4d50d87);
  146. GG(b,c,d,a,Block[8] ,20,$455a14ed);
  147. GG(a,b,c,d,Block[13], 5,$a9e3e905);
  148. GG(d,a,b,c,Block[2] , 9,$fcefa3f8);
  149. GG(c,d,a,b,Block[7] ,14,$676f02d9);
  150. GG(b,c,d,a,Block[12],20,$8d2a4c8a);
  151. HH(a,b,c,d,Block[5] , 4,$fffa3942);
  152. HH(d,a,b,c,Block[8] ,11,$8771f681);
  153. HH(c,d,a,b,Block[11],16,$6d9d6122);
  154. HH(b,c,d,a,Block[14],23,$fde5380c);
  155. HH(a,b,c,d,Block[1] , 4,$a4beea44);
  156. HH(d,a,b,c,Block[4] ,11,$4bdecfa9);
  157. HH(c,d,a,b,Block[7] ,16,$f6bb4b60);
  158. HH(b,c,d,a,Block[10],23,$bebfbc70);
  159. HH(a,b,c,d,Block[13], 4,$289b7ec6);
  160. HH(d,a,b,c,Block[0] ,11,$eaa127fa);
  161. HH(c,d,a,b,Block[3] ,16,$d4ef3085);
  162. HH(b,c,d,a,Block[6] ,23,$04881d05);
  163. HH(a,b,c,d,Block[9] , 4,$d9d4d039);
  164. HH(d,a,b,c,Block[12],11,$e6db99e5);
  165. HH(c,d,a,b,Block[15],16,$1fa27cf8);
  166. HH(b,c,d,a,Block[2] ,23,$c4ac5665);
  167. II(a,b,c,d,Block[0] , 6,$f4292244);
  168. II(d,a,b,c,Block[7] ,10,$432aff97);
  169. II(c,d,a,b,Block[14],15,$ab9423a7);
  170. II(b,c,d,a,Block[5] ,21,$fc93a039);
  171. II(a,b,c,d,Block[12], 6,$655b59c3);
  172. II(d,a,b,c,Block[3] ,10,$8f0ccc92);
  173. II(c,d,a,b,Block[10],15,$ffeff47d);
  174. II(b,c,d,a,Block[1] ,21,$85845dd1);
  175. II(a,b,c,d,Block[8] , 6,$6fa87e4f);
  176. II(d,a,b,c,Block[15],10,$fe2ce6e0);
  177. II(c,d,a,b,Block[6] ,15,$a3014314);
  178. II(b,c,d,a,Block[13],21,$4e0811a1);
  179. II(a,b,c,d,Block[4] , 6,$f7537e82);
  180. II(d,a,b,c,Block[11],10,$bd3af235);
  181. II(c,d,a,b,Block[2] ,15,$2ad7d2bb);
  182. II(b,c,d,a,Block[9] ,21,$eb86d391);
  183. inc(State[0],a);
  184. inc(State[1],b);
  185. inc(State[2],c);
  186. inc(State[3],d);
  187. end;
  188. procedure MD5Init(var Context: TMD5Context);
  189. begin
  190. with Context do
  191. begin
  192. State[0] := $67452301;
  193. State[1] := $efcdab89;
  194. State[2] := $98badcfe;
  195. State[3] := $10325476;
  196. Count[0] := 0;
  197. Count[1] := 0;
  198. FillChar(Buffer, SizeOf(TMD5Buffer),0);
  199. end;
  200. end;
  201. procedure MD5Update(var Context: TMD5Context; Var Buf; BufLen: cardinal);
  202. var
  203. Index: cardinal;
  204. PartLen: cardinal;
  205. I: cardinal;
  206. P : PByte;
  207. begin
  208. P:=PByte(@Buf);
  209. with Context do
  210. begin
  211. Index := (Count[0] shr 3) and $3f;
  212. inc(Count[0], BufLen shl 3);
  213. if Count[0] < (BufLen shl 3) then inc(Count[1]);
  214. inc(Count[1], BufLen shr 29);
  215. end;
  216. PartLen := 64 - Index;
  217. if BufLen >= PartLen then
  218. begin
  219. Move(Buf,Context.Buffer[Index], PartLen);
  220. Transform(@Context.Buffer, Context.State);
  221. I := PartLen;
  222. while I+63 < BufLen do
  223. begin
  224. Transform(@P[I], Context.State);
  225. inc(I, 64);
  226. end;
  227. Index := 0;
  228. end
  229. else I := 0;
  230. Move(P[I],Context.Buffer[Index], BufLen - I);
  231. end;
  232. procedure MD5Final(var Context: TMD5Context; var Digest: TMD5Digest);
  233. var
  234. Bits: TMD5CBits;
  235. I : cardinal;
  236. Pad : cardinal;
  237. begin
  238. Invert(@Context.Count, @Bits, 8);
  239. I:=(Context.Count[0] shr 3) and $3f;
  240. if I<56 then
  241. Pad:=56-I
  242. else
  243. Pad:=120-I;
  244. MD5Update(Context, Padding, Pad);
  245. MD5Update(Context, Bits, 8);
  246. Invert(@Context.State, @Digest, 16);
  247. FillChar(Context, SizeOf(TMD5Context),0);
  248. end;
  249. function MD5String(M: string): TMD5Digest;
  250. var
  251. Context: TMD5Context;
  252. begin
  253. MD5Init(Context);
  254. MD5Update(Context, M[1], length(M));
  255. MD5Final(Context, Result);
  256. end;
  257. function MD5File(N: string): TMD5Digest;
  258. begin
  259. Result:=MD5File(N,DefBufSize);
  260. end;
  261. function MD5File(N: string; BufSize : Cardinal): TMD5Digest;
  262. var
  263. F : File;
  264. Buf : Pchar;
  265. Context: TMD5Context;
  266. Count : Longint;
  267. begin
  268. MD5Init(Context);
  269. Assign(F,N);
  270. {$i-}
  271. Reset(F,1);
  272. {$i+}
  273. if (IOResult=0) then
  274. begin
  275. GetMem(Buf,BufSize);
  276. Repeat
  277. BlockRead(F,Buf^,Bufsize,Count);
  278. If (Count>0) then
  279. MD5Update(Context, Buf^, Count);
  280. Until (Count<BufSize);
  281. Close(F);
  282. end;
  283. MD5Final(Context, Result);
  284. end;
  285. function MD5Print(D: TMD5Digest): string;
  286. var
  287. I: byte;
  288. begin
  289. Result := '';
  290. for I := 0 to 15 do
  291. Result := Result + HexStr(D[i],2);
  292. Result:=LowerCase(Result);
  293. end;
  294. function MD5Match(D1, D2: TMD5Digest): boolean;
  295. var
  296. I: byte;
  297. begin
  298. I := 0;
  299. Result := TRUE;
  300. while Result and (I < 16) do begin
  301. Result := D1[I] = D2[I];
  302. inc(I);
  303. end;
  304. end;
  305. Initialization
  306. FillChar(Padding,SizeOF(Padding),0);
  307. Padding[0]:=$80;
  308. end.