Table of Contents
Python
There are several Python libraries for interacting with smartcard and readers. We will be using pyscard, which contains both a higher level API and a low-level API for working directly with the C compiled pc/sc interface. Our focus will be on the higher-level API.
As a library, pyscard offers a higher-level interface than Java’s smartcardio, with things like event handling, signal listeners, and extensive documentation. The downside to this is that it takes a little more effort to get all of the library dependencies installed. In particular, psycard requires a non-Python development tool called SWIG which helps connect Python with the C/C++ pc/sc binaries. The pyscard library also requires that a native C/C++ compiler be installed on the system. As such, simply doing a pip install psycard
won’t cut it.
Installing on Windows
Installing Python and Pip
First, make sure that you have both Python 3 and Pip installed. You can test this by running python --version
and pip --version
from the command line. This guide was made using Python 3.6 and Pip 10, but any 3.x version should work. If you don’t have Python/Pip installed, then the recommended install method is to use the Windows package manager, Chocolatey.
You can install Chocolatey by running the following command from an administrative command prompt. Or you can download a standard installer from the website.
@"%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -InputFormat None -ExecutionPolicy Bypass -Command "iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))" && SET "PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin"
Once Chocolately is installed, run the following commands to install Python and Pip
choco install python3
choco install pip
Installing psycard and its dependencies
The first and easiest option is to use one of the pre-built binary installers available from AppVeyor. From the site, select the job that matches your preferred Python version and architecture. For Windows 10 on a 64-bit processor, you would choose the Python 3.6.x, ARCH=64 options. Next, select the ARTIFACTS tab, and then select the .msi installer file. Executing this file will install the needed dependencies along with the library itself.
When installing on Windows, you have two options. First, you can manually set up the dependencies by installing SWIG and Visual C++ 10.0. After both are installed, you can run pip install pyscard
.
Installation on Linux
Python and pip usually come pre-installed on Linux systems. However, these systems typically include both Python 2 and Python 3. On older systems, the command python
will refer to the 2.x version, while python3
will refer to the 3.x one. The same goes for pip. On some systems, there might be both a pip
and a pip3
. You can find out which version you have installed by running python --version
, and you can see the install location with a which python
command.
If you need to install python or pip, use the following commands:
sudo add-apt-repository ppa:deadsnakes/ppa
sudo apt-get update
sudo apt-get install python3.6 or sudo apt-get install python3.7
sudo apt-get install python3-pip
Next, install SWIG if it is not already present
sudo apt-get install swig3.0
Finally, install the pyscard library using pip. The pip installer will also use GCC to build several needed C files.
sudo pip install pyscard
Python and Virtual Envrionments
The above instructions will install the pyscard library globally on your system, making it available to every Python project on your system. This is not the preferred method for Python development. Instead, I recommend that you set up a virtual environment for each Python project, and then from within the environment, install any needed Python dependencies and libraries. By using a virtual environment you can pin down a specific Python and library version. A virtual environment also makes your app much easier to distribute.
The easiest way to get started using Python virtual environments is with the virtualEnvWrapper extension set. Setting up the extensions is fairly easy, but it does require that you edit your .bashrc
file on Linux, or your system path on Windows. Detailed instructions are available at Installation — virtualenvwrapper 6.1.2.dev4+g11fdae8 documentation
If you get an error when sourcing your updated .bashrc
, you may need to update an environmental variable. First, get the location of your Python install with a which python
. Then edit ~/.bashrc
and before the other virtualenvwrapper commands, add the following:
export VIRTUALENVWRAPPER_PYTHON=/path/to/python3
Once the wrapper is installed, you would then use the following commands to set up the environment:
# create a new directory for the project
mkdir -p /path/to/project # no -p on Windows
cd /path/to/project
# create and activate the virtual environment
mkvirtualenv -a /path/to/project smartcard
workon smartcard
Now that the environment is active, install any needed dependencies or libraries using pip
. These libraries will only be installed for the current project
pip install pyscard
Using pyscard
The library has some very good documentation available at pyscard user’s guide — pyscard 2.2.0 documentation. The following code mostly follows the example from their quick start guide.
Example 1
# example1
from smartcard.Exceptions import CardConnectionException, NoCardException
from smartcard.System import *
from smartcard import util
class MustBeEvenException(Exception):
pass
if __name__ == '__main__':
# get and print a list of readers attached to the system
sc_readers = readers()
print(sc_readers)
# create a connection to the first reader
first_reader = sc_readers[0]
connection = first_reader.createConnection()
# get ready for a command
get_uid = util.toBytes("FF CA 00 00 00")
alt_get_uid = [0xFF, 0xCA, 0x00, 0x00, 0x00] # alternative to using the helper
try:
# send the command and capture the response data and status
connection.connect()
data, sw1, sw2 = connection.transmit(get_uid)
# print the response
uid = util.toHexString(data)
status = util.toHexString([sw1, sw2])
print("UID = {}\tstatus = {}".format(uid, status))
except NoCardException:
print("ERROR: Card not present")
The above code is pretty self-explanatory and mirrors the code that was used in the Java example. One nice thing is that the library already includes several utility functions, so we don’t need to make our own. For the command, we use the utility function toBytes()
which converts a string of hexadecimal pairs (optionally separated by space) into an array. The alternative would be to use a list of integers, e.g. [0xFF, 0xCA, ...]
Next, we obtain a list of all of the attached card readers, connect to the first one, and the open a connection to the card. Once the connection is open, we can send commands and receive responses. All responses come in a three-tuple of (data, sw1, sw2)
, and we use a utility function to pretty print these as a hex string.
Example 2
One problem with the above workflow is that it assumes the card is present on the reader. But what if we want to wait until a card is activated, then run a command? This type of scenario is where pyscard really shines
# example2
from smartcard.CardRequest import CardRequest
from smartcard.Exceptions import CardRequestTimeoutException
from smartcard.CardType import AnyCardType
from smartcard import util
WAIT_FOR_SECONDS = 5
if __name__ == '__main__':
# respond to the insertion of any type of smart card
card_type = AnyCardType()
# create the request. Wait for up to x seconds for a card to be attached
request = CardRequest(timeout=WAIT_FOR_SECONDS, cardType=card_type)
# listen for the card
service = None
try:
service = request.waitforcard()
except CardRequestTimeoutException:
print("ERROR: No card detected")
exit(-1)
# when a card is attached, open a connection
conn = service.connection
conn.connect()
# get and print the ATR and UID of the card
get_uid = util.toBytes("FF CA 00 00 00")
print("ATR = {}".format(util.toHexString(conn.getATR())))
data, sw1, sw2 = conn.transmit(get_uid)
uid = util.toHexString(data)
status = util.toHexString([sw1, sw2])
print("UID = {}\tstatus = {}".format(uid, status))
Here we use the pyscard library to create a wait-loop for detecting the card. In this example we want to respond to any card type, but for most applications, you will use the ATRCardType()
class to specify the type of card to respond to. If the card is attached to the reader (or is already present) during the timeframe, the program continues. Otherwise, an exception is raised and the program halts.
If we wanted to operate on cards sequentially (to program a batch of cards for instance), we could easily attach another event that would execute when a card was removed and restart the wait-loop for the next.
Standards and Specifications
The following is a list and description of various standards that smart cards, smart card readers, smartcard communications protocols are based on. Many of the ISO standards are not free, and are quite expensive to legitimately purchase. Most of the other standards are available at no cost
ISO 14443
Identification cards – Contactless integrated circuit cards – Proximity cards
- ISO/IEC 14443 - Wikipedia
- ISO/IEC 14443-4:2018 - Cards and security devices for personal identification — Contactless proximity objects — Part 4: Transmission protocol
- 4 Parts:
- Part 1 - Physical Characteristics
- Part 2 - Radio frequency power and signal interface
- Part 3 - Initialization and anticollision
- Part 4 - Transmission protocol
- Two types of cards, Type A and Type B
- Both use same transmission protocol, but differ in modulation methods and coding schemes
ISO 18092 / ECMA-340
Near Field Communication Interface and Protocol-1 (NFCIP-1)
- Near-field communication - Wikipedia
- https://www.ecma-international.org/publications/standards/Ecma-340.htm (free)
- Publicly Available Standards (free)
- Section 12.4 details commands and structures
ISO 21481 / ECMA-352
Near Field Communication Interface and Protocol-1 (NFCIP-2)
- Near-field communication - Wikipedia
- https://www.ecma-international.org/publications/files/ECMA-ST/ECMA-352.pdf (free)
- This NFCIP-2 Standard specifies the mechanism to detect and select one of three communication modes (NFC, PCD, VCD)
- Not really applicable to programming NFC devices
ISO 7816
Smart Card Standard
- ISO/IEC 7816 - Wikipedia
- Large, 15 part standard for Smart Cards
- Several sections relevant for sending and processing commands
- Section 4 contains the syntax for APDU commands
- Sections 8 and 9 contain common commands
- Parts
- 7816-1:2011 Part 1: Cards with contacts—Physical characteristics
- 7816-2:2007 Part 2: Cards with contacts—Dimensions and location of the contacts
- 7816-3:2006 Part 3: Cards with contacts—Electrical interface and transmission protocols
- 7816-4:2013 Part 4: Organization, security and commands for interchange
- 7816-5:2004 Part 5: Registration of application providers
- 7816-6:2016 Part 6: Interindustry data elements for interchange
- 7816-7:1999 Part 7: Interindustry commands for Structured Card Query Language (SCQL)
- 7816-8:2016 Part 8: Commands and mechanisms for security operations
- 7816-9:2017 Part 9: Commands for card management
- 7816-10:1999 Part 10: Electronic signals and answer to reset for synchronous cards
- 7816-11:2017 Part 11: Personal verification through biometric methods
- 7816-12:2005 Part 12: Cards with contacts—USB electrical interface and operating procedures
- 7816-13:2007 Part 13: Commands for application management in a multi-application environment
- 7816-15:2016 Part 15: Cryptographic information application
PC/SC
The standard for integrating Smart Cards into computing environments
- https://www.pcscworkgroup.com/
- The Java Smart Card I/O API runs on top of the PC/SC Stack
- Tools and libraries:
- PCSC Lite: PC/SC compliant API for Linux (https://pcsclite.apdu.fr/)
- PCSC Tools: Linux tools for testing, reading, and sending PC/SC commands (pcsc-tools)
- PS/SC SDK for Windows: by SpringCard (PC/SC SDK - Download - SpringCard)
CCID (chip card interface device)
USB protocol that allows a smart card to be connected to a computer via a card reader
- CCID (protocol) - Wikipedia
- http://www.usb.org/developers/docs/devclass_docs/DWG_Smart-Card_CCID_Rev110.pdf
ATR - Answer to Reset
- CCID (protocol) - Wikipedia
- The ATR is provided when a card is first read. The historical section is vendor-dependent but it typically used to identify the type and capabilities of the card
NDEF - NFC Data Exchange Format