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.
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
| Member | Kind | What it does |
|---|---|---|
HashText | method | 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. |
HashFile | method | Opens FileName for reading (other programs may read it meanwhile but not write to it) and returns HashStream of its whole content. |
HashStream | method | Hashes Stream from its current position to its end and returns the digest as lower-case hexadecimal. |
FileMatches | method | Returns True when the digest of the file, under the current Algorithm, equals Expected. |
Algorithm | property | 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. |
OnProgress | event | 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). |
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.
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.
HexText := Calculator.HashText('abc'); // ba7816bf...f20015ad with the default SHA-256HashFile 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.
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).
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.
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.
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.
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;
Related
TAtlasHash · TAtlasHashKind · TAtlasCryptoProgressEvent · TAtlasFileProtector