Skip to main content

5. Tamper Detection & Validation

Validation sequence

Run checks in this order on every card read. Stop and mark tampered on the first failure.

  1. Uninitialised card pre-check — if the magic field is all 0x00 or all 0xFF, treat the card as uninitialised (not tampered) and halt. Display "Unactivated card" to the user. Do not proceed to step 1. See System Design §18.
  2. Magic and version check — reject the payload if magic does not match the expected value or version is unsupported.
  3. Key version lookup — reject if no session grant is available for the card's keyVersion.
  4. HMAC verification — recompute HMAC over encrypted buffer and trailer fields; reject on mismatch.
  5. AES-GCM decryption — attempt decryption; reject if the GCM authentication tag fails.
  6. Counter check — reject if the on-card counter is less than or equal to the last known counter for this card (rollback).
  7. Timestamp check — reject if lastTimestamp is significantly in the future (beyond clock drift allowance).
  8. Status check — if status is any blocked value, deny writes; allow read-only operations.
  9. Balance consistency — reject if balance ≠ lastBalance when no transaction was expected, or if balance does not match the balanceAfter of the most recent log entry.
  10. Log chain verification — recompute each entry hash from session.startTime; reject if any hash mismatches.
  11. Root hash verification — recompute rootHash from the log chain head; reject if it does not match the trailer value.

Failure conditions

Mark a card as tampered when any of the following are true:

  • HMAC mismatch
  • AES-GCM decryption failure
  • counter rollback detected
  • lastTimestamp rollback detected
  • balance inconsistency with lastBalance or first log entry
  • Log chain hash mismatch at any position
  • rootHash mismatch
  • Unsupported magic or version

Response to tamper detection

  • Do not write to the card.
  • Set the card status to BLOCKED_TAMPER (code 1) on the next successful authenticated write if the card is still operable.
  • Log the event with tamper type, cardId, counter, and terminalId for backend reconciliation.
  • Display a generic blocked message to the user; do not expose cryptographic details.
  • If the card cannot be written (e.g., read fails completely), report the event to the backend immediately.

Log chain

  • Each log entry includes a 6-byte hash field.
  • hash[n] = SHA256(deltaTime || amount || balanceAfter || flags || hash[n-1])[0..5]
  • The chain is anchored at session.startTime: hash[0] uses startTime bytes as the initial previous value.
  • The trailer rootHash stores the hash of the most recent log entry (the chain head).

Validation guarantees

  • Any single-bit modification to a log entry invalidates the chain from that point forward.
  • rootHash in the trailer ties the entire log sequence to current card state.
  • Trailer HMAC binds the root hash, counter, active pointer, and metadata, preventing selective replay of a valid historical trailer with a modified payload.