md5.pp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684
  1. {
  2. This file is part of the Free Pascal packages.
  3. Copyright (c) 1999-2006 by the Free Pascal development team
  4. Implements a MD2 digest algorithm (RFC 1319)
  5. Implements a MD4 digest algorithm (RFC 1320)
  6. Implements a MD5 digest algorithm (RFC 1321)
  7. See the file COPYING.FPC, included in this distribution,
  8. for details about the copyright.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. **********************************************************************}
  13. unit md5;
  14. {$mode objfpc}
  15. {$inline on}
  16. {$h+}
  17. interface
  18. (******************************************************************************
  19. * types and constants
  20. ******************************************************************************)
  21. const
  22. MDDefBufSize = 1024;
  23. type
  24. TMDVersion = (
  25. MD_VERSION_2,
  26. MD_VERSION_4,
  27. MD_VERSION_5
  28. );
  29. PMDDigest = ^TMDDigest;
  30. TMDDigest = array[0..15] of Byte;
  31. PMD2Digset = PMDDigest;
  32. TMD2Digest = TMDDigest;
  33. PMD4Digset = PMDDigest;
  34. TMD4Digest = TMDDigest;
  35. PMD5Digset = PMDDigest;
  36. TMD5Digest = TMDDigest;
  37. PMDContext = ^TMDContext;
  38. TMDContext = record
  39. Version : TMDVersion;
  40. Align : PtrUInt;
  41. State : array[0..3] of Cardinal;
  42. BufCnt : PtrUInt;
  43. Buffer : array[0..63] of Byte;
  44. case Integer of
  45. 0: (Length : PtrUInt);
  46. 1: (Checksum : array[0..15] of Byte);
  47. end;
  48. PMD2Context = PMDContext;
  49. TMD2Context = TMDContext;
  50. PMD4Context = PMDContext;
  51. TMD4Context = TMDContext;
  52. PMD5Context = PMDContext;
  53. TMD5Context = TMDContext;
  54. (******************************************************************************
  55. * Core raw functions
  56. ******************************************************************************)
  57. procedure MDInit(var Context: TMDContext; const Version: TMDVersion);
  58. procedure MDUpdate(var Context: TMDContext; var Buf; const BufLen: PtrUInt);
  59. procedure MDFinal(var Context: TMDContext; var Digest: TMDDigest);
  60. (******************************************************************************
  61. * Auxilary functions
  62. ******************************************************************************)
  63. function MDString(const S: String; const Version: TMDVersion): TMDDigest;
  64. function MDBuffer(var Buf; const BufLen: PtrUInt; const Version: TMDVersion): TMDDigest;
  65. function MDFile(const Filename: String; const Version: TMDVersion; const Bufsize: PtrUInt = MDDefBufSize): TMDDigest;
  66. (******************************************************************************
  67. * Helper functions
  68. ******************************************************************************)
  69. function MDPrint(const Digest: TMDDigest): String;
  70. function MDMatch(const Digest1, Digest2: TMDDigest): Boolean;
  71. (******************************************************************************
  72. * Dedicated raw functions
  73. ******************************************************************************)
  74. procedure MD2Init(var Context: TMD2Context); inline;
  75. procedure MD2Update(var Context: TMD2Context; var Buf; const BufLen: PtrUInt); inline;
  76. procedure MD2Final(var Context: TMD2Context; var Digest: TMD2Digest); inline;
  77. procedure MD4Init(var Context: TMD4Context); inline;
  78. procedure MD4Update(var Context: TMD4Context; var Buf; const BufLen: PtrUInt); inline;
  79. procedure MD4Final(var Context: TMD4Context; var Digest: TMD4Digest); inline;
  80. procedure MD5Init(var Context: TMD5Context); inline;
  81. procedure MD5Update(var Context: TMD5Context; var Buf; const BufLen: PtrUInt); inline;
  82. procedure MD5Final(var Context: TMD5Context; var Digest: TMD5Digest); inline;
  83. (******************************************************************************
  84. * Dedicated auxilary functions
  85. ******************************************************************************)
  86. function MD2String(const S: String): TMD2Digest; inline;
  87. function MD2Buffer(var Buf; const BufLen: PtrUInt): TMD2Digest; inline;
  88. function MD2File(const Filename: String; const Bufsize: PtrUInt = MDDefBufSize): TMD2Digest; inline;
  89. function MD4String(const S: String): TMD4Digest; inline;
  90. function MD4Buffer(var Buf; const BufLen: PtrUInt): TMD4Digest; inline;
  91. function MD4File(const Filename: String; const Bufsize: PtrUInt = MDDefBufSize): TMD4Digest; inline;
  92. function MD5String(const S: String): TMD5Digest; inline;
  93. function MD5Buffer(var Buf; const BufLen: PtrUInt): TMD5Digest; inline;
  94. function MD5File(const Filename: String; const Bufsize: PtrUInt = MDDefBufSize): TMD5Digest; inline;
  95. (******************************************************************************
  96. * Dedicated helper functions
  97. ******************************************************************************)
  98. function MD2Print(const Digest: TMD2Digest): String; inline;
  99. function MD2Match(const Digest1, Digest2: TMD2Digest): Boolean; inline;
  100. function MD4Print(const Digest: TMD4Digest): String; inline;
  101. function MD4Match(const Digest1, Digest2: TMD4Digest): Boolean; inline;
  102. function MD5Print(const Digest: TMD5Digest): String; inline;
  103. function MD5Match(const Digest1, Digest2: TMD5Digest): Boolean; inline;
  104. implementation
  105. function rol(x: Cardinal; n: Byte): Cardinal;
  106. begin
  107. Result := (x shl n) or (x shr (32 - n));
  108. end;
  109. // inverts the bytes of (Count div 4) cardinals from source to target.
  110. procedure Invert(Source, Dest: Pointer; Count: PtrUInt);
  111. var
  112. S: PByte;
  113. T: PCardinal;
  114. I: PtrUInt;
  115. begin
  116. S := Source;
  117. T := Dest;
  118. for I := 1 to (Count div 4) do
  119. begin
  120. T^ := S[0] or (S[1] shl 8) or (S[2] shl 16) or (S[3] shl 24);
  121. inc(S,4);
  122. inc(T);
  123. end;
  124. end;
  125. procedure MD2Transform(var Context: TMDContext; Buffer: Pointer);
  126. const
  127. PI_SUBST: array[0..255] of Byte = (
  128. 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6,
  129. 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188,
  130. 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24,
  131. 138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251,
  132. 245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63,
  133. 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50,
  134. 39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165,
  135. 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
  136. 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157,
  137. 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27,
  138. 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
  139. 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197,
  140. 234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65,
  141. 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123,
  142. 8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233,
  143. 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228,
  144. 166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237,
  145. 31, 26, 219, 153, 141, 51, 159, 17, 131, 20
  146. );
  147. var
  148. i: Cardinal;
  149. j: Cardinal;
  150. t: Cardinal;
  151. x: array[0..47] of Byte;
  152. begin
  153. { Form encryption block from state, block, state ^ block }
  154. Move(Context.State, x[0], 16);
  155. Move(Buffer^, x[16], 16);
  156. for i := 0 to 15 do
  157. x[i+32] := PByte(@Context.State)[i] xor PByte(Buffer)[i];
  158. { Encrypt block (18 rounds) }
  159. t := 0;
  160. for i := 0 to 17 do
  161. begin
  162. for j := 0 to 47 do
  163. begin
  164. x[j] := x[j] xor PI_SUBST[t];
  165. t := x[j];
  166. end;
  167. t := (t + i) and $FF;
  168. end;
  169. { Save new state }
  170. Move(x[0], Context.State, 16);
  171. { Update checksum }
  172. t := Context.Checksum[15];
  173. for i := 0 to 15 do
  174. begin
  175. Context.Checksum[i] := Context.Checksum[i] xor PI_SUBST[PByte(Buffer)[i] xor t];
  176. t := Context.Checksum[i];
  177. end;
  178. { Zeroize sensitive information. }
  179. FillChar(x, Sizeof(x), 0);
  180. end;
  181. procedure MD4Transform(var Context: TMDContext; Buffer: Pointer);
  182. procedure R1(var a: Cardinal; b,c,d,x: Cardinal; s: Byte);
  183. // F(x,y,z) = (x and y) or ((not x) and z)
  184. begin
  185. a := rol(a + {F(b,c,d)}((b and c) or ((not b) and d)) + x, s);
  186. end;
  187. procedure R2(var a: Cardinal; b,c,d,x: Cardinal; s: Byte);
  188. // G(x,y,z) = (x and y) or (x and z) or (y and z);
  189. begin
  190. a := rol(a + {G(b,c,d)}((b and c) or (b and d) or (c and d)) + x + $5A827999, s);
  191. end;
  192. procedure R3(var a: Cardinal; b,c,d,x: Cardinal; s: Byte);
  193. // H(x,y,z) = x xor y xor z
  194. begin
  195. a := rol(a + {H(b,c,d)}(b xor c xor d) + x + $6ED9EBA1, s);
  196. end;
  197. var
  198. a, b, c, d: Cardinal;
  199. Block: array[0..15] of Cardinal;
  200. begin
  201. Invert(Buffer, @Block, 64);
  202. a := Context.State[0];
  203. b := Context.State[1];
  204. c := Context.State[2];
  205. d := Context.State[3];
  206. // Round 1
  207. R1(a,b,c,d,Block[0], 3); R1(d,a,b,c,Block[1], 7); R1(c,d,a,b,Block[2], 11); R1(b,c,d,a,Block[3], 19);
  208. R1(a,b,c,d,Block[4], 3); R1(d,a,b,c,Block[5], 7); R1(c,d,a,b,Block[6], 11); R1(b,c,d,a,Block[7], 19);
  209. R1(a,b,c,d,Block[8], 3); R1(d,a,b,c,Block[9], 7); R1(c,d,a,b,Block[10],11); R1(b,c,d,a,Block[11],19);
  210. R1(a,b,c,d,Block[12], 3); R1(d,a,b,c,Block[13], 7); R1(c,d,a,b,Block[14],11); R1(b,c,d,a,Block[15],19);
  211. // Round 2
  212. R2(a,b,c,d,Block[0], 3); R2(d,a,b,c,Block[4], 5); R2(c,d,a,b,Block[8], 9); R2(b,c,d,a,Block[12],13);
  213. R2(a,b,c,d,Block[1], 3); R2(d,a,b,c,Block[5], 5); R2(c,d,a,b,Block[9], 9); R2(b,c,d,a,Block[13],13);
  214. R2(a,b,c,d,Block[2], 3); R2(d,a,b,c,Block[6], 5); R2(c,d,a,b,Block[10], 9); R2(b,c,d,a,Block[14],13);
  215. R2(a,b,c,d,Block[3], 3); R2(d,a,b,c,Block[7], 5); R2(c,d,a,b,Block[11], 9); R2(b,c,d,a,Block[15],13);
  216. // Round 3
  217. R3(a,b,c,d,Block[0], 3); R3(d,a,b,c,Block[8], 9); R3(c,d,a,b,Block[4], 11); R3(b,c,d,a,Block[12],15);
  218. R3(a,b,c,d,Block[2], 3); R3(d,a,b,c,Block[10], 9); R3(c,d,a,b,Block[6], 11); R3(b,c,d,a,Block[14],15);
  219. R3(a,b,c,d,Block[1], 3); R3(d,a,b,c,Block[9], 9); R3(c,d,a,b,Block[5], 11); R3(b,c,d,a,Block[13],15);
  220. R3(a,b,c,d,Block[3], 3); R3(d,a,b,c,Block[11], 9); R3(c,d,a,b,Block[7], 11); R3(b,c,d,a,Block[15],15);
  221. inc(Context.State[0], a);
  222. inc(Context.State[1], b);
  223. inc(Context.State[2], c);
  224. inc(Context.State[3], d);
  225. inc(Context.Length,64);
  226. end;
  227. procedure MD5Transform(var Context: TMDContext; Buffer: Pointer);
  228. procedure R1(var a: Cardinal; b,c,d,x: Cardinal; s: Byte; ac: Cardinal);
  229. // F(x,y,z) = (x and y) or ((not x) and z)
  230. begin
  231. a := b + rol(a + {F(b,c,d)}((b and c) or ((not b) and d)) + x + ac, s);
  232. end;
  233. procedure R2(var a: Cardinal; b,c,d,x: Cardinal; s: Byte; ac: Cardinal);
  234. // G(x,y,z) = (x and z) or (y and (not z))
  235. begin
  236. a := b + rol(a + {G(b,c,d)}((b and d) or (c and (not d))) + x + ac, s);
  237. end;
  238. procedure R3(var a: Cardinal; b,c,d,x: Cardinal; s: Byte; ac: Cardinal);
  239. // H(x,y,z) = x xor y xor z;
  240. begin
  241. a := b + rol(a + {H(b,c,d)}(b xor c xor d) + x + ac, s);
  242. end;
  243. procedure R4(var a: Cardinal; b,c,d,x: Cardinal; s: Byte; ac: Cardinal);
  244. // I(x,y,z) = y xor (x or (not z));
  245. begin
  246. a := b + rol(a + {I(b,c,d)}(c xor (b or (not d))) + x + ac, s);
  247. end;
  248. var
  249. a, b, c, d: Cardinal;
  250. Block: array[0..15] of Cardinal;
  251. begin
  252. Invert(Buffer, @Block, 64);
  253. a := Context.State[0];
  254. b := Context.State[1];
  255. c := Context.State[2];
  256. d := Context.State[3];
  257. // Round 1
  258. R1(a,b,c,d,Block[0] , 7,$d76aa478); R1(d,a,b,c,Block[1] ,12,$e8c7b756); R1(c,d,a,b,Block[2] ,17,$242070db); R1(b,c,d,a,Block[3] ,22,$c1bdceee);
  259. R1(a,b,c,d,Block[4] , 7,$f57c0faf); R1(d,a,b,c,Block[5] ,12,$4787c62a); R1(c,d,a,b,Block[6] ,17,$a8304613); R1(b,c,d,a,Block[7] ,22,$fd469501);
  260. R1(a,b,c,d,Block[8] , 7,$698098d8); R1(d,a,b,c,Block[9] ,12,$8b44f7af); R1(c,d,a,b,Block[10],17,$ffff5bb1); R1(b,c,d,a,Block[11],22,$895cd7be);
  261. R1(a,b,c,d,Block[12], 7,$6b901122); R1(d,a,b,c,Block[13],12,$fd987193); R1(c,d,a,b,Block[14],17,$a679438e); R1(b,c,d,a,Block[15],22,$49b40821);
  262. // Round 2
  263. R2(a,b,c,d,Block[1] , 5,$f61e2562); R2(d,a,b,c,Block[6] , 9,$c040b340); R2(c,d,a,b,Block[11],14,$265e5a51); R2(b,c,d,a,Block[0] ,20,$e9b6c7aa);
  264. R2(a,b,c,d,Block[5] , 5,$d62f105d); R2(d,a,b,c,Block[10], 9,$02441453); R2(c,d,a,b,Block[15],14,$d8a1e681); R2(b,c,d,a,Block[4] ,20,$e7d3fbc8);
  265. R2(a,b,c,d,Block[9] , 5,$21e1cde6); R2(d,a,b,c,Block[14], 9,$c33707d6); R2(c,d,a,b,Block[3] ,14,$f4d50d87); R2(b,c,d,a,Block[8] ,20,$455a14ed);
  266. R2(a,b,c,d,Block[13], 5,$a9e3e905); R2(d,a,b,c,Block[2] , 9,$fcefa3f8); R2(c,d,a,b,Block[7] ,14,$676f02d9); R2(b,c,d,a,Block[12],20,$8d2a4c8a);
  267. // Round 3
  268. R3(a,b,c,d,Block[5] , 4,$fffa3942); R3(d,a,b,c,Block[8] ,11,$8771f681); R3(c,d,a,b,Block[11],16,$6d9d6122); R3(b,c,d,a,Block[14],23,$fde5380c);
  269. R3(a,b,c,d,Block[1] , 4,$a4beea44); R3(d,a,b,c,Block[4] ,11,$4bdecfa9); R3(c,d,a,b,Block[7] ,16,$f6bb4b60); R3(b,c,d,a,Block[10],23,$bebfbc70);
  270. R3(a,b,c,d,Block[13], 4,$289b7ec6); R3(d,a,b,c,Block[0] ,11,$eaa127fa); R3(c,d,a,b,Block[3] ,16,$d4ef3085); R3(b,c,d,a,Block[6] ,23,$04881d05);
  271. R3(a,b,c,d,Block[9] , 4,$d9d4d039); R3(d,a,b,c,Block[12],11,$e6db99e5); R3(c,d,a,b,Block[15],16,$1fa27cf8); R3(b,c,d,a,Block[2] ,23,$c4ac5665);
  272. // Round 4
  273. R4(a,b,c,d,Block[0] , 6,$f4292244); R4(d,a,b,c,Block[7] ,10,$432aff97); R4(c,d,a,b,Block[14],15,$ab9423a7); R4(b,c,d,a,Block[5] ,21,$fc93a039);
  274. R4(a,b,c,d,Block[12], 6,$655b59c3); R4(d,a,b,c,Block[3] ,10,$8f0ccc92); R4(c,d,a,b,Block[10],15,$ffeff47d); R4(b,c,d,a,Block[1] ,21,$85845dd1);
  275. R4(a,b,c,d,Block[8] , 6,$6fa87e4f); R4(d,a,b,c,Block[15],10,$fe2ce6e0); R4(c,d,a,b,Block[6] ,15,$a3014314); R4(b,c,d,a,Block[13],21,$4e0811a1);
  276. R4(a,b,c,d,Block[4] , 6,$f7537e82); R4(d,a,b,c,Block[11],10,$bd3af235); R4(c,d,a,b,Block[2] ,15,$2ad7d2bb); R4(b,c,d,a,Block[9] ,21,$eb86d391);
  277. inc(Context.State[0],a);
  278. inc(Context.State[1],b);
  279. inc(Context.State[2],c);
  280. inc(Context.State[3],d);
  281. inc(Context.Length,64);
  282. end;
  283. procedure MDInit(var Context: TMDContext; const Version: TMDVersion);
  284. begin
  285. FillChar(Context, Sizeof(TMDContext), 0);
  286. Context.Version := Version;
  287. case Version of
  288. MD_VERSION_4, MD_VERSION_5:
  289. begin
  290. Context.Align := 64;
  291. Context.State[0] := $67452301;
  292. Context.State[1] := $efcdab89;
  293. Context.State[2] := $98badcfe;
  294. Context.State[3] := $10325476;
  295. Context.Length := 0;
  296. Context.BufCnt := 0;
  297. end;
  298. MD_VERSION_2:
  299. begin
  300. Context.Align := 16;
  301. end;
  302. end;
  303. end;
  304. procedure MDUpdate(var Context: TMDContext; var Buf; const BufLen: PtrUInt);
  305. var
  306. Align: PtrUInt;
  307. Src: Pointer;
  308. Num: PtrUInt;
  309. begin
  310. if BufLen = 0 then
  311. Exit;
  312. Align := Context.Align;
  313. Src := @Buf;
  314. Num := 0;
  315. // 1. Transform existing data in buffer
  316. if Context.BufCnt > 0 then
  317. begin
  318. // 1.1 Try to fill buffer to "Align" bytes
  319. Num := Align - Context.BufCnt;
  320. if Num > BufLen then
  321. Num := BufLen;
  322. Move(Src^, Context.Buffer[Context.BufCnt], Num);
  323. Context.BufCnt := Context.BufCnt + Num;
  324. Src := Pointer(PtrUInt(Src) + Num);
  325. // 1.2 If buffer contains "Align" bytes, transform it
  326. if Context.BufCnt = Align then
  327. begin
  328. case Context.Version of
  329. MD_VERSION_2: MD2Transform(Context, @Context.Buffer);
  330. MD_VERSION_4: MD4Transform(Context, @Context.Buffer);
  331. MD_VERSION_5: MD5Transform(Context, @Context.Buffer);
  332. end;
  333. Context.BufCnt := 0;
  334. end;
  335. end;
  336. // 2. Transform "Align"-Byte blocks of Buf
  337. Num := BufLen - Num;
  338. while Num >= Align do
  339. begin
  340. case Context.Version of
  341. MD_VERSION_2: MD2Transform(Context, Src);
  342. MD_VERSION_4: MD4Transform(Context, Src);
  343. MD_VERSION_5: MD5Transform(Context, Src);
  344. end;
  345. Src := Pointer(PtrUInt(Src) + Align);
  346. Num := Num - Align;
  347. end;
  348. // 3. If there's a block smaller than "Align" Bytes left, add it to buffer
  349. if Num > 0 then
  350. begin
  351. Context.BufCnt := Num;
  352. Move(Src^, Context.Buffer, Num);
  353. end;
  354. end;
  355. procedure MDFinal(var Context: TMDContext; var Digest: TMDDigest);
  356. const
  357. PADDING_MD45: array[0..15] of Cardinal = ($80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
  358. var
  359. Length: QWord;
  360. Pads: Cardinal;
  361. begin
  362. case Context.Version of
  363. MD_VERSION_4, MD_VERSION_5:
  364. begin
  365. // 1. Compute length of the whole stream in bits
  366. Length := 8 * (Context.Length + Context.BufCnt);
  367. // 2. Append padding bits
  368. Pads := (120 - Context.BufCnt) mod 64;
  369. if Pads > 0 then
  370. MDUpdate(Context, PADDING_MD45, Pads) else
  371. MDUpdate(Context, PADDING_MD45, 56);
  372. // 3. Append length of the stream
  373. Invert(@Length, @Length, 8);
  374. MDUpdate(Context, Length, 8);
  375. // 4. Invert state to digest
  376. Invert(@Context.State, @Digest, 16);
  377. end;
  378. MD_VERSION_2:
  379. begin
  380. Pads := 16 - Context.BufCnt;
  381. Length := Pads;
  382. while Pads > 0 do
  383. begin
  384. MDUpdate(Context, Length, 1);
  385. Dec(Pads);
  386. end;
  387. MDUpdate(Context, Context.Checksum, 16);
  388. Move(Context.State, Digest, 16);
  389. end;
  390. end;
  391. FillChar(Context, SizeOf(TMDContext), 0);
  392. end;
  393. function MDString(const S: String; const Version: TMDVersion): TMDDigest;
  394. var
  395. Context: TMDContext;
  396. begin
  397. MDInit(Context, Version);
  398. MDUpdate(Context, PChar(S)^, length(S));
  399. MDFinal(Context, Result);
  400. end;
  401. function MDBuffer(var Buf; const BufLen: PtrUInt; const Version: TMDVersion): TMDDigest;
  402. var
  403. Context: TMDContext;
  404. begin
  405. MDInit(Context, Version);
  406. MDUpdate(Context, buf, buflen);
  407. MDFinal(Context, Result);
  408. end;
  409. function MDFile(const Filename: String; const Version: TMDVersion; const BufSize: PtrUInt): TMDDigest;
  410. var
  411. F: File;
  412. Buf: Pchar;
  413. Context: TMDContext;
  414. Count: Cardinal;
  415. ofm: Longint;
  416. begin
  417. MDInit(Context, Version);
  418. Assign(F, Filename);
  419. {$i-}
  420. ofm := FileMode;
  421. FileMode := 0;
  422. Reset(F, 1);
  423. {$i+}
  424. if IOResult = 0 then
  425. begin
  426. GetMem(Buf, BufSize);
  427. repeat
  428. BlockRead(F, Buf^, Bufsize, Count);
  429. if Count > 0 then
  430. MDUpdate(Context, Buf^, Count);
  431. until Count < BufSize;
  432. FreeMem(Buf, BufSize);
  433. Close(F);
  434. end;
  435. MDFinal(Context, Result);
  436. FileMode := ofm;
  437. end;
  438. function MDPrint(const Digest: TMDDigest): String;
  439. var
  440. I: Byte;
  441. begin
  442. Result := '';
  443. for I := 0 to 15 do
  444. Result := Result + HexStr(Digest[i],2);
  445. Result := LowerCase(Result);
  446. end;
  447. function MDMatch(const Digest1, Digest2: TMDDigest): Boolean;
  448. var
  449. A: array[0..3] of Cardinal absolute Digest1;
  450. B: array[0..3] of Cardinal absolute Digest2;
  451. begin
  452. Result := (A[0] = B[0]) and (A[1] = B[1]) and (A[2] = B[2]) and (A[3] = B[3]);
  453. end;
  454. procedure MD2Init(var Context: TMD2Context);
  455. begin
  456. MDInit(Context, MD_VERSION_2);
  457. end;
  458. procedure MD2Update(var Context: TMD2Context; var Buf; const BufLen: PtrUInt);
  459. begin
  460. MDUpdate(Context, Buf, BufLen);
  461. end;
  462. procedure MD2Final(var Context: TMD2Context; var Digest: TMD2Digest);
  463. begin
  464. MDFinal(Context, Digest);
  465. end;
  466. procedure MD4Init(var Context: TMD4Context);
  467. begin
  468. MDInit(Context, MD_VERSION_4);
  469. end;
  470. procedure MD4Update(var Context: TMD4Context; var Buf; const BufLen: PtrUInt);
  471. begin
  472. MDUpdate(Context, Buf, BufLen);
  473. end;
  474. procedure MD4Final(var Context: TMD4Context; var Digest: TMD4Digest);
  475. begin
  476. MDFinal(Context, Digest);
  477. end;
  478. procedure MD5Init(var Context: TMD5Context);
  479. begin
  480. MDInit(Context, MD_VERSION_5);
  481. end;
  482. procedure MD5Update(var Context: TMD5Context; var Buf; const BufLen: PtrUInt);
  483. begin
  484. MDUpdate(Context, Buf, BufLen);
  485. end;
  486. procedure MD5Final(var Context: TMD5Context; var Digest: TMD5Digest);
  487. begin
  488. MDFinal(Context, Digest);
  489. end;
  490. function MD2String(const S: String): TMD2Digest;
  491. begin
  492. Result := MDString(S, MD_VERSION_2);
  493. end;
  494. function MD2Buffer(var Buf; const BufLen: PtrUInt): TMD2Digest;
  495. begin
  496. Result := MDBuffer(Buf, BufLen, MD_VERSION_2);
  497. end;
  498. function MD2File(const Filename: String; const Bufsize: PtrUInt): TMD2Digest;
  499. begin
  500. Result := MDFile(Filename, MD_VERSION_2, Bufsize);
  501. end;
  502. function MD4String(const S: String): TMD4Digest;
  503. begin
  504. Result := MDString(S, MD_VERSION_4);
  505. end;
  506. function MD4Buffer(var Buf; const BufLen: PtrUInt): TMD4Digest;
  507. begin
  508. Result := MDBuffer(Buf, BufLen, MD_VERSION_4);
  509. end;
  510. function MD4File(const Filename: String; const Bufsize: PtrUInt): TMD4Digest;
  511. begin
  512. Result := MDFile(Filename, MD_VERSION_4, Bufsize);
  513. end;
  514. function MD5String(const S: String): TMD5Digest;
  515. begin
  516. Result := MDString(S, MD_VERSION_5);
  517. end;
  518. function MD5Buffer(var Buf; const BufLen: PtrUInt): TMD5Digest;
  519. begin
  520. Result := MDBuffer(Buf, BufLen, MD_VERSION_5);
  521. end;
  522. function MD5File(const Filename: String; const Bufsize: PtrUInt): TMD5Digest;
  523. begin
  524. Result := MDFile(Filename, MD_VERSION_5, Bufsize);
  525. end;
  526. function MD2Print(const Digest: TMD2Digest): String;
  527. begin
  528. Result := MDPrint(Digest);
  529. end;
  530. function MD2Match(const Digest1, Digest2: TMD2Digest): Boolean;
  531. begin
  532. Result := MDMatch(Digest1, Digest2);
  533. end;
  534. function MD4Print(const Digest: TMD4Digest): String;
  535. begin
  536. Result := MDPrint(Digest);
  537. end;
  538. function MD4Match(const Digest1, Digest2: TMD4Digest): Boolean;
  539. begin
  540. Result := MDMatch(Digest1, Digest2);
  541. end;
  542. function MD5Print(const Digest: TMD5Digest): String;
  543. begin
  544. Result := MDPrint(Digest);
  545. end;
  546. function MD5Match(const Digest1, Digest2: TMD5Digest): Boolean;
  547. begin
  548. Result := MDMatch(Digest1, Digest2);
  549. end;
  550. end.