EdgeNFC
Free tool · no signup
An NTAG 424 DNA tag rewrites part of its own URL on every read. This decodes what it wrote — the UID, the read counter, the truncated AES-CMAC, or the encrypted PICC blob — explains each field, and points at the byte-order mistake that breaks most first integrations.
Nothing leaves your browser. Parsing and every cryptographic check run locally in this tab, in the same Rust/WebAssembly core EdgeNFC verifies production taps with. Your URL and your key are never uploaded, never logged, never stored — the only request this page makes is fetching that core.
Decoder
Paste the whole URL, or just the query string. Both mirror modes are supported and detected automatically.
Never paste a production master key into any web tool — including this one. Use a test key. This field is memory-only: it is not stored, not put in the URL, and is wiped when you leave the page. That is enforced by the code, but the habit matters more than any one page's promise.
The key is the system master key. The core derives this tag's SDMFileReadKey from it with AN10922 (role 0x01) exactly as a tag provisioned by EdgeNFC expects. If your SDMFileReadKey is written to the chip directly rather than diversified, the structural analysis below is still exact but the MAC check will not match — that is a key-hierarchy difference, not a forgery.
Ready. Paste a URL and press Decode.
Reference
An NTAG 424 DNA in SDM mode fills placeholders inside its stored NDEF URL at read time. There are two shapes you will meet in the field.
uid is 14 hex digits (7 bytes), ctr is 6 hex digits (3-byte SDMReadCtr) and mac is 16 hex digits (the 8-byte truncated SDMMAC). Simple and human-inspectable — at the cost of publishing the tag's UID to anyone who reads the link.
picc_data is 32 hex digits: exactly one AES block holding a tag byte, the UID and the counter, encrypted with the SDMMetaReadKey. The UID never appears in the clear, so a passer-by who reads the link cannot identify the tag. This is the recommended default.
Decrypted, the block is tag byte ‖ UID ‖ SDMReadCtr ‖ padding. In the tag byte, bit 7 means "UID present", bit 6 means "counter present" and the low nibble is the UID length — 0xC7 for a normal 7-byte NTAG 424 UID. The counter inside is stored LSB-first.
A tag may also mirror encrypted file contents as an extra parameter (enc). Those bytes are part of the MAC input, so a verifier must take them from the raw URL byte range the SDM offsets describe — never from re-serialized parameters, which is how canonicalization drift creeps in.
The bug everyone hits
If your CMAC never matches and you are sure the key is right, this is almost always why.
The chip mirrors SDMReadCtr into the URL most-significant byte first, so ctr=000005 is the number 5. But the three bytes that go into the session-key input the MAC is computed over are the same counter least-significant byte first — 05 00 00.
Feed the URL bytes straight through and you have silently MAC'd counter 0x050000 = 327,680 instead of 5. Nothing errors. The key is fine. The MAC simply never matches, at every counter value except the byte-symmetric ones. The decoder above prints both orderings for whatever you paste, and if your MAC matches the reversed counter it will say so outright.
Reference
Five steps, in this order. Everything before the last one is arithmetic; the last one is policy.
This tool cannot tell you a tag is genuine, and neither can any URL on its own. It validates a MAC against a key you supplied. Authenticity also needs the things a browser cannot see: that the UID is one of yours, and that this counter value has never been accepted before. Anyone who tells you a decoder proves genuineness is selling you something.
Built by EdgeNFC, which does this for a living: hosted NTAG 424 verification with unlimited scans, or an on-premise core if the keys must never leave your building. Free tier, no card.