dcpmd4.pas 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. {******************************************************************************}
  2. {* DCPcrypt v2.0 written by David Barton ([email protected]) **********}
  3. {******************************************************************************}
  4. {* A binary compatible implementation of MD4 **********************************}
  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 DCPmd4;
  26. {$MODE Delphi}
  27. interface
  28. uses
  29. Classes, Sysutils, DCPcrypt2, DCPconst;
  30. type
  31. TDCP_md4= 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. function LRot32(a, b: longword): longword;
  53. begin
  54. Result:= (a shl b) or (a shr (32-b));
  55. end;
  56. procedure TDCP_md4.Compress;
  57. var
  58. Data: array[0..15] of dword;
  59. A, B, C, D: dword;
  60. begin
  61. dcpFillChar(Data, SizeOf(Data), 0);
  62. Move(HashBuffer,Data,Sizeof(Data));
  63. A:= CurrentHash[0];
  64. B:= CurrentHash[1];
  65. C:= CurrentHash[2];
  66. D:= CurrentHash[3];
  67. A:= LRot32(A + (D xor (B and (C xor D))) + Data[ 0],3);
  68. D:= LRot32(D + (C xor (A and (B xor C))) + Data[ 1],7);
  69. C:= LRot32(C + (B xor (D and (A xor B))) + Data[ 2],11);
  70. B:= LRot32(B + (A xor (C and (D xor A))) + Data[ 3],19);
  71. A:= LRot32(A + (D xor (B and (C xor D))) + Data[ 4],3);
  72. D:= LRot32(D + (C xor (A and (B xor C))) + Data[ 5],7);
  73. C:= LRot32(C + (B xor (D and (A xor B))) + Data[ 6],11);
  74. B:= LRot32(B + (A xor (C and (D xor A))) + Data[ 7],19);
  75. A:= LRot32(A + (D xor (B and (C xor D))) + Data[ 8],3);
  76. D:= LRot32(D + (C xor (A and (B xor C))) + Data[ 9],7);
  77. C:= LRot32(C + (B xor (D and (A xor B))) + Data[10],11);
  78. B:= LRot32(B + (A xor (C and (D xor A))) + Data[11],19);
  79. A:= LRot32(A + (D xor (B and (C xor D))) + Data[12],3);
  80. D:= LRot32(D + (C xor (A and (B xor C))) + Data[13],7);
  81. C:= LRot32(C + (B xor (D and (A xor B))) + Data[14],11);
  82. B:= LRot32(B + (A xor (C and (D xor A))) + Data[15],19);
  83. A:= LRot32(A + ((B and C) or (B and D) or (C and D)) + Data[ 0] + $5a827999,3);
  84. D:= LRot32(D + ((A and B) or (A and C) or (B and C)) + Data[ 4] + $5a827999,5);
  85. C:= LRot32(C + ((D and A) or (D and B) or (A and B)) + Data[ 8] + $5a827999,9);
  86. B:= LRot32(B + ((C and D) or (C and A) or (D and A)) + Data[12] + $5a827999,13);
  87. A:= LRot32(A + ((B and C) or (B and D) or (C and D)) + Data[ 1] + $5a827999,3);
  88. D:= LRot32(D + ((A and B) or (A and C) or (B and C)) + Data[ 5] + $5a827999,5);
  89. C:= LRot32(C + ((D and A) or (D and B) or (A and B)) + Data[ 9] + $5a827999,9);
  90. B:= LRot32(B + ((C and D) or (C and A) or (D and A)) + Data[13] + $5a827999,13);
  91. A:= LRot32(A + ((B and C) or (B and D) or (C and D)) + Data[ 2] + $5a827999,3);
  92. D:= LRot32(D + ((A and B) or (A and C) or (B and C)) + Data[ 6] + $5a827999,5);
  93. C:= LRot32(C + ((D and A) or (D and B) or (A and B)) + Data[10] + $5a827999,9);
  94. B:= LRot32(B + ((C and D) or (C and A) or (D and A)) + Data[14] + $5a827999,13);
  95. A:= LRot32(A + ((B and C) or (B and D) or (C and D)) + Data[ 3] + $5a827999,3);
  96. D:= LRot32(D + ((A and B) or (A and C) or (B and C)) + Data[ 7] + $5a827999,5);
  97. C:= LRot32(C + ((D and A) or (D and B) or (A and B)) + Data[11] + $5a827999,9);
  98. B:= LRot32(B + ((C and D) or (C and A) or (D and A)) + Data[15] + $5a827999,13);
  99. A:= LRot32(A + (B xor C xor D) + Data[ 0] + $6ed9eba1,3);
  100. D:= LRot32(D + (A xor B xor C) + Data[ 8] + $6ed9eba1,9);
  101. C:= LRot32(C + (D xor A xor B) + Data[ 4] + $6ed9eba1,11);
  102. B:= LRot32(B + (C xor D xor A) + Data[12] + $6ed9eba1,15);
  103. A:= LRot32(A + (B xor C xor D) + Data[ 2] + $6ed9eba1,3);
  104. D:= LRot32(D + (A xor B xor C) + Data[10] + $6ed9eba1,9);
  105. C:= LRot32(C + (D xor A xor B) + Data[ 6] + $6ed9eba1,11);
  106. B:= LRot32(B + (C xor D xor A) + Data[14] + $6ed9eba1,15);
  107. A:= LRot32(A + (B xor C xor D) + Data[ 1] + $6ed9eba1,3);
  108. D:= LRot32(D + (A xor B xor C) + Data[ 9] + $6ed9eba1,9);
  109. C:= LRot32(C + (D xor A xor B) + Data[ 5] + $6ed9eba1,11);
  110. B:= LRot32(B + (C xor D xor A) + Data[13] + $6ed9eba1,15);
  111. A:= LRot32(A + (B xor C xor D) + Data[ 3] + $6ed9eba1,3);
  112. D:= LRot32(D + (A xor B xor C) + Data[11] + $6ed9eba1,9);
  113. C:= LRot32(C + (D xor A xor B) + Data[ 7] + $6ed9eba1,11);
  114. B:= LRot32(B + (C xor D xor A) + Data[15] + $6ed9eba1,15);
  115. Inc(CurrentHash[0],A);
  116. Inc(CurrentHash[1],B);
  117. Inc(CurrentHash[2],C);
  118. Inc(CurrentHash[3],D);
  119. Index:= 0;
  120. FillChar(HashBuffer,Sizeof(HashBuffer),0);
  121. end;
  122. class function TDCP_md4.GetHashSize: integer;
  123. begin
  124. Result:= 128;
  125. end;
  126. class function TDCP_md4.GetId: integer;
  127. begin
  128. Result:= DCP_md4;
  129. end;
  130. class function TDCP_md4.GetAlgorithm: string;
  131. begin
  132. Result:= 'MD4';
  133. end;
  134. class function TDCP_md4.SelfTest: boolean;
  135. const
  136. Test1Out: array[0..15] of byte=
  137. ($a4,$48,$01,$7a,$af,$21,$d8,$52,$5f,$c1,$0a,$e8,$7a,$a6,$72,$9d);
  138. Test2Out: array[0..15] of byte=
  139. ($d7,$9e,$1c,$30,$8a,$a5,$bb,$cd,$ee,$a8,$ed,$63,$df,$41,$2d,$a9);
  140. var
  141. TestHash: TDCP_md4;
  142. TestOut: array[0..19] of byte;
  143. begin
  144. dcpFillChar(TestOut, SizeOf(TestOut), 0);
  145. TestHash:= TDCP_md4.Create(nil);
  146. TestHash.Init;
  147. TestHash.UpdateStr('abc');
  148. TestHash.Final(TestOut);
  149. Result:= CompareMem(@TestOut,@Test1Out,Sizeof(Test1Out));
  150. TestHash.Init;
  151. TestHash.UpdateStr('abcdefghijklmnopqrstuvwxyz');
  152. TestHash.Final(TestOut);
  153. Result:= CompareMem(@TestOut,@Test2Out,Sizeof(Test2Out)) and Result;
  154. TestHash.Free;
  155. end;
  156. procedure TDCP_md4.Init;
  157. begin
  158. Burn;
  159. CurrentHash[0]:= $67452301;
  160. CurrentHash[1]:= $efcdab89;
  161. CurrentHash[2]:= $98badcfe;
  162. CurrentHash[3]:= $10325476;
  163. fInitialized:= true;
  164. end;
  165. procedure TDCP_md4.Burn;
  166. begin
  167. LenHi:= 0; LenLo:= 0;
  168. Index:= 0;
  169. FillChar(HashBuffer,Sizeof(HashBuffer),0);
  170. FillChar(CurrentHash,Sizeof(CurrentHash),0);
  171. fInitialized:= false;
  172. end;
  173. procedure TDCP_md4.Update(const Buffer; Size: longword);
  174. var
  175. PBuf: ^byte;
  176. begin
  177. if not fInitialized then
  178. raise EDCP_hash.Create('Hash not initialized');
  179. Inc(LenHi,Size shr 29);
  180. Inc(LenLo,Size*8);
  181. if LenLo< (Size*8) then
  182. Inc(LenHi);
  183. PBuf:= @Buffer;
  184. while Size> 0 do
  185. begin
  186. if (Sizeof(HashBuffer)-Index)<= DWord(Size) then
  187. begin
  188. Move(PBuf^,HashBuffer[Index],Sizeof(HashBuffer)-Index);
  189. Dec(Size,Sizeof(HashBuffer)-Index);
  190. Inc(PBuf,Sizeof(HashBuffer)-Index);
  191. Compress;
  192. end
  193. else
  194. begin
  195. Move(PBuf^,HashBuffer[Index],Size);
  196. Inc(Index,Size);
  197. Size:= 0;
  198. end;
  199. end;
  200. end;
  201. procedure TDCP_md4.Final(var Digest);
  202. begin
  203. if not fInitialized then
  204. raise EDCP_hash.Create('Hash not initialized');
  205. HashBuffer[Index]:= $80;
  206. if Index>= 56 then
  207. Compress;
  208. PDWord(@HashBuffer[56])^:= LenLo;
  209. PDWord(@HashBuffer[60])^:= LenHi;
  210. Compress;
  211. Move(CurrentHash,Digest,Sizeof(CurrentHash));
  212. Burn;
  213. end;
  214. end.