{"_id":"@dmlibs/dm-ntag424-sdm","_rev":"2-c6b934c04819398216dbf6ff1867b1a2","name":"@dmlibs/dm-ntag424-sdm","dist-tags":{"latest":"2.0.0"},"versions":{"1.0.0":{"name":"@dmlibs/dm-ntag424-sdm","version":"1.0.0","keywords":["ntag424","ntag 424 dna","sdm","sun","nfc","secure dynamic messaging","cmac"],"author":"","license":"ISC","_id":"@dmlibs/dm-ntag424-sdm@1.0.0","maintainers":[{"name":"dev.masters","email":"fk.1996.5@gmail.com"}],"dist":{"shasum":"aa6224154793a7b667e8a6cedb8e4d081b2513aa","tarball":"https://registry.npmjs.org/@dmlibs/dm-ntag424-sdm/-/dm-ntag424-sdm-1.0.0.tgz","fileCount":18,"integrity":"sha512-RkCo+3kPB0KCXALA2RWpPiHxxIiZPYu1+wMB8OqdJcOyH4alpapvk2HGIJ8IKQgks6R+OZkfu+zUFyAeGXTnyQ==","signatures":[{"sig":"MEYCIQDOZk3+3dbAq+Bl4HPplT3fPnZihE3agaKS9wAnIDS7yAIhAIwKSHHCk8in0Gjz8Wp94LEoVhNJGaOH5SVdt/grWWCv","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":26430},"main":"dist/index.js","type":"commonjs","types":"dist/index.d.ts","gitHead":"0da0e32fbefc61433be218a81cb1e5317e1f54b1","scripts":{"build":"tsc","prepublishOnly":"npm run build","release:patch:publish":"npm version patch && npm publish --access public"},"_npmUser":{"name":"dev.masters","email":"fk.1996.5@gmail.com"},"_npmVersion":"10.9.8","description":"Server-side verification for NTAG 424 DNA SDM (Secure Dynamic Messaging) dynamic URLs","directories":{},"_nodeVersion":"22.22.3","_hasShrinkwrap":false,"devDependencies":{"ts-node":"^10.9.2","typescript":"^5.9.3","@types/node":"^24.10.1"},"_npmOperationalInternal":{"tmp":"tmp/dm-ntag424-sdm_1.0.0_1786909728885_0.989304938432291","host":"s3://npm-registry-packages-npm-production"}},"2.0.0":{"name":"@dmlibs/dm-ntag424-sdm","version":"2.0.0","main":"dist/index.js","types":"dist/index.d.ts","type":"commonjs","scripts":{"build":"tsc","prepublishOnly":"npm run build","release:patch:publish":"npm version patch && npm publish --access public"},"keywords":["ntag424","ntag 424 dna","sdm","sun","nfc","secure dynamic messaging","cmac"],"author":"","license":"ISC","description":"Server-side verification for NTAG 424 DNA SDM (Secure Dynamic Messaging) dynamic URLs","devDependencies":{"@types/node":"^24.10.1","ts-node":"^10.9.2","typescript":"^5.9.3"},"_id":"@dmlibs/dm-ntag424-sdm@2.0.0","gitHead":"0da0e32fbefc61433be218a81cb1e5317e1f54b1","_nodeVersion":"22.22.3","_npmVersion":"10.9.8","dist":{"integrity":"sha512-CSlPfJL5pbJ9bH3xGKMDMLMCXPsp8v9fZID9mhQ+R6Oe2sdMfO991r1EGAdaem+AhBIH15NK5xvqq0nU59TQEw==","shasum":"2d639588582aa7c93937e8bd76b2748e705ee429","tarball":"https://registry.npmjs.org/@dmlibs/dm-ntag424-sdm/-/dm-ntag424-sdm-2.0.0.tgz","fileCount":18,"unpackedSize":26514,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIAn2+qVmWfYyXQzEAw4fYIT0OUJt4f9E4WXJkUxPNgpVAiBZAnf1e638muqMB0kl0gSRAmxbv9sjVioE3qOKXD62QQ=="}]},"_npmUser":{"name":"dev.masters","email":"fk.1996.5@gmail.com"},"directories":{},"maintainers":[{"name":"dev.masters","email":"fk.1996.5@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/dm-ntag424-sdm_2.0.0_1786911788937_0.6025433684565384"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-16T19:48:48.699Z","modified":"2026-08-16T20:23:09.237Z","1.0.0":"2026-08-16T19:48:49.040Z","2.0.0":"2026-08-16T20:23:09.088Z"},"license":"ISC","keywords":["ntag424","ntag 424 dna","sdm","sun","nfc","secure dynamic messaging","cmac"],"description":"Server-side verification for NTAG 424 DNA SDM (Secure Dynamic Messaging) dynamic URLs","maintainers":[{"name":"dev.masters","email":"fk.1996.5@gmail.com"}],"readme":"# @dmlibs/dm-ntag424-sdm\n\nServer-side verification for **NTAG 424 DNA** SDM / SUN (Secure Dynamic Messaging) dynamic URLs.\n\nWhen a phone scans the tag, the tag appends two query params to its URL:\n\n- `e` — encrypted PICC data (UID + scan counter), 32 hex chars\n- `c` — truncated AES-CMAC of the scan, 16 hex chars\n\nThis library decrypts `e`, recomputes the CMAC with the tag's keys, and verifies `c`\nwith a timing-safe comparison. No dependencies — Node's built-in `crypto` only.\n\n## Install\n\n```bash\nnpm install @dmlibs/dm-ntag424-sdm\n```\n\n## Configure\n\nAdd the two AES-128 keys you programmed into the tag's SDM settings to your `.env`\n(32 hexadecimal characters each):\n\n```env\nDM_NTAG424_SDM_META_READ_KEY=00112233445566778899AABBCCDDEEFF\nDM_NTAG424_SDM_FILE_READ_KEY=FFEEDDCCBBAA99887766554433221100\n```\n\n- `DM_NTAG424_SDM_META_READ_KEY` — the **SDMMetaRead** key (decrypts the PICC data).\n- `DM_NTAG424_SDM_FILE_READ_KEY` — the **SDMFileRead** key (derives the CMAC session key).\n\nIf a key is missing or malformed, `verifyNtag424Sdm` rejects with an `Ntag424ConfigError`\nwith a hint about what to fix.\n\n## Use\n\n```ts\nimport {\n  verifyNtag424Sdm,\n  Ntag424VerificationError,\n} from \"@dmlibs/dm-ntag424-sdm\";\n\napp.get(\"/verify\", async (req, res) => {\n  try {\n    const { uid, counter } = await verifyNtag424Sdm({\n      encryptedPiccData: req.query.e as string,\n      receivedCmac: req.query.c as string,\n    });\n\n    // Replay protection is YOUR responsibility:\n    // load the last counter you stored for this uid and require counter > stored.\n    // Then persist the new counter.\n\n    res.json({ uid, counter });\n  } catch (error) {\n    if (error instanceof Ntag424VerificationError) {\n      res.status(403).json({ message: \"Invalid scan\" });\n      return;\n    }\n    throw error; // config error / unexpected — let it surface\n  }\n});\n```\n\n### Result\n\n`verifyNtag424Sdm` is async and resolves only when the scan is authentic:\n\n```ts\ninterface Ntag424VerificationResult {\n  valid: true;\n  uid: string;        // 7-byte tag UID, uppercase hex\n  counter: number;    // SDMReadCtr — increments on every scan\n  piccDataTag: number;\n}\n```\n\n### Errors\n\n| Error | Meaning | What to do |\n| --- | --- | --- |\n| `Ntag424ConfigError` | Env key missing or not 32 hex chars | Fix your `.env` |\n| `Ntag424VerificationError` | Bad `e`/`c` format, wrong key, or forged/corrupted scan | Reject the request |\n\nBoth extend `Ntag424Error`.\n\n## Expected tag configuration\n\n- PICC data mirror enabled with UID + SDMReadCtr (PICC data tag `0xC7`, 7-byte UID).\n- PICC data encrypted with the SDMMetaRead key (AES-128-CBC, zero IV).\n- `SDMMACInputOffset == SDMMACOffset` (the CMAC is computed over empty input).\n","readmeFilename":"README.md"}