YOUSEFUL / DELPHI / COMPONENTS

TAtlasHashCalculator

Non-visual component that returns SHA-2 (or legacy SHA-1 and MD5) digests of text, streams and files as hexadecimal, and checks a file against a published checksum in constant time.

Non-visual component Palette: Atlas Crypto Unit Atlas.CryptoComponents · Inherits TComponent · Product Atlas Crypto

Description

Put it on a form or data module from the Atlas Crypto palette page, or create it in code with TAtlasHashCalculator.Create(nil). Algorithm selects the hash for every method; SHA-256 is the default. Results are lower-case hexadecimal. Text is hashed as its UTF-8 bytes. HashFile and HashStream read in 256 KB pieces and call OnProgress after each read, so a long file can show progress and be cancelled.

The component is a thin front end to TAtlasHash; use that class for byte results, data that arrives in pieces, or HMAC. The component keeps nothing between calls except its two properties. Failures raise EAtlasCryptoError (a malformed expected checksum, a nil stream, cancel) or the RTL's file exceptions (EFOpenError for a missing or locked file). Add Atlas.Crypto to uses as well when you set Algorithm in code, because TAtlasHashKind is declared there.

Members

MemberKindWhat it does
HashTextmethodReturns the digest of the UTF-8 encoding of Text as lower-case hexadecimal: 64 digits for SHA-256, 96 for SHA-384, 128 for SHA-512.
HashFilemethodOpens FileName for reading (other programs may read it meanwhile but not write to it) and returns HashStream of its whole content.
HashStreammethodHashes Stream from its current position to its end and returns the digest as lower-case hexadecimal.
FileMatchesmethodReturns True when the digest of the file, under the current Algorithm, equals Expected.
AlgorithmpropertyThe hash every method uses: hkSHA256 (the default), hkSHA384, hkSHA512, or the legacy hkSHA1 and hkMD5, which are only for checksums published with those algorithms.
OnProgresseventCalled by HashFile and HashStream after every read of up to 256 KB, and once more after the final empty read, with Done (bytes hashed so far) and Total (bytes from the starting position to the end).

Properties

Algorithm property

property Algorithm: TAtlasHashKind read FAlgorithm write FAlgorithm default hkSHA256;

The hash every method uses: hkSHA256 (the default), hkSHA384, hkSHA512, or the legacy hkSHA1 and hkMD5, which are only for checksums published with those algorithms. Published, so it can be set in the Object Inspector.

pascal
Calculator.Algorithm := hkSHA512;

Events

OnProgress event

property OnProgress: TAtlasCryptoProgressEvent read FOnProgress write FOnProgress;

Called by HashFile and HashStream after every read of up to 256 KB, and once more after the final empty read, with Done (bytes hashed so far) and Total (bytes from the starting position to the end). Set Cancel to True to stop; the method then raises EAtlasCryptoError. The event runs on the thread that called the method. HashText does not call it. See TAtlasCryptoProgressEvent.

Methods

HashText method

function HashText(const Text: string): string;

Returns the digest of the UTF-8 encoding of Text as lower-case hexadecimal: 64 digits for SHA-256, 96 for SHA-384, 128 for SHA-512. Does not call OnProgress.

pascal
HexText := Calculator.HashText('abc');  // ba7816bf...f20015ad with the default SHA-256

HashFile method

function HashFile(const FileName: string): string;

Opens FileName for reading (other programs may read it meanwhile but not write to it) and returns HashStream of its whole content. A missing or locked file raises the RTL's EFOpenError.

pascal
HexText := Calculator.HashFile(FileName);

HashStream method

function HashStream(Stream: TStream): string;

Hashes Stream from its current position to its end and returns the digest as lower-case hexadecimal. Reads 256 KB at a time; after each read, including the last, empty one, OnProgress receives the bytes hashed so far and Stream.Size - Stream.Position as measured at the start. The stream must be able to report its size. A nil stream raises EAtlasCryptoError (A stream is required); setting Cancel in OnProgress raises EAtlasCryptoError (Hashing was cancelled).

