You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

fastmd5.pas 9.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. { Copyright (C) 2005 Bas Steendijk and Peter Green
  2. For conditions of distribution and use, see copyright notice in zlib_license.txt
  3. Which is included in the package
  4. ----------------------------------------------------------------------------- }
  5. unit fastmd5;
  6. {
  7. pascal implementation of MD5
  8. written by Bas Steendijk - steendijk@xs4all.nl
  9. based on RFC1321 - The MD5 Message-Digest Algorithm
  10. optimized for speed: saved on copying and sub calls in the core routine
  11. verified on:
  12. - Borland Delphi 3
  13. - Borland Turbo Pascal 7
  14. - Free Pascal 1.0.6 for i386 (on *nix)
  15. - various other versions of freepascal on windows and linux i386
  16. - various other versions of delphi
  17. - free pascal 1.9.5 on powerpc darwin
  18. this unit is endian portable but is likely to be significantly slower on big endian systems
  19. }
  20. {$Q-,R-}
  21. interface
  22. type
  23. Tmd5=array[0..15] of byte;
  24. {$i uint32.inc}
  25. type
  26. dvar=array[0..0] of byte;
  27. Tmd5state=record
  28. buf:array[0..63] of byte;
  29. H:array[0..3] of uint32;
  30. msglen:longint;
  31. msglenhi:longint;
  32. end;
  33. procedure md5processblock(var h:array of uint32;const data);
  34. procedure md5init(var state:tmd5state);
  35. procedure md5process(var state:tmd5state;const data;len:longint);
  36. procedure md5finish(var state:tmd5state;var result);
  37. procedure getmd5(const data;len:longint;var result);
  38. function md5tostr(const md5:tmd5):string;
  39. implementation
  40. function inttohex(val,bits:integer):string;
  41. const
  42. hexchar:array[0..15] of char='0123456789abcdef';
  43. begin
  44. inttohex := hexchar[val shr 4]+hexchar[val and $f];
  45. end;
  46. {$ifdef cpu386}
  47. function rol(w,bits:uint32): uint32; assembler;
  48. asm
  49. {cpu386 is not defined on freepascal. but fpc assembler is incompatible, uses different code}
  50. {inline($89/$d1/$d3/$c0);}
  51. mov ecx,edx
  52. rol eax,cl
  53. end;
  54. {$else}
  55. function rol(w,bits:uint32):uint32;
  56. begin
  57. rol := (w shl bits) or (w shr (32-bits));
  58. end;
  59. {$endif}
  60. {function swapbytes(invalue:uint32):uint32;
  61. var
  62. inbytes : array[0..3] of byte absolute invalue;
  63. outbytes : array[0..3] of byte absolute result;
  64. begin
  65. outbytes[0] := inbytes[3];
  66. outbytes[1] := inbytes[2];
  67. outbytes[2] := inbytes[1];
  68. outbytes[3] := inbytes[0];
  69. end;}
  70. procedure md5processblock(var h:array of uint32;const data);
  71. const
  72. S11=7; S12=12; S13=17; S14=22;
  73. S21=5; S22=9; S23=14; S24=20;
  74. S31=4; S32=11; S33=16; S34=23;
  75. S41=6; S42=10; S43=15; S44=21;
  76. var
  77. A,B,C,D:uint32;
  78. w:array[0..63] of byte absolute data;
  79. x:array[0..15] of uint32 {$ifndef ENDIAN_BIG} absolute data{$endif} ;
  80. y:array[0..63] of byte absolute x;
  81. {$ifdef ENDIAN_BIG}counter : integer;{$endif}
  82. begin
  83. A := h[0];
  84. B := h[1];
  85. C := h[2];
  86. D := h[3];
  87. {$ifdef ENDIAN_BIG}
  88. for counter := 0 to 63 do begin
  89. y[counter] := w[counter xor 3];
  90. end;
  91. {$endif}
  92. a := rol(a + ((b and c) or ((not b) and d)) + x[ 0] + $d76aa478, S11) + b;
  93. d := rol(d + ((a and b) or ((not a) and c)) + x[ 1] + $e8c7b756, S12) + a;
  94. c := rol(c + ((d and a) or ((not d) and b)) + x[ 2] + $242070db, S13) + d;
  95. b := rol(b + ((c and d) or ((not c) and a)) + x[ 3] + $c1bdceee, S14) + c;
  96. a := rol(a + ((b and c) or ((not b) and d)) + x[ 4] + $f57c0faf, S11) + b;
  97. d := rol(d + ((a and b) or ((not a) and c)) + x[ 5] + $4787c62a, S12) + a;
  98. c := rol(c + ((d and a) or ((not d) and b)) + x[ 6] + $a8304613, S13) + d;
  99. b := rol(b + ((c and d) or ((not c) and a)) + x[ 7] + $fd469501, S14) + c;
  100. a := rol(a + ((b and c) or ((not b) and d)) + x[ 8] + $698098d8, S11) + b;
  101. d := rol(d + ((a and b) or ((not a) and c)) + x[ 9] + $8b44f7af, S12) + a;
  102. c := rol(c + ((d and a) or ((not d) and b)) + x[10] + $ffff5bb1, S13) + d;
  103. b := rol(b + ((c and d) or ((not c) and a)) + x[11] + $895cd7be, S14) + c;
  104. a := rol(a + ((b and c) or ((not b) and d)) + x[12] + $6b901122, S11) + b;
  105. d := rol(d + ((a and b) or ((not a) and c)) + x[13] + $fd987193, S12) + a;
  106. c := rol(c + ((d and a) or ((not d) and b)) + x[14] + $a679438e, S13) + d;
  107. b := rol(b + ((c and d) or ((not c) and a)) + x[15] + $49b40821, S14) + c;
  108. a := rol(a + ((b and d) or (c and (not d))) + x[ 1] + $f61e2562, S21) + b;
  109. d := rol(d + ((a and c) or (b and (not c))) + x[ 6] + $c040b340, S22) + a;
  110. c := rol(c + ((d and b) or (a and (not b))) + x[11] + $265e5a51, S23) + d;
  111. b := rol(b + ((c and a) or (d and (not a))) + x[ 0] + $e9b6c7aa, S24) + c;
  112. a := rol(a + ((b and d) or (c and (not d))) + x[ 5] + $d62f105d, S21) + b;
  113. d := rol(d + ((a and c) or (b and (not c))) + x[10] + $02441453, S22) + a;
  114. c := rol(c + ((d and b) or (a and (not b))) + x[15] + $d8a1e681, S23) + d;
  115. b := rol(b + ((c and a) or (d and (not a))) + x[ 4] + $e7d3fbc8, S24) + c;
  116. a := rol(a + ((b and d) or (c and (not d))) + x[ 9] + $21e1cde6, S21) + b;
  117. d := rol(d + ((a and c) or (b and (not c))) + x[14] + $c33707d6, S22) + a;
  118. c := rol(c + ((d and b) or (a and (not b))) + x[ 3] + $f4d50d87, S23) + d;
  119. b := rol(b + ((c and a) or (d and (not a))) + x[ 8] + $455a14ed, S24) + c;
  120. a := rol(a + ((b and d) or (c and (not d))) + x[13] + $a9e3e905, S21) + b;
  121. d := rol(d + ((a and c) or (b and (not c))) + x[ 2] + $fcefa3f8, S22) + a;
  122. c := rol(c + ((d and b) or (a and (not b))) + x[ 7] + $676f02d9, S23) + d;
  123. b := rol(b + ((c and a) or (d and (not a))) + x[12] + $8d2a4c8a, S24) + c;
  124. a := rol(a + (b xor c xor d) + x[ 5] + $fffa3942, S31) + b;
  125. d := rol(d + (a xor b xor c) + x[ 8] + $8771f681, S32) + a;
  126. c := rol(c + (d xor a xor b) + x[11] + $6d9d6122, S33) + d;
  127. b := rol(b + (c xor d xor a) + x[14] + $fde5380c, S34) + c;
  128. a := rol(a + (b xor c xor d) + x[ 1] + $a4beea44, S31) + b;
  129. d := rol(d + (a xor b xor c) + x[ 4] + $4bdecfa9, S32) + a;
  130. c := rol(c + (d xor a xor b) + x[ 7] + $f6bb4b60, S33) + d;
  131. b := rol(b + (c xor d xor a) + x[10] + $bebfbc70, S34) + c;
  132. a := rol(a + (b xor c xor d) + x[13] + $289b7ec6, S31) + b;
  133. d := rol(d + (a xor b xor c) + x[ 0] + $eaa127fa, S32) + a;
  134. c := rol(c + (d xor a xor b) + x[ 3] + $d4ef3085, S33) + d;
  135. b := rol(b + (c xor d xor a) + x[ 6] + $04881d05, S34) + c;
  136. a := rol(a + (b xor c xor d) + x[ 9] + $d9d4d039, S31) + b;
  137. d := rol(d + (a xor b xor c) + x[12] + $e6db99e5, S32) + a;
  138. c := rol(c + (d xor a xor b) + x[15] + $1fa27cf8, S33) + d;
  139. b := rol(b + (c xor d xor a) + x[ 2] + $c4ac5665, S34) + c;
  140. a := rol(a + (c xor (b or (not d))) + x[ 0] + $f4292244, S41) + b;
  141. d := rol(d + (b xor (a or (not c))) + x[ 7] + $432aff97, S42) + a;
  142. c := rol(c + (a xor (d or (not b))) + x[14] + $ab9423a7, S43) + d;
  143. b := rol(b + (d xor (c or (not a))) + x[ 5] + $fc93a039, S44) + c;
  144. a := rol(a + (c xor (b or (not d))) + x[12] + $655b59c3, S41) + b;
  145. d := rol(d + (b xor (a or (not c))) + x[ 3] + $8f0ccc92, S42) + a;
  146. c := rol(c + (a xor (d or (not b))) + x[10] + $ffeff47d, S43) + d;
  147. b := rol(b + (d xor (c or (not a))) + x[ 1] + $85845dd1, S44) + c;
  148. a := rol(a + (c xor (b or (not d))) + x[ 8] + $6fa87e4f, S41) + b;
  149. d := rol(d + (b xor (a or (not c))) + x[15] + $fe2ce6e0, S42) + a;
  150. c := rol(c + (a xor (d or (not b))) + x[ 6] + $a3014314, S43) + d;
  151. b := rol(b + (d xor (c or (not a))) + x[13] + $4e0811a1, S44) + c;
  152. a := rol(a + (c xor (b or (not d))) + x[ 4] + $f7537e82, S41) + b;
  153. d := rol(d + (b xor (a or (not c))) + x[11] + $bd3af235, S42) + a;
  154. c := rol(c + (a xor (d or (not b))) + x[ 2] + $2ad7d2bb, S43) + d;
  155. b := rol(b + (d xor (c or (not a))) + x[ 9] + $eb86d391, S44) + c;
  156. inc(h[0],A);
  157. inc(h[1],B);
  158. inc(h[2],C);
  159. inc(h[3],D);
  160. end;
  161. procedure md5init(var state:tmd5state);
  162. begin
  163. state.h[0] := $67452301;
  164. state.h[1] := $EFCDAB89;
  165. state.h[2] := $98BADCFE;
  166. state.h[3] := $10325476;
  167. state.msglen := 0;
  168. state.msglenhi := 0;
  169. end;
  170. procedure md5process(var state:tmd5state;const data;len:longint);
  171. var
  172. a,b:longint;
  173. ofs:longint;
  174. p:dvar absolute data;
  175. begin
  176. b := state.msglen and 63;
  177. inc(state.msglen,len);
  178. while (state.msglen > $20000000) do begin
  179. dec(state.msglen,$20000000);
  180. inc(state.msglenhi);
  181. end;
  182. ofs := 0;
  183. if b > 0 then begin
  184. a := 64-b;
  185. if a > len then a := len;
  186. move(p[0],state.buf[b],a);
  187. inc(ofs,a);
  188. dec(len,a);
  189. if b+a = 64 then md5processblock(state.h,state.buf);
  190. if len = 0 then exit;
  191. end;
  192. while len >= 64 do begin
  193. md5processblock(state.h,p[ofs]);
  194. inc(ofs,64);
  195. dec(len,64);
  196. end;
  197. if len > 0 then move(p[ofs],state.buf[0],len);
  198. end;
  199. procedure md5finish(var state:tmd5state;var result);
  200. var
  201. b :integer;
  202. {$ifdef endian_big}
  203. h :tmd5 absolute state.h;
  204. r :tmd5 absolute result;
  205. counter :integer ;
  206. {$endif}
  207. begin
  208. b := state.msglen and 63;
  209. state.buf[b] := $80;
  210. if b >= 56 then begin
  211. {-- for a := b+1 to 63 do state.buf[a] := 0; }
  212. fillchar(state.buf[b+1],63-b,0);
  213. md5processblock(state.h,state.buf);
  214. fillchar(state.buf,56,0);
  215. end else begin
  216. {-- for a := b+1 to 55 do state.buf[a] := 0; }
  217. fillchar(state.buf[b+1],55-b,0);
  218. end;
  219. state.msglen := state.msglen shl 3;
  220. state.buf[56] := state.msglen;
  221. state.buf[57] := state.msglen shr 8;
  222. state.buf[58] := state.msglen shr 16;
  223. state.buf[59] := state.msglen shr 24;
  224. state.buf[60] := state.msglenhi;
  225. state.buf[61] := state.msglenhi shr 8;
  226. state.buf[62] := state.msglenhi shr 16;
  227. state.buf[63] := state.msglenhi shr 24;
  228. md5processblock(state.h,state.buf);
  229. {$ifdef ENDIAN_BIG}
  230. for counter := 0 to 15 do begin
  231. r[counter] := h[counter xor 3];
  232. end;
  233. {$else}
  234. move(state.h,result,16);
  235. {$endif}
  236. fillchar(state,sizeof(state),0);
  237. end;
  238. procedure getmd5(const data;len:longint;var result);
  239. var
  240. t:tmd5state;
  241. begin
  242. md5init(t);
  243. md5process(t,data,len);
  244. md5finish(t,result);
  245. end;
  246. function md5tostr(const md5:tmd5):string;
  247. var
  248. a:integer;
  249. s:string;
  250. begin
  251. s := '';
  252. for a := 0 to 15 do s := s + inttohex(md5[a],2);
  253. md5tostr := s;
  254. end;
  255. end.