How to Verify a Record

Every equipment log in this system is cryptographically linked in a hash chain. You can independently verify that any record has not been tampered with using standard tools.

Interactive Verifier

Paste an Entry Hash from a PDF and verify it step-by-step in your browser. No tools needed — uses your browser's built-in SHA-256.

What Does Verification Prove?

  • Data integrity — the session data (times, equipment, technician, photo reference) has not been modified since the record was created.
  • Chain integrity — no records have been inserted, deleted, or reordered in the chain. Each entry links to the previous one.
  • Tamper evidence — if anyone modifies any record in the chain, all subsequent hashes break, making the alteration detectable.
  • Photo integrity — both check-in and check-out photos are SHA-256 hashed. Reusing the same photo across entries is permanently flagged as a duplicate.
  • Identity & signature— the technician's hand-drawn signature hash is sealed into the chain. Forging another person's entry is detectable.
  • Independent timestamp (RFC 3161) — a signed timestamp from FreeTSA.org proves the record existed at a specific time, even if the entire server were compromised.

Tools Needed

You only need a SHA-256 hash function and a way to make HTTP requests. These are available on every operating system:

macOS / Linux

curl, echo, shasum (or sha256sum), python3, jq

All pre-installed. No downloads needed.

Windows

PowerShell (Invoke-WebRequest, Get-FileHash), or install Git Bash / WSL

Browser Only

Use the built-in verifier on this site, or any online SHA-256 tool (e.g. emn178.github.io/online-tools/sha256.html)

How the Hash Chain Works

When a technician checks out equipment, the system creates a hash chain entry containing:

{

  "sessionId": "...",

  "equipmentId": "...",

  "userId": "...",

  "checkInAt": "2026-04-05T01:00:00.000Z",

  "checkOutAt": "2026-04-05T02:30:00.000Z",

  "checkInPhotoKey": "user/timestamp.jpg",

  "checkOutPhotoKey": "user/timestamp.jpg",

  "checkInPhotoHash": "a1b2c3d4...",

  "checkInPhotoDuplicate": false,

  "checkOutPhotoHash": "e5f6a7b8...",

  "checkOutPhotoDuplicate": false,

  "signatureHash": "9c0d1e2f...",

  "durationMinutes": 90,

  "calibrationSnapshot": { ... },

  "integrityFlags": []

}

Three hashes are computed:

  1. Data Hash = SHA-256 of the payload (keys sorted alphabetically, stringified with no spaces)
  2. Entry Hash = SHA-256 of sequenceNumber:previousHash:dataHash
  3. Previous Hash= the Entry Hash of the preceding record (or "GENESIS" for the first entry)
This creates a chain: modifying any record's payload changes its Data Hash, which changes its Entry Hash, which breaks the Previous Hash link of every subsequent record.

Step-by-Step Manual Verification

1Get the chain entry from the API

Replace ENTRY_HASH with the Entry Hash from the PDF:

curl -s https://your-domain.com/api/verify/ENTRY_HASH | jq .

The response includes a chain object with payload, dataHash, previousHash, and entryHash.

2Recompute the Data Hash

Extract the payload, sort keys alphabetically, stringify without spaces, and hash:

# Using jq + shasum (macOS/Linux)
curl -s https://your-domain.com/api/verify/ENTRY_HASH \
  | jq -cS '.chain.payload' \
  | tr -d '\n' \
  | shasum -a 256

# Or using Python
python3 -c "
import json, hashlib, sys
data = json.load(sys.stdin)
payload = data['chain']['payload']
canonical = json.dumps(payload, sort_keys=True, separators=(',',':'))
print(hashlib.sha256(canonical.encode()).hexdigest())
" < <(curl -s https://your-domain.com/api/verify/ENTRY_HASH)

The output should match the Data Hashon the PDF. If it doesn't, the payload has been modified.

3Recompute the Entry Hash

Combine the sequence number, previous hash, and data hash, then SHA-256:

# Format: sequenceNumber:previousHash:dataHash
echo -n "2:PREVIOUS_HASH_HERE:DATA_HASH_HERE" | shasum -a 256

# Or using Python
python3 -c "
import hashlib
seq = 2  # chain position from PDF
prev = 'PREVIOUS_HASH_HERE'
data = 'DATA_HASH_HERE'
input_str = f'{seq}:{prev}:{data}'
print(hashlib.sha256(input_str.encode()).hexdigest())
"

The output should match the Entry Hash on the PDF.

4Verify the chain link

The Previous Hash on this entry should be the Entry Hash of the preceding record (Chain Position N-1). Fetch the previous entry and confirm:

# Fetch previous entry using its hash
curl -s https://your-domain.com/api/verify/PREVIOUS_HASH_HERE | jq .chain.entryHash

