DEV Community

William Baptist
William Baptist

Posted on Edited on

Building a File Fingerprint in Python

Calculate a file fingerprint, save it as a reference, then change the file and compare the results.

You can also follow my free guide on Tidy Desk Digital.

For a browser-based option, use my free file fingerprint checker.

A hash turns data into a fixed-length value, often called a fingerprint. We'll use SHA-256, a hash method producing 32 bytes, small units of stored data. It displays them as 64 hexadecimal characters: digits 0 to 9 and letters a to f.

You'll need Python 3, a plain-text editor and a command window. No extra packages are required.

1. Create the example file

A text editor may add a line ending even when you only type abc. Let Python write the exact three bytes instead. Save this as MakeExample.py in your practice folder:

from pathlib import Path


Path("Example.txt").write_bytes(b"abc")
Enter fullscreen mode Exit fullscreen mode

Run it from a command window in that folder:

python3 MakeExample.py
Enter fullscreen mode Exit fullscreen mode

Use your installation's Python 3 command if it is not named python3. This creates or replaces Example.txt, so use a practice folder without a file you need to keep. b"abc" is a bytes value; write_bytes adds no line ending. The file now contains exactly three bytes, regardless of your editor's line-ending setting.

2. Save the program

Save this as FingerprintFile.py:

import hashlib as HashLib
import os as Os
import stat as Stat
import sys as Sys


def FingerprintFile(FilePath):
    Fingerprint = HashLib.sha256()
    Total = 0
    with open(FilePath, "rb") as InputFile:
        if not Stat.S_ISREG(Os.fstat(InputFile.fileno()).st_mode):
            raise ValueError("input must be a regular file")
        while True:
            Block = InputFile.read(65536)
            if not Block:
                break
            Fingerprint.update(Block)
            Total += len(Block)
    return Fingerprint.hexdigest(), Total


def Main():
    if len(Sys.argv) != 2:
        print("Usage: python3 FingerprintFile.py input-file", file=Sys.stderr)
        return 2
    try:
        Fingerprint, Total = FingerprintFile(Sys.argv[1])
    except (OSError, ValueError) as Problem:
        print(f"Fingerprint stopped: {Problem}", file=Sys.stderr)
        return 2
    print(f"SHA-256: {Fingerprint}")
    print(f"Bytes read: {Total}")
    return 0


if __name__ == "__main__":
    Sys.exit(Main())
Enter fullscreen mode Exit fullscreen mode

HashLib.sha256() starts the calculation. Each update adds the next block of bytes; adding blocks works like adding their combined contents at once. After the file ends, hexdigest returns the printable value.

The input opens in rb, read-only binary mode, without translating line endings. with closes it when reading finishes. Nothing is printed as a complete fingerprint until the full read succeeds.

Use known regular files, such as documents. Stat.S_ISREG checks the opened file's type, but a special file can block during opening before that check runs.

3. Calculate the fingerprint

Open a command window in your folder and run:

python3 FingerprintFile.py Example.txt
Enter fullscreen mode Exit fullscreen mode

Use your installation's Python 3 command if it is not named python3. The output is:

SHA-256: ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad
Bytes read: 3
Enter fullscreen mode Exit fullscreen mode

The exit code, a small result number another script can check, is 0 when calculation succeeds or 2 for an input/command error. This program calculates one value; it does not compare values or return a mismatch code.

4. Change the file and compare

Copy the example to another file and calculate its fingerprint. The values should match. Add a character to the copy and calculate again; its stored contents changed, so expect a different value.

Keep the reference separately from the checked file. If someone can replace both, they can calculate a new value and make the replacement match. A fingerprint from the same untrusted page as a download adds no independent reason to trust it.

The program only reads the file, so the input bytes stay unchanged.

A match checks content against a reference, not the author's identity or whether the file is safe to open. Different files can share a fixed-length value. When both stable files are available and you need a direct byte-for-byte answer, compare their contents directly.

Use a file that will not change during reading. The program does not lock it or take a frozen copy, and follows symbolic links, paths pointing to other files. Reading may affect recorded last-access times. Small read blocks do not impose file-size or time limits.

Save output to a new report filename, not over the input. Do not use this calculation as a password-storage design; protecting passwords is a different job.

Reference

Top comments (0)