- Notifications
You must be signed in to change notification settings - Fork3
PN532.js is a JavaScript library for PN532 base on Web Bluetooth and Web Serial.
License
taichunmin/pn532.js
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
PN532.js is a JavaScript library for PN532 base on Web Bluetooth and Web Serial.
Node SerialPort is a JavaScript library for connecting to serial ports that works in NodeJS and Electron.
A subset of the Web Bluetooth API is available in ChromeOS, Chrome for Android 6.0, Mac (Chrome 56) and Windows 10 (Chrome 70). See MDN'sBrowser compatibility table for more information.
For Linux and earlier versions of Windows, enable the#experimental-web-platform-features
flag inabout://flags
.
The Web Serial API is available on all desktop platforms (ChromeOS, Linux, macOS, and Windows) in Chrome 89. See MDN'sBrowser compatibility table for more information.
On Android, support for USB-based serial ports is possible using the WebUSB API and theSerial API polyfill. This polyfill is limited to hardware and platforms where the device is accessible via the WebUSB API because it has not been claimed by a built-in device driver.
PN532.js support Web Serial and Web Bluetooth. You can connect PN532 to PC via an USB2TTL module (e.g.CH340
,PL2303
) or via BLE UART module (e.g.JDY-33
,HC-08
).
See Mtools Tec'sHow to make PN532 work on Bluetooth andHow To Test PN532 Working With Bluetooth Module? for more information.
Using npm:
$ npm install pn532.js# Also install SerialPort if you want to run in node.js$ npm install serialport
Using yarn:
$ yarn add pn532.js# Also install SerialPort if you want to run in node.js$ yarn add serialport
Once the package is installed, you can import the library usingimport
orrequire
:
// importimport{Pn532,Packet,utils:Pn532utils}from'pn532.js'importCrypto1from'pn532.js/Crypto1.js'importLoggerRxTxfrom'pn532.js/plugin/LoggerRxTx.js'importPn532Hf14afrom'pn532.js/plugin/Hf14a.js'importPn532SerialPortAdapterfrom'pn532.js/plugin/SerialPortAdapter.js'importPn532WebbleAdapterfrom'pn532.js/plugin/WebbleAdapter.js'importPn532WebserialAdapterfrom'pn532.js/plugin/WebserialAdapter.js'// requireconst{ Pn532, Packet,utils:Pn532utils}=require('pn532.js')constCrypto1=require('pn532.js/Crypto1.js')constLoggerRxTx=require('pn532.js/plugin/LoggerRxTx.js')constPn532Hf14a=require('pn532.js/plugin/Hf14a.js')constPn532SerialPortAdapter=require('pn532.js/plugin/SerialPortAdapter.js')constPn532WebbleAdapter=require('pn532.js/plugin/WebbleAdapter.js')constPn532WebserialAdapter=require('pn532.js/plugin/WebserialAdapter.js')
Using jsDelivr CDN:
<!-- PN532.js require lodash@4, place before any pn532 libraries --><scriptsrc="https://cdn.jsdelivr.net/npm/lodash@4/lodash.min.js"></script><!-- PN532.js Core --><scriptsrc="https://cdn.jsdelivr.net/npm/pn532.js@0/dist/pn532.min.js"></script><!-- PN532.js Crypto1 --><scriptsrc="https://cdn.jsdelivr.net/npm/pn532.js@0/dist/Crypto1.min.js"></script><!-- PN532.js Hf14a plugin --><scriptsrc="https://cdn.jsdelivr.net/npm/pn532.js@0/dist/plugin/Hf14a.min.js"></script><!-- PN532.js LoggerRxTx plugin --><scriptsrc="https://cdn.jsdelivr.net/npm/pn532.js@0/dist/plugin/LoggerRxTx.min.js"></script><!-- PN532.js WebbleAdapter plugin --><scriptsrc="https://cdn.jsdelivr.net/npm/pn532.js@0/dist/plugin/WebbleAdapter.min.js"></script><!-- PN532.js WebserialAdapter plugin --><scriptsrc="https://cdn.jsdelivr.net/npm/pn532.js@0/dist/plugin/WebserialAdapter.min.js"></script>
After thescript
tag, you can use thePN532.js
as following:
// setupconst{ _,// lodash: https://cdn.jsdelivr.net/npm/lodash@4/lodash.min.jsPn532:{ Pn532, Packet,utils:Pn532utils}, Crypto1, Pn532Hf14a, Pn532LoggerRxTx, Pn532WebbleAdapter, Pn532WebserialAdapter,}=window
A pn532 instance must register exactly one adapter plugin:
// setupconst{ _,// lodash: https://cdn.jsdelivr.net/npm/lodash@4/lodash.min.jsPn532:{ Pn532, Packet,utils:Pn532utils}, Crypto1, Pn532Hf14a, Pn532WebbleAdapter, Pn532WebserialAdapter,}=window// Pn532WebserialAdapterconstpn532usb=newPn532()pn532usb.use(newPn532WebserialAdapter())// A pn532 instance must register exactly one adapter pluginconsole.log(JSON.stringify(awaitpn532usb.getFirmwareVersion()))// {"firmware":"1.6","ic":"PN532","iso14443a":true,"iso14443b":true,"iso18092":true}// Pn532WebbleAdapterconstpn532ble=newPn532()pn532ble.use(newPn532WebbleAdapter())// A pn532 instance must register exactly one adapter pluginconsole.log(JSON.stringify(awaitpn532ble.getFirmwareVersion()))// {"firmware":"1.6","ic":"PN532","iso14443a":true,"iso14443b":true,"iso18092":true}// Pn532SerialPortAdapterimportPn532SerialPortAdapterfrom'pn532.js/plugin/SerialPortAdapter.js'// Run serialport-list to list port, see https://serialport.io/docs/bin-listconstpn532node=newPn532()pn532node.use(newPn532SerialPortAdapter(),{path:'/dev/tty.usbserial-120'})console.log(JSON.stringify(awaitpn532node.getFirmwareVersion()))// {"firmware":"1.6","ic":"PN532","iso14443a":true,"iso14443b":true,"iso18092":true}
// setupconst{ _,// lodash: https://cdn.jsdelivr.net/npm/lodash@4/lodash.min.jsPn532:{ Pn532, Packet,utils:Pn532utils}, Pn532Hf14a, Pn532WebserialAdapter,}=windowconstpn532=newPn532()pn532.use(newPn532WebserialAdapter())// A pn532 instance must register exactly one adapter pluginpn532.use(newPn532Hf14a())console.log(JSON.stringify(awaitpn532.$hf14a.mfSelectCard()))// {"pack":"Packet(9): 010004080407460D6D","atqa":"Packet(2): 0004","sak":"Packet(1): 08","uid":"Packet(4): 07460D6D","rats":"Packet(0)"}
If you are not familiar with Chinese Magic Card, see Proxmark3'sMagic Cards Notes for more information.
// setupconst{ _,// lodash: https://cdn.jsdelivr.net/npm/lodash@4/lodash.min.jsPn532:{ Pn532, Packet,utils:Pn532utils}, Pn532Hf14a, Pn532WebserialAdapter,}=windowconstpn532=newPn532()pn532.use(newPn532WebserialAdapter())// A pn532 instance must register exactly one adapter pluginpn532.use(newPn532Hf14a())constkey=Packet.fromHex('FFFFFFFFFFFF')// read a blockletresp1=awaitpn532.$hf14a.mfReadBlock({block:0,isKb:1, key})console.log(resp1.hex)// 0102030404080400000000000000BEAFconsole.log(resp1.inspect)// Packet(16): 01 02 03 04 04 08 04 00 00 00 00 00 00 00 BE AF// try to read a block with key B then Key Aletresp2=awaitpn532.$hf14a.mfReadBlockKeyBA({block:0,ka:key,kb:key})console.log(resp2.hex)// 0102030404080400000000000000BEAFconsole.log(resp2.inspect)// Packet(16): 01 02 03 04 04 08 04 00 00 00 00 00 00 00 BE AF// read a sectorletresp3=awaitpn532.$hf14a.mfReadSector({sector:0,isKb:1, key})console.log(JSON.stringify(resp3))// {"data":"Packet(64): 0102030404080400000000000000BEAF... (truncated)","success":[1,1,1,1]}console.log(resp3.data.hex)// 0102030404080400000000000000BEAF... (truncated)console.log(resp3.data.inspect)// Packet(64): 01 02 03 04 04 08 04 00 00 00 00 00 00 00 BE AF... (truncated)// try to read a sector with key B then Key Aletresp4=awaitpn532.$hf14a.mfReadSectorKeyBA({sector:0,ka:key,kb:key})console.log(JSON.stringify(resp4))// {"data":"Packet(64): 0102030404080400000000000000BEAF... (truncated)","success":{"key":[1,1],"read":[1,1,1,1]}}console.log(resp4.data.hex)// 0102030404080400000000000000BEAF... (truncated)console.log(resp4.data.inspect)// Packet(64): 01 02 03 04 04 08 04 00 00 00 00 00 00 00 BE AF... (truncated)// try to read a Mifare Classic 1k by keysletresp5=awaitpn532.$hf14a.mfReadCardByKeys({sectorMax:16,keys:[key]})console.log(JSON.stringify(resp5))// {"data":"Packet(1024): 0102030404080400000000000000BEAF... (truncated)","success":{"key":["Packet(6): FFFFFFFFFFFF",... (truncated)],"read":[1,1,1,1,... (truncated)]}}console.log(resp5.data.hex)// 0102030404080400000000000000BEAF... (truncated)console.log(resp5.data.inspect)// Packet(1024): 01 02 03 04 04 08 04 00 00 00 00 00 00 00 BE AF... (truncated)// write a blockconstdataBlock=Packet.fromHex('000102030405060708090A0B0C0D0E0F')awaitpn532.$hf14a.mfWriteBlock({block:1,isKb:1, key,data:dataBlock})// try to write a block with key B then Key Aawaitpn532.$hf14a.mfWriteBlockKeyBA({block:1,ka:key,kb:key,data:dataBlock})// write a sectorconstdataSector=newPacket(64)dataSector.set(Packet.fromHex('FFFFFFFFFFFF08778F00FFFFFFFFFFFF'),48)letresp6=awaitpn532.$hf14a.mfWriteSector({sector:1,isKb:1, key,data:dataSector})console.log(JSON.stringify(resp6))// {"success":[1,1,1,1]}// try to write a sector with key B then Key Aletresp7=awaitpn532.$hf14a.mfWriteSectorKeyBA({sector:1,ka:key,kb:key,data:dataSector})console.log(JSON.stringify(resp7))// {"success":[1,1,1,1]}// try to write a Mifare Classic 1k by keysconstdataCard=newPacket(1024)dataCard.set(Packet.fromHex('0102030404080400000000000000BEAF'))for(leti=0;i<16;i++)dataCard.set(Packet.fromHex('FFFFFFFFFFFF08778F00FFFFFFFFFFFF'),i*64+48)letresp8=awaitpn532.$hf14a.mfWriteCardByKeys({sectorMax:16,keys:[key],data:dataCard})console.log(JSON.stringify(resp8))// {"success":[1,1,1,1,... (truncated)]}
If you are not familiar with Chinese Magic Card, see Proxmark3'sMagic Cards Notes for more information.
// setupconst{ _,// lodash: https://cdn.jsdelivr.net/npm/lodash@4/lodash.min.jsPn532:{ Pn532, Packet,utils:Pn532utils}, Pn532Hf14a, Pn532WebserialAdapter,}=windowconstpn532=newPn532()pn532.use(newPn532WebserialAdapter())// A pn532 instance must register exactly one adapter pluginpn532.use(newPn532Hf14a())// read a blockletresp1=awaitpn532.$hf14a.mfReadBlockGen1a({block:0})console.log(resp1.hex)// 0102030404080400000000000000BEAFconsole.log(resp1.inspect)// Packet(16): 01 02 03 04 04 08 04 00 00 00 00 00 00 00 BE AF// read a sectorletresp2=awaitpn532.$hf14a.mfReadSectorGen1a({sector:0})console.log(JSON.stringify(resp2))// {"data":"Packet(64): 0102030404080400000000000000BEAF... (truncated)","success":[1,1,1,1]}console.log(resp2.data.hex)// 0102030404080400000000000000BEAF... (truncated)console.log(resp2.data.inspect)// Packet(64): 01 02 03 04 04 08 04 00 00 00 00 00 00 00 BE AF... (truncated)// read a Mifare Classic 1k Gen1Aletresp3=awaitpn532.$hf14a.mfReadCardGen1a({sectorMax:16})console.log(JSON.stringify(resp3))// {"data":"Packet(1024): 0102030404080400000000000000BEAF... (truncated)","success":[1,1,1,1,... (truncated)]}console.log(resp3.data.hex)// 0102030404080400000000000000BEAF... (truncated)console.log(resp3.data.inspect)// Packet(1024): 01 02 03 04 04 08 04 00 00 00 00 00 00 00 BE AF... (truncated)// write a blockconstdataBlock=Packet.fromHex('000102030405060708090A0B0C0D0E0F')awaitpn532.$hf14a.mfWriteBlockGen1a({block:1,data:dataBlock})// write a sectorconstdataSector=newPacket(64)dataSector.set(Packet.fromHex('FFFFFFFFFFFF08778F00FFFFFFFFFFFF'),48)letresp4=awaitpn532.$hf14a.mfWriteSectorGen1a({sector:1,data:dataSector})console.log(JSON.stringify(resp4))// {"success":[1,1,1,1]}// write a Mifare Classic 1k Gen1AconstdataCard=newPacket(1024)dataCard.set(Packet.fromHex('0102030404080400000000000000BEAF'))for(leti=0;i<16;i++)dataCard.set(Packet.fromHex('FFFFFFFFFFFF08778F00FFFFFFFFFFFF'),i*64+48)letresp5=awaitpn532.$hf14a.mfWriteCardGen1a({sectorMax:16,data:dataCard})console.log(JSON.stringify(resp5))// {"success":[1,1,1,1,... (truncated)]}// set a random UIDawaitpn532.$hf14a.mfSetUidGen1a({uid:newPacket(_.times(4,()=>_.random(0,0xFF)))})// wipe a Mifare Classic 1k Gen1Aletresp6=awaitpn532.$hf14a.mfWipeGen1a({sectorMax:16,uid:Packet.fromHex('01020304')})console.log(JSON.stringify(resp6))// {"success":[1,1,1,1,... (truncated)]}
- PN532 User Manual v1.6 | NXP
- PN532/C1 Product data sheet v3.6 | NXP
- Mifare Classic 1k ev1 v3.2 | NXP
- Mifare Classic 4k ev1 v3.2 | NXP
- Mifare Identifcation Procedure - AN10833 | NXP
- MIFARE ISO/IEC 14443 PICC selection - AN10834 | NXP
- MIFARE product and handling of UIDs - AN10927 | NXP
- A 2018 practical guide to hacking NFC/RFID
- Magic Cards Notes
- elechouse/PN532: NFC library for Arduino
- nfc-tools/libnfc
- RfidResearchGroup/RFIDtools: RFID Tools android app
About
PN532.js is a JavaScript library for PN532 base on Web Bluetooth and Web Serial.