Secure QR (ZCode)

Generate and scan encrypted, self-expiring QR codes with a password.

0/600
Plain mode

Your QR code will appear here.

What is the Secure QR (ZCode)?

Secure QR (ZCode) generates and scans QR codes built on ZentryCode — an AES-256-GCM encrypted, self-expiring data format for QR codes. Unlike a normal QR code that anyone can read by scanning it, a ZCode can require a password, automatically stop working after a set time, and be tamper-evident: editing the expiry or ciphertext of a captured ZCode invalidates it instead of silently succeeding.

How to use it

  1. Switch to the Generate tab and type the data you want to embed (a note, a Wi-Fi password, a link, anything up to 600 characters).
  2. Optionally set a password — leaving it blank creates a Plain-mode code anyone can scan and read.
  3. Optionally set an expiry — the code stops decoding once it elapses, even if the password is correct.
  4. Click Generate ZCode, then download or copy the resulting QR code.
  5. Switch to the Scan tab to read a ZCode back: use your camera, or upload a QR image.
  6. After a scan, expired codes show an Expired badge immediately with no password prompt; encrypted codes prompt for a password; plain codes decode automatically.

Features

  • All 4 modes: Plain, Sealed, Ephemeral, and Strict
  • AES-256-GCM authenticated encryption with scrypt password derivation
  • Self-expiring codes, enforced cryptographically — not just a cosmetic timestamp
  • Live camera scanning, plus QR-image upload as a fallback
  • Tamper-evident: a modified expiry or ciphertext fails authentication instead of silently succeeding
  • Deliberately generic "wrong password" messaging, so a scanner can't be used to distinguish a wrong password from tampered data

Privacy

Unlike most tools on Zentry Tools, this one is not fully client-side, and we want to be upfront about that rather than overstate it. The underlying ZentryCode library is a Node.js library built on Node's own crypto module, so the actual AES-256-GCM encryption, decryption and expiry enforcement run on a Zentry Tools server function, not in your browser's JavaScript. Your data and password are sent to that function over HTTPS to be processed, and are never logged, stored, or written to disk — the function does the encode/decode operation and immediately returns the result. If you need guaranteed end-to-end, server-never-sees-it confidentiality, keep that trade-off in mind. Camera access, if you use it, is used only to read the QR code in front of the camera and is never recorded or uploaded.

Frequently Asked Questions

Plain has no password or expiry — a normal, readable QR code. Sealed adds a password that never expires. Ephemeral adds both a password and an expiry, enforced even with the correct password. Strict is Ephemeral plus a flag meant for an app to layer an online revocation check on top.

No. Expiry and password verification both happen inside our server function using the real ZentryCode library, not in JavaScript running in your browser. There's no client-side check to disable, because the check isn't performed client-side in the first place — a tampered expiry timestamp also fails the code's built-in authentication check regardless.

Partially. Strict mode flags a ZCode for an app-level revocation check, but that check requires the consuming app to maintain its own revocation database and supply it to the library's decode() call. Zentry Tools doesn't run a revocation database, so on this specific site, Strict mode enforces the same offline expiry as Ephemeral mode — it doesn't add extra protection here. If you need true revocation, you'd build that backend yourself using the same library.

Your browser requires explicit permission before any website can access your camera. If you deny it, you can still scan by uploading a photo or screenshot of the QR code instead.

You'll see a generic "incorrect password or invalid code" message. This is intentional — the library treats a wrong password and tampered ciphertext identically, so a scanner can't be used to tell an attacker which one it was.