MD5_32.pas 11 KB

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