In short, this post explains how to initialize an ISO 14443-A smart card with short or standard frame thanks to the hydra NFC v2 console. Straightforwardly, you will be able to send correct commands or ill-formed command to fuzz a card. In a next post, we will see how to initialize an ISO 14443-B smart card and how to build TPDUs commands.
In a previous post, we saw how to connect automatically to a smart card, and then exchange APDUs commands. But, how to initialize a card and what is the communication protocol used to transmit the APDU? In this post, we will focus on the ISO 14443 norm since most of the banking smart cards use it (as well electronic passport). More especially, we will talk about the initialization of an ISO 14443-A card with the Hydra NFC v2 console.
Within this norm, a card can be the A or the B type. Four parts explain it:
- ISO 14443 Part 1 & 2.
- It explains how the signal must be modulated. We won’t talk about it in this post.
- ISO 14443 Part 3.
- It defines the initialization sequence which is different between type A & B.
- It explains how a communication frame must be built.
- ISO 14443 Part 4. It defines the transmission protocol based on the Transport Data Protocol Unit (TPDU) which is common to type A & B:
- It details initialization commands for instance when the card indicates its communication capacity (communication speed, block size), and the reader can indicate which one to use.
- How to exchange data thanks to the TPDUs.
ISO 14443-A Initialization sequence
We connect with picocom (but you could use putty as well).
$ picocom -b 115200 /dev/ttyACM0 Type [C-a] [C-h] to see available commands Terminal ready >
This time, we don’t enter in “nfc” menu, but in “dnfc”.
> dnfc HydraNFC Shield v2 initialized with success. Device: SPI2 GPIO resistor: floating Mode: master Frequency: 10.50mhz (160khz, 320khz, 650khz, 1.31mhz, 2.62mhz, 5.25mhz, 21mhz) Polarity: 0 Phase: 1 Bit order: MSB first
If we type “help”, we see there is a lot of commands! This menu can be considered as the low-level command sandbox . Don’t worry, we will not use all the commands!
dnfc2> help Configuration: spi2 [frequency (value hz/khz/mhz)] Interaction: [cs-on/cs-off] <read/write (value:repeat)> [exit] show Show DNFCv2 parameters frequency Set SPI Bus frequency trigger Setup DNFCv2 SPI2 trigger set-nfc-mode Set NFC Mode and TX/RX BitRate in kbit/s get-nfc-mode Get NFC Mode rf-off-on Set RF field off/on reqa Send ISO 14443-A REQA wupa Send ISO 14443-A WUPA send Send bytes according to the selected mode send-auto Send bytes according to the selected mode and add the two-bytes CRC nfc-transp Enter NFC Transparent Mode nfc-stream Enter NFC Stream Mode read SPI Read byte (repeat with :<num>) hd SPI Read byte (repeat with :<num>) and print hexdump write SPI Write byte (repeat with :<num>) <integer> SPI Write byte (repeat with :<num>) <string> SPI Write string cs-on SPI Alias for "chip-select on" cs-off SPI Alias for "chip-select off" [ SPI Alias for "chip-select on" ] SPI Alias for "chip-select off" & Delay 1 usec (repeat with :<num>) % Delay 1 msec (repeat with :<num>) ~ SPI Write a random byte (repeat with :<num>) A Toggle AUX(PC4) high a Toggle AUX(PC4) low @ Read AUX(PC4) exit Exit DNFCv2 mode
Let see the “set-nfc-mode” command.
dnfc2> help set-nfc-mode Set NFC Mode and TX/RX BitRate in kbit/s nfc-mode Set NFC Mode POLL_NFCA=1, POLL_NFCA_T1T=2, POLL_NFCB=3, POLL_B_PRIME=4, POLL_B_CTS=5, POLL_NFCF=6, POLL_NFCV=7 POLL_PICOPASS=8, POLL_ACTIVE_P2P=9, LISTEN_NFCA=10, LISTEN_NFCB=11, LISTEN_NFCF=12, LISTEN_ACTIVE_P2P=13 nfc-mode-tx_br Set TX BitRate BR_106=0, BR_212=1, BR_424=2, BR_848=3, BR_52p97=235, BR_26p48=236, BR_1p66=237 nfc-mode-rx_br Set RX BitRate BR_106=0, BR_212=1, BR_424=2, BR_848=3, BR_52p97=235, BR_26p48=236, BR_1p66=237
We select ISO 14443-A type: the reader will send data with the modulation required by the type A. We keep the default bitrate for transmission and reception.
dnfc2> set-nfc-mode nfc-mode 1 nfc-mode = 1 nfc-mode-tx_br = 0 nfc-mode-rx_br = 0 rfalSetMode OK
We deactivate/activate the RF field to restart our card.
First, the REQA command is sent to detect a card. It is a short frame meaning only 7 coding bits are sent. To ease your understanding, we will not talk about the “protocol bits” in this post, as the start/stop bits and so on. The REQA value is 0x26.
dnfc2> reqa 04 00
Our card is detected since we receive a response: the Answer To Request, named ATQA!
Once a card was detected, we must execute an anti-collision sequence to select it: the reader asks the card UID, and then send it back to confirm that it wants to talk with it. Another aim of this sequence is to be able to correctly select a specific card when several cards answered the REQA. We will not cover this case, and consider that only one card was detected.
Now, the communication is based on a standard frame, meaning packet of full bytes (ie 8 bits) are sent. Most of the time, a two-byte Cyclic Redundancy Check error code is added at the end of the data to check their integrity. It is specific to the type A, so we named it CRC_A. It is defined in ISO/IEC 13239. Once again, we make a little approximation about the standard frame, it means we do not take about the start/end bit, as well the parity bit. We just talk about coding bit.
First, we send the Select Cascade Level 1 command:
|Select Cascade Level 1 command||The high nibble 2 means we send 2 bytes. The low nibble means we add 0 bits in the command. For instance, if the value was 23, it means we would send 2*8 + 3 = 11 bits.|
We use the send command to communicate them to the card. This command sends only the given bytes according to the selected mode.
dnfc2> send 9320 B9 CC 13 71 17
We received the first 4 UID bytes of the card.
|Card UID||BCC. It corresponds to the xor |
of the 4 previous bytes.
|B9 CC 13 71||17||Hum… Nothing, because we do not |
display it for the moment :). We will
add an option to display it or not.
Now, we send back a Select Cascade Level 1 command with the UID to indicate that we want to select this card. This time, we must add a CRC_A in the command. To avoid computing yourself the CRC, you can use the send-auto command that will automatically compute and add the CRC according to the selected mode.
|Select Cascade Level 1 command||This time we send|
7 bytes (without including the
|The card UID + BCC||Automatically|
We receive the SAK (Select Acknowledge) indicating the anti-collision sequence is finished.
dnfc2> send-auto 9370B9CC137117 20
The third bit of the SAK equals 0: it means we received the full card UID. In fact, it size could be 4, 7 or 10 bytes. In this case, we shall have used Select Cascade Level 2 or 3 commands.
Request for answer to select (RATS)
Ok, so the reader and the card agreed to talk together. Now, the reader can inform the card about its communication preferences with the RATS command. It enables to indicate to the card:
- the Frame Size for proximity coupling Device Integer (FSDI) (high nibble). This integer indicates the maximum frame size that we’ll be sent by the reader (Frame Size for proximity coupling Device or FSD). It is typically the thing you would like to set to its lowest value, and then send a frame with a bigger value 🙂 .
|FSD (in bytes)||16||24||32||40||48||64||96||128||256||RFU|
- the CID. It enables to indicate the channel number. We set it to 0.
|Start byte||Parameter||CRC A|
|E0||00 (High nibble: FSDI, low nibble CID)||Automatically|
We send the command.
dnfc2> send-auto E000 0A 78 80 82 02 20 63 CB A3 A0
The card answers with the Answer to select (ATS) its communication options: its frame size, the presence of specific bytes, communication speed…
|0A||Length of the full command (this byte included) without the CRC_A|
|78||7: Bytes TA1/TB1/TC1 transmitted|
8: FSCI. It is like the FDSI but for the card. So, it tells the reader that it can send up to 256 bytes.
|80||TA1. It indicates the card supported communication speed.|
|82||TB1. It deals with delay between the frames.|
|02||TC1. It indicates if optional byte will be present in the TPDU header.|
|20 63 CB A3 A0||Historical bytes. It can gives other information about the card.|
Protocol and parameter selection request (PPS)
Finally, the reader can send a PPS to customize the communication speed. We send here a default value where no modification is done (and the speed modification is not implemented in this command).
dnfc2> send-auto D001 D0
The card acknowledges our parameters. And now, we are ready to send TPDUs!
In fact, all the initialization sequence was done automatically done with the connect command that we saw in the previous post. Do you remember?
> nfc NFCv2> connect > 26 < 04 00 > 93 20 < B9 CC 13 71 17 > 93 70 B9 CC 13 71 17 < 20 > E0 00 < 0A 78 80 82 02 20 63 CB A3 A0 > D0 01 < D0 ISO 14443-A card detected.
Another fun fact, the ISO 14443-A norm is used for the electronic passport. If you try to connect twice to your passport for instance with the connect command in the nfc menu, you will see the UID is not the same:
NFCv2> connect > 26 < 04 00 > 93 20 < 08 99 8B 85 9F [Line removed...] NFCv2> connect > 26 < 04 00 > 93 20 < 08 46 13 2C 71 [Line removed...] NFCv2>
It is weird. First time, the card UID is 99 8B 85 9F, and the second time it is 46 13 2C 71. A card UID is supposed be static, no? Yes, but for anonymity reason, and to prevent tracing someone with its ePassport UID, it is mandatory that the returned value is random.
We saw that we can perform the initialization sequence of an ISO 14443-A card within the Hydra NFC v2 menu:
- We can send short frame like the REQA.
- We can send raw standard frame, with or without the automatic computation of the CRC_A. So, you can send correct frame, or random data to fuzz the card.
In a next post, we will send:
- How to initialize an ISO 14443-B smartcards.
- How to build TPDUs.
- And how to script all these commands with Python.
In short, this post explains how to exchange APDU commands straightforwardly with contactless smartcards thanks to the Hydra NFC v2, either with a serial console or a python driver. As you control any bytes sent to the card, you can send ill-formed command to fuzz a card at the APDU level. In a next post, we will see how to send commands at a lower level with TPDUs commands or ISO 14433 initialization commands. Fuzzing at this level would be far more efficient.
APDU: the basic communication structure
How works a communication between a reader and a smartcard?
- The reader initializes the communication. The RF field is activated, and several low level commands are exchanged to detect a compatible card.
- Then, the reader exchange information with the card using the APDU (Application Protocol Data Unit) protocol. It sends a command to the card, which then answer back with a response.
What is the structure of an APDU? Hereafter, you have the generic format of a command.
|INS||Instruction byte. It characterizes the type of command.|
|P1||Parameter byte 1. It is an option related to the INS field.|
|P2||Parameter byte 2. It is an option related to the INS field.|
|Lc||Length of the Data field|
|Le||Number of bytes expected in the card response|
And below, you have the generic format of a response.
|Data||Card response (optional)|
|Status Word||2 bytes named SW1 & SW2|
We know the format of the APDUs. But which information is exchanged?
- Several applications can be embedded by the card, so the reader must select the one to use.
- Then, you can have command enabling to read information about the card.
- Finally, some of them enable to make payment:
- The terminal wants to make a payment. It sends a command indicating among other things the amount, the date, the currency.
- The card checks if the information is correct, for instance if the amount is not too high. If it is accepted, its response will contain a cryptogram to prove the transaction was certified.
- The terminal extracts this cryptogram, and check it to validate the transaction.
Sending APDU with the Hydra NFC v2
The goal of this post is not to explain all the commands of a transaction, but just to show you can send APDUs sraighforwardly with the Hydra NFC.
We saw that the reader needs to select the card payment application:
- But it does know which application is embedded: Mastercard, Visa …
- So, he selects a special application available on all the smart cards. Its response will list all the installed applications. Its name is 2PAY.SYS.DDF01.
- The APDU command to send is described below:
|INS||A4 (Select command)|
|P2||04 (The application name is set in the Data field)|
|Data||32 50 41 59 2E 53 59 53 2E 44 44 46 30 31 (the application name in hexadecimal)|
Let use the Hydra NFC v2!
We connect with picocom (but you could use putty as well).
$ picocom -b 115200 /dev/ttyACM0 Type [C-a] [C-h] to see available commands Terminal ready >
We type “help” to list the available commands.
> help Available commands help Available commands history Command history clear Clear screen show Show information logging Turn logging on or off sd SD card management nfc NFCv2 mode dnfc Debug/Developer NFCv2 mode debug Debug mode >
We select the nfc menu, and type once again help to get information.
> nfc NFCv2> help NFCv2 mode sd SD card management show Show NFC parameters nfc-all Select technology NFC-A/B/V/F nfc-a Select technology NFC-A (ISO14443A includes MIFARE...) nfc-b Select technology NFC-B (ISO14443B) nfc-st25tb Select technology NFC-B (ISO14443B ST25TB) nfc-v Select technology NFC-V Vicinity (ISO/IEC 15693) nfc-f Select technology NFC-F Felica scan Scan selected technology (NFC-A/B/V/F...) emul-3a Emul Tag ISO14443A ce Set Tag properties for Card Emulation (UID, SAK, T4T params...) emul-t4t Emulate Type 4 Tag with preset Tag properties connect Connect to a smartcard (ISO 14443 A & B) connect-opt Set options for connect & send commands send Send APDU data to a card initialized with the connect command (only ISO 14443 A & B tags) exit Exit NFC mode
We use the connect command to detect and initializes smart card.
NFCv2> connect > 26 < 04 00 > 93 20 < B9 CC 13 71 17 > 93 70 B9 CC 13 71 17 < 20 > E0 00 < 0A 78 80 82 02 20 63 CB A3 A0 > D0 01 < D0 ISO 14443-A card detected.
An ISO 14443-A card was discovered, and some information were exchanged. We will talk about it later.
Know, we can send the APDU command with “send”.
NFCv2> send 00A404000E325041592E5359532E444446303100 > 1A 00 00 A4 04 00 0E 32 50 41 59 2E 53 59 53 2E 44 44 < AA 00 > 0B 00 46 30 31 00 < 1B 00 6F 57 84 0E 32 50 41 59 2E 53 59 53 > BA 00 < 1A 00 2E 44 44 46 30 31 A5 45 BF 0C 42 61 > BB 00 < 1B 00 1B 4F 07 A0 00 00 00 42 10 10 50 02 > BA 00 < 1A 00 43 42 87 01 01 9F 28 08 40 02 00 00 > BB 00 < 1B 00 00 00 00 00 61 23 4F 07 A0 00 00 00 > BA 00 < 1A 00 04 10 10 50 0A 4D 41 53 54 45 52 43 > BB 00 < 1B 00 41 52 44 87 01 02 9F 28 08 40 00 20 > BA 00 < 0A 00 00 00 00 00 00 90 00 6F 57 84 0E 32 50 41 59 2E 53 59 53 2E 44 44 46 30 31 A5 45 BF 0C 42 61 1B 4F 07 A0 00 00 00 42 10 10 50 02 43 42 87 01 01 9F 28 08 40 02 00 00 00 00 00 00 61 23 4F 07 A0 00 00 00 04 10 10 50 0A 4D 41 53 54 45 52 43 41 52 44 87 01 02 9F 28 08 40 00 20 00 00 00 00 00 90 00
The APDU response is: 6F 57 84 0E 32 50 41 59 2E 53 59 53 2E 44 44 46 30 31 A5 45 BF 0C 42 61 1B 4F 07 A0 00 00 00 42 10 10 50 02 43 42 87 01 01 9F 28 08 40 02 00 00 00 00 00 00 61 23 4F 07 A0 00 00 00 04 10 10 50 0A 4D 41 53 54 45 52 43 41 52 44 87 01 02 9F 28 08 40 00 20 00 00 00 00 00 90 00.
We can interpret the data with emvlab.org/tlvutils. We will see later the meaning of the command line starting with a “>” or a “<“.
OK, but what happens if you want to send a lot of commands? And parse their results to create the next commands? It will be very tedious to forge/analyze them one by one…
No problems, there is a python driver to do it!
Hydra NFC v2 python driver
There is another way to communicate with a python driver https://github.com/gvinet/pynfcreader:
- It does not simply create a serial communication and send the commands that we saw previously.
- In fact, it uses a dedicated mode of the HydraNFC v2 named BBIO. In short, it enables to send short binary commands, instead of huge ASCII text.
Let see a script to communicate with our card:
import time from pynfcreader.devices.hydra_nfc_v2 import HydraNFCv2 from pynfcreader.sessions.iso14443.iso14443a import Iso14443ASession hydra_nfc = HydraNFCv2(port="/dev/ttyACM1", debug=False) hn = Iso14443ASession(drv=hydra_nfc, block_size=250) hn.connect() hn.field_off() time.sleep(0.1) hn.field_on() hn.polling()
With this driver:
- you can scripts your commands,
- and you can use it easily with a lot of python library enabling to communicate with contactless smart card.
So with the Hydra NFC v2:
- You have a contactless smart card reader available either with a serial console or a Python library.
- You can send incorrect APDU commands to fuzz the smartcards.
But, there still other fun things to do:
- The APDUs are not directly exchanged between the reader and the card. They are encapsulated in Transport Protocol Data Unit (TPDU) frames. It could be fun to able to send.
- In the same way, specific commands are sent to detect and intialize the card.
In the previous outputs, these commands correspond to the line starting with a “>” or a “<“, for instance:
- A REQA: “> 26”
- A TDPU: “> 1A 00 00 A4 04 00 0E 32 50 41 59 2E 53 59 53 2E 44 44”
The TPDU and the initialisation sequence is described by the ISO 14443 norm. In a next post, we will explain this communication protocol, and see how it’s easy to play with it thanks to the Hydra NFC v2!