Reading NFC Card ID on Ubuntu


27 Sep 2017 / by KhanhIceTea

Prerequisites

Install driver

My device is ACS122U : http://www.acs.com.hk/en/products/3/acr122u-usb-nfc-reader/#tab_downloads

Kernel modules

# echo "uinput" >> /etc/modules
# echo "install nfc /bin/false" >> /etc/modprobe.d/blacklist.conf
# echo "install pn533 /bin/false" >> /etc/modprobe.d/blacklist.conf

Install packages

sudo apt-get install swig libccid pcscd libpcsclite-dev libpcsclite1 python-dev python-pip gcc linux-headers-$(uname -r)

Run service

sudo service pcscd restart

Install python packages

sudo pip install pyscard python-uinput evdev

Source code

This is source code that read the card ID and simulate keystrokes to type card ID by text then pressing ENTER key.

#! /usr/bin/env python

from __future__ import print_function
from time import sleep

from smartcard.CardConnectionObserver import ConsoleCardConnectionObserver
from smartcard.CardMonitoring import CardMonitor, CardObserver
from smartcard.util import toHexString
from evdev import UInput, ecodes
import uinput


device = uinput.Device([uinput.KEY_0, uinput.KEY_1, uinput.KEY_2, uinput.KEY_3, uinput.KEY_4, uinput.KEY_5, uinput.KEY_6, uinput.KEY_7, uinput.KEY_8, uinput.KEY_9, uinput.KEY_A, uinput.KEY_B, uinput.KEY_C, uinput.KEY_D, uinput.KEY_E, uinput.KEY_F, uinput.KEY_G, uinput.KEY_H, uinput.KEY_I, uinput.KEY_J, uinput.KEY_K, uinput.KEY_L, uinput.KEY_M, uinput.KEY_N, uinput.KEY_O, uinput.KEY_P, uinput.KEY_Q, uinput.KEY_R, uinput.KEY_S, uinput.KEY_T, uinput.KEY_U, uinput.KEY_V, uinput.KEY_W, uinput.KEY_X, uinput.KEY_Y, uinput.KEY_Z, uinput.KEY_TAB])


def card_id_to_keyboards(card_id):
    id = card_id.replace(' ', '')

    return [getattr(uinput, 'KEY_'+x.upper()) for x in id]


# a simple card observer that tries to select DF_TELECOM on an inserted card
class selectDFTELECOMObserver(CardObserver):
    """A simple card observer that is notified
    when cards are inserted/removed from the system and
    prints the list of cards
    """

    def __init__(self):
        self.observer = ConsoleCardConnectionObserver()

    def update(self, observable, actions):
        try:
            (addedcards, removedcards) = actions
            for card in addedcards:
                print("+Inserted: ", toHexString(card.atr))
                card.connection = card.createConnection()
                card.connection.connect()
                card.connection.addObserver(self.observer)
                apdu = [0xFF, 0xCA, 0x00, 0x00, 0x00]
                response, sw1, sw2 = card.connection.transmit(apdu)
                keys = card_id_to_keyboards(toHexString(response))
                for key in keys:
                    device.emit_click(key)
                ui = UInput()
                ui.write(ecodes.EV_KEY, ecodes.KEY_ENTER, 0)
                ui.write(ecodes.EV_KEY, ecodes.KEY_ENTER, 1)
                ui.syn()
                ui.close()
            for card in removedcards:
                print("-Removed: ", toHexString(card.atr))
        except:
            pass

if __name__ == '__main__':
    print("Insert or remove a SIM card in the system.")
    print("This program will exit in 60 seconds")
    print("")
    cardmonitor = CardMonitor()
    selectobserver = selectDFTELECOMObserver()
    cardmonitor.addObserver(selectobserver)

    sleep(86400)

    # don't forget to remove observer, or the
    # monitor will poll forever...
    cardmonitor.deleteObserver(selectobserver)

    import sys
    if 'win32' == sys.platform:
        print('press Enter to continue')
        sys.stdin.read(1)

Run

$ sudo python main.py

Demo

This is my demo application that using card ID like a user password, so I can unlock my computer or enter sudo mode :D

It Just Works

If you want a "just-work" solution, checkout this repo. It is built on Java smartcardio.

$ java -jar rfid-reader2keyboard.jar

Good luck ! ;)


Sound good ?