Package: nfc2mqtt
nfc2mqttnfc2mqtt reads NFC tags withnfcpyand push them to MQTT.
nfc2mqtt stores all data in encrypted form on NFC tag. Because of that,nfcpyshould be able to writeNDEFon used tags.
For more information about tag payload please seenfc2mqtt tag payload.nfc2mqtt isNOT"simple" bridge between NFC and MQTT. It is not suposed to scan tag ID and send it to MQTT.
It stores encrypted payload on tag/card, and send this payload to MQTT after reading (if valid).nfc2mqttdosen'tstore list of valid tags, tag is valid when encrypted content is valid (can be decrypted and its not expired).
Because of that, scan process is longer (~1-2s) (we need not only tosensenfc tag, we also need to read tag data).InstalationPythonPython3 and pip3 should be installed and working.$ pip3 install nfc2mqttDockerThere is ready nfc2mqtt docker image. Just pullghcr.io/bkupidura/nfc2mqtt:latest.UsagePython$ nfc2mqtt -c /etc/nfc2mqtt.yamlDockerYou will need to discover NFC readerusb path, and probably blacklist some kernel modules (sudo modprobe -r pn533_usb).$ docker run --rm -d --name nfc2mqtt -v /data/config.yaml:/config.yaml --device /dev/bus/usb/003/009 ghcr.io/bkupidura/nfc2mqtt:latestnfc2mqtt tag payloadAll data written bynfc2mqtton tag is encrypted. Its stored asNDEF TextRecord.
NFC tag ID can't be trusted. nfc2mqtt willNOT use ID to identify tags.As nfc2mqtt stores everything in encrypted form, plenty of tag user bytes are wasted for encryption. Ex. simple payloadAnGP7 0({"id": "AnGP7", "valid_till": 0}) which without encryption is 7 bytes long, after encryption is 100 bytes long.Encryption of tags CAN'T be disabled.Payloadtag_id valid_till [data]tag_idIts "random" string generated during writing tag.
By default it contains[a-zA-Z0-9]and it is5character long.valid_tillStores time sinceepoch(UTC) (not valid after).
By default its set to0, tag is valid always (don't expire).
To generatevalid_tillfrom linux box usedate -d '2020-12-27T23:59:59' +%sdataData can be used to store any user/application data.
By default it is not set.MQTT endpointsnfc2mqtt/write_tagExpectemptymessage or JSON message.Ifemptymessage is received, next tag connected to NFC reader will be written with default payload. (randomtag_id, 0 asvalid_till).If JSON message is received, next tag conneccted to NFC reader will be written as described in JSON.
Supported JSON properties:id -tag_id, if missingtag_idwill be auto generated.valid_till -valid_till, if missingvalid_tillwill be set to0data -dataauthenticate_password - if provided, this password will be used to authenticate to tag. For more information please seenfcpy. This should be used only when tags were already protected by password not known tonfc2mqtt.ExamplesGenerate new tag with default values:$ mosquitto_pub ... -t 'nfc2mqtt/write_tag' -m ''.Generate new tag with known id:$ mosquitto_pub ... -t 'nfc2mqtt/write_tag' -m '{"id": "example"}'Generate new tag with valid_till:$ mosquitto_pub ... -t 'nfc2mqtt/write_tag' -m '{"valid_till": 1599947426}'Generate new tag with string data:$ mosquitto_pub ... -t 'nfc2mqtt/write_tag' -m '{"data": "string}'Generate new tag with JSON data:$ mosquitto_pub ... -t 'nfc2mqtt/write_tag' -m '{"data": {"json": true}}'Generate new tag with multiple fields:$ mosquitto_pub ... -t 'nfc2mqtt/write_tag' -m '{"id": "example", "valid_till": 1700000000, "data": {"field1": "value1", "field2": 1}}'nfc2mqtt/wipe_tagExpectemptymessage.When message is received, next tag connected to NFC reader will be formated. For more information please checknfcpy.Examples$ mosquitto_pub ... -t 'nfc2mqtt/wipe_tag' -m ''MQTT publishWhen valid tag is scanned, new message will be publish tonfc2mqtt/tag/<tag_id>.Payloadnfc2mqtt/tag/AnGP7->{"status": 1, "id": "AnGP7", "valid_till": 0, "tag": {"product": "NXP NTAG213", "type": "Type2Tag", "id": "049962228b5f80"}}nfc2mqtt/tag/Dj3dV->{"status": 1, "id": "Dj3dV", "valid_till": 0, "data": {"custom": "value"}, "tag": {"product": "NXP NTAG213", "type": "Type2Tag", "id": "049962228b5f80"}}nfc2mqtt/tag/h89u9->{"status": 1, "id": "h89u9", "valid_till": 1700000000, "data": "string data", "valid_till_dt_utc": "2023-11-14 22:13:20", "tag": {"product": "NXP NTAG213", "type": "Type2Tag", "id": "049962228b5f80"}}Scan tag statusValid-1, tag is valid and can be trustedInvalid-2, tag is invalid (unable to decrypt content)UnknownPayloadType-3, tag was readed (and decrypted) - but contains unknown payloadExpired-4, tag already expiredScanError-5, nfc2mqtt was not able to scan this tag (ex. too fast removed from reader, or wrong authentication password)NoNdef-6, tag dosen't containsNDEFfield used to store content (probably not formatted by nfc2mqtt, or not supportingNDEF)MQTT statusnfc2mqtt will use MQTT last will/birth message.When it connects to MQTT broker, it will publish1tonfc2mqtt/online.
When nfc2mqtt will be disconnected,nfc2mqtt/onlinewill be set to0.HardwareI own one NFC reader (ACR122U), so all development is done on it.TagsNOTsupported by nfc2mqtt:All Mifare cards - nfcpy is not able to write on those tags (probably because of missing CRYPTO1 support)NTAG210 - expose just 48 bytes for user data, its too small for encryptionTags supported by nfc2mqtt:NTAG212 -NOT TESTEDbut should workNTAG213 - worksNTAG215 -NOT TESTEDbut should workNTAG216 - works (preferable choice, as they expose 888 user data bytes)ConfigBefore first run you should changeauthenticate_passwordandencrypt_key. New keys can be generated withfernet token.Ensure thatencrypt_keyis different thanauthenticate_password.nfc:reader:usbauthenticate_password:pa2SB6ZC8NUFzX1IXBbA7OF9xj5cTrdAImkx3t9i0Fw=encrypt_key:Wv_o4fUMFrPFZv0Es02f361nW_kdpFLdXdTo7e7jo0c=id_length:5mqtt:server:localhostport:1883keepalive:30username:nfc2mqttpassword:passwordtopic:nfc2mqttlogging:level:infonfcreader -nfcpyreadder pathauthenticate_password - password used toauthenticateandprotect. If you change that, you will need to rewriteALLtags. Forwrite_tagMQTT endpoint please provide oldauthenticate_password. It can be generated withfernet token.encrypt_key - Fernet token used to encrypt tag content. If you change that, nfc2mqtt will not be able to decrypt tags with previousencrypt_key. You will need to rewriteALLtags. This can be helpfull if you lost tag withvalid_till: 0. It can be generated withfernet token.SecurityAll tags "created" by nfc2mqtt are protected from reading on NFC tag level.authenticate_passwordis used for that.
Tag probably still can be cloned and readed, but all data stored physicaly on tag is encrypted withsymmetric cipherand secure.What does it meanYou should assume that any tag lost or passed to stranger can be cloned and used in malicious way.
Attacker will not be able to read decrypted content of yours NFC tag (tag_id,valid_till,data). Also attacker will not be able to change NFC tag content (he would need to knowencrypt_key).So if you give yours petsitter NFC tag, withvalid_tillset to ex.utcnow()+1 week, this tag will work only for1 week, not longer.If you lost NFC tag withvalid_till: 0, you should changeencrypt_keyin nfc2mqtt and rewrite all trusted tags with newencrypt_key.Tags should be treated as physcial lock keys. If you lost tag for 2h (in the wild, not in yours apartment), you should assume that tag is copromised, and you should changeencrypt_key.Generate fernet token$ python3 -c 'from cryptography.fernet import Fernet;print(Fernet.generate_key().decode())'Worth readinghttps://docs.onion.io/omega2-docs/using-rfid-nfc-expansion.htmlhttps://nfcpy.readthedocs.io/en/latest/overview.htmlhttps://pcsclite.apdu.fr/https://www.blackhat.com/docs/sp-14/materials/arsenal/sp-14-Almeida-Hacking-MIFARE-Classic-Cards-Slides.pdfhttp://nfc-tools.org/index.php