sha1.pas 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902
  1. unit SHA1;
  2. {SHA1 - 160 bit Secure Hash Function}
  3. interface
  4. (*************************************************************************
  5. DESCRIPTION : SHA1 - 160 bit Secure Hash Function
  6. REQUIREMENTS : TP5-7, D1-D7/D9-D10/D12/D17-D18/D25S, FPC, VP
  7. EXTERNAL DATA : ---
  8. MEMORY USAGE : ---
  9. DISPLAY MODE : ---
  10. REFERENCES : - Latest specification of Secure Hash Standard:
  11. http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
  12. - Test vectors and intermediate values:
  13. http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA_All.pdf
  14. Version Date Author Modification
  15. ------- -------- ------- ------------------------------------------
  16. 1.00 03.01.02 W.Ehrhardt BP7 implementation
  17. 1.01 14.03.02 we D1-D6, FPC, VP
  18. 1.02 14.03.02 we TP6
  19. 1.03 14.03.02 we TP6/7 386-Code
  20. 1.04 14.03.02 we TP5.5
  21. 1.10 15.03.02 we self test with 2 strings
  22. 1.11 02.01.03 we const SFA with @ for FPC 1.0.6
  23. 1.20 23.07.03 we With SHA1File, SHA1Full
  24. 1.21 26.07.03 we With SHA1Full in self test
  25. 2.00 26.07.03 we common vers., longint for word32, D4+ - warnings
  26. 2.01 03.08.03 we type TSHA1Block for HMAC
  27. 2.02 23.08.03 we SHA1Compress in interface for prng
  28. 2.10 29.08.03 we XL versions for Win32
  29. 2.20 27.09.03 we FPC/go32v2
  30. 2.30 05.10.03 we STD.INC, TP5.0
  31. 2.40 10.10.03 we common version, english comments
  32. 2.45 11.10.03 we Speedup: partial unroll, no function calls
  33. 2.50 16.11.03 we Speedup in update, don't clear W in compress
  34. 2.51 17.11.03 we BIT16: partial unroll, BIT32: inline rot
  35. 2.52 17.11.03 we ExpandMessageBlocks
  36. 2.53 18.11.03 we LRot32, RB mit inline()
  37. 2.54 20.11.03 we Full range UpdateLen
  38. 2.55 30.11.03 we BIT16: {$F-}
  39. 2.56 30.11.03 we BIT16: LRot_5, LRot_30
  40. 3.00 01.12.03 we Common version 3.0
  41. 3.01 22.12.03 we BIT16: Two INCs
  42. 3.02 22.12.03 we BASM16: asm Lrot30
  43. 3.03 22.12.03 we TP5/5.5: LRot, RA inline
  44. 3.04 22,12.03 we Changed UpdateLen: Definition and TP5/5.5 inline
  45. 3.05 05.03.04 we Update fips180-2 URL
  46. 3.06 26.02.05 we With {$ifdef StrictLong}
  47. 3.07 05.05.05 we Use longint() in SH1Init to avoid D9 errors if $R+
  48. 3.08 17.12.05 we Force $I- in SHA1File
  49. 3.09 08.01.06 we SHA1Compress removed from interface
  50. 3.10 15.01.06 we uses Hash unit and THashDesc
  51. 3.11 18.01.06 we Descriptor fields HAlgNum, HSig
  52. 3.12 22.01.06 we Removed HSelfTest from descriptor
  53. 3.13 11.02.06 we Descriptor as typed const
  54. 3.14 26.03.06 we Round constants K1..K4, code reordering
  55. 3.15 07.08.06 we $ifdef BIT32: (const fname: shortstring...)
  56. 3.16 22.02.07 we values for OID vector
  57. 3.17 30.06.07 we Use conditional define FPC_ProcVar
  58. 3.18 04.10.07 we FPC: {$asmmode intel}
  59. 3.19 02.05.08 we Bit-API: SHA1FinalBits/Ex
  60. 3.20 05.05.08 we THashDesc constant with HFinalBit field
  61. 3.21 12.11.08 we uses BTypes, Ptr2Inc and/or Str255/Str127
  62. 3.22 12.03.10 we Fix VP feature in ExpandMessageBlocks
  63. 3.23 11.03.12 we Updated references
  64. 3.24 26.12.12 we D17 and PurePascal
  65. 3.25 16.08.15 we Removed $ifdef DLL / stdcall
  66. 3.26 15.05.17 we adjust OID to new MaxOIDLen
  67. **************************************************************************)
  68. (*-------------------------------------------------------------------------
  69. (C) Copyright 2002-2017 Wolfgang Ehrhardt
  70. This software is provided 'as-is', without any express or implied warranty.
  71. In no event will the authors be held liable for any damages arising from
  72. the use of this software.
  73. Permission is granted to anyone to use this software for any purpose,
  74. including commercial applications, and to alter it and redistribute it
  75. freely, subject to the following restrictions:
  76. 1. The origin of this software must not be misrepresented; you must not
  77. claim that you wrote the original software. If you use this software in
  78. a product, an acknowledgment in the product documentation would be
  79. appreciated but is not required.
  80. 2. Altered source versions must be plainly marked as such, and must not be
  81. misrepresented as being the original software.
  82. 3. This notice may not be removed or altered from any source distribution.
  83. ----------------------------------------------------------------------------*)
  84. {NOTE: FIPS Ch and May functions can be optimized. Wei Dai (Crypto++ 3.1)
  85. credits Rich Schroeppel ([email protected]), V 5.1 does not!?}
  86. {$i STD.INC}
  87. {$ifndef CPUI386}
  88. {$ifndef PurePascal}
  89. {$define PurePascal}
  90. {$endif}
  91. {$endif}
  92. uses
  93. BTypes,Hash;
  94. procedure SHA1Init(var Context: THashContext);
  95. {-initialize context}
  96. procedure SHA1Update(var Context: THashContext; Msg: pointer; Len: word);
  97. {-update context with Msg data}
  98. procedure SHA1UpdateXL(var Context: THashContext; Msg: pointer; Len: longint);
  99. {-update context with Msg data}
  100. procedure SHA1Final(var Context: THashContext; var Digest: TSHA1Digest);
  101. {-finalize SHA1 calculation, clear context}
  102. procedure SHA1FinalEx(var Context: THashContext; var Digest: THashDigest);
  103. {-finalize SHA1 calculation, clear context}
  104. procedure SHA1FinalBitsEx(var Context: THashContext; var Digest: THashDigest; BData: byte; bitlen: integer);
  105. {-finalize SHA1 calculation with bitlen bits from BData (big-endian), clear context}
  106. procedure SHA1FinalBits(var Context: THashContext; var Digest: TSHA1Digest; BData: byte; bitlen: integer);
  107. {-finalize SHA1 calculation with bitlen bits from BData (big-endian), clear context}
  108. function SHA1SelfTest: boolean;
  109. {-self test SHA1: compare with known value}
  110. procedure SHA1Full(var Digest: TSHA1Digest; Msg: pointer; Len: word);
  111. {-SHA1 of Msg with init/update/final}
  112. procedure SHA1FullXL(var Digest: TSHA1Digest; Msg: pointer; Len: longint);
  113. {-SHA1 of Msg with init/update/final}
  114. procedure SHA1File({$ifdef CONST} const {$endif} fname: Str255;
  115. var Digest: TSHA1Digest; var buf; bsize: word; var Err: word);
  116. {-SHA1 of file, buf: buffer with at least bsize bytes}
  117. implementation
  118. {$ifdef BIT16}
  119. {$F-}
  120. {$endif}
  121. const
  122. SHA1_BlockLen = 64;
  123. const {round constants}
  124. K1 = longint($5A827999); {round 00..19}
  125. K2 = longint($6ED9EBA1); {round 20..39}
  126. K3 = longint($8F1BBCDC); {round 40..59}
  127. K4 = longint($CA62C1D6); {round 60..79}
  128. {Internal types}
  129. type
  130. TWorkBuf = array[0..79] of longint;
  131. {1.3.14.3.2.26}
  132. {iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) hashAlgorithmIdentifier(26)}
  133. const
  134. SHA1_OID : TOID_Vec = (1,3,14,3,2,26,-1,-1,-1,-1,-1); {Len=6}
  135. {$ifndef VER5X}
  136. const
  137. SHA1_Desc: THashDesc = (
  138. HSig : C_HashSig;
  139. HDSize : sizeof(THashDesc);
  140. HDVersion : C_HashVers;
  141. HBlockLen : SHA1_BlockLen;
  142. HDigestlen: sizeof(TSHA1Digest);
  143. {$ifdef FPC_ProcVar}
  144. HInit : @SHA1Init;
  145. HFinal : @SHA1FinalEx;
  146. HUpdateXL : @SHA1UpdateXL;
  147. {$else}
  148. HInit : SHA1Init;
  149. HFinal : SHA1FinalEx;
  150. HUpdateXL : SHA1UpdateXL;
  151. {$endif}
  152. HAlgNum : longint(_SHA1);
  153. HName : 'SHA1';
  154. HPtrOID : @SHA1_OID;
  155. HLenOID : 6;
  156. HFill : 0;
  157. {$ifdef FPC_ProcVar}
  158. HFinalBit : @SHA1FinalBitsEx;
  159. {$else}
  160. HFinalBit : SHA1FinalBitsEx;
  161. {$endif}
  162. HReserved : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
  163. );
  164. {$else}
  165. var
  166. SHA1_Desc: THashDesc;
  167. {$endif}
  168. {$ifndef BIT16}
  169. {$ifdef PurePascal}
  170. {---------------------------------------------------------------------------}
  171. procedure UpdateLen(var whi, wlo: longint; BLen: longint);
  172. {-Add BLen to 64 bit value (wlo, whi)}
  173. var
  174. tmp: int64;
  175. begin
  176. tmp := int64(cardinal(wlo))+Blen;
  177. wlo := longint(tmp and $FFFFFFFF);
  178. inc(whi,longint(tmp shr 32));
  179. end;
  180. {---------------------------------------------------------------------------}
  181. function RB(A: longint): longint;
  182. {-reverse byte order in longint}
  183. begin
  184. RB := ((A and $FF) shl 24) or ((A and $FF00) shl 8) or ((A and $FF0000) shr 8) or ((A and longint($FF000000)) shr 24);
  185. end;
  186. {---------------------------------------------------------------------------}
  187. procedure ExpandMessageBlocks(var W: TWorkBuf; var Buf: THashBuffer);
  188. {-Calculate "expanded message blocks"}
  189. var
  190. i,T: longint;
  191. begin
  192. {Part 1: Transfer buffer with little -> big endian conversion}
  193. for i:= 0 to 15 do W[i]:= RB(THashBuf32(Buf)[i]);
  194. {Part 2: Calculate remaining "expanded message blocks"}
  195. for i:= 16 to 79 do begin
  196. T := W[i-3] xor W[i-8] xor W[i-14] xor W[i-16];
  197. W[i] := (T shl 1) or (T shr 31);
  198. end;
  199. end;
  200. {$else}
  201. {---------------------------------------------------------------------------}
  202. procedure UpdateLen(var whi, wlo: longint; BLen: longint);
  203. {-Add BLen to 64 bit value (wlo, whi)}
  204. begin
  205. asm
  206. mov edx, [wlo]
  207. mov ecx, [whi]
  208. mov eax, [Blen]
  209. add [edx], eax
  210. adc dword ptr [ecx], 0
  211. end;
  212. end;
  213. {---------------------------------------------------------------------------}
  214. function RB(A: longint): longint; assembler;
  215. {-reverse byte order in longint}
  216. asm
  217. {$ifdef LoadArgs}
  218. mov eax,[A]
  219. {$endif}
  220. xchg al,ah
  221. rol eax,16
  222. xchg al,ah
  223. end;
  224. {---------------------------------------------------------------------------}
  225. procedure ExpandMessageBlocks(var W: TWorkBuf; var Buf: THashBuffer); assembler;
  226. {-Calculate "expanded message blocks"}
  227. asm
  228. {$ifdef LoadArgs}
  229. mov edx,Buf
  230. mov ecx,W {load W before push ebx to avoid VP crash}
  231. push ebx {if compiling with no ASM stack frames}
  232. mov ebx,ecx
  233. {$else}
  234. push ebx
  235. mov ebx,eax
  236. {$endif}
  237. {part1: W[i]:= RB(TW32Buf(Buf)[i])}
  238. mov ecx,16
  239. @@1: mov eax,[edx]
  240. xchg al,ah
  241. rol eax,16
  242. xchg al,ah
  243. mov [ebx],eax
  244. add ebx,4
  245. add edx,4
  246. dec ecx
  247. jnz @@1
  248. {part2: W[i]:= LRot_1(W[i-3] xor W[i-8] xor W[i-14] xor W[i-16]);}
  249. mov ecx,64
  250. @@2: mov eax,[ebx- 3*4]
  251. xor eax,[ebx- 8*4]
  252. xor eax,[ebx-14*4]
  253. xor eax,[ebx-16*4]
  254. rol eax,1
  255. mov [ebx],eax
  256. add ebx,4
  257. dec ecx
  258. jnz @@2
  259. pop ebx
  260. end;
  261. {$endif}
  262. {---------------------------------------------------------------------------}
  263. procedure SHA1Compress(var Data: THashContext);
  264. {-Actual hashing function}
  265. var
  266. i: integer;
  267. A, B, C, D, E: longint;
  268. W: TWorkBuf;
  269. begin
  270. ExpandMessageBlocks(W, Data.Buffer);
  271. A := Data.Hash[0];
  272. B := Data.Hash[1];
  273. C := Data.Hash[2];
  274. D := Data.Hash[3];
  275. E := Data.Hash[4];
  276. {SHA1 compression function}
  277. {Partial unroll for more speed, full unroll is only slightly faster}
  278. {BIT32: rotateleft via inline}
  279. i := 0;
  280. while i<20 do begin
  281. inc(E, (A shl 5 or A shr 27) + (D xor (B and (C xor D))) + W[i ] + K1); B := B shr 2 or B shl 30;
  282. inc(D, (E shl 5 or E shr 27) + (C xor (A and (B xor C))) + W[i+1] + K1); A := A shr 2 or A shl 30;
  283. inc(C, (D shl 5 or D shr 27) + (B xor (E and (A xor B))) + W[i+2] + K1); E := E shr 2 or E shl 30;
  284. inc(B, (C shl 5 or C shr 27) + (A xor (D and (E xor A))) + W[i+3] + K1); D := D shr 2 or D shl 30;
  285. inc(A, (B shl 5 or B shr 27) + (E xor (C and (D xor E))) + W[i+4] + K1); C := C shr 2 or C shl 30;
  286. inc(i,5);
  287. end;
  288. while i<40 do begin
  289. inc(E, (A shl 5 or A shr 27) + (D xor B xor C) + W[i ] + K2); B := B shr 2 or B shl 30;
  290. inc(D, (E shl 5 or E shr 27) + (C xor A xor B) + W[i+1] + K2); A := A shr 2 or A shl 30;
  291. inc(C, (D shl 5 or D shr 27) + (B xor E xor A) + W[i+2] + K2); E := E shr 2 or E shl 30;
  292. inc(B, (C shl 5 or C shr 27) + (A xor D xor E) + W[i+3] + K2); D := D shr 2 or D shl 30;
  293. inc(A, (B shl 5 or B shr 27) + (E xor C xor D) + W[i+4] + K2); C := C shr 2 or C shl 30;
  294. inc(i,5);
  295. end;
  296. while i<60 do begin
  297. inc(E, (A shl 5 or A shr 27) + ((B and C) or (D and (B or C))) + W[i ] + K3); B := B shr 2 or B shl 30;
  298. inc(D, (E shl 5 or E shr 27) + ((A and B) or (C and (A or B))) + W[i+1] + K3); A := A shr 2 or A shl 30;
  299. inc(C, (D shl 5 or D shr 27) + ((E and A) or (B and (E or A))) + W[i+2] + K3); E := E shr 2 or E shl 30;
  300. inc(B, (C shl 5 or C shr 27) + ((D and E) or (A and (D or E))) + W[i+3] + K3); D := D shr 2 or D shl 30;
  301. inc(A, (B shl 5 or B shr 27) + ((C and D) or (E and (C or D))) + W[i+4] + K3); C := C shr 2 or C shl 30;
  302. inc(i,5);
  303. end;
  304. while i<80 do begin
  305. inc(E, (A shl 5 or A shr 27) + (D xor B xor C) + W[i ] + K4); B := B shr 2 or B shl 30;
  306. inc(D, (E shl 5 or E shr 27) + (C xor A xor B) + W[i+1] + K4); A := A shr 2 or A shl 30;
  307. inc(C, (D shl 5 or D shr 27) + (B xor E xor A) + W[i+2] + K4); E := E shr 2 or E shl 30;
  308. inc(B, (C shl 5 or C shr 27) + (A xor D xor E) + W[i+3] + K4); D := D shr 2 or D shl 30;
  309. inc(A, (B shl 5 or B shr 27) + (E xor C xor D) + W[i+4] + K4); C := C shr 2 or C shl 30;
  310. inc(i,5);
  311. end;
  312. {Calculate new working hash}
  313. inc(Data.Hash[0], A);
  314. inc(Data.Hash[1], B);
  315. inc(Data.Hash[2], C);
  316. inc(Data.Hash[3], D);
  317. inc(Data.Hash[4], E);
  318. end;
  319. {$else}
  320. {$ifdef BASM16}
  321. {TP6-7/Delphi1 for 386+}
  322. {---------------------------------------------------------------------------}
  323. procedure UpdateLen(var whi, wlo: longint; BLen: longint); assembler;
  324. {-Add BLen to 64 bit value (wlo, whi)}
  325. asm
  326. les di,[wlo]
  327. db $66; mov ax,word ptr [BLen]
  328. db $66; sub dx,dx
  329. db $66; add es:[di],ax
  330. les di,[whi]
  331. db $66; adc es:[di],dx
  332. end;
  333. {---------------------------------------------------------------------------}
  334. function LRot_5(x: longint): longint;
  335. {-Rotate left 5}
  336. inline(
  337. $66/$58/ {pop eax }
  338. $66/$C1/$C0/$05/ {rol eax,5 }
  339. $66/$8B/$D0/ {mov edx,eax}
  340. $66/$C1/$EA/$10); {shr edx,16 }
  341. {---------------------------------------------------------------------------}
  342. function RB(A: longint): longint;
  343. {-reverse byte order in longint}
  344. inline(
  345. $58/ {pop ax }
  346. $5A/ {pop dx }
  347. $86/$C6/ {xchg dh,al }
  348. $86/$E2); {xchg dl,ah }
  349. {---------------------------------------------------------------------------}
  350. procedure ExpandMessageBlocks(var W: TWorkBuf; var Buf: THashBuffer); assembler;
  351. {-Calculate "expanded message blocks"}
  352. asm
  353. push ds
  354. {part 1: W[i]:= RB(TW32Buf(Buf)[i])}
  355. les di,[Buf]
  356. lds si,[W]
  357. mov cx,16
  358. @@1: db $66; mov ax,es:[di]
  359. xchg al,ah
  360. db $66; rol ax,16
  361. xchg al,ah
  362. db $66; mov [si],ax
  363. add si,4
  364. add di,4
  365. dec cx
  366. jnz @@1
  367. {part 2: W[i]:= LRot_1(W[i-3] xor W[i-8] xor W[i-14] xor W[i-16]);}
  368. mov cx,64
  369. @@2: db $66; mov ax,[si- 3*4]
  370. db $66; xor ax,[si- 8*4]
  371. db $66; xor ax,[si-14*4]
  372. db $66; xor ax,[si-16*4]
  373. db $66; rol ax,1
  374. db $66; mov [si],ax
  375. add si,4
  376. dec cx
  377. jnz @@2
  378. pop ds
  379. end;
  380. {---------------------------------------------------------------------------}
  381. procedure SHA1Compress(var Data: THashContext);
  382. {-Actual hashing function}
  383. var
  384. i: integer;
  385. A, B, C, D, E: longint;
  386. W: TWorkBuf;
  387. begin
  388. ExpandMessageBlocks(W, Data.Buffer);
  389. {Assign old working hash to variables A..E}
  390. A := Data.Hash[0];
  391. B := Data.Hash[1];
  392. C := Data.Hash[2];
  393. D := Data.Hash[3];
  394. E := Data.Hash[4];
  395. {SHA1 compression function}
  396. {Partial unroll for more speed, full unroll only marginally faster}
  397. {Two INCs, LRot_30 via BASM}
  398. i := 0;
  399. while i<20 do begin
  400. inc(E,LRot_5(A)); inc(E,(D xor (B and (C xor D))) + W[i ] + K1); asm db $66; rol word[B],30 end;
  401. inc(D,LRot_5(E)); inc(D,(C xor (A and (B xor C))) + W[i+1] + K1); asm db $66; rol word[A],30 end;
  402. inc(C,LRot_5(D)); inc(C,(B xor (E and (A xor B))) + W[i+2] + K1); asm db $66; rol word[E],30 end;
  403. inc(B,LRot_5(C)); inc(B,(A xor (D and (E xor A))) + W[i+3] + K1); asm db $66; rol word[D],30 end;
  404. inc(A,LRot_5(B)); inc(A,(E xor (C and (D xor E))) + W[i+4] + K1); asm db $66; rol word[C],30 end;
  405. inc(i,5);
  406. end;
  407. while i<40 do begin
  408. inc(E,LRot_5(A)); inc(E,(B xor C xor D) + W[i ] + K2); asm db $66; rol word[B],30 end;
  409. inc(D,LRot_5(E)); inc(D,(A xor B xor C) + W[i+1] + K2); asm db $66; rol word[A],30 end;
  410. inc(C,LRot_5(D)); inc(C,(E xor A xor B) + W[i+2] + K2); asm db $66; rol word[E],30 end;
  411. inc(B,LRot_5(C)); inc(B,(D xor E xor A) + W[i+3] + K2); asm db $66; rol word[D],30 end;
  412. inc(A,LRot_5(B)); inc(A,(C xor D xor E) + W[i+4] + K2); asm db $66; rol word[C],30 end;
  413. inc(i,5);
  414. end;
  415. while i<60 do begin
  416. inc(E,LRot_5(A)); inc(E,((B and C) or (D and (B or C))) + W[i ] + K3); asm db $66; rol word[B],30 end;
  417. inc(D,LRot_5(E)); inc(D,((A and B) or (C and (A or B))) + W[i+1] + K3); asm db $66; rol word[A],30 end;
  418. inc(C,LRot_5(D)); inc(C,((E and A) or (B and (E or A))) + W[i+2] + K3); asm db $66; rol word[E],30 end;
  419. inc(B,LRot_5(C)); inc(B,((D and E) or (A and (D or E))) + W[i+3] + K3); asm db $66; rol word[D],30 end;
  420. inc(A,LRot_5(B)); inc(A,((C and D) or (E and (C or D))) + W[i+4] + K3); asm db $66; rol word[C],30 end;
  421. inc(i,5);
  422. end;
  423. while i<80 do begin
  424. inc(E,LRot_5(A)); inc(E,(B xor C xor D) + W[i ] + K4); asm db $66; rol word[B],30 end;
  425. inc(D,LRot_5(E)); inc(D,(A xor B xor C) + W[i+1] + K4); asm db $66; rol word[A],30 end;
  426. inc(C,LRot_5(D)); inc(C,(E xor A xor B) + W[i+2] + K4); asm db $66; rol word[E],30 end;
  427. inc(B,LRot_5(C)); inc(B,(D xor E xor A) + W[i+3] + K4); asm db $66; rol word[D],30 end;
  428. inc(A,LRot_5(B)); inc(A,(C xor D xor E) + W[i+4] + K4); asm db $66; rol word[C],30 end;
  429. inc(i,5);
  430. end;
  431. {Calculate new working hash}
  432. inc(Data.Hash[0], A);
  433. inc(Data.Hash[1], B);
  434. inc(Data.Hash[2], C);
  435. inc(Data.Hash[3], D);
  436. inc(Data.Hash[4], E);
  437. end;
  438. {$else}
  439. {TP5/5.5}
  440. {---------------------------------------------------------------------------}
  441. procedure UpdateLen(var whi, wlo: longint; BLen: longint);
  442. {-Add BLen to 64 bit value (wlo, whi)}
  443. inline(
  444. $58/ {pop ax }
  445. $5A/ {pop dx }
  446. $5B/ {pop bx }
  447. $07/ {pop es }
  448. $26/$01/$07/ {add es:[bx],ax }
  449. $26/$11/$57/$02/ {adc es:[bx+02],dx}
  450. $5B/ {pop bx }
  451. $07/ {pop es }
  452. $26/$83/$17/$00/ {adc es:[bx],0 }
  453. $26/$83/$57/$02/$00);{adc es:[bx+02],0 }
  454. {---------------------------------------------------------------------------}
  455. function RB(A: longint): longint;
  456. {-reverse byte order in longint}
  457. inline(
  458. $58/ { pop ax }
  459. $5A/ { pop dx }
  460. $86/$C6/ { xchg dh,al}
  461. $86/$E2); { xchg dl,ah}
  462. {---------------------------------------------------------------------------}
  463. function LRot_1(x: longint): longint;
  464. {-Rotate left 1}
  465. inline(
  466. $58/ { pop ax }
  467. $5A/ { pop dx }
  468. $2B/$C9/ { sub cx,cx}
  469. $D1/$D0/ { rcl ax,1 }
  470. $D1/$D2/ { rcl dx,1 }
  471. $13/$C1); { adc ax,cx}
  472. {---------------------------------------------------------------------------}
  473. function LRot_5(x: longint): longint;
  474. {-Rotate left 5}
  475. inline(
  476. $58/ { pop ax }
  477. $5A/ { pop dx }
  478. $2B/$C9/ { sub cx,cx}
  479. $D1/$D0/ { rcl ax,1 }
  480. $D1/$D2/ { rcl dx,1 }
  481. $13/$C1/ { adc ax,cx}
  482. $D1/$D0/ { rcl ax,1 }
  483. $D1/$D2/ { rcl dx,1 }
  484. $13/$C1/ { adc ax,cx}
  485. $D1/$D0/ { rcl ax,1 }
  486. $D1/$D2/ { rcl dx,1 }
  487. $13/$C1/ { adc ax,cx}
  488. $D1/$D0/ { rcl ax,1 }
  489. $D1/$D2/ { rcl dx,1 }
  490. $13/$C1/ { adc ax,cx}
  491. $D1/$D0/ { rcl ax,1 }
  492. $D1/$D2/ { rcl dx,1 }
  493. $13/$C1); { adc ax,cx}
  494. {---------------------------------------------------------------------------}
  495. function LRot_30(x: longint): longint;
  496. {-Rotate left 30 = rot right 2}
  497. inline(
  498. $58/ { pop ax }
  499. $5A/ { pop dx }
  500. $8B/$CA/ { mov cx,dx}
  501. $D1/$E9/ { shr cx,1 }
  502. $D1/$D8/ { rcr ax,1 }
  503. $D1/$DA/ { rcr dx,1 }
  504. $8B/$CA/ { mov cx,dx}
  505. $D1/$E9/ { shr cx,1 }
  506. $D1/$D8/ { rcr ax,1 }
  507. $D1/$DA); { rcr dx,1 }
  508. {---------------------------------------------------------------------------}
  509. procedure ExpandMessageBlocks(var W: TWorkBuf; var Buf: THashBuffer);
  510. {-Calculate "expanded message blocks"}
  511. var
  512. i: integer;
  513. begin
  514. {Part 1: Transfer buffer with little -> big endian conversion}
  515. for i:= 0 to 15 do W[i]:= RB(THashBuf32(Buf)[i]);
  516. {Part 2: Calculate remaining "expanded message blocks"}
  517. for i:= 16 to 79 do W[i]:= LRot_1(W[i-3] xor W[i-8] xor W[i-14] xor W[i-16]);
  518. end;
  519. {---------------------------------------------------------------------------}
  520. procedure SHA1Compress(var Data: THashContext);
  521. {-Actual hashing function}
  522. var
  523. i: integer;
  524. A, B, C, D, E: longint;
  525. W: TWorkBuf;
  526. begin
  527. ExpandMessageBlocks(W, Data.Buffer);
  528. {Assign old working hash to variables A..E}
  529. A := Data.Hash[0];
  530. B := Data.Hash[1];
  531. C := Data.Hash[2];
  532. D := Data.Hash[3];
  533. E := Data.Hash[4];
  534. {SHA1 compression function}
  535. {Partial unroll for more speed, full unroll only marginally faster}
  536. {BIT16: rotateleft via function call}
  537. i := 0;
  538. while i<20 do begin
  539. inc(E,LRot_5(A) + (D xor (B and (C xor D))) + W[i ] + K1); B := LRot_30(B);
  540. inc(D,LRot_5(E) + (C xor (A and (B xor C))) + W[i+1] + K1); A := LRot_30(A);
  541. inc(C,LRot_5(D) + (B xor (E and (A xor B))) + W[i+2] + K1); E := LRot_30(E);
  542. inc(B,LRot_5(C) + (A xor (D and (E xor A))) + W[i+3] + K1); D := LRot_30(D);
  543. inc(A,LRot_5(B) + (E xor (C and (D xor E))) + W[i+4] + K1); C := LRot_30(C);
  544. inc(i,5);
  545. end;
  546. while i<40 do begin
  547. inc(E,LRot_5(A) + (B xor C xor D) + W[i ] + K2); B := LRot_30(B);
  548. inc(D,LRot_5(E) + (A xor B xor C) + W[i+1] + K2); A := LRot_30(A);
  549. inc(C,LRot_5(D) + (E xor A xor B) + W[i+2] + K2); E := LRot_30(E);
  550. inc(B,LRot_5(C) + (D xor E xor A) + W[i+3] + K2); D := LRot_30(D);
  551. inc(A,LRot_5(B) + (C xor D xor E) + W[i+4] + K2); C := LRot_30(C);
  552. inc(i,5);
  553. end;
  554. while i<60 do begin
  555. inc(E,LRot_5(A) + ((B and C) or (D and (B or C))) + W[i ] + K3); B := LRot_30(B);
  556. inc(D,LRot_5(E) + ((A and B) or (C and (A or B))) + W[i+1] + K3); A := LRot_30(A);
  557. inc(C,LRot_5(D) + ((E and A) or (B and (E or A))) + W[i+2] + K3); E := LRot_30(E);
  558. inc(B,LRot_5(C) + ((D and E) or (A and (D or E))) + W[i+3] + K3); D := LRot_30(D);
  559. inc(A,LRot_5(B) + ((C and D) or (E and (C or D))) + W[i+4] + K3); C := LRot_30(C);
  560. inc(i,5);
  561. end;
  562. while i<80 do begin
  563. inc(E,LRot_5(A) + (B xor C xor D) + W[i ] + K4); B := LRot_30(B);
  564. inc(D,LRot_5(E) + (A xor B xor C) + W[i+1] + K4); A := LRot_30(A);
  565. inc(C,LRot_5(D) + (E xor A xor B) + W[i+2] + K4); E := LRot_30(E);
  566. inc(B,LRot_5(C) + (D xor E xor A) + W[i+3] + K4); D := LRot_30(D);
  567. inc(A,LRot_5(B) + (C xor D xor E) + W[i+4] + K4); C := LRot_30(C);
  568. inc(i,5);
  569. end;
  570. {Calculate new working hash}
  571. inc(Data.Hash[0], A);
  572. inc(Data.Hash[1], B);
  573. inc(Data.Hash[2], C);
  574. inc(Data.Hash[3], D);
  575. inc(Data.Hash[4], E);
  576. end;
  577. {$endif BASM16}
  578. {$endif BIT16}
  579. {---------------------------------------------------------------------------}
  580. procedure SHA1Init(var Context: THashContext);
  581. {-initialize context}
  582. begin
  583. {Clear context, buffer=0!!}
  584. fillchar(Context,sizeof(Context),0);
  585. with Context do begin
  586. Hash[0] := longint($67452301);
  587. Hash[1] := longint($EFCDAB89);
  588. Hash[2] := longint($98BADCFE);
  589. Hash[3] := longint($10325476);
  590. Hash[4] := longint($C3D2E1F0);
  591. end;
  592. end;
  593. {---------------------------------------------------------------------------}
  594. procedure SHA1UpdateXL(var Context: THashContext; Msg: pointer; Len: longint);
  595. {-update context with Msg data}
  596. var
  597. i: integer;
  598. begin
  599. {Update message bit length}
  600. if Len<=$1FFFFFFF then UpdateLen(Context.MLen[1], Context.MLen[0], Len shl 3)
  601. else begin
  602. for i:=1 to 8 do UpdateLen(Context.MLen[1], Context.MLen[0], Len)
  603. end;
  604. while Len > 0 do begin
  605. {fill block with msg data}
  606. Context.Buffer[Context.Index]:= pByte(Msg)^;
  607. inc(Ptr2Inc(Msg));
  608. inc(Context.Index);
  609. dec(Len);
  610. if Context.Index=SHA1_BlockLen then begin
  611. {If 512 bit transferred, compress a block}
  612. Context.Index:= 0;
  613. SHA1Compress(Context);
  614. while Len>=SHA1_BlockLen do begin
  615. move(Msg^,Context.Buffer,SHA1_BlockLen);
  616. SHA1Compress(Context);
  617. inc(Ptr2Inc(Msg),SHA1_BlockLen);
  618. dec(Len,SHA1_BlockLen);
  619. end;
  620. end;
  621. end;
  622. end;
  623. {---------------------------------------------------------------------------}
  624. procedure SHA1Update(var Context: THashContext; Msg: pointer; Len: word);
  625. {-update context with Msg data}
  626. begin
  627. SHA1UpdateXL(Context, Msg, Len);
  628. end;
  629. {---------------------------------------------------------------------------}
  630. procedure SHA1FinalBitsEx(var Context: THashContext; var Digest: THashDigest; BData: byte; bitlen: integer);
  631. {-finalize SHA1 calculation with bitlen bits from BData (big-endian), clear context}
  632. var
  633. i: integer;
  634. begin
  635. {Message padding}
  636. {append bits from BData and a single '1' bit}
  637. if (bitlen>0) and (bitlen<=7) then begin
  638. Context.Buffer[Context.Index]:= (BData and BitAPI_Mask[bitlen]) or BitAPI_PBit[bitlen];
  639. UpdateLen(Context.MLen[1], Context.MLen[0], bitlen);
  640. end
  641. else Context.Buffer[Context.Index]:= $80;
  642. for i:=Context.Index+1 to 63 do Context.Buffer[i] := 0;
  643. {2. Compress if more than 448 bits, (no room for 64 bit length}
  644. if Context.Index>= 56 then begin
  645. SHA1Compress(Context);
  646. fillchar(Context.Buffer,56,0);
  647. end;
  648. {Write 64 bit msg length into the last bits of the last block}
  649. {(in big endian format) and do a final compress}
  650. THashBuf32(Context.Buffer)[14] := RB(Context.MLen[1]);
  651. THashBuf32(Context.Buffer)[15] := RB(Context.MLen[0]);
  652. SHA1Compress(Context);
  653. {Hash->Digest to little endian format}
  654. fillchar(Digest, sizeof(Digest), 0);
  655. for i:=0 to 4 do THashDig32(Digest)[i]:= RB(Context.Hash[i]);
  656. {Clear context}
  657. fillchar(Context,sizeof(Context),0);
  658. end;
  659. {---------------------------------------------------------------------------}
  660. procedure SHA1FinalBits(var Context: THashContext; var Digest: TSHA1Digest; BData: byte; bitlen: integer);
  661. {-finalize SHA1 calculation with bitlen bits from BData (big-endian), clear context}
  662. var
  663. tmp: THashDigest;
  664. begin
  665. SHA1FinalBitsEx(Context, tmp, BData, bitlen);
  666. move(tmp, Digest, sizeof(Digest));
  667. end;
  668. {---------------------------------------------------------------------------}
  669. procedure SHA1FinalEx(var Context: THashContext; var Digest: THashDigest);
  670. {-finalize SHA1 calculation, clear context}
  671. begin
  672. SHA1FinalBitsEx(Context,Digest,0,0);
  673. end;
  674. {---------------------------------------------------------------------------}
  675. procedure SHA1Final(var Context: THashContext; var Digest: TSHA1Digest);
  676. {-finalize SHA1 calculation, clear context}
  677. var
  678. tmp: THashDigest;
  679. begin
  680. SHA1FinalBitsEx(Context, tmp, 0, 0);
  681. move(tmp, Digest, sizeof(Digest));
  682. end;
  683. {---------------------------------------------------------------------------}
  684. function SHA1SelfTest: boolean;
  685. {-self test SHA1: compare with known value}
  686. const
  687. s1: string[ 3] = 'abc';
  688. s2: string[56] = 'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq';
  689. D1: TSHA1Digest= ($a9,$99,$3e,$36,$47,$06,$81,$6a,$ba,$3e,$25,$71,$78,$50,$c2,$6c,$9c,$d0,$d8,$9d);
  690. D2: TSHA1Digest= ($84,$98,$3E,$44,$1C,$3B,$D2,$6E,$BA,$AE,$4A,$A1,$F9,$51,$29,$E5,$E5,$46,$70,$F1);
  691. D3: TSHA1Digest= ($bb,$6b,$3e,$18,$f0,$11,$5b,$57,$92,$52,$41,$67,$6f,$5b,$1a,$e8,$87,$47,$b0,$8a);
  692. D4: TSHA1Digest= ($98,$23,$2a,$15,$34,$53,$14,$9a,$f8,$d5,$2a,$61,$50,$3a,$50,$74,$b8,$59,$70,$e8);
  693. var
  694. Context: THashContext;
  695. Digest : TSHA1Digest;
  696. function SingleTest(s: Str127; TDig: TSHA1Digest): boolean;
  697. {-do a single test, const not allowed for VER<7}
  698. { Two sub tests: 1. whole string, 2. one update per char}
  699. var
  700. i: integer;
  701. begin
  702. SingleTest := false;
  703. {1. Hash complete string}
  704. SHA1Full(Digest, @s[1],length(s));
  705. {Compare with known value}
  706. if not HashSameDigest(@SHA1_Desc, PHashDigest(@Digest), PHashDigest(@TDig)) then exit;
  707. {2. one update call for all chars}
  708. SHA1Init(Context);
  709. for i:=1 to length(s) do SHA1Update(Context,@s[i],1);
  710. SHA1Final(Context,Digest);
  711. {Compare with known value}
  712. if not HashSameDigest(@SHA1_Desc, PHashDigest(@Digest), PHashDigest(@TDig)) then exit;
  713. SingleTest := true;
  714. end;
  715. begin
  716. SHA1SelfTest := false;
  717. {1 Zero bit from NESSIE test vectors}
  718. SHA1Init(Context);
  719. SHA1FinalBits(Context,Digest,0,1);
  720. if not HashSameDigest(@SHA1_Desc, PHashDigest(@Digest), PHashDigest(@D3)) then exit;
  721. {4 hightest bits of $50, D4 calculated with program shatest from RFC 4634}
  722. SHA1Init(Context);
  723. SHA1FinalBits(Context,Digest,$50,4);
  724. if not HashSameDigest(@SHA1_Desc, PHashDigest(@Digest), PHashDigest(@D4)) then exit;
  725. {strings from SHA1 document}
  726. SHA1SelfTest := SingleTest(s1, D1) and SingleTest(s2, D2)
  727. end;
  728. {---------------------------------------------------------------------------}
  729. procedure SHA1FullXL(var Digest: TSHA1Digest; Msg: pointer; Len: longint);
  730. {-SHA1 of Msg with init/update/final}
  731. var
  732. Context: THashContext;
  733. begin
  734. SHA1Init(Context);
  735. SHA1UpdateXL(Context, Msg, Len);
  736. SHA1Final(Context, Digest);
  737. end;
  738. {---------------------------------------------------------------------------}
  739. procedure SHA1Full(var Digest: TSHA1Digest; Msg: pointer; Len: word);
  740. {-SHA1 of Msg with init/update/final}
  741. begin
  742. SHA1FullXL(Digest, Msg, Len);
  743. end;
  744. {---------------------------------------------------------------------------}
  745. procedure SHA1File({$ifdef CONST} const {$endif} fname: Str255;
  746. var Digest: TSHA1Digest; var buf; bsize: word; var Err: word);
  747. {-SHA1 of file, buf: buffer with at least bsize bytes}
  748. var
  749. tmp: THashDigest;
  750. begin
  751. HashFile(fname, @SHA1_Desc, tmp, buf, bsize, Err);
  752. move(tmp, Digest, sizeof(Digest));
  753. end;
  754. begin
  755. {$ifdef VER5X}
  756. fillchar(SHA1_Desc, sizeof(SHA1_Desc), 0);
  757. with SHA1_Desc do begin
  758. HSig := C_HashSig;
  759. HDSize := sizeof(THashDesc);
  760. HDVersion := C_HashVers;
  761. HBlockLen := SHA1_BlockLen;
  762. HDigestlen:= sizeof(TSHA1Digest);
  763. HInit := SHA1Init;
  764. HFinal := SHA1FinalEx;
  765. HUpdateXL := SHA1UpdateXL;
  766. HAlgNum := longint(_SHA1);
  767. HName := 'SHA1';
  768. HPtrOID := @SHA1_OID;
  769. HLenOID := 6;
  770. HFinalBit := SHA1FinalBitsEx;
  771. end;
  772. {$endif}
  773. RegisterHash(_SHA1, @SHA1_Desc);
  774. end.