md5.pp 8.1 KB

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