Reading and writing NFC tags

6 minute read

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 (target equals 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 activate it:

        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

Reading records

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)

Writing records

It’s easy to write NDEF records to a card — reassign the tag.ndef.records field:

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.

Note: The 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

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'))

URI records

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:recipient@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.

What’s next?

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.