md5.pp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880
  1. {
  2. This file is part of the Free Pascal packages.
  3. Copyright (c) 1999-2014 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. {
  14. Original implementor copyright:
  15. Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
  16. rights reserved.
  17. License to copy and use this software is granted provided that it
  18. is identified as the "RSA Data Security, Inc. MD5 Message-Digest
  19. Algorithm" in all material mentioning or referencing this software
  20. or this function.
  21. License is also granted to make and use derivative works provided
  22. that such works are identified as "derived from the RSA Data
  23. Security, Inc. MD5 Message-Digest Algorithm" in all material
  24. mentioning or referencing the derived work.
  25. RSA Data Security, Inc. makes no representations concerning either
  26. the merchantability of this software or the suitability of this
  27. software for any particular purpose. It is provided "as is"
  28. without express or implied warranty of any kind.
  29. These notices must be retained in any copies of any part of this
  30. documentation and/or software.
  31. }
  32. // Define to use original MD5 code on i386 processors.
  33. // Undefine to use original implementation.
  34. { the assembler implementation does not work on Darwin }
  35. {$ifdef darwin}
  36. {$DEFINE MD5PASCAL}
  37. {$endif darwin}
  38. unit md5;
  39. {$mode objfpc}
  40. {$inline on}
  41. {$h+}
  42. interface
  43. (******************************************************************************
  44. * types and constants
  45. ******************************************************************************)
  46. const
  47. MDDefBufSize = 1024;
  48. type
  49. TMDVersion = (
  50. MD_VERSION_2,
  51. MD_VERSION_4,
  52. MD_VERSION_5
  53. );
  54. PMDDigest = ^TMDDigest;
  55. TMDDigest = array[0..15] of Byte;
  56. PMD2Digset = PMDDigest;
  57. TMD2Digest = TMDDigest;
  58. PMD4Digset = PMDDigest;
  59. TMD4Digest = TMDDigest;
  60. PMD5Digset = PMDDigest;
  61. TMD5Digest = TMDDigest;
  62. PMDContext = ^TMDContext;
  63. TMDHashFunc = procedure(Context: PMDContext; Buffer: Pointer);
  64. TMDContext = record
  65. Version : TMDVersion;
  66. Hash : TMDHashFunc;
  67. Align : PtrUInt;
  68. State : array[0..3] of Cardinal;
  69. BufCnt : QWord;
  70. Buffer : array[0..63] of Byte;
  71. case Integer of
  72. 0: (Length : QWord);
  73. 1: (Checksum : array[0..15] of Byte);
  74. end;
  75. PMD2Context = PMDContext;
  76. TMD2Context = TMDContext;
  77. PMD4Context = PMDContext;
  78. TMD4Context = TMDContext;
  79. PMD5Context = PMDContext;
  80. TMD5Context = TMDContext;
  81. (******************************************************************************
  82. * Core raw functions
  83. ******************************************************************************)
  84. procedure MDInit(out Context: TMDContext; const Version: TMDVersion);
  85. procedure MDUpdate(var Context: TMDContext; var Buf; const BufLen: PtrUInt);
  86. procedure MDFinal(var Context: TMDContext; out Digest: TMDDigest);
  87. (******************************************************************************
  88. * Auxilary functions
  89. ******************************************************************************)
  90. function MDString(const S: String; const Version: TMDVersion): TMDDigest;
  91. function MDBuffer(var Buf; const BufLen: PtrUInt; const Version: TMDVersion): TMDDigest;
  92. function MDFile(const Filename: RawByteString; const Version: TMDVersion; const Bufsize: PtrUInt = MDDefBufSize): TMDDigest;
  93. function MDFile(const Filename: UnicodeString; const Version: TMDVersion; const Bufsize: PtrUInt = MDDefBufSize): TMDDigest;
  94. (******************************************************************************
  95. * Helper functions
  96. ******************************************************************************)
  97. function MDPrint(const Digest: TMDDigest): String;
  98. function MDMatch(const Digest1, Digest2: TMDDigest): Boolean;
  99. (******************************************************************************
  100. * Dedicated raw functions
  101. ******************************************************************************)
  102. procedure MD2Init(out Context: TMD2Context); inline;
  103. procedure MD2Update(var Context: TMD2Context; var Buf; const BufLen: PtrUInt); external name 'MD_UPDATE';
  104. procedure MD2Final(var Context: TMD2Context; out Digest: TMD2Digest); external name 'MD_FINAL';
  105. procedure MD4Init(out Context: TMD4Context); inline;
  106. procedure MD4Update(var Context: TMD4Context; var Buf; const BufLen: PtrUInt); external name 'MD_UPDATE';
  107. procedure MD4Final(var Context: TMD4Context; out Digest: TMD4Digest); external name 'MD_FINAL';
  108. procedure MD5Init(out Context: TMD5Context); inline;
  109. procedure MD5Update(var Context: TMD5Context; var Buf; const BufLen: PtrUInt); external name 'MD_UPDATE';
  110. procedure MD5Final(var Context: TMD5Context; out Digest: TMD5Digest); external name 'MD_FINAL';
  111. (******************************************************************************
  112. * Dedicated auxilary functions
  113. ******************************************************************************)
  114. function MD2String(const S: String): TMD2Digest; inline;
  115. function MD2Buffer(var Buf; const BufLen: PtrUInt): TMD2Digest;
  116. function MD2File(const Filename: RawByteString; const Bufsize: PtrUInt = MDDefBufSize): TMD2Digest; overload; inline;
  117. function MD2File(const Filename: UnicodeString; const Bufsize: PtrUInt = MDDefBufSize): TMD2Digest; overload; inline;
  118. function MD4String(const S: String): TMD4Digest; inline;
  119. function MD4Buffer(var Buf; const BufLen: PtrUInt): TMD4Digest;
  120. function MD4File(const Filename: RawByteString; const Bufsize: PtrUInt = MDDefBufSize): TMD4Digest; inline;
  121. function MD4File(const Filename: UnicodeString; const Bufsize: PtrUInt = MDDefBufSize): TMD4Digest; inline;
  122. function MD5String(const S: String): TMD5Digest; inline;
  123. function MD5Buffer(var Buf; const BufLen: PtrUInt): TMD5Digest;
  124. function MD5File(const Filename: RawByteString; const Bufsize: PtrUInt = MDDefBufSize): TMD5Digest; inline;
  125. function MD5File(const Filename: UnicodeString; const Bufsize: PtrUInt = MDDefBufSize): TMD5Digest; inline;
  126. (******************************************************************************
  127. * Dedicated helper functions
  128. ******************************************************************************)
  129. function MD2Print(const Digest: TMD2Digest): String; inline;
  130. function MD2Match(const Digest1, Digest2: TMD2Digest): Boolean; inline;
  131. function MD4Print(const Digest: TMD4Digest): String; inline;
  132. function MD4Match(const Digest1, Digest2: TMD4Digest): Boolean; inline;
  133. function MD5Print(const Digest: TMD5Digest): String; inline;
  134. function StrtoMD5(const MD5String:String):TMDDigest;
  135. function MD5Match(const Digest1, Digest2: TMD5Digest): Boolean; inline;
  136. implementation
  137. uses sysutils;
  138. // inverts the bytes of (Count div 4) cardinals from source to target.
  139. procedure Invert(Source, Dest: Pointer; Count: PtrUInt);
  140. var
  141. S: PByte;
  142. T: PCardinal;
  143. I: PtrUInt;
  144. begin
  145. S := Source;
  146. T := Dest;
  147. for I := 1 to (Count div 4) do
  148. begin
  149. T^ := S[0] or (S[1] shl 8) or (S[2] shl 16) or (S[3] shl 24);
  150. inc(S,4);
  151. inc(T);
  152. end;
  153. end;
  154. procedure MD2Transform(var Context: TMDContext; Buffer: Pointer);
  155. const
  156. PI_SUBST: array[0..255] of Byte = (
  157. 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6,
  158. 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188,
  159. 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24,
  160. 138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251,
  161. 245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63,
  162. 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50,
  163. 39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165,
  164. 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
  165. 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157,
  166. 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27,
  167. 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
  168. 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197,
  169. 234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65,
  170. 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123,
  171. 8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233,
  172. 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228,
  173. 166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237,
  174. 31, 26, 219, 153, 141, 51, 159, 17, 131, 20
  175. );
  176. var
  177. i: Cardinal;
  178. j: Cardinal;
  179. t: Cardinal;
  180. x: array[0..47] of Byte;
  181. begin
  182. { Form encryption block from state, block, state ^ block }
  183. Move(Context.State, x[0], 16);
  184. Move(Buffer^, x[16], 16);
  185. for i := 0 to 15 do
  186. x[i+32] := PByte(@Context.State)[i] xor PByte(Buffer)[i];
  187. { Encrypt block (18 rounds) }
  188. t := 0;
  189. for i := 0 to 17 do
  190. begin
  191. for j := 0 to 47 do
  192. begin
  193. x[j] := x[j] xor PI_SUBST[t];
  194. t := x[j];
  195. end;
  196. t := (t + i) and $FF;
  197. end;
  198. { Save new state }
  199. Move(x[0], Context.State, 16);
  200. { Update checksum }
  201. t := Context.Checksum[15];
  202. for i := 0 to 15 do
  203. begin
  204. Context.Checksum[i] := Context.Checksum[i] xor PI_SUBST[PByte(Buffer)[i] xor t];
  205. t := Context.Checksum[i];
  206. end;
  207. { Zeroize sensitive information. }
  208. FillChar(x, Sizeof(x), 0);
  209. end;
  210. procedure MD4Transform(var Context: TMDContext; Buffer: Pointer);
  211. {$push}
  212. {$r-,q-}
  213. procedure R1(var a: Cardinal; b,c,d,x: Cardinal; s: Byte);
  214. // F(x,y,z) = (x and y) or ((not x) and z)
  215. begin
  216. a := roldword(dword(a + {F(b,c,d)}((b and c) or ((not b) and d)) + x), s);
  217. end;
  218. procedure R2(var a: Cardinal; b,c,d,x: Cardinal; s: Byte);
  219. // G(x,y,z) = (x and y) or (x and z) or (y and z);
  220. begin
  221. a := roldword(dword(a + {G(b,c,d)}((b and c) or (b and d) or (c and d)) + x + $5A827999), s);
  222. end;
  223. procedure R3(var a: Cardinal; b,c,d,x: Cardinal; s: Byte);
  224. // H(x,y,z) = x xor y xor z
  225. begin
  226. a := roldword(dword(a + {H(b,c,d)}(b xor c xor d) + x + $6ED9EBA1), s);
  227. end;
  228. {$pop}
  229. var
  230. a, b, c, d: Cardinal;
  231. Block: array[0..15] of Cardinal;
  232. begin
  233. Invert(Buffer, @Block, 64);
  234. a := Context.State[0];
  235. b := Context.State[1];
  236. c := Context.State[2];
  237. d := Context.State[3];
  238. // Round 1
  239. 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);
  240. 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);
  241. 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);
  242. 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);
  243. // Round 2
  244. 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);
  245. 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);
  246. 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);
  247. 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);
  248. // Round 3
  249. 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);
  250. 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);
  251. 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);
  252. 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);
  253. {$push}
  254. {$r-,q-}
  255. inc(Context.State[0], a);
  256. inc(Context.State[1], b);
  257. inc(Context.State[2], c);
  258. inc(Context.State[3], d);
  259. {$pop}
  260. inc(Context.Length,64);
  261. end;
  262. {$IF (NOT(DEFINED(MD5PASCAL))) and (DEFINED(CPUI386)) }
  263. {$i md5i386.inc}
  264. {$ENDIF}
  265. {$IF (NOT(DEFINED(MD5PASCAL))) and (DEFINED(CPUX86_64)) }
  266. {$OPTIMIZATION USERBP} //PEEPHOLE
  267. procedure MD5Transform(var Context: TMDContext; Buffer: Pointer);
  268. type
  269. TBlock = array[0..15] of Cardinal;
  270. PBlock = ^TBlock;
  271. var
  272. a, b, c, d: Cardinal;
  273. //Block: array[0..15] of Cardinal absolute Buffer;
  274. Block: PBlock absolute Buffer;
  275. begin
  276. //Invert(Buffer, @Block, 64);
  277. a := Context.State[0];
  278. b := Context.State[1];
  279. c := Context.State[2];
  280. d := Context.State[3];
  281. {$push}
  282. {$r-,q-}
  283. // Round 1
  284. a := b + roldword(dword(a + ((b and c) or ((not b) and d)) + Block^[0] + $d76aa478), 7);
  285. d := a + roldword(dword(d + ((a and b) or ((not a) and c)) + Block^[1] + $e8c7b756), 12);
  286. c := d + roldword(dword(c + ((d and a) or ((not d) and b)) + Block^[2] + $242070db), 17);
  287. b := c + roldword(dword(b + ((c and d) or ((not c) and a)) + Block^[3] + $c1bdceee), 22);
  288. a := b + roldword(dword(a + ((b and c) or ((not b) and d)) + Block^[4] + $f57c0faf), 7);
  289. d := a + roldword(dword(d + ((a and b) or ((not a) and c)) + Block^[5] + $4787c62a), 12);
  290. c := d + roldword(dword(c + ((d and a) or ((not d) and b)) + Block^[6] + $a8304613), 17);
  291. b := c + roldword(dword(b + ((c and d) or ((not c) and a)) + Block^[7] + $fd469501), 22);
  292. a := b + roldword(dword(a + ((b and c) or ((not b) and d)) + Block^[8] + $698098d8), 7);
  293. d := a + roldword(dword(d + ((a and b) or ((not a) and c)) + Block^[9] + $8b44f7af), 12);
  294. c := d + roldword(dword(c + ((d and a) or ((not d) and b)) + Block^[10] + $ffff5bb1), 17);
  295. b := c + roldword(dword(b + ((c and d) or ((not c) and a)) + Block^[11] + $895cd7be), 22);
  296. a := b + roldword(dword(a + ((b and c) or ((not b) and d)) + Block^[12] + $6b901122), 7);
  297. d := a + roldword(dword(d + ((a and b) or ((not a) and c)) + Block^[13] + $fd987193), 12);
  298. c := d + roldword(dword(c + ((d and a) or ((not d) and b)) + Block^[14] + $a679438e), 17);
  299. b := c + roldword(dword(b + ((c and d) or ((not c) and a)) + Block^[15] + $49b40821), 22);
  300. // Round 2
  301. a := b + roldword(dword(a + ((b and d) or (c and (not d))) + Block^[1] + $f61e2562), 5);
  302. d := a + roldword(dword(d + ((a and c) or (b and (not c))) + Block^[6] + $c040b340), 9);
  303. c := d + roldword(dword(c + ((d and b) or (a and (not b))) + Block^[11] + $265e5a51), 14);
  304. b := c + roldword(dword(b + ((c and a) or (d and (not a))) + Block^[0] + $e9b6c7aa), 20);
  305. a := b + roldword(dword(a + ((b and d) or (c and (not d))) + Block^[5] + $d62f105d), 5);
  306. d := a + roldword(dword(d + ((a and c) or (b and (not c))) + Block^[10] + $02441453), 9);
  307. c := d + roldword(dword(c + ((d and b) or (a and (not b))) + Block^[15] + $d8a1e681), 14);
  308. b := c + roldword(dword(b + ((c and a) or (d and (not a))) + Block^[4] + $e7d3fbc8), 20);
  309. a := b + roldword(dword(a + ((b and d) or (c and (not d))) + Block^[9] + $21e1cde6), 5);
  310. d := a + roldword(dword(d + ((a and c) or (b and (not c))) + Block^[14] + $c33707d6), 9);
  311. c := d + roldword(dword(c + ((d and b) or (a and (not b))) + Block^[3] + $f4d50d87), 14);
  312. b := c + roldword(dword(b + ((c and a) or (d and (not a))) + Block^[8] + $455a14ed), 20);
  313. a := b + roldword(dword(a + ((b and d) or (c and (not d))) + Block^[13] + $a9e3e905), 5);
  314. d := a + roldword(dword(d + ((a and c) or (b and (not c))) + Block^[2] + $fcefa3f8), 9);
  315. c := d + roldword(dword(c + ((d and b) or (a and (not b))) + Block^[7] + $676f02d9), 14);
  316. b := c + roldword(dword(b + ((c and a) or (d and (not a))) + Block^[12] + $8d2a4c8a), 20);
  317. // Round 3
  318. a := b + roldword(dword(a + (b xor c xor d) + Block^[5] + $fffa3942), 4);
  319. d := a + roldword(dword(d + (a xor b xor c) + Block^[8] + $8771f681), 11);
  320. c := d + roldword(dword(c + (d xor a xor b) + Block^[11] + $6d9d6122), 16);
  321. b := c + roldword(dword(b + (c xor d xor a) + Block^[14] + $fde5380c), 23);
  322. a := b + roldword(dword(a + (b xor c xor d) + Block^[1] + $a4beea44), 4);
  323. d := a + roldword(dword(d + (a xor b xor c) + Block^[4] + $4bdecfa9), 11);
  324. c := d + roldword(dword(c + (d xor a xor b) + Block^[7] + $f6bb4b60), 16);
  325. b := c + roldword(dword(b + (c xor d xor a) + Block^[10] + $bebfbc70), 23);
  326. a := b + roldword(dword(a + (b xor c xor d) + Block^[13] + $289b7ec6), 4);
  327. d := a + roldword(dword(d + (a xor b xor c) + Block^[0] + $eaa127fa), 11);
  328. c := d + roldword(dword(c + (d xor a xor b) + Block^[3] + $d4ef3085), 16);
  329. b := c + roldword(dword(b + (c xor d xor a) + Block^[6] + $04881d05), 23);
  330. a := b + roldword(dword(a + (b xor c xor d) + Block^[9] + $d9d4d039), 4);
  331. d := a + roldword(dword(d + (a xor b xor c) + Block^[12] + $e6db99e5), 11);
  332. c := d + roldword(dword(c + (d xor a xor b) + Block^[15] + $1fa27cf8), 16);
  333. b := c + roldword(dword(b + (c xor d xor a) + Block^[2] + $c4ac5665), 23);
  334. // Round 4
  335. a := b + roldword(dword(a + (c xor (b or (not d))) + Block^[0] + $f4292244), 6);
  336. d := a + roldword(dword(d + (b xor (a or (not c))) + Block^[7] + $432aff97), 10);
  337. c := d + roldword(dword(c + (a xor (d or (not b))) + Block^[14] + $ab9423a7), 15);
  338. b := c + roldword(dword(b + (d xor (c or (not a))) + Block^[5] + $fc93a039), 21);
  339. a := b + roldword(dword(a + (c xor (b or (not d))) + Block^[12] + $655b59c3), 6);
  340. d := a + roldword(dword(d + (b xor (a or (not c))) + Block^[3] + $8f0ccc92), 10);
  341. c := d + roldword(dword(c + (a xor (d or (not b))) + Block^[10] + $ffeff47d), 15);
  342. b := c + roldword(dword(b + (d xor (c or (not a))) + Block^[1] + $85845dd1), 21);
  343. a := b + roldword(dword(a + (c xor (b or (not d))) + Block^[8] + $6fa87e4f), 6);
  344. d := a + roldword(dword(d + (b xor (a or (not c))) + Block^[15] + $fe2ce6e0), 10);
  345. c := d + roldword(dword(c + (a xor (d or (not b))) + Block^[6] + $a3014314), 15);
  346. b := c + roldword(dword(b + (d xor (c or (not a))) + Block^[13] + $4e0811a1), 21);
  347. a := b + roldword(dword(a + (c xor (b or (not d))) + Block^[4] + $f7537e82), 6);
  348. d := a + roldword(dword(d + (b xor (a or (not c))) + Block^[11] + $bd3af235), 10);
  349. c := d + roldword(dword(c + (a xor (d or (not b))) + Block^[2] + $2ad7d2bb), 15);
  350. b := c + roldword(dword(b + (d xor (c or (not a))) + Block^[9] + $eb86d391), 21);
  351. inc(Context.State[0],a);
  352. inc(Context.State[1],b);
  353. inc(Context.State[2],c);
  354. inc(Context.State[3],d);
  355. {$pop}
  356. inc(Context.Length,64);
  357. end;
  358. {$OPTIMIZATION DEFAULT}
  359. {$ENDIF}
  360. {$IF DEFINED(MD5PASCAL) or (NOT ((DEFINED(CPUX86_64)) or (DEFINED(CPUI386))))}
  361. // Original version
  362. procedure MD5Transform(var Context: TMDContext; Buffer: Pointer);
  363. {$push}
  364. {$r-,q-}
  365. procedure R1(var a: Cardinal; b,c,d,x: Cardinal; s: Byte; ac: Cardinal);
  366. // F(x,y,z) = (x and y) or ((not x) and z)
  367. begin
  368. a := b + roldword(dword(a + {F(b,c,d)}((b and c) or ((not b) and d)) + x + ac), s);
  369. end;
  370. procedure R2(var a: Cardinal; b,c,d,x: Cardinal; s: Byte; ac: Cardinal);
  371. // G(x,y,z) = (x and z) or (y and (not z))
  372. begin
  373. a := b + roldword(dword(a + {G(b,c,d)}((b and d) or (c and (not d))) + x + ac), s);
  374. end;
  375. procedure R3(var a: Cardinal; b,c,d,x: Cardinal; s: Byte; ac: Cardinal);
  376. // H(x,y,z) = x xor y xor z;
  377. begin
  378. a := b + roldword(dword(a + {H(b,c,d)}(b xor c xor d) + x + ac), s);
  379. end;
  380. procedure R4(var a: Cardinal; b,c,d,x: Cardinal; s: Byte; ac: Cardinal);
  381. // I(x,y,z) = y xor (x or (not z));
  382. begin
  383. a := b + roldword(dword(a + {I(b,c,d)}(c xor (b or (not d))) + x + ac), s);
  384. end;
  385. {$pop}
  386. var
  387. a, b, c, d: Cardinal;
  388. Block: array[0..15] of Cardinal;
  389. begin
  390. Invert(Buffer, @Block, 64);
  391. a := Context.State[0];
  392. b := Context.State[1];
  393. c := Context.State[2];
  394. d := Context.State[3];
  395. // Round 1
  396. 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);
  397. 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);
  398. 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);
  399. 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);
  400. // Round 2
  401. 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);
  402. 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);
  403. 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);
  404. 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);
  405. // Round 3
  406. 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);
  407. 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);
  408. 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);
  409. 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);
  410. // Round 4
  411. 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);
  412. 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);
  413. 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);
  414. 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);
  415. {$push}
  416. {$r-,q-}
  417. inc(Context.State[0],a);
  418. inc(Context.State[1],b);
  419. inc(Context.State[2],c);
  420. inc(Context.State[3],d);
  421. {$pop}
  422. inc(Context.Length,64);
  423. end;
  424. {$ENDIF}
  425. procedure MDInit(out Context: TMDContext; const Version: TMDVersion);
  426. begin
  427. FillChar(Context, Sizeof(TMDContext), 0);
  428. Context.Version := Version;
  429. case Version of
  430. MD_VERSION_4, MD_VERSION_5:
  431. begin
  432. if Version = MD_VERSION_4 then
  433. Context.Hash := TMDHashFunc(@MD4Transform)
  434. else
  435. Context.Hash := TMDHashFunc(@MD5Transform);
  436. Context.Align := 64;
  437. Context.State[0] := $67452301;
  438. Context.State[1] := $efcdab89;
  439. Context.State[2] := $98badcfe;
  440. Context.State[3] := $10325476;
  441. Context.Length := 0;
  442. Context.BufCnt := 0;
  443. end;
  444. MD_VERSION_2:
  445. begin
  446. Context.Align := 16;
  447. Context.Hash := TMDHashFunc(@MD2Transform)
  448. end;
  449. end;
  450. end;
  451. procedure MDUpdate(var Context: TMDContext; var Buf; const BufLen: PtrUInt); [public,alias:'MD_UPDATE'];
  452. var
  453. Align: PtrUInt;
  454. Src: Pointer;
  455. Num: PtrUInt;
  456. begin
  457. if BufLen = 0 then
  458. Exit;
  459. Align := Context.Align;
  460. Src := @Buf;
  461. Num := 0;
  462. // 1. Transform existing data in buffer
  463. if Context.BufCnt > 0 then
  464. begin
  465. // 1.1 Try to fill buffer to "Align" bytes
  466. Num := Align - Context.BufCnt;
  467. if Num > BufLen then
  468. Num := BufLen;
  469. Move(Src^, Context.Buffer[Context.BufCnt], Num);
  470. Context.BufCnt := Context.BufCnt + Num;
  471. Src := Pointer(PtrUInt(Src) + Num);
  472. // 1.2 If buffer contains "Align" bytes, transform it
  473. if Context.BufCnt = Align then
  474. begin
  475. Context.Hash(@Context, @Context.Buffer);
  476. Context.BufCnt := 0;
  477. end;
  478. end;
  479. // 2. Transform "Align"-Byte blocks of Buf
  480. Num := BufLen - Num;
  481. while Num >= Align do
  482. begin
  483. Context.Hash(@Context, Src);
  484. Src := Pointer(PtrUInt(Src) + Align);
  485. Num := Num - Align;
  486. end;
  487. // 3. If there's a block smaller than "Align" Bytes left, add it to buffer
  488. if Num > 0 then
  489. begin
  490. Context.BufCnt := Num;
  491. Move(Src^, Context.Buffer, Num);
  492. end;
  493. end;
  494. procedure MDFinal(var Context: TMDContext; out Digest: TMDDigest); [public,alias:'MD_FINAL'];
  495. const
  496. {$ifdef FPC_BIG_ENDIAN}
  497. PADDING_MD45: array[0..15] of Cardinal = ($80000000,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
  498. {$else FPC_BIG_ENDIAN}
  499. PADDING_MD45: array[0..15] of Cardinal = ($80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
  500. {$endif FPC_BIG_ENDIAN}
  501. var
  502. Length: QWord;
  503. Pads: Cardinal;
  504. begin
  505. case Context.Version of
  506. MD_VERSION_4, MD_VERSION_5:
  507. begin
  508. // 1. Compute length of the whole stream in bits
  509. Length := 8 * (Context.Length + Context.BufCnt);
  510. // 2. Append padding bits
  511. if Context.BufCnt >= 56 then
  512. Pads := 120 - Context.BufCnt
  513. else
  514. Pads := 56 - Context.BufCnt;
  515. MDUpdate(Context, PADDING_MD45, Pads);
  516. // 3. Append length of the stream
  517. Length := NtoLE(Length);
  518. MDUpdate(Context, Length, 8);
  519. // 4. Invert state to digest
  520. Invert(@Context.State, @Digest, 16);
  521. end;
  522. MD_VERSION_2:
  523. begin
  524. Pads := 16 - Context.BufCnt;
  525. Length := NtoLE(QWord(Pads));
  526. while Pads > 0 do
  527. begin
  528. MDUpdate(Context, Length, 1);
  529. Dec(Pads);
  530. end;
  531. MDUpdate(Context, Context.Checksum, 16);
  532. Move(Context.State, Digest, 16);
  533. end;
  534. end;
  535. FillChar(Context, SizeOf(TMDContext), 0);
  536. end;
  537. function MDString(const S: String; const Version: TMDVersion): TMDDigest;
  538. var
  539. Context: TMDContext;
  540. begin
  541. MDInit(Context, Version);
  542. MDUpdate(Context, PChar(S)^, length(S));
  543. MDFinal(Context, Result);
  544. end;
  545. function MDBuffer(var Buf; const BufLen: PtrUInt; const Version: TMDVersion): TMDDigest;
  546. var
  547. Context: TMDContext;
  548. begin
  549. MDInit(Context, Version);
  550. MDUpdate(Context, buf, buflen);
  551. MDFinal(Context, Result);
  552. end;
  553. function MDFile(const Filename: RawByteString; const Version: TMDVersion; const BufSize: PtrUInt): TMDDigest;
  554. var
  555. F: File;
  556. Buf: Pchar;
  557. Context: TMDContext;
  558. Count: Cardinal;
  559. ofm: Longint;
  560. begin
  561. MDInit(Context, Version);
  562. Assign(F, Filename);
  563. {$push}{$i-}
  564. ofm := FileMode;
  565. FileMode := 0;
  566. Reset(F, 1);
  567. {$pop}
  568. if IOResult = 0 then
  569. begin
  570. GetMem(Buf, BufSize);
  571. repeat
  572. BlockRead(F, Buf^, Bufsize, Count);
  573. if Count > 0 then
  574. MDUpdate(Context, Buf^, Count);
  575. until Count < BufSize;
  576. FreeMem(Buf, BufSize);
  577. Close(F);
  578. end;
  579. MDFinal(Context, Result);
  580. FileMode := ofm;
  581. end;
  582. function MDFile(const Filename: UnicodeString; const Version: TMDVersion; const BufSize: PtrUInt): TMDDigest;
  583. var
  584. F: File;
  585. Buf: Pchar;
  586. Context: TMDContext;
  587. Count: Cardinal;
  588. ofm: Longint;
  589. begin
  590. MDInit(Context, Version);
  591. Assign(F, Filename);
  592. {$push}{$i-}
  593. ofm := FileMode;
  594. FileMode := 0;
  595. Reset(F, 1);
  596. {$pop}
  597. if IOResult = 0 then
  598. begin
  599. GetMem(Buf, BufSize);
  600. repeat
  601. BlockRead(F, Buf^, Bufsize, Count);
  602. if Count > 0 then
  603. MDUpdate(Context, Buf^, Count);
  604. until Count < BufSize;
  605. FreeMem(Buf, BufSize);
  606. Close(F);
  607. end;
  608. MDFinal(Context, Result);
  609. FileMode := ofm;
  610. end;
  611. function MDPrint(const Digest: TMDDigest): String;
  612. var
  613. I: Byte;
  614. begin
  615. Result := '';
  616. for I := 0 to 15 do
  617. Result := Result + HexStr(Digest[i],2);
  618. Result := LowerCase(Result);
  619. end;
  620. function MDMatch(const Digest1, Digest2: TMDDigest): Boolean;
  621. var
  622. A: array[0..3] of Cardinal absolute Digest1;
  623. B: array[0..3] of Cardinal absolute Digest2;
  624. begin
  625. {$push}
  626. {$B+}
  627. Result := (A[0] = B[0]) and (A[1] = B[1]) and (A[2] = B[2]) and (A[3] = B[3]);
  628. {$pop}
  629. end;
  630. procedure MD2Init(out Context: TMD2Context);
  631. begin
  632. MDInit(Context, MD_VERSION_2);
  633. end;
  634. procedure MD4Init(out Context: TMD4Context);
  635. begin
  636. MDInit(Context, MD_VERSION_4);
  637. end;
  638. procedure MD5Init(out Context: TMD5Context);
  639. begin
  640. MDInit(Context, MD_VERSION_5);
  641. end;
  642. function MD2String(const S: String): TMD2Digest;
  643. begin
  644. Result := MDString(S, MD_VERSION_2);
  645. end;
  646. function MD2Buffer(var Buf; const BufLen: PtrUInt): TMD2Digest;
  647. begin
  648. Result := MDBuffer(Buf, BufLen, MD_VERSION_2);
  649. end;
  650. function MD2File(const Filename: RawByteString; const Bufsize: PtrUInt): TMD2Digest;
  651. begin
  652. Result := MDFile(Filename, MD_VERSION_2, Bufsize);
  653. end;
  654. function MD2File(const Filename: UnicodeString; const Bufsize: PtrUInt): TMD2Digest;
  655. begin
  656. Result := MDFile(Filename, MD_VERSION_2, Bufsize);
  657. end;
  658. function MD4String(const S: String): TMD4Digest;
  659. begin
  660. Result := MDString(S, MD_VERSION_4);
  661. end;
  662. function MD4Buffer(var Buf; const BufLen: PtrUInt): TMD4Digest;
  663. begin
  664. Result := MDBuffer(Buf, BufLen, MD_VERSION_4);
  665. end;
  666. function MD4File(const Filename: RawByteString; const Bufsize: PtrUInt): TMD4Digest;
  667. begin
  668. Result := MDFile(Filename, MD_VERSION_4, Bufsize);
  669. end;
  670. function MD4File(const Filename: UnicodeString; const Bufsize: PtrUInt): TMD4Digest;
  671. begin
  672. Result := MDFile(Filename, MD_VERSION_4, Bufsize);
  673. end;
  674. function MD5String(const S: String): TMD5Digest;
  675. begin
  676. Result := MDString(S, MD_VERSION_5);
  677. end;
  678. function MD5Buffer(var Buf; const BufLen: PtrUInt): TMD5Digest;
  679. begin
  680. Result := MDBuffer(Buf, BufLen, MD_VERSION_5);
  681. end;
  682. function MD5File(const Filename: RawByteString; const Bufsize: PtrUInt): TMD5Digest;
  683. begin
  684. Result := MDFile(Filename, MD_VERSION_5, Bufsize);
  685. end;
  686. function MD5File(const Filename: UnicodeString; const Bufsize: PtrUInt): TMD5Digest;
  687. begin
  688. Result := MDFile(Filename, MD_VERSION_5, Bufsize);
  689. end;
  690. function MD2Print(const Digest: TMD2Digest): String;
  691. begin
  692. Result := MDPrint(Digest);
  693. end;
  694. function MD2Match(const Digest1, Digest2: TMD2Digest): Boolean;
  695. begin
  696. Result := MDMatch(Digest1, Digest2);
  697. end;
  698. function MD4Print(const Digest: TMD4Digest): String;
  699. begin
  700. Result := MDPrint(Digest);
  701. end;
  702. function MD4Match(const Digest1, Digest2: TMD4Digest): Boolean;
  703. begin
  704. Result := MDMatch(Digest1, Digest2);
  705. end;
  706. function MD5Print(const Digest: TMD5Digest): String;
  707. begin
  708. Result := MDPrint(Digest);
  709. end;
  710. function MD5Match(const Digest1, Digest2: TMD5Digest): Boolean;
  711. begin
  712. Result := MDMatch(Digest1, Digest2);
  713. end;
  714. //convert the String representation of a digest to a TMDDigest
  715. //on error all fields are set to $00
  716. function StrtoMD5(const MD5String:String):TMDDigest;
  717. var I: Byte;
  718. t: longint;
  719. f: boolean;
  720. begin
  721. f:= Length(MD5String) = 32;
  722. if f then
  723. for I := 0 to 15 do
  724. begin
  725. f:= f and TryStrToInt('$'+copy(MD5String,i*2+1, 2), t);
  726. Result[I]:= t;
  727. end;
  728. if not f then
  729. FillChar(Result, Sizeof(Result), 0);
  730. end;
  731. end.