Welcome to the new DelphiDabbler Code Library Documentation.

This is a new site that's currently running on alpha code. There are going to be bugs. If you discover any, please report them on the site's issues page (GitHub account required). Thanks.

Warning: Many URLs are going to change. Refer to the README file to discover which library project's documentation has been completed.

MD5 How-to: How To Compare Two Digests

Applies to: ~>1.0

One of the most common tasks when working with MD5 message digests (hashes) is to compare two digests. This is usually done to check if some data or file has changed.

TPJMD5Digest helps here in that you can directly compare two digests to equality or inequality. For example, if you have two TPJMD5Digest records, D1 and D2, you can compare them like this:

begin
  ...
  if D1 = D2 then {do something};
  if D1 <> D2 then {do something else};
  ...
end;

We are able to do this because TPJMD5Digest overloads the Equal and NotEqual operators to enable two TPJMD5Digest records to be compared for equality and inequality.

Another common requirement is to compare a digest with a string representation of the digest. This is often used when downloading files from the Internet. The download site displays the MD5 hash of the file to be downloaded. When you have downloaded the file you get a string representation of its MD5 hash and compare it with the string displayed on the web page. This function provides a way of doing this for a given file and hash string need:

function CompareFileHashToMD5String(const FileName: TFileName;
  const MD5Str: string): Boolean;
begin
  Result := SameText(TPJMD5.CalculateFile(FileName), MD5Str);
end;

It is easier to see what’s happening if we introduce a few local variables:

function CompareFileHashToMD5String(const FileName: TFileName;
  const MD5Str: string): Boolean;
var
  S: string;
  D: TPJMD5Digest;
begin
  D := TPJMD5.CalculateFile(FileName);
  S := D;
  Result := SameText(S, MD5Str);
end;

For more information about casting a TPJMD5Digest record to a string see How To Get a Digest String.

The function gets the MD5 hash of the file using TPJMD5.CalculateFile. It then relies on the ability of TPJMD5Digest to be cast to a string to get the string representation of the file’s hash. Finally it compares the has string with the given string, MD5Hash and returns True if they are the same and False if different. In the shortened version the result from TPJMD5.CalculateFile is cast to a string because it is used in a string context (SameText expects a string parameter).

But, we don’t need to use SameText at all because TPJMD5Digest also provides Equal and NotEqual operator overloads that allow strings to be compared directly to TPJMD5Digest records. Consequently the above function can be reduced to:

function CompareFileHashToMD5String(const FileName: TFileName;
  const MD5Str: string): Boolean;
begin
  Result := (TPJMD5.CalculateFile(FileName) = MD5Str);
end;

Obviously there’s now no need for the function unless you want it for documentary purposes - you can simply in line the comparison.

Finally you can compare a TPJMD5Digest record with a TBytes array because of yet another overload of the Equal and NotEqual operators. To be equal the TBytes array must have 16 elements and each byte must match the bytes of the TPJMD5Digest record’s Bytes field.

You might do this when checking the content of an HTTP response against an MD5 digest. The MD5 digest arrives in the HTTP header as a Base64 encoded string. Say your decoding code converts this encoding into a byte array, and you have calculated the MD5 hash of the content, which is stored in a stream. Here’s a little function that validates the content:

function CheckContent(const MD5Bytes: TBytes; const Content: TStream): Boolean;
var
  D: TPJMD5Digest;
begin
  Content.Position := 0;
  D := TPJMD5.Calculate(Content);
  Result := D = MD5Bytes;
end;

To learn more about casting TPJMD5Digest to TBytes see How To Get Raw Digest Data.

This function gets the MD5 hash of the whole stream, using one of TStream overloads of the TPJMD5.Calculate method. Note that the stream is positioned at the start to ensure the whole stream is read.

See Also