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]);