For the first entry (Chain Position #1), the Previous Hash is the literal string GENESIS.

5Full chain audit (optional)

To verify the entire chain, repeat steps 2-4 for every entry from #1 to the latest. If any hash doesn't match, the chain has been tampered with at that point.

# One-liner: full chain verification using the API
python3 -c "
import json, hashlib, urllib.request

BASE = 'https://your-domain.com'
# Start with the entry you want to verify
hash_to_check = 'ENTRY_HASH'

while hash_to_check and hash_to_check != 'GENESIS':
    resp = urllib.request.urlopen(f'{BASE}/api/verify/{hash_to_check}')
    data = json.loads(resp.read())
    c = data['chain']

    # Verify data hash
    canonical = json.dumps(c['payload'], sort_keys=True, separators=(',',':'))
    calc_data = hashlib.sha256(canonical.encode()).hexdigest()
    assert calc_data == c['dataHash'], f'Data hash mismatch at #{c["sequenceNumber"]}'

    # Verify entry hash
    input_str = f'{c["sequenceNumber"]}:{c["previousHash"]}:{c["dataHash"]}'
    calc_entry = hashlib.sha256(input_str.encode()).hexdigest()
    assert calc_entry == c['entryHash'], f'Entry hash mismatch at #{c["sequenceNumber"]}'

    print(f'#{c["sequenceNumber"]} OK  {c["entryHash"][:16]}...')
    hash_to_check = c['previousHash']

print('Chain verified successfully.')
"

Photo Integrity Verification

Each equipment photo is SHA-256 hashed at the time of submission. The hash is sealed into the chain payload. To verify a photo has not been altered:

# Hash the original photo file
shasum -a 256 equipment-photo.jpg

# Compare with the hash in the chain payload:
# checkInPhotoHash  = SHA-256 of the check-in photo
# checkOutPhotoHash = SHA-256 of the check-out photo

# The system also detects duplicate photos:
# checkInPhotoDuplicate  = true if photo was used before
# checkOutPhotoDuplicate = true if photo was used before

If a photo has been reused from a previous session, the integrityFlags array in the chain payload will contain a warning with the original session ID and date.

Identity & Signature Verification

The technician's hand-drawn signature is captured as a PNG data URL and SHA-256 hashed. This hash (signatureHash) is sealed into the chain, creating a unique biometric trace. If someone forges an entry under another technician's name, the signature hash will not match.

# The signatureHash in the payload is:
# SHA-256 of the raw signature data URL
# e.g., "data:image/png;base64,iVBOR..."
#
# To verify:
echo -n "data:image/png;base64,iVBOR..." | shasum -a 256

RFC 3161 Trusted Timestamp Verification

Each completed session receives a signed timestamp from FreeTSA.org, an independent third-party Timestamp Authority. This proves the record existed at a specific time — even if the entire server were compromised, the TSA's signature is independently verifiable.

The TSA response (TSR) is stored in DER format (base64-encoded). You can verify it using OpenSSL:

# 1. Save the entry hash to a file
echo -n "ENTRY_HASH_HERE" > /tmp/hash.txt

# 2. Create a timestamp query from the hash
openssl ts -query -data /tmp/hash.txt -sha256   -out /tmp/query.tsq

# 3. Decode the stored TSR (base64 from the session)
echo "TSR_BASE64_HERE" | base64 -d > /tmp/response.tsr

# 4. Download FreeTSA certificates and verify
curl -s https://freetsa.org/files/tsa.crt -o /tmp/tsa.crt
curl -s https://freetsa.org/files/cacert.pem -o /tmp/ca.pem

openssl ts -verify -data /tmp/hash.txt   -in /tmp/response.tsr   -CAfile /tmp/ca.pem   -untrusted /tmp/tsa.crt

# Expected output: "Verification: OK"

A successful verification confirms the record existed at the time shown in the TSA response, signed by an authority outside our control. The TSR is a cryptographic proof that cannot be backdated or forged without access to FreeTSA's private key.

Windows (PowerShell)

If you don't have curl/jq, use PowerShell:

# Step 1: Fetch the entry
$resp = Invoke-RestMethod "https://your-domain.com/api/verify/ENTRY_HASH"
$payload = $resp.chain.payload | ConvertTo-Json -Compress -Depth 10

# Step 2: Compute data hash
$bytes = [System.Text.Encoding]::UTF8.GetBytes($payload)
$sha = [System.Security.Cryptography.SHA256]::Create()
$hash = $sha.ComputeHash($bytes)
$dataHash = -join ($hash | ForEach-Object { $_.ToString("x2") })
Write-Host "Data Hash: $dataHash"

# Step 3: Compute entry hash
$seq = $resp.chain.sequenceNumber
$prev = $resp.chain.previousHash
$input = "$seq`:$prev`:$dataHash"
$bytes2 = [System.Text.Encoding]::UTF8.GetBytes($input)
$hash2 = $sha.ComputeHash($bytes2)
$entryHash = -join ($hash2 | ForEach-Object { $_.ToString("x2") })
Write-Host "Entry Hash: $entryHash"

Note: PowerShell's JSON key ordering may differ. For exact results, use the Python method above via WSL or Git Bash.

This page is publicly accessible. No authentication required.