Now that we’ve resolved all of the major teething issues we had with Python 3 and nfcpy, we can look at reading the contents of tags presented by the user and writing our own. There’s a wide variety of tags that can be written, so I’ll cover a couple of the most interesting — Wi-Fi credentials and URIs.
Structural NFC code
The structural code here is a bit involved, so I’ll break it up into sections and explain each bit.
The first step is importing modules and opening a handle to our
ContactlessFrontend — the device we’re using as the interface between the computer running Python and our NFC devices in the real world. In my case, I’m using a USB-connected ACR122U device; if you’re not sure where
usb:072f:2200 comes from, read the first part of the series.
from time import sleep import nfc with nfc.ContactlessFrontend('usb:072f:2200') as clf:
Once the frontend is opened, we need to sense for tags. However, we don’t just want to check for tags once and bail out; so I stick the code in a
while True loop to handle endlessly looking for tags.
For this example, I’m only looking for
106A-class tags, but there are a couple others we could look for too. If we don’t find anything (
None), we wait for 100ms to stop the CPU from burning up, and then search again.
while True: target = clf.sense(RemoteTarget('106A')) if target is None: sleep(0.1) # don't burn the CPU continue serial = target.sdd_res.hex()
At this point, we’ve determined that there is an NFC target near the reader and we also have its serial number. We could even bail out here if checking the serial number was sufficient for us. The last step in getting the juicy information out (like NDEF records contained) is to
tag = nfc.tag.activate(clf, target)
At this point, we’re ready to move onto something more interesting. For example, we might want to read the contents of the records, run a query against a database, or write something back.
Reading and writing
Now that we’ve found an NFC device near us and have activated it, we can start to pull information out. The
ndef property of our tag object lets us access the NDEF memory area on the chip; this contains all of the most exciting information. Depending on what we’re expecting to find and what we get, we might need to take various different actions.
For the purposes of this example, I’ll just print out the record information found. You’ll need to modify the code to behave differently for your specific situation.
if not tag.ndef: print("No NDEF records found!") continue for record in tag.ndef.records: print("Found record: " + record)
It’s easy to write NDEF records to a card — reassign the
import ndef record = ndef.TextRecord("Hello sigsec readers!") # 'tag' is an nfcpy tag acquired earlier... tag.ndef.records = [record]
This does require that the card is already NDEF formatted; it’s possible you might get a card that doesn’t come adequately prepared, so the code may fail in this case. For more info and some background reading, head to the nfcpy documentation.
nfc.ndef package is deprecated and will cause problems if used. Stick to the
ndef package in the
ndeflib pip module.
NDEF record types
There are a number of different types of records that we can create, with different uses and applications. To write any of these to a smartcard or NFC tag, use the steps in the heading above with the
record object produced below.
Text records are super easy; they contain a string of some text, a language key and an encoding. If you don’t specify anything,
ndeflib will use
en for the language and
UTF-8 for the encoding by default.
record = ndef.TextRecord(text, language, encoding) # eg. record = ndef.TextRecord("Hello sigsec readers!")
Wi-Fi config records
Making a Wi-Fi configuration record is a little bit more involved due to the number of parameters we need to set. Once the parameters are identified, it’s just as straight-forward. If you get stuck, try reading the
ndeflib documentation for this feature.
credential = ndef.wifi.Credential() credential.set_attribute('ssid', b'MyNetworkSSID') credential.set_attribute('authentication-type', 'WPA2-Personal') credential.set_attribute('encryption-type', 'AES') credential.set_attribute('network-key', b'WiFi-Pa$$w0rd') credential.set_attribute('mac-address', bytes([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF])) record = ndef.WifiSimpleConfigRecord() record.set_attribute('credential', credential) record.set_attribute('rf-bands', ('2.4GHz', '5.0GHz'))
A lot of useful actions can be constructed using the URI record. The basic form of the record constructor is:
record = ndef.UriRecord("https://www.example.org/")
If you want to go straight to Google Maps navigation, put in an address in this format (or look here for more Google intents):
record = ndef.UriRecord("google.navigation:q=1600+Pennsylvania+Avenue,+Washington+DC")
To compose an email (even including a pre-filled subject line), use this format:
record = ndef.UriRecord("mailto:email@example.com?subject=Hello%20there")
To dial a phone number, use this format:
record = ndef.UriRecord("tel:+61400123456")
There’s a lot of other actions that can happen: if you’ve installed apps like YouTube, Facebook or Twitter, putting in links to videos or profiles in these services will generally cause the corresponding app to open automatically when the tag is read. This can be a great way to get people in touch with you if you want to put NFC stickers onto business cards or belongings.
For me, I’ve ordered a set of 10 NFC stickers off eBay to play around with. I think I’ll write Wi-Fi configurations onto a couple of them for use at home and in the office. With the rest, though, I don’t have any specific plan in mind.
I like the idea of connecting the reader to a database so I can handle basic scanning in and out of belongings, like if I loan something to a friend… but this seems like it could be more easily done with just a spreadsheet and manual tracking.
Projects I’ve seen online from others include making access control systems, time clocks, inventory management and a lot of other security related applications. Perhaps in the future I’ll write a post about one of these uses.