pascal
HexText := Calculator.HashStream(Stream);

FileMatches method

function FileMatches(const FileName, Expected: string): Boolean;

Returns True when the digest of the file, under the current Algorithm, equals Expected. Expected is hexadecimal in either case; spaces before and after it are ignored. The digests are compared in constant time. A checksum of another length (for example a SHA-1 value while Algorithm is SHA-256) gives False. Text that is not hexadecimal raises EAtlasCryptoError rather than returning False, so a malformed checksum is never mistaken for a mismatch.

pascal
Valid := Calculator.FileMatches(FileName, 'BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD');

Examples

Verify a download against its published checksum

Creates the component in code, checks a file against an upper-case SHA-256 checksum with surrounding spaces, then switches to SHA-1. Prints TRUE and a9993e364706816aba3e25717850c26c9cd0d89d.

pascal
uses System.SysUtils, System.IOUtils, Atlas.Crypto, Atlas.CryptoComponents;

procedure CheckDownload;
var
  Calculator: TAtlasHashCalculator;
  FileName: string;
begin
  FileName := TPath.Combine(TPath.GetTempPath, 'atlas-crypto-checksum.txt');
  TFile.WriteAllBytes(FileName, TAtlasBytes.OfString('abc'));
  Calculator := TAtlasHashCalculator.Create(nil);
  try
    WriteLn(Calculator.FileMatches(FileName, 'BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD '));
    Calculator.Algorithm := hkSHA1;
    WriteLn(Calculator.HashFile(FileName));
  finally
    Calculator.Free;
    TFile.Delete(FileName);
  end;
end;

Hash a large file with a progress bar and a Cancel button

A form built in code. OnProgress moves the bar and reports the Cancel button; cancelling raises EAtlasCryptoError, shown in a message box. For very large files, run the hash on a background thread instead of pumping messages.

pascal
uses System.SysUtils, System.Classes, Vcl.Forms, Vcl.Controls, Vcl.StdCtrls, Vcl.ComCtrls, Vcl.Dialogs,
  Atlas.Crypto, Atlas.CryptoComponents;

type
  THashForm = class(TForm)
  private
    FCalculator: TAtlasHashCalculator;
    FBar: TProgressBar;
    FCancelled: Boolean;
    procedure CalculatorProgress(Sender: TObject; Done, Total: Int64; var Cancel: Boolean);
    procedure CancelClick(Sender: TObject);
  public
    constructor Create(AOwner: TComponent); override;
    function Checksum(const FileName: string): string;
  end;

constructor THashForm.Create(AOwner: TComponent);
var
  Button: TButton;
begin
  inherited CreateNew(AOwner);
  Caption := 'Checksum';
  FCalculator := TAtlasHashCalculator.Create(Self);
  FCalculator.OnProgress := CalculatorProgress;
  FBar := TProgressBar.Create(Self);
  FBar.Parent := Self;
  FBar.SetBounds(12, 12, 300, 20);
  FBar.Max := 1000;
  Button := TButton.Create(Self);
  Button.Parent := Self;
  Button.SetBounds(12, 44, 90, 28);
  Button.Caption := 'Cancel';
  Button.OnClick := CancelClick;
end;

procedure THashForm.CalculatorProgress(Sender: TObject; Done, Total: Int64; var Cancel: Boolean);
begin
  if Total > 0 then FBar.Position := Round(Done / Total * 1000);
  Application.ProcessMessages; // lets the Cancel button be clicked
  Cancel := FCancelled;
end;

procedure THashForm.CancelClick(Sender: TObject);
begin
  FCancelled := True;
end;

function THashForm.Checksum(const FileName: string): string;
begin
  FCancelled := False;
  try
    Result := FCalculator.HashFile(FileName);
  except
    on E: EAtlasCryptoError do
    begin
      ShowMessage(E.Message);
      Result := '';
    end;
  end;
end;

TAtlasHash · TAtlasHashKind · TAtlasCryptoProgressEvent · TAtlasFileProtector

Also in Atlas Crypto

TAtlasFileProtector