| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261 |
- unit SHA1;
- {
- SHA1.pas: SHA-1 hash implementation, based on RFC 3174 and MD5.pas
- Author: Jordan Russell, 2010-02-24
- License for SHA1.pas: Public domain, no copyright claimed
- }
- interface
- type
- TSHA1Word = LongWord;
- TSHA1Buf = array[0..4] of TSHA1Word;
- TSHA1In = array[0..15] of TSHA1Word;
- TSHA1WArray = array[0..79] of TSHA1Word;
- TSHA1Context = record
- buf: TSHA1Buf;
- bytes: array[0..1] of TSHA1Word;
- in_: TSHA1In;
- W: TSHA1WArray;
- end;
- TSHA1Digest = array[0..19] of Byte;
- procedure SHA1Init(var ctx: TSHA1Context);
- procedure SHA1Update(var ctx: TSHA1Context; const buffer; len: Cardinal);
- function SHA1Final(var ctx: TSHA1Context): TSHA1Digest;
- function SHA1Buf(const Buffer; Len: Cardinal): TSHA1Digest;
- function SHA1DigestsEqual(const A, B: TSHA1Digest): Boolean;
- function SHA1DigestToString(const D: TSHA1Digest): String;
- implementation
- procedure SHA1Transform(var buf: TSHA1Buf; const in_: TSHA1In; var W: TSHA1WArray); forward;
- function ByteSwap(const X: TSHA1Word): TSHA1Word;
- begin
- Result :=
- (X shl 24) or
- ((X and $FF00) shl 8) or
- ((X and $FF0000) shr 8) or
- (X shr 24);
- end;
- (*
- * Start SHA-1 accumulation. Set byte count to 0 and buffer to mysterious
- * initialization constants.
- *)
- procedure SHA1Init(var ctx: TSHA1Context);
- begin
- ctx.buf[0] := TSHA1Word($67452301);
- ctx.buf[1] := TSHA1Word($efcdab89);
- ctx.buf[2] := TSHA1Word($98badcfe);
- ctx.buf[3] := TSHA1Word($10325476);
- ctx.buf[4] := TSHA1Word($c3d2e1f0);
- ctx.bytes[0] := 0;
- ctx.bytes[1] := 0;
- end;
- (*
- * Update context to reflect the concatenation of another buffer full
- * of bytes.
- *)
- procedure SHA1Update(var ctx: TSHA1Context; const buffer; len: Cardinal);
- var
- buf: ^Byte;
- t: TSHA1Word;
- begin
- buf := @buffer;
- { Update byte count }
- t := ctx.bytes[0];
- Inc(ctx.bytes[0], len);
- if Cardinal(ctx.bytes[0]) < Cardinal(t) then
- Inc(ctx.bytes[1]); { Carry from low to high }
- t := 64 - (t and $3f); { Space available in ctx.in (at least 1) }
- if Cardinal(t) > Cardinal(len) then begin
- Move(buf^, Pointer(Cardinal(@ctx.in_) + 64 - t)^, len);
- Exit;
- end;
- { First chunk is an odd size }
- Move(buf^, Pointer(Cardinal(@ctx.in_) + 64 - t)^, t);
- SHA1Transform(ctx.buf, ctx.in_, ctx.W);
- Inc(buf, t);
- Dec(len, t);
- { Process data in 64-byte chunks }
- while Cardinal(len) >= Cardinal(64) do begin
- Move(buf^, ctx.in_, 64);
- SHA1Transform(ctx.buf, ctx.in_, ctx.W);
- Inc(buf, 64);
- Dec(len, 64);
- end;
- { Handle any remaining bytes of data. }
- Move(buf^, ctx.in_, len);
- end;
- (*
- * Final wrapup - pad to 64-byte boundary with the bit pattern
- * 1 0* (64-bit count of bits processed, MSB-first)
- *)
- function SHA1Final(var ctx: TSHA1Context): TSHA1Digest;
- var
- count, i: Integer;
- p: ^Byte;
- begin
- count := ctx.bytes[0] and $3f; { Number of bytes in ctx.in }
- p := @ctx.in_;
- Inc(p, count);
- { Set the first char of padding to 0x80. There is always room. }
- p^ := $80;
- Inc(p);
- { Bytes of padding needed to make 56 bytes (-8..55) }
- count := 56 - 1 - count;
- if count < 0 then begin { Padding forces an extra block }
- FillChar(p^, count + 8, 0);
- SHA1Transform(ctx.buf, ctx.in_, ctx.W);
- p := @ctx.in_;
- count := 56;
- end;
- FillChar(p^, count, 0);
- { Append length in bits and transform }
- ctx.in_[15] := ByteSwap(ctx.bytes[0] shl 3);
- ctx.in_[14] := ByteSwap((ctx.bytes[1] shl 3) or (ctx.bytes[0] shr 29));
- SHA1Transform(ctx.buf, ctx.in_, ctx.W);
- for i := 0 to High(ctx.buf) do
- ctx.buf[i] := ByteSwap(ctx.buf[i]);
- Move(ctx.buf, Result, SizeOf(Result));
- FillChar(ctx, SizeOf(ctx), 0); { In case it's sensitive }
- end;
- (*
- * The core of the SHA-1 algorithm, this alters an existing SHA-1 hash to
- * reflect the addition of 16 longwords of new data. SHA1Update blocks
- * the data and converts bytes into longwords for this routine.
- *)
- procedure SHA1Transform(var buf: TSHA1Buf; const in_: TSHA1In; var W: TSHA1WArray);
- const
- K1 = $5A827999;
- K2 = $6ED9EBA1;
- K3 = $8F1BBCDC;
- K4 = $CA62C1D6;
- var
- t: Integer;
- temp, A, B, C, D, E: TSHA1Word;
- begin
- for t := 0 to 15 do begin
- { ByteSwap inlined: }
- temp := in_[t];
- W[t] := (temp shl 24) or
- ((temp and $FF00) shl 8) or
- ((temp and $FF0000) shr 8) or
- (temp shr 24);
- end;
- for t := 16 to 79 do begin
- temp := W[t-3] xor W[t-8] xor W[t-14] xor W[t-16];
- W[t] := (temp shl 1) or (temp shr (32-1));
- end;
- A := buf[0];
- B := buf[1];
- C := buf[2];
- D := buf[3];
- E := buf[4];
- for t := 0 to 19 do begin
- temp := ((A shl 5) or (A shr (32-5))) +
- (D xor (B and (C xor D))) + E + W[t] + K1;
- E := D;
- D := C;
- C := (B shl 30) or (B shr (32-30));
- B := A;
- A := temp;
- end;
- for t := 20 to 39 do begin
- temp := ((A shl 5) or (A shr (32-5))) + (B xor C xor D) + E + W[t] + K2;
- E := D;
- D := C;
- C := (B shl 30) or (B shr (32-30));
- B := A;
- A := temp;
- end;
- for t := 40 to 59 do begin
- temp := ((A shl 5) or (A shr (32-5))) +
- ((B and C) or (B and D) or (C and D)) + E + W[t] + K3;
- E := D;
- D := C;
- C := (B shl 30) or (B shr (32-30));
- B := A;
- A := temp;
- end;
- for t := 60 to 79 do begin
- temp := ((A shl 5) or (A shr (32-5))) + (B xor C xor D) + E + W[t] + K4;
- E := D;
- D := C;
- C := (B shl 30) or (B shr (32-30));
- B := A;
- A := temp;
- end;
- Inc(buf[0], A);
- Inc(buf[1], B);
- Inc(buf[2], C);
- Inc(buf[3], D);
- Inc(buf[4], E);
- end;
- { New functions by JR: }
- function SHA1Buf(const Buffer; Len: Cardinal): TSHA1Digest;
- var
- Context: TSHA1Context;
- begin
- SHA1Init(Context);
- SHA1Update(Context, Buffer, Len);
- Result := SHA1Final(Context);
- end;
- function SHA1DigestsEqual(const A, B: TSHA1Digest): Boolean;
- var
- I: Integer;
- begin
- for I := Low(TSHA1Digest) to High(TSHA1Digest) do
- if A[I] <> B[I] then begin
- Result := False;
- Exit;
- end;
- Result := True;
- end;
- function SHA1DigestToString(const D: TSHA1Digest): String;
- const
- Digits: array[0..15] of Char = '0123456789abcdef';
- var
- Buf: array[0..39] of Char;
- P: PChar;
- I: Integer;
- begin
- P := @Buf;
- for I := 0 to 19 do begin
- P^ := Digits[D[I] shr 4];
- Inc(P);
- P^ := Digits[D[I] and 15];
- Inc(P);
- end;
- SetString(Result, Buf, 40);
- end;
- end.
|