dcpmd5.pas 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. {******************************************************************************}
  2. {* DCPcrypt v2.0 written by David Barton ([email protected]) **********}
  3. {******************************************************************************}
  4. {* A binary compatible implementation of MD5 **********************************}
  5. {******************************************************************************}
  6. {* Copyright (c) 1999-2002 David Barton *}
  7. {* Permission is hereby granted, free of charge, to any person obtaining a *}
  8. {* copy of this software and associated documentation files (the "Software"), *}
  9. {* to deal in the Software without restriction, including without limitation *}
  10. {* the rights to use, copy, modify, merge, publish, distribute, sublicense, *}
  11. {* and/or sell copies of the Software, and to permit persons to whom the *}
  12. {* Software is furnished to do so, subject to the following conditions: *}
  13. {* *}
  14. {* The above copyright notice and this permission notice shall be included in *}
  15. {* all copies or substantial portions of the Software. *}
  16. {* *}
  17. {* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *}
  18. {* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *}
  19. {* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *}
  20. {* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *}
  21. {* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *}
  22. {* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *}
  23. {* DEALINGS IN THE SOFTWARE. *}
  24. {******************************************************************************}
  25. unit DCPmd5;
  26. {$MODE Delphi}
  27. interface
  28. uses
  29. Classes, Sysutils, DCPcrypt2, DCPconst;
  30. type
  31. TDCP_md5= class(TDCP_hash)
  32. protected
  33. LenHi, LenLo: longword;
  34. Index: DWord;
  35. CurrentHash: array[0..3] of DWord;
  36. HashBuffer: array[0..63] of byte;
  37. procedure Compress;
  38. public
  39. class function GetId: integer; override;
  40. class function GetAlgorithm: string; override;
  41. class function GetHashSize: integer; override;
  42. class function SelfTest: boolean; override;
  43. procedure Init; override;
  44. procedure Burn; override;
  45. procedure Update(const Buffer; Size: longword); override;
  46. procedure Final(var Digest); override;
  47. end;
  48. {******************************************************************************}
  49. {******************************************************************************}
  50. implementation
  51. {$R-}{$Q-}
  52. {$macro on}{$define LRot32:=RolDWord}
  53. procedure TDCP_md5.Compress;
  54. var
  55. Data: array[0..15] of dword;
  56. A, B, C, D: dword;
  57. begin
  58. dcpFillChar(Data, SizeOf(Data), 0);
  59. Move(HashBuffer,Data,Sizeof(Data));
  60. A:= CurrentHash[0];
  61. B:= CurrentHash[1];
  62. C:= CurrentHash[2];
  63. D:= CurrentHash[3];
  64. A:= B + LRot32(A + (D xor (B and (C xor D))) + Data[ 0] + $d76aa478,7);
  65. D:= A + LRot32(D + (C xor (A and (B xor C))) + Data[ 1] + $e8c7b756,12);
  66. C:= D + LRot32(C + (B xor (D and (A xor B))) + Data[ 2] + $242070db,17);
  67. B:= C + LRot32(B + (A xor (C and (D xor A))) + Data[ 3] + $c1bdceee,22);
  68. A:= B + LRot32(A + (D xor (B and (C xor D))) + Data[ 4] + $f57c0faf,7);
  69. D:= A + LRot32(D + (C xor (A and (B xor C))) + Data[ 5] + $4787c62a,12);
  70. C:= D + LRot32(C + (B xor (D and (A xor B))) + Data[ 6] + $a8304613,17);
  71. B:= C + LRot32(B + (A xor (C and (D xor A))) + Data[ 7] + $fd469501,22);
  72. A:= B + LRot32(A + (D xor (B and (C xor D))) + Data[ 8] + $698098d8,7);
  73. D:= A + LRot32(D + (C xor (A and (B xor C))) + Data[ 9] + $8b44f7af,12);
  74. C:= D + LRot32(C + (B xor (D and (A xor B))) + Data[10] + $ffff5bb1,17);
  75. B:= C + LRot32(B + (A xor (C and (D xor A))) + Data[11] + $895cd7be,22);
  76. A:= B + LRot32(A + (D xor (B and (C xor D))) + Data[12] + $6b901122,7);
  77. D:= A + LRot32(D + (C xor (A and (B xor C))) + Data[13] + $fd987193,12);
  78. C:= D + LRot32(C + (B xor (D and (A xor B))) + Data[14] + $a679438e,17);
  79. B:= C + LRot32(B + (A xor (C and (D xor A))) + Data[15] + $49b40821,22);
  80. A:= B + LRot32(A + (C xor (D and (B xor C))) + Data[ 1] + $f61e2562,5);
  81. D:= A + LRot32(D + (B xor (C and (A xor B))) + Data[ 6] + $c040b340,9);
  82. C:= D + LRot32(C + (A xor (B and (D xor A))) + Data[11] + $265e5a51,14);
  83. B:= C + LRot32(B + (D xor (A and (C xor D))) + Data[ 0] + $e9b6c7aa,20);
  84. A:= B + LRot32(A + (C xor (D and (B xor C))) + Data[ 5] + $d62f105d,5);
  85. D:= A + LRot32(D + (B xor (C and (A xor B))) + Data[10] + $02441453,9);
  86. C:= D + LRot32(C + (A xor (B and (D xor A))) + Data[15] + $d8a1e681,14);
  87. B:= C + LRot32(B + (D xor (A and (C xor D))) + Data[ 4] + $e7d3fbc8,20);
  88. A:= B + LRot32(A + (C xor (D and (B xor C))) + Data[ 9] + $21e1cde6,5);
  89. D:= A + LRot32(D + (B xor (C and (A xor B))) + Data[14] + $c33707d6,9);
  90. C:= D + LRot32(C + (A xor (B and (D xor A))) + Data[ 3] + $f4d50d87,14);
  91. B:= C + LRot32(B + (D xor (A and (C xor D))) + Data[ 8] + $455a14ed,20);
  92. A:= B + LRot32(A + (C xor (D and (B xor C))) + Data[13] + $a9e3e905,5);
  93. D:= A + LRot32(D + (B xor (C and (A xor B))) + Data[ 2] + $fcefa3f8,9);
  94. C:= D + LRot32(C + (A xor (B and (D xor A))) + Data[ 7] + $676f02d9,14);
  95. B:= C + LRot32(B + (D xor (A and (C xor D))) + Data[12] + $8d2a4c8a,20);
  96. A:= B + LRot32(A + (B xor C xor D) + Data[ 5] + $fffa3942,4);
  97. D:= A + LRot32(D + (A xor B xor C) + Data[ 8] + $8771f681,11);
  98. C:= D + LRot32(C + (D xor A xor B) + Data[11] + $6d9d6122,16);
  99. B:= C + LRot32(B + (C xor D xor A) + Data[14] + $fde5380c,23);
  100. A:= B + LRot32(A + (B xor C xor D) + Data[ 1] + $a4beea44,4);
  101. D:= A + LRot32(D + (A xor B xor C) + Data[ 4] + $4bdecfa9,11);
  102. C:= D + LRot32(C + (D xor A xor B) + Data[ 7] + $f6bb4b60,16);
  103. B:= C + LRot32(B + (C xor D xor A) + Data[10] + $bebfbc70,23);
  104. A:= B + LRot32(A + (B xor C xor D) + Data[13] + $289b7ec6,4);
  105. D:= A + LRot32(D + (A xor B xor C) + Data[ 0] + $eaa127fa,11);
  106. C:= D + LRot32(C + (D xor A xor B) + Data[ 3] + $d4ef3085,16);
  107. B:= C + LRot32(B + (C xor D xor A) + Data[ 6] + $04881d05,23);
  108. A:= B + LRot32(A + (B xor C xor D) + Data[ 9] + $d9d4d039,4);
  109. D:= A + LRot32(D + (A xor B xor C) + Data[12] + $e6db99e5,11);
  110. C:= D + LRot32(C + (D xor A xor B) + Data[15] + $1fa27cf8,16);
  111. B:= C + LRot32(B + (C xor D xor A) + Data[ 2] + $c4ac5665,23);
  112. A:= B + LRot32(A + (C xor (B or (not D))) + Data[ 0] + $f4292244,6);
  113. D:= A + LRot32(D + (B xor (A or (not C))) + Data[ 7] + $432aff97,10);
  114. C:= D + LRot32(C + (A xor (D or (not B))) + Data[14] + $ab9423a7,15);
  115. B:= C + LRot32(B + (D xor (C or (not A))) + Data[ 5] + $fc93a039,21);
  116. A:= B + LRot32(A + (C xor (B or (not D))) + Data[12] + $655b59c3,6);
  117. D:= A + LRot32(D + (B xor (A or (not C))) + Data[ 3] + $8f0ccc92,10);
  118. C:= D + LRot32(C + (A xor (D or (not B))) + Data[10] + $ffeff47d,15);
  119. B:= C + LRot32(B + (D xor (C or (not A))) + Data[ 1] + $85845dd1,21);
  120. A:= B + LRot32(A + (C xor (B or (not D))) + Data[ 8] + $6fa87e4f,6);
  121. D:= A + LRot32(D + (B xor (A or (not C))) + Data[15] + $fe2ce6e0,10);
  122. C:= D + LRot32(C + (A xor (D or (not B))) + Data[ 6] + $a3014314,15);
  123. B:= C + LRot32(B + (D xor (C or (not A))) + Data[13] + $4e0811a1,21);
  124. A:= B + LRot32(A + (C xor (B or (not D))) + Data[ 4] + $f7537e82,6);
  125. D:= A + LRot32(D + (B xor (A or (not C))) + Data[11] + $bd3af235,10);
  126. C:= D + LRot32(C + (A xor (D or (not B))) + Data[ 2] + $2ad7d2bb,15);
  127. B:= C + LRot32(B + (D xor (C or (not A))) + Data[ 9] + $eb86d391,21);
  128. Inc(CurrentHash[0],A);
  129. Inc(CurrentHash[1],B);
  130. Inc(CurrentHash[2],C);
  131. Inc(CurrentHash[3],D);
  132. Index:= 0;
  133. FillChar(HashBuffer,Sizeof(HashBuffer),0);
  134. end;
  135. class function TDCP_md5.GetHashSize: integer;
  136. begin
  137. Result:= 128;
  138. end;
  139. class function TDCP_md5.GetId: integer;
  140. begin
  141. Result:= DCP_md5;
  142. end;
  143. class function TDCP_md5.GetAlgorithm: string;
  144. begin
  145. Result:= 'MD5';
  146. end;
  147. class function TDCP_md5.SelfTest: boolean;
  148. const
  149. Test1Out: array[0..15] of byte=
  150. ($90,$01,$50,$98,$3c,$d2,$4f,$b0,$d6,$96,$3f,$7d,$28,$e1,$7f,$72);
  151. Test2Out: array[0..15] of byte=
  152. ($c3,$fc,$d3,$d7,$61,$92,$e4,$00,$7d,$fb,$49,$6c,$ca,$67,$e1,$3b);
  153. var
  154. TestHash: TDCP_md5;
  155. TestOut: array[0..19] of byte;
  156. begin
  157. dcpFillChar(TestOut, SizeOf(TestOut), 0);
  158. TestHash:= TDCP_md5.Create(nil);
  159. TestHash.Init;
  160. TestHash.UpdateStr('abc');
  161. TestHash.Final(TestOut);
  162. Result:= CompareMem(@TestOut,@Test1Out,Sizeof(Test1Out));
  163. TestHash.Init;
  164. TestHash.UpdateStr('abcdefghijklmnopqrstuvwxyz');
  165. TestHash.Final(TestOut);
  166. Result:= CompareMem(@TestOut,@Test2Out,Sizeof(Test2Out)) and Result;
  167. TestHash.Free;
  168. end;
  169. procedure TDCP_md5.Init;
  170. begin
  171. Burn;
  172. CurrentHash[0]:= $67452301;
  173. CurrentHash[1]:= $efcdab89;
  174. CurrentHash[2]:= $98badcfe;
  175. CurrentHash[3]:= $10325476;
  176. fInitialized:= true;
  177. end;
  178. procedure TDCP_md5.Burn;
  179. begin
  180. LenHi:= 0; LenLo:= 0;
  181. Index:= 0;
  182. FillChar(HashBuffer,Sizeof(HashBuffer),0);
  183. FillChar(CurrentHash,Sizeof(CurrentHash),0);
  184. fInitialized:= false;
  185. end;
  186. procedure TDCP_md5.Update(const Buffer; Size: longword);
  187. var
  188. PBuf: ^byte;
  189. begin
  190. if not fInitialized then
  191. raise EDCP_hash.Create('Hash not initialized');
  192. Inc(LenHi,Size shr 29);
  193. Inc(LenLo,Size*8);
  194. if LenLo< (Size*8) then
  195. Inc(LenHi);
  196. PBuf:= @Buffer;
  197. while Size> 0 do
  198. begin
  199. if (Sizeof(HashBuffer)-Index)<= DWord(Size) then
  200. begin
  201. Move(PBuf^,HashBuffer[Index],Sizeof(HashBuffer)-Index);
  202. Dec(Size,Sizeof(HashBuffer)-Index);
  203. Inc(PBuf,Sizeof(HashBuffer)-Index);
  204. Compress;
  205. end
  206. else
  207. begin
  208. Move(PBuf^,HashBuffer[Index],Size);
  209. Inc(Index,Size);
  210. Size:= 0;
  211. end;
  212. end;
  213. end;
  214. procedure TDCP_md5.Final(var Digest);
  215. begin
  216. if not fInitialized then
  217. raise EDCP_hash.Create('Hash not initialized');
  218. HashBuffer[Index]:= $80;
  219. if Index>= 56 then
  220. Compress;
  221. PDWord(@HashBuffer[56])^:= LenLo;
  222. PDWord(@HashBuffer[60])^:= LenHi;
  223. Compress;
  224. Move(CurrentHash,Digest,Sizeof(CurrentHash));
  225. Burn;
  226. end;
  227. end.