NFC programming on desktop Linux
Near field communication (NFC) is one of those relatively recent technologies that still offers a glimmer of science-fiction cachet. Contactless communication triggered by proximity, battery-free radio signals, nigh-invisible tags buried within everyday objects: these are all positive qualities. But, while support for NFC has become a staple on Linux-powered phones and tablets, it has remained elusive for desktop users. Recently, I endeavored to set up a simple and convenient NFC system on my own workstation, and encountered more than a handful of pain points along the way.
For starters, it is important to note how simple NFC support is on mobile Linux devices. Android support for reading and writing the contents of NFC tags is excellent, there are APIs for building NFC functionality into one's app, and there are even several completely free-software Android apps available that utilize NFC. The story is similar on other Linux-based mobile platforms (modulo the relative size and age of the associated development community, that is).
It is enough to make the desktop user a tad jealous: on a mobile device, one can trigger a range of system actions by touching a tag, keychain, or card to the device. There are clear applications for desktop usage there as well. A tag could unlock the system, launch a script or application, or even exchange data (reading or writing the tag's built-in storage).
But essentially no one does this on a laptop or desktop Linux machine. There is a chicken-and-egg problem to surmount, for one thing. NFC hardware is often talked about as if it is cheap, but in fact is rather expensive and difficult to acquire—50 to 90 US dollars seems to be the going rate for readers from known vendors. That is a not insubstantial investment and is a bit at odds with NFC's advertised benefits of ubiquitous, cheap radio tags.
NFC tags, in particular, are often touted as objects that will be so inexpensive that someday they will come embedded inside everything (more often than not, this vision is couched in terms of refrigerators monitoring their own contents, but there are other examples). They are small and require no battery power; when in proximity to the magnetic coil of an NFC reader, the tag antenna picks up enough energy to activate the chip and allow access to the storage. In reality, though, NFC tags seem to retail at a bit more than a dollar a piece, which gets expensive quickly. On the plus side, most tag readers come with a couple of tags tossed into the box, so I set out to find a kit that might be usable on a daily basis.
Hardware wars
My first attempt at selecting NFC hardware was a false start. There are precious few retail USB-connected NFC adapters on the market, and most of them emphasize only read support. Not wanting to get stuck with a device that would not let me write tags conveniently, I narrowed down the search a little and hunted for devices that advertised write support, too—of which there are vanishingly few. I found a really cheap generic option and took the plunge. In hindsight, worrying about advertised write support was likely unnecessary (most reader chips appear to support writing as well), since it limited the options I found. Worse still, the device I ended up getting did not actually have a working Linux driver (although the seller claimed that it did).
I did find a small utility on GitHub that worked with a related chip, and even managed to get it running with my adapter, but this approach was a dead end in the long run. Under the hood, the device in question was constructed of a microcontroller hooked up to an NFC sensor over a Serial Peripheral Interface (SPI) bus. While one can effectively control it by sending the supported commands to the microcontroller over a serial connection, this means writing bespoke code. The device is unsupported by the official Linux NFC stack maintained by Intel and by the leading open-source alternative, libnfc.
Naturally, the fact that there is more than one NFC stack available introduces complexities as well. For those unfamiliar, libnfc supports only a handful of NFC chips, but most of the existing Linux NFC programs are written for libnfc. The Linux NFC project is unrelated to libnfc; it supports a few more devices, but it is also a newer effort and it has less in the way of working code. That code does, however, include neard, a daemon that monitors an NFC reader waiting to sense a tag.
Eventually, I gave in a bought an NFC breakout board from Adafruit, along with an adapter to hook it up over a serial connection through a USB port. As is often the case with "hobbyist" electronics vendors, the board is rather pricey for what it contains (significantly more than the generic USB adapters, although as I had discovered, they certainly constitute a gamble) and much of the software written for it seems to target the Arduino at the expense of everything else. Nevertheless, it was reported to work with libnfc, and the chip (an NXP pn532) is supported by Linux NFC, too. The breakout board's documentation was missing a few critical steps (such as creating the /etc/nfc/libnfc.conf configuration file and an entry in /etc/nfc/devices.d/ to describe the hardware), but it did work.
The software side
Libnfc ships with a suite of command-line utilities for reading and writing the various flavors of NFC tags—which is another hurdle interested users will need to overcome. Separate tools are used for each NFC tag format. NFC itself is defined by an industry consortium (evidently led by NFC chipmaker NXP), but the radio frequency band (13.56 MHz) used is just about the only thing that any two randomly selected NFC tags are guaranteed to have in common. There is considerable variation in the storage capacity that any NFC tag will include, the format in which it stores data, and even the format of the tags' unique identifiers. Luckily only a few formats are in widespread use.
For example, the most common tags found in "large" devices like ID cards or keychains are of the "MiFare Classic" variety, which ranges in its storage capacity from one to four KB. The format includes a four-byte ID number and sets aside two blocks to store a pair of 64KB secret keys, plus a region that stores the permissions for accessing the contents of the rest of the storage. When one buys a bag of fresh MiFare Classic tags on eBay, they are supposed to come with no keys or access restrictions installed (and usually they do, of course, but it does not hurt to check).
The key slots and permissions block can be used to program the tags as secure tokens that protect the data placed in storage; one first writes in the keys, then programs the permissions (the values available include read, write, increment-only, and decrement-only). The key slots are designated A and B, but they are equivalent in all other respects (e.g., key A does not trump key B).
The makeup of the bytes stored in the slots is left up to the programmer: the tag's NFC chip simply compares the key presented by a tag reader with the contents of the slot to decide whether access should be granted; whether it is strong cryptographic key or arbitrary text is immaterial on the tag's end of the transaction. After writing in one or both keys, any tag reader that does not present a matching copy of a stored key will be denied access to the storage blocks, and any tag reader that does have a matching key will still be limited by the encoded access permissions.
In contrast, the "MiFare Ultralight" tag flavor is the one most commonly found in cheap NFC stickers. This tag format holds just 64 bytes of storage (plus a seven-byte serial number) and contains no keys or other features that could be used for higher-level authentication. In practice, though, this is enough to enable the simplest form of NFC tag usage: a program reads the serial number of a tag, then performs some pre-determined action in response. The 64-byte storage is also enough to store a moderate-sized string like a URL, so the stickers can be used to store or distribute such messages to readers.
The upshot of all this variety, though, is that libnfc provides separate tools for coping with each possible NFC tag type, and there is not much of a unified API available. For instance, to dump the contents of a MiFare Classic tag to a file, you could run:
nfc-mfclassic r a foo.mfd
This executes a read using key slot A for authentication (you would substitute the b flag to specifying key slot B if you have configured your own keys and permissions ahead of time). The MiFare Dump (MFD) file format produced can be parsed into a convenient, human-readable format with a variety of tools, such as Pavel Zhovner's mfdread. You can write to a tag using the w command instead of r; to copy your own keys to the tag, you supply them in a separate MFD file as the fourth argument:
nfc-mfclassic w a foodata.mfd fookeys.mfd
MiFare Ultralight tags, requiring no keys, have simpler tools as well:
nfc-mfultralight r foo.mfd
This performs a basic dump of the storage contents. I had no trouble reading and writing the tag collection I had picked up, but the libnfc suite does not make for a practical tool (for instance, one must know in advance what tag format is being read in order to interact with it). The libnfc site links to several projects that use the library, though they vary in freshness and a good percentage of them are not designed for Linux. For instance, there is a KDE4 plasmoid providing a unified interface to reading NFC tags, but it has since been discontinued, as has the D-Bus interface on which it was built.
The Linux NFC project, in contrast, is aiming for a practical framework that is also Linux-specific—and it is still actively developed. Neard will monitor an attached tag reader and send out D-Bus messages in response to NFC events. There is an API called NeardAL that comes with sample code for C. At the moment, the only tools available that work with neard are still of the manual, command-line variety. More importantly, neard does not yet seem to support the Adafruit breakout board, although it does support the board's NFC chip, so perhaps not all is lost.
Tag, you're it
Moving forward, neard and Linux NFC would appear to offer the best long-term solution. The project is set on eventually constructing modules that could be used by desktop developers, whereas the libnfc project seems content to provide a low-level library and not worry about the rest. For those who want to fool around with reading and writing tags today, however, libnfc allows you to do that.
In a way, the NFC situation is analogous to that of hardware sensors like
accelerometers, GPS receivers, and ambient light sensors. Phone
buyers expect their new devices to come with these sensors, so the
OEMs comply, and the software ecosystem quickly takes advantage of
them. That is why it is gratifying to see recent work on the desktop side
(such as Bastien Nocera's iio-sensor-proxy and Richard Hughes's
ColorHugALS) looking to close the gap. My hope would be that NFC
support on the desktop will catch up, too, given some time.
Posted May 29, 2015 15:25 UTC (Fri)
by foom (subscriber, #14868)
[Link]
NTAG203 or NTAG213 are a better option for standard tags.
Posted May 29, 2015 18:09 UTC (Fri)
by jnareb (subscriber, #46500)
[Link]
That specialized NFC devices (MiFare, PayPass ATM cards,...) do not speak it is another matter...
Posted May 29, 2015 23:05 UTC (Fri)
by gerdesj (subscriber, #5446)
[Link] (4 responses)
I had this idea that as I generally keep my mobile (cellphone) in my pocket then my laptop could unlock when it senses it and lock when I move away. I could override this with a password or a token or something if the laptop is on a desk and/or my mobile is in the car/toilet.
I was about to make a silly quip about waiting for pam_nfc to appear and then did a quick Google - http://nfc-tools.org/index.php?title=Pam_nfc . I even guessed the name correctly.
Play time!
Posted May 30, 2015 9:16 UTC (Sat)
by jnareb (subscriber, #46500)
[Link] (3 responses)
For "neighbourhood" (around 0.5 meter - 1 meter) unlocking you would need Bluetooth, I think.
Posted May 30, 2015 22:59 UTC (Sat)
by gerdesj (subscriber, #5446)
[Link] (2 responses)
Thanks for the response. This occurred to me shortly after I "paid by bonk" for a coffee today and had to contort myself to actually get at the bloody reader that was positioned badly by the till and other stuff on the counter.
NFC is clearly not what I'm looking for here unless I want to be seen playing pocket billiards whilst attempting to get my mobe and laptop in the right position. The left hand side USB ports are towards the rear (as I see it) of my laptop, near my knees, which is the side I usually have my mobile. Now the RHS ones are at the front - right next to my pocket.
Bluetooth it is then.
Posted May 31, 2015 22:18 UTC (Sun)
by dash (guest, #6182)
[Link] (1 responses)
Posted May 31, 2015 23:28 UTC (Sun)
by gerdesj (subscriber, #5446)
[Link]
Thanks for the heads up. As it turns out Gentoo is pretty multi-lingual and I'm sure it speaks Debian - I know it can deal with RedHat (but with a pretty bad accent)
Cheers
Posted Jun 30, 2015 13:41 UTC (Tue)
by hadess (subscriber, #24252)
[Link]
For example, I'd love to be able to tap my bike rental card, and see the last few trips I made through its website, or tap my credit card and be brought to my bank's login page. But I couldn't find generic ways to do this. But if you do, feel free to come talk to me about it :)
NFC programming on desktop Linux
NDEF format
NFC programming on desktop Linux
NFC programming on desktop Linux
NFC programming on desktop Linux
In that case you might be interested in BlueProximity which is packaged at least in Debian and derivatives.
NFC programming on desktop Linux
NFC programming on desktop Linux
Jon
Re: NFC programming on desktop Linux
