MD5.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. unit MD5;
  2. {
  3. MD5.pas: Translated from C to Delphi by Jordan Russell on 2004-03-16.
  4. Still in the public domain. The original C code was taken from dpkg.
  5. }
  6. (*
  7. * This code implements the MD5 message-digest algorithm.
  8. * The algorithm is due to Ron Rivest. This code was
  9. * written by Colin Plumb in 1993, no copyright is claimed.
  10. * This code is in the public domain; do with it what you wish.
  11. *
  12. * Equivalent code is available from RSA Data Security, Inc.
  13. * This code has been tested against that, and is equivalent,
  14. * except that you don't need to include two pages of legalese
  15. * with every copy.
  16. *
  17. * To compute the message digest of a chunk of bytes, declare an
  18. * MD5Context structure, pass it to MD5Init, call MD5Update as
  19. * needed on buffers full of bytes, and then call MD5Final, which
  20. * will fill a supplied 16-byte array with the digest.
  21. *
  22. * Changed so as no longer to depend on Colin Plumb's `usual.h' header
  23. * definitions; now uses stuff from dpkg's config.h.
  24. * - Ian Jackson <[email protected]>.
  25. * Still in the public domain.
  26. *)
  27. interface
  28. type
  29. TMD5Word = LongWord;
  30. TMD5Buf = array[0..3] of TMD5Word;
  31. TMD5In = array[0..15] of TMD5Word;
  32. TMD5Context = record
  33. buf: TMD5Buf;
  34. bytes: array[0..1] of TMD5Word;
  35. in_: TMD5In;
  36. end;
  37. TMD5Digest = array[0..15] of Byte;
  38. procedure MD5Init(var ctx: TMD5Context);
  39. procedure MD5Update(var ctx: TMD5Context; const buffer; len: Cardinal);
  40. function MD5Final(var ctx: TMD5Context): TMD5Digest;
  41. function MD5Buf(const Buffer; Len: Cardinal): TMD5Digest;
  42. function MD5DigestsEqual(const A, B: TMD5Digest): Boolean;
  43. function MD5DigestToString(const D: TMD5Digest): String;
  44. implementation
  45. procedure MD5Transform(var buf: TMD5Buf; const in_: TMD5In); forward;
  46. // JR: Didn't bother translating this function since Delphi doesn't run on
  47. // any big-endian CPUs.
  48. procedure byteSwap(var buf: TMD5Word; words: Cardinal);
  49. begin
  50. end;
  51. (*
  52. * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
  53. * initialization constants.
  54. *)
  55. procedure MD5Init(var ctx: TMD5Context);
  56. begin
  57. ctx.buf[0] := TMD5Word($67452301);
  58. ctx.buf[1] := TMD5Word($efcdab89);
  59. ctx.buf[2] := TMD5Word($98badcfe);
  60. ctx.buf[3] := TMD5Word($10325476);
  61. ctx.bytes[0] := 0;
  62. ctx.bytes[1] := 0;
  63. end;
  64. (*
  65. * Update context to reflect the concatenation of another buffer full
  66. * of bytes.
  67. *)
  68. procedure MD5Update(var ctx: TMD5Context; const buffer; len: Cardinal);
  69. var
  70. buf: ^Byte;
  71. t: TMD5Word;
  72. begin
  73. buf := @buffer;
  74. { Update byte count }
  75. t := ctx.bytes[0];
  76. Inc(ctx.bytes[0], len);
  77. if Cardinal(ctx.bytes[0]) < Cardinal(t) then
  78. Inc(ctx.bytes[1]); { Carry from low to high }
  79. t := 64 - (t and $3f); { Space available in ctx.in (at least 1) }
  80. if Cardinal(t) > Cardinal(len) then begin
  81. Move(buf^, Pointer(Cardinal(@ctx.in_) + 64 - t)^, len);
  82. Exit;
  83. end;
  84. { First chunk is an odd size }
  85. Move(buf^, Pointer(Cardinal(@ctx.in_) + 64 - t)^, t);
  86. byteSwap(ctx.in_[0], 16);
  87. MD5Transform(ctx.buf, ctx.in_);
  88. Inc(buf, t);
  89. Dec(len, t);
  90. { Process data in 64-byte chunks }
  91. while Cardinal(len) >= Cardinal(64) do begin
  92. Move(buf^, ctx.in_, 64);
  93. byteSwap(ctx.in_[0], 16);
  94. MD5Transform(ctx.buf, ctx.in_);
  95. Inc(buf, 64);
  96. Dec(len, 64);
  97. end;
  98. { Handle any remaining bytes of data. }
  99. Move(buf^, ctx.in_, len);
  100. end;
  101. (*
  102. * Final wrapup - pad to 64-byte boundary with the bit pattern
  103. * 1 0* (64-bit count of bits processed, MSB-first)
  104. *)
  105. function MD5Final(var ctx: TMD5Context): TMD5Digest;
  106. var
  107. count: Integer;
  108. p: ^Byte;
  109. begin
  110. count := ctx.bytes[0] and $3f; { Number of bytes in ctx.in }
  111. p := @ctx.in_;
  112. Inc(p, count);
  113. { Set the first char of padding to 0x80. There is always room. }
  114. p^ := $80;
  115. Inc(p);
  116. { Bytes of padding needed to make 56 bytes (-8..55) }
  117. count := 56 - 1 - count;
  118. if count < 0 then begin { Padding forces an extra block }
  119. FillChar(p^, count + 8, 0);
  120. byteSwap(ctx.in_[0], 16);
  121. MD5Transform(ctx.buf, ctx.in_);
  122. p := @ctx.in_;
  123. count := 56;
  124. end;
  125. FillChar(p^, count, 0);
  126. byteSwap(ctx.in_[0], 14);
  127. { Append length in bits and transform }
  128. ctx.in_[14] := ctx.bytes[0] shl 3;
  129. ctx.in_[15] := (ctx.bytes[1] shl 3) or (ctx.bytes[0] shr 29);
  130. MD5Transform(ctx.buf, ctx.in_);
  131. byteSwap(ctx.buf[0], 4);
  132. Move(ctx.buf, Result, 16);
  133. FillChar(ctx, SizeOf(ctx), 0); { In case it's sensitive }
  134. end;
  135. { The four core functions - F1 is optimized somewhat }
  136. // JR: These macros have been unrolled...
  137. { This is the central step in the MD5 algorithm. }
  138. // JR: These macros have been unrolled...
  139. (*
  140. * The core of the MD5 algorithm, this alters an existing MD5 hash to
  141. * reflect the addition of 16 longwords of new data. MD5Update blocks
  142. * the data and converts bytes into longwords for this routine.
  143. *)
  144. procedure MD5Transform(var buf: TMD5Buf; const in_: TMD5In);
  145. var
  146. a, b, c, d: TMD5Word;
  147. begin
  148. a := buf[0];
  149. b := buf[1];
  150. c := buf[2];
  151. d := buf[3];
  152. // JR: The stuff below was generated using GenTransformCode.dpr
  153. Inc(a, in_[0] + $d76aa478 + (d xor (b and (c xor d)))); a := ((a shl 7) or (a shr (32-7))) + b;
  154. Inc(d, in_[1] + $e8c7b756 + (c xor (a and (b xor c)))); d := ((d shl 12) or (d shr (32-12))) + a;
  155. Inc(c, in_[2] + $242070db + (b xor (d and (a xor b)))); c := ((c shl 17) or (c shr (32-17))) + d;
  156. Inc(b, in_[3] + $c1bdceee + (a xor (c and (d xor a)))); b := ((b shl 22) or (b shr (32-22))) + c;
  157. Inc(a, in_[4] + $f57c0faf + (d xor (b and (c xor d)))); a := ((a shl 7) or (a shr (32-7))) + b;
  158. Inc(d, in_[5] + $4787c62a + (c xor (a and (b xor c)))); d := ((d shl 12) or (d shr (32-12))) + a;
  159. Inc(c, in_[6] + $a8304613 + (b xor (d and (a xor b)))); c := ((c shl 17) or (c shr (32-17))) + d;
  160. Inc(b, in_[7] + $fd469501 + (a xor (c and (d xor a)))); b := ((b shl 22) or (b shr (32-22))) + c;
  161. Inc(a, in_[8] + $698098d8 + (d xor (b and (c xor d)))); a := ((a shl 7) or (a shr (32-7))) + b;
  162. Inc(d, in_[9] + $8b44f7af + (c xor (a and (b xor c)))); d := ((d shl 12) or (d shr (32-12))) + a;
  163. Inc(c, in_[10] + $ffff5bb1 + (b xor (d and (a xor b)))); c := ((c shl 17) or (c shr (32-17))) + d;
  164. Inc(b, in_[11] + $895cd7be + (a xor (c and (d xor a)))); b := ((b shl 22) or (b shr (32-22))) + c;
  165. Inc(a, in_[12] + $6b901122 + (d xor (b and (c xor d)))); a := ((a shl 7) or (a shr (32-7))) + b;
  166. Inc(d, in_[13] + $fd987193 + (c xor (a and (b xor c)))); d := ((d shl 12) or (d shr (32-12))) + a;
  167. Inc(c, in_[14] + $a679438e + (b xor (d and (a xor b)))); c := ((c shl 17) or (c shr (32-17))) + d;
  168. Inc(b, in_[15] + $49b40821 + (a xor (c and (d xor a)))); b := ((b shl 22) or (b shr (32-22))) + c;
  169. Inc(a, in_[1] + $f61e2562 + (c xor (d and (b xor c)))); a := ((a shl 5) or (a shr (32-5))) + b;
  170. Inc(d, in_[6] + $c040b340 + (b xor (c and (a xor b)))); d := ((d shl 9) or (d shr (32-9))) + a;
  171. Inc(c, in_[11] + $265e5a51 + (a xor (b and (d xor a)))); c := ((c shl 14) or (c shr (32-14))) + d;
  172. Inc(b, in_[0] + $e9b6c7aa + (d xor (a and (c xor d)))); b := ((b shl 20) or (b shr (32-20))) + c;
  173. Inc(a, in_[5] + $d62f105d + (c xor (d and (b xor c)))); a := ((a shl 5) or (a shr (32-5))) + b;
  174. Inc(d, in_[10] + $02441453 + (b xor (c and (a xor b)))); d := ((d shl 9) or (d shr (32-9))) + a;
  175. Inc(c, in_[15] + $d8a1e681 + (a xor (b and (d xor a)))); c := ((c shl 14) or (c shr (32-14))) + d;
  176. Inc(b, in_[4] + $e7d3fbc8 + (d xor (a and (c xor d)))); b := ((b shl 20) or (b shr (32-20))) + c;
  177. Inc(a, in_[9] + $21e1cde6 + (c xor (d and (b xor c)))); a := ((a shl 5) or (a shr (32-5))) + b;
  178. Inc(d, in_[14] + $c33707d6 + (b xor (c and (a xor b)))); d := ((d shl 9) or (d shr (32-9))) + a;
  179. Inc(c, in_[3] + $f4d50d87 + (a xor (b and (d xor a)))); c := ((c shl 14) or (c shr (32-14))) + d;
  180. Inc(b, in_[8] + $455a14ed + (d xor (a and (c xor d)))); b := ((b shl 20) or (b shr (32-20))) + c;
  181. Inc(a, in_[13] + $a9e3e905 + (c xor (d and (b xor c)))); a := ((a shl 5) or (a shr (32-5))) + b;
  182. Inc(d, in_[2] + $fcefa3f8 + (b xor (c and (a xor b)))); d := ((d shl 9) or (d shr (32-9))) + a;
  183. Inc(c, in_[7] + $676f02d9 + (a xor (b and (d xor a)))); c := ((c shl 14) or (c shr (32-14))) + d;
  184. Inc(b, in_[12] + $8d2a4c8a + (d xor (a and (c xor d)))); b := ((b shl 20) or (b shr (32-20))) + c;
  185. Inc(a, in_[5] + $fffa3942 + (b xor c xor d)); a := ((a shl 4) or (a shr (32-4))) + b;
  186. Inc(d, in_[8] + $8771f681 + (a xor b xor c)); d := ((d shl 11) or (d shr (32-11))) + a;
  187. Inc(c, in_[11] + $6d9d6122 + (d xor a xor b)); c := ((c shl 16) or (c shr (32-16))) + d;
  188. Inc(b, in_[14] + $fde5380c + (c xor d xor a)); b := ((b shl 23) or (b shr (32-23))) + c;
  189. Inc(a, in_[1] + $a4beea44 + (b xor c xor d)); a := ((a shl 4) or (a shr (32-4))) + b;
  190. Inc(d, in_[4] + $4bdecfa9 + (a xor b xor c)); d := ((d shl 11) or (d shr (32-11))) + a;
  191. Inc(c, in_[7] + $f6bb4b60 + (d xor a xor b)); c := ((c shl 16) or (c shr (32-16))) + d;
  192. Inc(b, in_[10] + $bebfbc70 + (c xor d xor a)); b := ((b shl 23) or (b shr (32-23))) + c;
  193. Inc(a, in_[13] + $289b7ec6 + (b xor c xor d)); a := ((a shl 4) or (a shr (32-4))) + b;
  194. Inc(d, in_[0] + $eaa127fa + (a xor b xor c)); d := ((d shl 11) or (d shr (32-11))) + a;
  195. Inc(c, in_[3] + $d4ef3085 + (d xor a xor b)); c := ((c shl 16) or (c shr (32-16))) + d;
  196. Inc(b, in_[6] + $04881d05 + (c xor d xor a)); b := ((b shl 23) or (b shr (32-23))) + c;
  197. Inc(a, in_[9] + $d9d4d039 + (b xor c xor d)); a := ((a shl 4) or (a shr (32-4))) + b;
  198. Inc(d, in_[12] + $e6db99e5 + (a xor b xor c)); d := ((d shl 11) or (d shr (32-11))) + a;
  199. Inc(c, in_[15] + $1fa27cf8 + (d xor a xor b)); c := ((c shl 16) or (c shr (32-16))) + d;
  200. Inc(b, in_[2] + $c4ac5665 + (c xor d xor a)); b := ((b shl 23) or (b shr (32-23))) + c;
  201. Inc(a, in_[0] + $f4292244 + (c xor (b or (not d)))); a := ((a shl 6) or (a shr (32-6))) + b;
  202. Inc(d, in_[7] + $432aff97 + (b xor (a or (not c)))); d := ((d shl 10) or (d shr (32-10))) + a;
  203. Inc(c, in_[14] + $ab9423a7 + (a xor (d or (not b)))); c := ((c shl 15) or (c shr (32-15))) + d;
  204. Inc(b, in_[5] + $fc93a039 + (d xor (c or (not a)))); b := ((b shl 21) or (b shr (32-21))) + c;
  205. Inc(a, in_[12] + $655b59c3 + (c xor (b or (not d)))); a := ((a shl 6) or (a shr (32-6))) + b;
  206. Inc(d, in_[3] + $8f0ccc92 + (b xor (a or (not c)))); d := ((d shl 10) or (d shr (32-10))) + a;
  207. Inc(c, in_[10] + $ffeff47d + (a xor (d or (not b)))); c := ((c shl 15) or (c shr (32-15))) + d;
  208. Inc(b, in_[1] + $85845dd1 + (d xor (c or (not a)))); b := ((b shl 21) or (b shr (32-21))) + c;
  209. Inc(a, in_[8] + $6fa87e4f + (c xor (b or (not d)))); a := ((a shl 6) or (a shr (32-6))) + b;
  210. Inc(d, in_[15] + $fe2ce6e0 + (b xor (a or (not c)))); d := ((d shl 10) or (d shr (32-10))) + a;
  211. Inc(c, in_[6] + $a3014314 + (a xor (d or (not b)))); c := ((c shl 15) or (c shr (32-15))) + d;
  212. Inc(b, in_[13] + $4e0811a1 + (d xor (c or (not a)))); b := ((b shl 21) or (b shr (32-21))) + c;
  213. Inc(a, in_[4] + $f7537e82 + (c xor (b or (not d)))); a := ((a shl 6) or (a shr (32-6))) + b;
  214. Inc(d, in_[11] + $bd3af235 + (b xor (a or (not c)))); d := ((d shl 10) or (d shr (32-10))) + a;
  215. Inc(c, in_[2] + $2ad7d2bb + (a xor (d or (not b)))); c := ((c shl 15) or (c shr (32-15))) + d;
  216. Inc(b, in_[9] + $eb86d391 + (d xor (c or (not a)))); b := ((b shl 21) or (b shr (32-21))) + c;
  217. Inc(buf[0], a);
  218. Inc(buf[1], b);
  219. Inc(buf[2], c);
  220. Inc(buf[3], d);
  221. end;
  222. { New functions by JR: }
  223. function MD5Buf(const Buffer; Len: Cardinal): TMD5Digest;
  224. var
  225. Context: TMD5Context;
  226. begin
  227. MD5Init(Context);
  228. MD5Update(Context, Buffer, Len);
  229. Result := MD5Final(Context);
  230. end;
  231. function MD5DigestsEqual(const A, B: TMD5Digest): Boolean;
  232. var
  233. I: Integer;
  234. begin
  235. for I := Low(TMD5Digest) to High(TMD5Digest) do
  236. if A[I] <> B[I] then begin
  237. Result := False;
  238. Exit;
  239. end;
  240. Result := True;
  241. end;
  242. function MD5DigestToString(const D: TMD5Digest): String;
  243. const
  244. Digits: array[0..15] of Char = '0123456789abcdef';
  245. var
  246. Buf: array[0..31] of Char;
  247. P: PChar;
  248. I: Integer;
  249. begin
  250. P := @Buf;
  251. for I := 0 to 15 do begin
  252. P^ := Digits[D[I] shr 4];
  253. Inc(P);
  254. P^ := Digits[D[I] and 15];
  255. Inc(P);
  256. end;
  257. SetString(Result, Buf, 32);
  258. end;
  259. end.