MD5Unit.pas 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. unit MD5Unit;
  2. interface
  3. uses
  4. Windows;
  5. type
  6. MD5Count = array[0..1] of DWORD;
  7. MD5State = array[0..3] of DWORD;
  8. MD5Block = array[0..15] of DWORD;
  9. MD5CBits = array[0..7] of Byte;
  10. MD5Digest = array[0..15] of Byte;
  11. MD5Buffer = array[0..63] of Byte;
  12. MD5Context = record
  13. State: MD5State;
  14. Count: MD5Count;
  15. Buffer: MD5Buffer;
  16. end;
  17. procedure MD5Init(var Context: MD5Context);
  18. procedure MD5Update(var Context: MD5Context; Input: pChar; Length: longword);
  19. procedure MD5Final(var Context: MD5Context; var Digest: MD5Digest);
  20. function MD5String(M: string): MD5Digest;
  21. function MD5File(N: string): MD5Digest;
  22. function MD5Print(D: MD5Digest): string;
  23. function MD5Match(D1, D2: MD5Digest): Boolean;
  24. function RivestStr(Str: string): string; //MD5 string
  25. function RivestFile(FileName: string): string; //MD5 file
  26. function MD5_Str(AStr: string): string;
  27. function MD5_File(AFile: string): string;
  28. implementation
  29. uses SysUtils;
  30. var
  31. PADDING: MD5Buffer = (
  32. $80, $00, $00, $00, $00, $00, $00, $00,
  33. $00, $00, $00, $00, $00, $00, $00, $00,
  34. $00, $00, $00, $00, $00, $00, $00, $00,
  35. $00, $00, $00, $00, $00, $00, $00, $00,
  36. $00, $00, $00, $00, $00, $00, $00, $00,
  37. $00, $00, $00, $00, $00, $00, $00, $00,
  38. $00, $00, $00, $00, $00, $00, $00, $00,
  39. $00, $00, $00, $00, $00, $00, $00, $00);
  40. function F(x, y, z: DWORD): DWORD;
  41. begin
  42. Result := (x and y) or ((not x) and z);
  43. end;
  44. function G(x, y, z: DWORD): DWORD;
  45. begin
  46. Result := (x and z) or (y and (not z));
  47. end;
  48. function H(x, y, z: DWORD): DWORD;
  49. begin
  50. Result := x xor y xor z;
  51. end;
  52. function I(x, y, z: DWORD): DWORD;
  53. begin
  54. Result := y xor (x or (not z));
  55. end;
  56. procedure rot(var x: DWORD; n: BYTE);
  57. begin
  58. x := (x shl n) or (x shr (32 - n));
  59. end;
  60. procedure FF(var a: DWORD; b, c, d, x: DWORD; s: BYTE; ac: DWORD);
  61. begin
  62. inc(a, F(b, c, d) + x + ac);
  63. rot(a, s);
  64. inc(a, b);
  65. end;
  66. procedure GG(var a: DWORD; b, c, d, x: DWORD; s: BYTE; ac: DWORD);
  67. begin
  68. inc(a, G(b, c, d) + x + ac);
  69. rot(a, s);
  70. inc(a, b);
  71. end;
  72. procedure HH(var a: DWORD; b, c, d, x: DWORD; s: BYTE; ac: DWORD);
  73. begin
  74. inc(a, H(b, c, d) + x + ac);
  75. rot(a, s);
  76. inc(a, b);
  77. end;
  78. procedure II(var a: DWORD; b, c, d, x: DWORD; s: BYTE; ac: DWORD);
  79. begin
  80. inc(a, I(b, c, d) + x + ac);
  81. rot(a, s);
  82. inc(a, b);
  83. end;
  84. // Encode Count bytes at Source into (Count / 4) DWORDs at Target
  85. procedure Encode(Source, Target: pointer; Count: longword);
  86. var
  87. S: PByte;
  88. T: PDWORD;
  89. I: longword;
  90. begin
  91. S := Source;
  92. T := Target;
  93. for I := 1 to Count div 4 do
  94. begin
  95. T^ := S^;
  96. inc(S);
  97. T^ := T^ or (S^ shl 8);
  98. inc(S);
  99. T^ := T^ or (S^ shl 16);
  100. inc(S);
  101. T^ := T^ or (S^ shl 24);
  102. inc(S);
  103. inc(T);
  104. end;
  105. end;
  106. // Decode Count DWORDs at Source into (Count * 4) Bytes at Target
  107. procedure Decode(Source, Target: pointer; Count: longword);
  108. var
  109. S: PDWORD;
  110. T: PByte;
  111. I: longword;
  112. begin
  113. S := Source;
  114. T := Target;
  115. for I := 1 to Count do
  116. begin
  117. T^ := S^ and $ff;
  118. inc(T);
  119. T^ := (S^ shr 8) and $ff;
  120. inc(T);
  121. T^ := (S^ shr 16) and $ff;
  122. inc(T);
  123. T^ := (S^ shr 24) and $ff;
  124. inc(T);
  125. inc(S);
  126. end;
  127. end;
  128. // Transform State according to first 64 bytes at Buffer
  129. procedure Transform(Buffer: pointer; var State: MD5State);
  130. var
  131. a, b, c, d: DWORD;
  132. Block: MD5Block;
  133. begin
  134. Encode(Buffer, @Block, 64);
  135. a := State[0];
  136. b := State[1];
  137. c := State[2];
  138. d := State[3];
  139. FF (a, b, c, d, Block[ 0], 7, $d76aa478);
  140. FF (d, a, b, c, Block[ 1], 12, $e8c7b756);
  141. FF (c, d, a, b, Block[ 2], 17, $242070db);
  142. FF (b, c, d, a, Block[ 3], 22, $c1bdceee);
  143. FF (a, b, c, d, Block[ 4], 7, $f57c0faf);
  144. FF (d, a, b, c, Block[ 5], 12, $4787c62a);
  145. FF (c, d, a, b, Block[ 6], 17, $a8304613);
  146. FF (b, c, d, a, Block[ 7], 22, $fd469501);
  147. FF (a, b, c, d, Block[ 8], 7, $698098d8);
  148. FF (d, a, b, c, Block[ 9], 12, $8b44f7af);
  149. FF (c, d, a, b, Block[10], 17, $ffff5bb1);
  150. FF (b, c, d, a, Block[11], 22, $895cd7be);
  151. FF (a, b, c, d, Block[12], 7, $6b901122);
  152. FF (d, a, b, c, Block[13], 12, $fd987193);
  153. FF (c, d, a, b, Block[14], 17, $a679438e);
  154. FF (b, c, d, a, Block[15], 22, $49b40821);
  155. GG (a, b, c, d, Block[ 1], 5, $f61e2562);
  156. GG (d, a, b, c, Block[ 6], 9, $c040b340);
  157. GG (c, d, a, b, Block[11], 14, $265e5a51);
  158. GG (b, c, d, a, Block[ 0], 20, $e9b6c7aa);
  159. GG (a, b, c, d, Block[ 5], 5, $d62f105d);
  160. GG (d, a, b, c, Block[10], 9, $2441453);
  161. GG (c, d, a, b, Block[15], 14, $d8a1e681);
  162. GG (b, c, d, a, Block[ 4], 20, $e7d3fbc8);
  163. GG (a, b, c, d, Block[ 9], 5, $21e1cde6);
  164. GG (d, a, b, c, Block[14], 9, $c33707d6);
  165. GG (c, d, a, b, Block[ 3], 14, $f4d50d87);
  166. GG (b, c, d, a, Block[ 8], 20, $455a14ed);
  167. GG (a, b, c, d, Block[13], 5, $a9e3e905);
  168. GG (d, a, b, c, Block[ 2], 9, $fcefa3f8);
  169. GG (c, d, a, b, Block[ 7], 14, $676f02d9);
  170. GG (b, c, d, a, Block[12], 20, $8d2a4c8a);
  171. HH (a, b, c, d, Block[ 5], 4, $fffa3942);
  172. HH (d, a, b, c, Block[ 8], 11, $8771f681);
  173. HH (c, d, a, b, Block[11], 16, $6d9d6122);
  174. HH (b, c, d, a, Block[14], 23, $fde5380c);
  175. HH (a, b, c, d, Block[ 1], 4, $a4beea44);
  176. HH (d, a, b, c, Block[ 4], 11, $4bdecfa9);
  177. HH (c, d, a, b, Block[ 7], 16, $f6bb4b60);
  178. HH (b, c, d, a, Block[10], 23, $bebfbc70);
  179. HH (a, b, c, d, Block[13], 4, $289b7ec6);
  180. HH (d, a, b, c, Block[ 0], 11, $eaa127fa);
  181. HH (c, d, a, b, Block[ 3], 16, $d4ef3085);
  182. HH (b, c, d, a, Block[ 6], 23, $4881d05);
  183. HH (a, b, c, d, Block[ 9], 4, $d9d4d039);
  184. HH (d, a, b, c, Block[12], 11, $e6db99e5);
  185. HH (c, d, a, b, Block[15], 16, $1fa27cf8);
  186. HH (b, c, d, a, Block[ 2], 23, $c4ac5665);
  187. II (a, b, c, d, Block[ 0], 6, $f4292244);
  188. II (d, a, b, c, Block[ 7], 10, $432aff97);
  189. II (c, d, a, b, Block[14], 15, $ab9423a7);
  190. II (b, c, d, a, Block[ 5], 21, $fc93a039);
  191. II (a, b, c, d, Block[12], 6, $655b59c3);
  192. II (d, a, b, c, Block[ 3], 10, $8f0ccc92);
  193. II (c, d, a, b, Block[10], 15, $ffeff47d);
  194. II (b, c, d, a, Block[ 1], 21, $85845dd1);
  195. II (a, b, c, d, Block[ 8], 6, $6fa87e4f);
  196. II (d, a, b, c, Block[15], 10, $fe2ce6e0);
  197. II (c, d, a, b, Block[ 6], 15, $a3014314);
  198. II (b, c, d, a, Block[13], 21, $4e0811a1);
  199. II (a, b, c, d, Block[ 4], 6, $f7537e82);
  200. II (d, a, b, c, Block[11], 10, $bd3af235);
  201. II (c, d, a, b, Block[ 2], 15, $2ad7d2bb);
  202. II (b, c, d, a, Block[ 9], 21, $eb86d391);
  203. inc(State[0], a);
  204. inc(State[1], b);
  205. inc(State[2], c);
  206. inc(State[3], d);
  207. end;
  208. // Initialize given Context
  209. procedure MD5Init(var Context: MD5Context);
  210. begin
  211. with Context do begin
  212. State[0] := $67452301;
  213. State[1] := $efcdab89;
  214. State[2] := $98badcfe;
  215. State[3] := $10325476;
  216. Count[0] := 0;
  217. Count[1] := 0;
  218. ZeroMemory(@Buffer, SizeOf(MD5Buffer));
  219. end;
  220. end;
  221. // Update given Context to include Length bytes of Input
  222. procedure MD5Update(var Context: MD5Context; Input: pChar; Length: longword);
  223. var
  224. Index: longword;
  225. PartLen: longword;
  226. I: longword;
  227. begin
  228. with Context do
  229. begin
  230. Index := (Count[0] shr 3) and $3f;
  231. inc(Count[0], Length shl 3);
  232. if Count[0] < (Length shl 3) then inc(Count[1]);
  233. inc(Count[1], Length shr 29);
  234. end;
  235. PartLen := 64 - Index;
  236. if Length >= PartLen then
  237. begin
  238. CopyMemory(@Context.Buffer[Index], Input, PartLen);
  239. Transform(@Context.Buffer, Context.State);
  240. I := PartLen;
  241. while I + 63 < Length do begin
  242. Transform(@Input[I], Context.State);
  243. inc(I, 64);
  244. end;
  245. Index := 0;
  246. end
  247. else I := 0;
  248. CopyMemory(@Context.Buffer[Index], @Input[I], Length - I);
  249. end;
  250. // Finalize given Context, create Digest and zeroize Context
  251. procedure MD5Final(var Context: MD5Context; var Digest: MD5Digest);
  252. var
  253. Bits: MD5CBits;
  254. Index: longword;
  255. PadLen: longword;
  256. begin
  257. Decode(@Context.Count, @Bits, 2);
  258. Index := (Context.Count[0] shr 3) and $3f;
  259. if Index < 56 then PadLen := 56 - Index else PadLen := 120 - Index;
  260. MD5Update(Context, @PADDING, PadLen);
  261. MD5Update(Context, @Bits, 8);
  262. Decode(@Context.State, @Digest, 4);
  263. ZeroMemory(@Context, SizeOf(MD5Context));
  264. end;
  265. // Create digest of given Message
  266. function MD5String(M: string): MD5Digest;
  267. var
  268. Context: MD5Context;
  269. begin
  270. MD5Init(Context);
  271. MD5Update(Context, pChar(M), length(M));
  272. MD5Final(Context, Result);
  273. end;
  274. // Create digest of file with given Name
  275. function MD5File(N: string): MD5Digest;
  276. var
  277. FileHandle: THandle;
  278. MapHandle: THandle;
  279. ViewPointer: pointer;
  280. Context: MD5Context;
  281. begin
  282. MD5Init(Context);
  283. FileHandle := CreateFile(pChar(N), GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE,
  284. nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or FILE_FLAG_SEQUENTIAL_SCAN, 0);
  285. if FileHandle <> INVALID_HANDLE_VALUE then
  286. try
  287. MapHandle := CreateFileMapping(FileHandle, nil, PAGE_READONLY, 0, 0, nil);
  288. if MapHandle <> 0 then
  289. try
  290. ViewPointer := MapViewOfFile(MapHandle, FILE_MAP_READ, 0, 0, 0);
  291. if ViewPointer <> nil then
  292. try
  293. MD5Update(Context, ViewPointer, GetFileSize(FileHandle, nil));
  294. finally
  295. UnmapViewOfFile(ViewPointer);
  296. end;
  297. finally
  298. CloseHandle(MapHandle);
  299. end;
  300. finally
  301. CloseHandle(FileHandle);
  302. end;
  303. MD5Final(Context, Result);
  304. end;
  305. // Create hex representation of given Digest
  306. function MD5Print(D: MD5Digest): string;
  307. var
  308. I: byte;
  309. const
  310. Digits: array[0..15] of char =
  311. ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f');
  312. begin
  313. Result := '';
  314. for I := 0 to 15 do
  315. Result := Result + Digits[(D[I] shr 4) and $0f] + Digits[D[I] and $0f];
  316. end;
  317. // Compare two Digests
  318. function MD5Match(D1, D2: MD5Digest): boolean;
  319. var
  320. I: byte;
  321. begin
  322. I := 0;
  323. Result := TRUE;
  324. while Result and (I < 16) do begin
  325. Result := D1[I] = D2[I];
  326. inc(I);
  327. end;
  328. end;
  329. function RivestStr(Str: string): string;
  330. begin
  331. Result := MD5Print(MD5String(Str));
  332. end;
  333. function RivestFile(FileName: string): string;
  334. begin
  335. Result := MD5Print(MD5File(FileName));
  336. end;
  337. function MD5_Str(AStr: string): string;
  338. begin
  339. Result := RivestStr(AStr);
  340. end;
  341. function MD5_File(AFile: string): string;
  342. begin
  343. Result := RivestFile(AFile);
  344. end;
  345. end.