Record format & recovery
TagVault records are not tied to the app. The format below is complete enough to write your own reader, and the recovery script decrypts a record on any computer with Python 3, offline.
This is a compatibility specification, not a security certification. The app and format have not yet had an independent security audit.
Downloads
On the tag
One NFC Forum NDEF well-known Text record (TNF 0x01, type T), language en, UTF-8. The text is the Base64 encoding of the binary envelope below. Anyone with an NFC reader can copy it; it is only useful together with the passphrase.
Binary envelope
| Offset | Length | Field |
|---|---|---|
| 0 | 5 | ASCII TVLT followed by version byte 0x02 |
| 5 | 1 | KDF id: 0x01 = PBKDF2-HMAC-SHA256 |
| 6 | 4 | Iterations, unsigned 32-bit big-endian; exactly 600,000 |
| 10 | 16 | Random salt, new for every record |
| 26 | 12 | ChaCha20-Poly1305 nonce |
| 38 | variable | Ciphertext |
| end − 16 | 16 | Poly1305 authentication tag |
Key and encryption
- Passphrase: trim leading and trailing whitespace, normalise to Unicode NFC, encode as UTF-8. Case-sensitive.
- Key: PBKDF2-HMAC-SHA256, 600,000 iterations, 32-byte output.
- Cipher: ChaCha20-Poly1305 with the 26-byte header as associated data.
- Plaintext: UTF-8 JSON
{"secret": "…"}.
Readers must reject unknown magic, version, KDF or iteration values. A failed authentication means a wrong passphrase or a damaged record; no partial plaintext is ever returned.
Recovering a record
- Use any NFC reader app to copy the Base64 text of the tag's Text record into a file, for example
record.txt. - Install the one dependency:
python3 -m pip install cryptography - Run
python3 tagvault_v2_decrypt.py record.txtand type the passphrase when asked. The input is hidden.
The secret is printed to the terminal. Do this on a computer you trust, and clear the terminal afterwards.
Test vector
For checking an implementation only. Never use this passphrase for a real secret.
- Passphrase:
Café Soho London 1666 - Expected secret:
fixture-secret-not-a-real-credential
VFZMVAIBAAknwAABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGht82rRamc5CvvBFf4tU//ntlyjgAUTDoqPFgZ3oNjRpBOqd2T4OZ11kf0ewrn1twSW8hQ5tEp0pCsk5u+fiA6ndUQ==