sha1.pp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. {
  2. This file is part of the Free Pascal packages.
  3. Copyright (c) 2009-2014 by the Free Pascal development team
  4. Implements a SHA-1 digest algorithm (RFC 3174)
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. // Normally, if an optimized version is available for OS/CPU, that will be used
  12. // Define to use existing unoptimized implementation
  13. { the assembler implementation does not work on darwin }
  14. {$ifdef darwin}
  15. {$DEFINE SHA1PASCAL}
  16. {$endif darwin}
  17. unit sha1;
  18. {$mode objfpc}{$h+}
  19. interface
  20. type
  21. TSHA1Digest = array[0..19] of Byte;
  22. TSHA1Context = record
  23. State: array[0..4] of Cardinal;
  24. Buffer: array[0..63] of Byte;
  25. BufCnt: PtrUInt; { in current block, i.e. in range of 0..63 }
  26. Length: QWord; { total count of bytes processed }
  27. end;
  28. { core }
  29. procedure SHA1Init(out ctx: TSHA1Context);
  30. procedure SHA1Update(var ctx: TSHA1Context; const Buf; BufLen: PtrUInt);
  31. procedure SHA1Final(var ctx: TSHA1Context; out Digest: TSHA1Digest);
  32. { auxiliary }
  33. function SHA1String(const S: String): TSHA1Digest;
  34. function SHA1Buffer(const Buf; BufLen: PtrUInt): TSHA1Digest;
  35. function SHA1File(const Filename: String; const Bufsize: PtrUInt = 1024): TSHA1Digest;
  36. { helpers }
  37. function SHA1Print(const Digest: TSHA1Digest): String;
  38. function SHA1Match(const Digest1, Digest2: TSHA1Digest): Boolean;
  39. implementation
  40. // inverts the bytes of (Count div 4) cardinals from source to target.
  41. procedure Invert(Source, Dest: Pointer; Count: PtrUInt);
  42. var
  43. S: PByte;
  44. T: PCardinal;
  45. I: PtrUInt;
  46. begin
  47. S := Source;
  48. T := Dest;
  49. for I := 1 to (Count div 4) do
  50. begin
  51. T^ := S[3] or (S[2] shl 8) or (S[1] shl 16) or (S[0] shl 24);
  52. inc(S,4);
  53. inc(T);
  54. end;
  55. end;
  56. procedure SHA1Init(out ctx: TSHA1Context);
  57. begin
  58. FillChar(ctx, sizeof(TSHA1Context), 0);
  59. ctx.State[0] := $67452301;
  60. ctx.State[1] := $efcdab89;
  61. ctx.State[2] := $98badcfe;
  62. ctx.State[3] := $10325476;
  63. ctx.State[4] := $c3d2e1f0;
  64. end;
  65. const
  66. K20 = $5A827999;
  67. K40 = $6ED9EBA1;
  68. K60 = $8F1BBCDC;
  69. K80 = $CA62C1D6;
  70. {$IF (NOT(DEFINED(SHA1PASCAL))) and (DEFINED(CPU386)) }
  71. // Use assembler version if we have a suitable CPU as well
  72. // Define SHA1PASCAL to force use of original reference code
  73. {$i sha1i386.inc}
  74. {$ELSE}
  75. // Use original version if asked for, or when we have no optimized assembler version
  76. procedure SHA1Transform(var ctx: TSHA1Context; Buf: Pointer);
  77. var
  78. A, B, C, D, E, T: Cardinal;
  79. Data: array[0..15] of Cardinal;
  80. i: Integer;
  81. begin
  82. A := ctx.State[0];
  83. B := ctx.State[1];
  84. C := ctx.State[2];
  85. D := ctx.State[3];
  86. E := ctx.State[4];
  87. Invert(Buf, @Data, 64);
  88. {$push}
  89. {$r-,q-}
  90. i := 0;
  91. repeat
  92. T := (B and C) or (not B and D) + K20 + E;
  93. E := D;
  94. D := C;
  95. C := rordword(B, 2);
  96. B := A;
  97. A := T + roldword(A, 5) + Data[i and 15];
  98. Data[i and 15] := roldword(Data[i and 15] xor Data[(i+2) and 15] xor Data[(i+8) and 15] xor Data[(i+13) and 15], 1);
  99. Inc(i);
  100. until i > 19;
  101. repeat
  102. T := (B xor C xor D) + K40 + E;
  103. E := D;
  104. D := C;
  105. C := rordword(B, 2);
  106. B := A;
  107. A := T + roldword(A, 5) + Data[i and 15];
  108. Data[i and 15] := roldword(Data[i and 15] xor Data[(i+2) and 15] xor Data[(i+8) and 15] xor Data[(i+13) and 15], 1);
  109. Inc(i);
  110. until i > 39;
  111. repeat
  112. T := (B and C) or (B and D) or (C and D) + K60 + E;
  113. E := D;
  114. D := C;
  115. C := rordword(B, 2);
  116. B := A;
  117. A := T + roldword(A, 5) + Data[i and 15];
  118. Data[i and 15] := roldword(Data[i and 15] xor Data[(i+2) and 15] xor Data[(i+8) and 15] xor Data[(i+13) and 15], 1);
  119. Inc(i);
  120. until i > 59;
  121. repeat
  122. T := (B xor C xor D) + K80 + E;
  123. E := D;
  124. D := C;
  125. C := rordword(B, 2);
  126. B := A;
  127. A := T + roldword(A, 5) + Data[i and 15];
  128. Data[i and 15] := roldword(Data[i and 15] xor Data[(i+2) and 15] xor Data[(i+8) and 15] xor Data[(i+13) and 15], 1);
  129. Inc(i);
  130. until i > 79;
  131. Inc(ctx.State[0], A);
  132. Inc(ctx.State[1], B);
  133. Inc(ctx.State[2], C);
  134. Inc(ctx.State[3], D);
  135. Inc(ctx.State[4], E);
  136. {$pop}
  137. Inc(ctx.Length,64);
  138. end;
  139. {$ENDIF}
  140. procedure SHA1Update(var ctx: TSHA1Context; const Buf; BufLen: PtrUInt);
  141. var
  142. Src: PByte;
  143. Num: PtrUInt;
  144. begin
  145. if BufLen = 0 then
  146. Exit;
  147. Src := @Buf;
  148. Num := 0;
  149. // 1. Transform existing data in buffer
  150. if ctx.BufCnt > 0 then
  151. begin
  152. // 1.1 Try to fill buffer up to block size
  153. Num := 64 - ctx.BufCnt;
  154. if Num > BufLen then
  155. Num := BufLen;
  156. Move(Src^, ctx.Buffer[ctx.BufCnt], Num);
  157. Inc(ctx.BufCnt, Num);
  158. Inc(Src, Num);
  159. // 1.2 If buffer is filled, transform it
  160. if ctx.BufCnt = 64 then
  161. begin
  162. SHA1Transform(ctx, @ctx.Buffer);
  163. ctx.BufCnt := 0;
  164. end;
  165. end;
  166. // 2. Transform input data in 64-byte blocks
  167. Num := BufLen - Num;
  168. while Num >= 64 do
  169. begin
  170. SHA1Transform(ctx, Src);
  171. Inc(Src, 64);
  172. Dec(Num, 64);
  173. end;
  174. // 3. If there's less than 64 bytes left, add it to buffer
  175. if Num > 0 then
  176. begin
  177. ctx.BufCnt := Num;
  178. Move(Src^, ctx.Buffer, Num);
  179. end;
  180. end;
  181. const
  182. PADDING: array[0..63] of Byte =
  183. ($80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  184. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  185. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  186. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  187. );
  188. procedure SHA1Final(var ctx: TSHA1Context; out Digest: TSHA1Digest);
  189. var
  190. Length: QWord;
  191. Pads: Cardinal;
  192. begin
  193. // 1. Compute length of the whole stream in bits
  194. Length := 8 * (ctx.Length + ctx.BufCnt);
  195. // 2. Append padding bits
  196. if ctx.BufCnt >= 56 then
  197. Pads := 120 - ctx.BufCnt
  198. else
  199. Pads := 56 - ctx.BufCnt;
  200. SHA1Update(ctx, PADDING, Pads);
  201. // 3. Append length of the stream (8 bytes)
  202. Length := NtoBE(Length);
  203. SHA1Update(ctx, Length, 8);
  204. // 4. Invert state to digest
  205. Invert(@ctx.State, @Digest, 20);
  206. FillChar(ctx, sizeof(TSHA1Context), 0);
  207. end;
  208. function SHA1String(const S: String): TSHA1Digest;
  209. var
  210. Context: TSHA1Context;
  211. begin
  212. SHA1Init(Context);
  213. SHA1Update(Context, PChar(S)^, length(S));
  214. SHA1Final(Context, Result);
  215. end;
  216. function SHA1Buffer(const Buf; BufLen: PtrUInt): TSHA1Digest;
  217. var
  218. Context: TSHA1Context;
  219. begin
  220. SHA1Init(Context);
  221. SHA1Update(Context, buf, buflen);
  222. SHA1Final(Context, Result);
  223. end;
  224. function SHA1File(const Filename: String; const Bufsize: PtrUInt): TSHA1Digest;
  225. var
  226. F: File;
  227. Buf: Pchar;
  228. Context: TSHA1Context;
  229. Count: Cardinal;
  230. ofm: Longint;
  231. begin
  232. SHA1Init(Context);
  233. Assign(F, Filename);
  234. {$push}{$i-}
  235. ofm := FileMode;
  236. FileMode := 0;
  237. Reset(F, 1);
  238. {$pop}
  239. if IOResult = 0 then
  240. begin
  241. GetMem(Buf, BufSize);
  242. repeat
  243. BlockRead(F, Buf^, Bufsize, Count);
  244. if Count > 0 then
  245. SHA1Update(Context, Buf^, Count);
  246. until Count < BufSize;
  247. FreeMem(Buf, BufSize);
  248. Close(F);
  249. end;
  250. SHA1Final(Context, Result);
  251. FileMode := ofm;
  252. end;
  253. const
  254. HexTbl: array[0..15] of char='0123456789abcdef'; // lowercase
  255. function SHA1Print(const Digest: TSHA1Digest): String;
  256. var
  257. I: Integer;
  258. P: PChar;
  259. begin
  260. SetLength(Result, 40);
  261. P := Pointer(Result);
  262. for I := 0 to 19 do
  263. begin
  264. P[0] := HexTbl[(Digest[i] shr 4) and 15];
  265. P[1] := HexTbl[Digest[i] and 15];
  266. Inc(P,2);
  267. end;
  268. end;
  269. function SHA1Match(const Digest1, Digest2: TSHA1Digest): Boolean;
  270. var
  271. A: array[0..4] of Cardinal absolute Digest1;
  272. B: array[0..4] of Cardinal absolute Digest2;
  273. begin
  274. {$push}
  275. {$B+}
  276. Result := (A[0] = B[0]) and (A[1] = B[1]) and (A[2] = B[2]) and (A[3] = B[3]) and (A[4] = B[4]);
  277. {$pop}
  278. end;
  279. end.
  280. k