PageRenderTime 45ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/ProSnooperFx_src/indy10.0.52_source/Protocols/IdHashSHA1.pas

http://github.com/lookias/ProSnooper
Pascal | 343 lines | 226 code | 21 blank | 96 comment | 7 complexity | 2f9f78a936b5f8e7261ac4caa0dd6fa2 MD5 | raw file
  1. { $HDR$}
  2. {**********************************************************************}
  3. { Unit archived using Team Coherence }
  4. { Team Coherence is Copyright 2002 by Quality Software Components }
  5. { }
  6. { For further information / comments, visit our WEB site at }
  7. { http://www.TeamCoherence.com }
  8. {**********************************************************************}
  9. {}
  10. { $Log: 11607: IdHashSHA1.pas
  11. {
  12. { Rev 1.6 2003-10-12 15:25:50 HHellström
  13. { Comments added
  14. }
  15. {
  16. { Rev 1.5 2003-10-12 03:08:24 HHellström
  17. { New implementation; copyright changed. The source code formatting has been
  18. { adjusted to fit the margins. The new implementation is faster on dotNet
  19. { compared to the old one, but is slightly slower on Win32.
  20. }
  21. {
  22. { Rev 1.4 2003-10-11 18:44:54 HHellström
  23. { Range checking and overflow checking disabled in the Coder method only. The
  24. { purpose of this setting is to force the arithmetic operations performed on
  25. { LongWord variables to be modulo $100000000. This hack entails reasonable
  26. { performance on both Win32 and dotNet.
  27. }
  28. {
  29. { Rev 1.3 10/10/2003 2:20:56 PM GGrieve
  30. { turn range checking off
  31. }
  32. {
  33. { Rev 1.2 2003-09-21 17:31:02 HHellström Version: 1.2
  34. { DotNET compatibility
  35. }
  36. {
  37. { Rev 1.1 2/16/2003 03:19:18 PM JPMugaas
  38. { Should now compile on D7 better.
  39. }
  40. {
  41. { Rev 1.0 11/13/2002 07:53:48 AM JPMugaas
  42. }
  43. unit IdHashSHA1;
  44. interface
  45. uses
  46. Classes,
  47. IdHash;
  48. const
  49. BufferSize = 64;
  50. type
  51. T512BitRecord = array [0..BufferSize-1] of Byte;
  52. TIdHashSHA1 = class(TIdHash160)
  53. protected
  54. FCheckSum: T5x4LongWordRecord;
  55. FCBuffer: T512BitRecord;
  56. procedure Coder;
  57. public
  58. function HashValue(AStream: TStream): T5x4LongWordRecord; override;
  59. end;
  60. implementation
  61. { TIdHashSHA1 }
  62. function SwapLongword(Const ALongword: Longword): Longword;
  63. begin
  64. Result:= ((ALongword and $FF) shl 24) or ((ALongword and $FF00) shl 8) or ((ALongword and $FF0000) shr 8) or ((ALongword and $FF000000) shr 24);
  65. end;
  66. function TIdHashSHA1.HashValue(AStream: TStream): T5x4LongWordRecord;
  67. var
  68. LSize: LongInt;
  69. LLenHi: LongWord;
  70. LLenLo: LongWord;
  71. i: Integer;
  72. begin
  73. FCheckSum[0] := $67452301;
  74. FCheckSum[1] := $EFCDAB89;
  75. FCheckSum[2] := $98BADCFE;
  76. FCheckSum[3] := $10325476;
  77. FCheckSum[4] := $C3D2E1F0;
  78. LLenHi := 0;
  79. LLenLo := 0;
  80. repeat
  81. LSize := AStream.Read(FCBuffer,BufferSize);
  82. Inc(LLenLo,LSize*8);
  83. if LLenLo < LongWord(LSize*8) then
  84. Inc(LLenHi);
  85. if LSize < BufferSize then begin
  86. FCBuffer[LSize] := $80;
  87. if LSize >= BufferSize - 8 then begin
  88. for i := LSize + 1 to Pred(BufferSize) do
  89. FCBuffer[i] := 0;
  90. Coder;
  91. LSize := -1;
  92. end;
  93. for i := LSize + 1 to Pred(BufferSize - 8) do
  94. FCBuffer[i] := 0;
  95. FCBuffer[BufferSize-8] := LLenHi shr 24;
  96. FCBuffer[BufferSize-7] := (LLenHi shr 16) and $FF;
  97. FCBuffer[BufferSize-6] := (LLenHi shr 8) and $FF;
  98. FCBuffer[BufferSize-5] := LLenHi and $FF;
  99. FCBuffer[BufferSize-4] := LLenLo shr 24;
  100. FCBuffer[BufferSize-3] := (LLenLo shr 16) and $FF;
  101. FCBuffer[BufferSize-2] := (LLenLo shr 8) and $FF;
  102. FCBuffer[BufferSize-1] := LLenLo and $FF;
  103. LSize := 0;
  104. end;
  105. Coder;
  106. until LSize < BufferSize;
  107. FCheckSum[0] := SwapLongWord(FCheckSum[0]);
  108. FCheckSum[1] := SwapLongWord(FCheckSum[1]);
  109. FCheckSum[2] := SwapLongWord(FCheckSum[2]);
  110. FCheckSum[3] := SwapLongWord(FCheckSum[3]);
  111. FCheckSum[4] := SwapLongWord(FCheckSum[4]);
  112. Result:=FCheckSum;
  113. end;
  114. {$Q-,R-} // Operations performed modulo $100000000
  115. procedure TIdHashSHA1.Coder;
  116. var
  117. T, A, B, C, D, E: LongWord;
  118. { The size of the W variable has been reduced to make the Coder method
  119. consume less memory on dotNet. This change has been tested with the v1.1
  120. framework and entails a general increase of performance by >50%. }
  121. W: array [0..19] of LongWord;
  122. i: LongWord;
  123. begin
  124. { The first 16 W values are identical to the input block with endian
  125. conversion. }
  126. for i := 0 to 15 do
  127. W[i]:= (FCBuffer[i*4] shl 24) or
  128. (FCBuffer[i*4+1] shl 16) or
  129. (FCBuffer[i*4+2] shl 8) or
  130. FCBuffer[i*4+3];
  131. { In normal x86 code all of the remaining 64 W values would be calculated
  132. here. Here only the four next values are calculated, to reduce the code
  133. size of the first of the four loops below. }
  134. for i := 16 to 19 do begin
  135. T := W[i-3] xor W[i-8] xor W[i-14] xor W[i-16];
  136. W[i] := (T shl 1) or (T shr 31);
  137. end;
  138. A:= FCheckSum[0];
  139. B:= FCheckSum[1];
  140. C:= FCheckSum[2];
  141. D:= FCheckSum[3];
  142. E:= FCheckSum[4];
  143. { The following loop could be expanded, but has been kept together to reduce
  144. the code size. A small code size entails better performance due to CPU
  145. caching.
  146. Note that the code size could be reduced further by using the SHA-1
  147. reference code:
  148. for i := 0 to 19 do begin
  149. T := E + (A shl 5) + (A shr 27) + (D xor (B and (C xor D))) + W[i];
  150. Inc(T,$5A827999);
  151. E := D;
  152. D := C;
  153. C := (B shl 30) + (B shr 2);
  154. B := A;
  155. A := T;
  156. end;
  157. The reference code is usually (at least partly) expanded, mostly because
  158. the assignments that circle the state variables A, B, C, D and E are costly,
  159. in particular on dotNET. (In x86 code further optimization can be achieved
  160. by eliminating the loop variable, which occupies a CPU register that is
  161. better used by one of the state variables, plus by expanding the W array
  162. at the beginning.) }
  163. i := 0;
  164. repeat
  165. Inc(E,(A shl 5) + (A shr 27) + (D xor (B and (C xor D))) + W[i+0]);
  166. Inc(E,$5A827999);
  167. B := (B shl 30) + (B shr 2);
  168. Inc(D,(E shl 5) + (E shr 27) + (C xor (A and (B xor C))) + W[i+1]);
  169. Inc(D,$5A827999);
  170. A := (A shl 30) + (A shr 2);
  171. Inc(C,(D shl 5) + (D shr 27) + (B xor (E and (A xor B))) + W[i+2]);
  172. Inc(C,$5A827999);
  173. E := (E shl 30) + (E shr 2);
  174. Inc(B,(C shl 5) + (C shr 27) + (A xor (D and (E xor A))) + W[i+3]);
  175. Inc(B,$5A827999);
  176. D := (D shl 30) + (D shr 2);
  177. Inc(A,(B shl 5) + (B shr 27) + (E xor (C and (D xor E))) + W[i+4]);
  178. Inc(A,$5A827999);
  179. C := (C shl 30) + (C shr 2);
  180. Inc(i,5);
  181. until i = 20;
  182. { The following three loops will only use the first 16 elements of the W
  183. array in a circular, recursive pattern. The following assignments are a
  184. trade-off to avoid having to split up the first loop. }
  185. W[0] := W[16];
  186. W[1] := W[17];
  187. W[2] := W[18];
  188. W[3] := W[19];
  189. { In the following three loops the recursive W array expansion is performed
  190. "just in time" following a circular pattern. Using circular indicies (e.g.
  191. (i+2) and $F) is not free, but the cost of declaring a large W array would
  192. be higher on dotNET. Before attempting to optimize this code, please note
  193. that the following language features are also costly:
  194. * Assignments and moves/copies, in particular on dotNET
  195. * Constant lookup tables, in particular on dotNET
  196. * Sub functions, in particular on x86
  197. * if..then and case..of. }
  198. i := 20;
  199. repeat
  200. T := W[(i+13) and $F] xor W[(i+8) and $F];
  201. T := T xor W[(i+2) and $F] xor W[i and $F];
  202. T := (T shl 1) or (T shr 31);
  203. W[i and $F] := T;
  204. Inc(E,(A shl 5) + (A shr 27) + (B xor C xor D) + T + $6ED9EBA1);
  205. B := (B shl 30) + (B shr 2);
  206. T := W[(i+14) and $F] xor W[(i+9) and $F];
  207. T := T xor W[(i+3) and $F] xor W[(i+1) and $F];
  208. T := (T shl 1) or (T shr 31);
  209. W[(i+1) and $F] := T;
  210. Inc(D,(E shl 5) + (E shr 27) + (A xor B xor C) + T + $6ED9EBA1);
  211. A := (A shl 30) + (A shr 2);
  212. T := W[(i+15) and $F] xor W[(i+10) and $F];
  213. T := T xor W[(i+4) and $F] xor W[(i+2) and $F];
  214. T := (T shl 1) or (T shr 31);
  215. W[(i+2) and $F] := T;
  216. Inc(C,(D shl 5) + (D shr 27) + (E xor A xor B) + T + $6ED9EBA1);
  217. E := (E shl 30) + (E shr 2);
  218. T := W[i and $F] xor W[(i+11) and $F];
  219. T := T xor W[(i+5) and $F] xor W[(i+3) and $F];
  220. T := (T shl 1) or (T shr 31);
  221. W[(i+3) and $F] := T;
  222. Inc(B,(C shl 5) + (C shr 27) + (D xor E xor A) + T + $6ED9EBA1);
  223. D := (D shl 30) + (D shr 2);
  224. T := W[(i+1) and $F] xor W[(i+12) and $F];
  225. T := T xor W[(i+6) and $F] xor W[(i+4) and $F];
  226. T := (T shl 1) or (T shr 31);
  227. W[(i+4) and $F] := T;
  228. Inc(A,(B shl 5) + (B shr 27) + (C xor D xor E) + T + $6ED9EBA1);
  229. C := (C shl 30) + (C shr 2);
  230. Inc(i,5);
  231. until i = 40;
  232. { Note that the constant $70E44324 = $100000000 - $8F1BBCDC has been selected
  233. to slightly reduce the probability that the CPU flag C (Carry) is set. This
  234. trick is taken from the StreamSec(R) StrSecII(TM) implementation of SHA-1.
  235. It entails a marginal but measurable performance gain on some CPUs. }
  236. i := 40;
  237. repeat
  238. T := W[(i+13) and $F] xor W[(i+8) and $F];
  239. T := T xor W[(i+2) and $F] xor W[i and $F];
  240. T := (T shl 1) or (T shr 31);
  241. W[i and $F] := T;
  242. Inc(E,(A shl 5) + (A shr 27) + ((B and C) or (D and (B or C))) + T);
  243. Dec(E,$70E44324);
  244. B := (B shl 30) + (B shr 2);
  245. T := W[(i+14) and $F] xor W[(i+9) and $F];
  246. T := T xor W[(i+3) and $F] xor W[(i+1) and $F];
  247. T := (T shl 1) or (T shr 31);
  248. W[(i+1) and $F] := T;
  249. Inc(D,(E shl 5) + (E shr 27) + ((A and B) or (C and (A or B))) + T);
  250. Dec(D,$70E44324);
  251. A := (A shl 30) + (A shr 2);
  252. T := W[(i+15) and $F] xor W[(i+10) and $F];
  253. T := T xor W[(i+4) and $F] xor W[(i+2) and $F];
  254. T := (T shl 1) or (T shr 31);
  255. W[(i+2) and $F] := T;
  256. Inc(C,(D shl 5) + (D shr 27) + ((E and A) or (B and (E or A))) + T);
  257. Dec(C,$70E44324);
  258. E := (E shl 30) + (E shr 2);
  259. T := W[i and $F] xor W[(i+11) and $F];
  260. T := T xor W[(i+5) and $F] xor W[(i+3) and $F];
  261. T := (T shl 1) or (T shr 31);
  262. W[(i+3) and $F] := T;
  263. Inc(B,(C shl 5) + (C shr 27) + ((D and E) or (A and (D or E))) + T);
  264. Dec(B,$70E44324);
  265. D := (D shl 30) + (D shr 2);
  266. T := W[(i+1) and $F] xor W[(i+12) and $F];
  267. T := T xor W[(i+6) and $F] xor W[(i+4) and $F];
  268. T := (T shl 1) or (T shr 31);
  269. W[(i+4) and $F] := T;
  270. Inc(A,(B shl 5) + (B shr 27) + ((C and D) or (E and (C or D))) + T);
  271. Dec(A,$70E44324);
  272. C := (C shl 30) + (C shr 2);
  273. Inc(i,5);
  274. until i = 60;
  275. { Note that the constant $359D3E2A = $100000000 - $CA62C1D6 has been selected
  276. to slightly reduce the probability that the CPU flag C (Carry) is set. This
  277. trick is taken from the StreamSec(R) StrSecII(TM) implementation of SHA-1.
  278. It entails a marginal but measurable performance gain on some CPUs. }
  279. repeat
  280. T := W[(i+13) and $F] xor W[(i+8) and $F];
  281. T := T xor W[(i+2) and $F] xor W[i and $F];
  282. T := (T shl 1) or (T shr 31);
  283. W[i and $F] := T;
  284. Inc(E,(A shl 5) + (A shr 27) + (B xor C xor D) + T - $359D3E2A);
  285. B := (B shl 30) + (B shr 2);
  286. T := W[(i+14) and $F] xor W[(i+9) and $F];
  287. T := T xor W[(i+3) and $F] xor W[(i+1) and $F];
  288. T := (T shl 1) or (T shr 31);
  289. W[(i+1) and $F] := T;
  290. Inc(D,(E shl 5) + (E shr 27) + (A xor B xor C) + T - $359D3E2A);
  291. A := (A shl 30) + (A shr 2);
  292. T := W[(i+15) and $F] xor W[(i+10) and $F];
  293. T := T xor W[(i+4) and $F] xor W[(i+2) and $F];
  294. T := (T shl 1) or (T shr 31);
  295. W[(i+2) and $F] := T;
  296. Inc(C,(D shl 5) + (D shr 27) + (E xor A xor B) + T - $359D3E2A);
  297. E := (E shl 30) + (E shr 2);
  298. T := W[i and $F] xor W[(i+11) and $F];
  299. T := T xor W[(i+5) and $F] xor W[(i+3) and $F];
  300. T := (T shl 1) or (T shr 31);
  301. W[(i+3) and $F] := T;
  302. Inc(B,(C shl 5) + (C shr 27) + (D xor E xor A) + T - $359D3E2A);
  303. D := (D shl 30) + (D shr 2);
  304. T := W[(i+1) and $F] xor W[(i+12) and $F];
  305. T := T xor W[(i+6) and $F] xor W[(i+4) and $F];
  306. T := (T shl 1) or (T shr 31);
  307. W[(i+4) and $F] := T;
  308. Inc(A,(B shl 5) + (B shr 27) + (C xor D xor E) + T - $359D3E2A);
  309. C := (C shl 30) + (C shr 2);
  310. Inc(i,5);
  311. until i = 80;
  312. FCheckSum[0]:= FCheckSum[0] + A;
  313. FCheckSum[1]:= FCheckSum[1] + B;
  314. FCheckSum[2]:= FCheckSum[2] + C;
  315. FCheckSum[3]:= FCheckSum[3] + D;
  316. FCheckSum[4]:= FCheckSum[4] + E;
  317. end;
  318. end.