2 This file is part of the Free Pascal packages
.
3 Copyright (c
) 2009 by the Free Pascal development team
5 Implements a SHA-1 digest
algorithm (RFC
3174)
7 See the file COPYING
.FPC
, included
in this distribution
,
8 for details about the copyright
.
10 This program is distributed
in the hope that it will be useful
,
11 but WITHOUT ANY WARRANTY
; without even the implied warranty of
12 MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE
.
14 **********************************************************************}
22 TSHA1Digest
= array
[0..19] of Byte
;
25 State
: array
[0..4] of Cardinal
;
26 Buffer
: array
[0..63] of Byte
;
27 BufCnt
: PtrUInt
; { in current block
, i
.e
. in range of
0..63 }
28 Length
: QWord
; { total count of bytes processed
}
32 procedure
SHA1Init(out ctx
: TSHA1Context
);
33 procedure
SHA1Update(var ctx
: TSHA1Context
; const Buf
; BufLen
: PtrUInt
);
34 procedure
SHA1Final(var ctx
: TSHA1Context
; out Digest
: TSHA1Digest
);
37 function
SHA1String(const S
: String
): TSHA1Digest
;
38 function
SHA1Buffer(const Buf
; BufLen
: PtrUInt
): TSHA1Digest
;
39 function
SHA1File(const Filename
: String
; const Bufsize
: PtrUInt
= 1024): TSHA1Digest
;
42 function
SHA1Print(const Digest
: TSHA1Digest
): String
;
43 function
SHA1Match(const Digest1
, Digest2
: TSHA1Digest
): Boolean
;
47 // inverts the bytes
of (Count div
4) cardinals from source to target
.
48 procedure
Invert(Source
, Dest
: Pointer
; Count
: PtrUInt
);
56 for I
:= 1 to (Count div
4) do
58 T^
:= S
[3] or (S
[2] shl
8) or (S
[1] shl
16) or (S
[0] shl
24);
64 procedure
SHA1Init(out ctx
: TSHA1Context
);
66 FillChar(ctx
, sizeof(TSHA1Context
), 0);
67 ctx
.State
[0] := $67452301;
68 ctx
.State
[1] := $efcdab89;
69 ctx
.State
[2] := $98badcfe;
70 ctx
.State
[3] := $10325476;
71 ctx
.State
[4] := $c3d2e1f0;
80 procedure
SHA1Transform(var ctx
: TSHA1Context
; Buf
: Pointer
);
82 A
, B
, C
, D
, E
, T
: Cardinal
;
83 Data
: array
[0..15] of Cardinal
;
91 Invert(Buf
, @Data, 64);
96 T
:= (B
and C
) or (not B
and D
) + K20
+ E
;
101 A
:= T
+ roldword(A
, 5) + Data
[i
and 15];
102 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);
107 T
:= (B xor C xor D
) + K40
+ E
;
112 A
:= T
+ roldword(A
, 5) + Data
[i
and 15];
113 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);
118 T
:= (B
and C
) or (B
and D
) or (C
and D
) + K60
+ E
;
123 A
:= T
+ roldword(A
, 5) + Data
[i
and 15];
124 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 T
:= (B xor C xor D
) + K80
+ E
;
134 A
:= T
+ roldword(A
, 5) + Data
[i
and 15];
135 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);
139 Inc(ctx
.State
[0], A
);
140 Inc(ctx
.State
[1], B
);
141 Inc(ctx
.State
[2], C
);
142 Inc(ctx
.State
[3], D
);
143 Inc(ctx
.State
[4], E
);
148 procedure
SHA1Update(var ctx
: TSHA1Context
; const Buf
; BufLen
: PtrUInt
);
159 // 1. Transform existing
data in buffer
160 if ctx
.BufCnt
> 0 then
162 // 1.1 Try to fill buffer up to block size
163 Num
:= 64 - ctx
.BufCnt
;
167 Move(Src^
, ctx
.Buffer
[ctx
.BufCnt
], Num
);
168 Inc(ctx
.BufCnt
, Num
);
171 // 1.2 If buffer is filled
, transform it
172 if ctx
.BufCnt
= 64 then
174 SHA1Transform(ctx
, @ctx.Buffer
);
179 // 2. Transform input
data in 64-byte blocks
183 SHA1Transform(ctx
, Src
);
188 // 3. If there
's less than 64 bytes left, add it to buffer
192 Move(Src^, ctx.Buffer, Num);
197 PADDING: array[0..63] of Byte =
198 ($80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
199 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
200 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
201 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
204 procedure SHA1Final(var ctx: TSHA1Context; out Digest: TSHA1Digest);
209 // 1. Compute length of the whole stream in bits
210 Length := 8 * (ctx.Length + ctx.BufCnt);
212 // 2. Append padding bits
213 if ctx.BufCnt >= 56 then
214 Pads := 120 - ctx.BufCnt
216 Pads := 56 - ctx.BufCnt;
217 SHA1Update(ctx, PADDING, Pads);
219 // 3. Append length of the stream (8 bytes)
220 Length := NtoBE(Length);
221 SHA1Update(ctx, Length, 8);
223 // 4. Invert state to digest
224 Invert(@ctx.State, @Digest, 20);
225 FillChar(ctx, sizeof(TSHA1Context), 0);
228 function SHA1String(const S: String): TSHA1Digest;
230 Context: TSHA1Context;
233 SHA1Update(Context, PChar(S)^, length(S));
234 SHA1Final(Context, Result);
237 function SHA1Buffer(const Buf; BufLen: PtrUInt): TSHA1Digest;
239 Context: TSHA1Context;
242 SHA1Update(Context, buf, buflen);
243 SHA1Final(Context, Result);
246 function SHA1File(const Filename: String; const Bufsize: PtrUInt): TSHA1Digest;
250 Context: TSHA1Context;
265 GetMem(Buf, BufSize);
267 BlockRead(F, Buf^, Bufsize, Count);
269 SHA1Update(Context, Buf^, Count);
270 until Count < BufSize;
271 FreeMem(Buf, BufSize);
275 SHA1Final(Context, Result);
280 HexTbl: array[0..15] of char='0123456789abcdef
'; // lowercase
282 function SHA1Print(const Digest: TSHA1Digest): String;
287 SetLength(Result, 40);
288 P := Pointer(Result);
291 P[0] := HexTbl[(Digest[i] shr 4) and 15];
292 P[1] := HexTbl[Digest[i] and 15];
297 function SHA1Match(const Digest1, Digest2: TSHA1Digest): Boolean;
299 A: array[0..4] of Cardinal absolute Digest1;
300 B: array[0..4] of Cardinal absolute Digest2;
302 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]);