Hackernoon logoExamining Your EMV Chip Cards by@kennyshi

Examining Your EMV Chip Cards

Author profile picture

@kennyshiKenny Shi

Now we are a few years into EMV mandates in the US, we all have one or more EMV chip cards in our wallet and have used them in stores. 
In the old days, the curious bunch bought magnetic card readers to see what’s encoded in the mag stripe. These mag card readers, and many of the similar used in restaurants and stores, simply emulate keyboard input, so what's read when a card is swiped is sent through keyboard I/O to the operating system. Thus, opening Notepad allows us to see what's in the mag stripe.


Payment card footprint is ISO/IEC 7810 ID-1 standard. Payment card with Chip is conforming to ISO/IEC 7816, which is also called a Smart Card. Some of the professional grade laptops come with a built-in smart card slot (for access cards), but any USB smart card reader will do. For example, this one for $15. Most of them work with Windows and Mac, but if you are on Linux, chances are they will also work, but you might want to dig a little deeper.


You can certainly write your own software to interact with the reader. Or you can download and use free Smart Card Shell from CardContact Developer Network. You can get access to their git repository if you register with their developer network and store the access key in a SmartCard HSM.
Smart Card Shell is written in Java, so you want to have a JRE on your computer. The latest OpenJDK 14 works smoothly.
Once installed, there are 2 ways to run the shell. scsh3 (or scsh3.cmd) runs the shell in a command line console; scsh3gui (or scsh3gui.cmd) runs a simple GUI which has a a nice "trace" tab that logs not only what you explicitly print in your script, but also the raw interaction with the card.
Since we are interested in EMV, Smart Card Shell also provides EMV abstraction library to work with them.
You can git clone or download the scripts from https://github.com/CardContact/scsh-scripts
Now, insert an EMV chip card into your smart card reader, fire up the shell, and load the emv/dump.js script (make sure you have the right path to where the script is):
Congratulations! Now you have successfully peeked into your EMV card!

A Little Deep Dive

Let's look at dump.js
emv.js abstracts the operations supported by EMV, emvView.js pretty formats the data for display.
var card = new Card(_scsh3.reader);
Card is what Smart Card Shell provides as an abstraction to interact with smart cards. RESET_COLD is to power off and on to the card.

var aid = e.getAID();

if (aid != null) {
} else {
The very first step of an EMV processing is to select a Payment Service Envrionment (PSE). In general, there are contact and contactless environments. Since we are using a card reader which by definition is contact, selectPSE() with false to indicate it's not contactless.
An EMV card may support one or many "Applications" which are denoted by Application ID (AID). For example, Visa Credit has an AID, Visa Debit has a different AID, MasterCard has many AIDs for different products, etc. On a single card, it can support multiple AIDs, for example, both credit and debit; multiple AIDs are priorized.
Terminals have supported AIDs as provisioned by acquirers. So this is a handshake for the terminal and card to agree on which AID to process on. The complete list of AIDs can be found here. The sample script that simulates a terminal supports 3 AIDs, which can be found in emv.js:
EMV.AIDLIST = new Array();
EMV.AIDLIST[0] = { aid : "A00000002501", partial : true, name : "AMEX" };
EMV.AIDLIST[1] = { aid : "A0000000031010", partial : false, name : "VISA" };
EMV.AIDLIST[2] = { aid : "A0000000041010", partial : false, name : "MC" };
Each AID has specific File Control Information (FCI), which can be retrieved from card. FCI denotes how terminals can read the application data from the card. This can be seen from the tryAID() function in emv.js:
                var fci = this.select(aid, true);

                if (fci.length > 0) {
                        this.cardDE[EMV.AID] = aid;
Card can also decide which data are required from terminal before terminals start to read application data. Terminals format these Processing Data Object List (PDOL) and send them to cards in Get Processing Options operation. This is done in initApplProc() function in emv.js:
        var pdol = this.cardDE[EMV.PDOL];
        var pdolenc = null;

        if (typeof(pdol) != "undefined") {
                pdolenc = this.createDOL(pdol);
                var length = pdolenc.length
                var length = length.toString(HEX);
                if (pdolenc.length <= 0xF) {
                        length = "0".concat(length);
                var length = new ByteString(length, HEX);
                pdolenc = new ByteString("83", HEX).concat(length).concat(pdolenc);

        var data = this.getProcessingOptions(pdolenc);
Get Processing Options returns Application Interchange Profile (AIP), which processing steps are supported (card authentication, cardholder verification, etc.) for this transaction.
Now, the terminal can read the application data from the card. Application File Locator (AFL) has the instruction on how to read the data. AFL also indicates which data read are used in Data Authentication (DA) process. These are encoded in the 4 bytes for every Short File Identifier (SFI) inside AFL.
This is in emv.js:
        while(afl.length > 0) {
                var sfi = afl.byteAt(0) >> 3;   // Short file identifier
                var srec = afl.byteAt(1);       // Start record
                var erec = afl.byteAt(2);       // End record
                var dar = afl.byteAt(3);        // Number of records included in data authentication

                for (; srec <= erec; srec++) {
                        // Read all indicated records
                        var data = this.readRecord(sfi, srec);
                        print("Record No. " + srec);

                        // Decode template
                        var tl = new TLVList(data, TLV.EMV);
                        assert(tl.length == 1);
                        var t = tl.index(0);
                        assert(t.getTag() == EMV.TEMPLATE);

                        // Add data authentication input                        
                        if (dar > 0) {
                                if (sfi <= 10) {        // Only value
                                } else {                // Full template
At this point, we have all the code needed to read application data from EMV cards!

Examining Application Data

Let's go through the output.
<----------------------------Display Data Elements-----------------------------

Application Identifier (AID) - card: A000000025010801

Application Label: 414D45524943414E2045585052455353 - AMERICAN EXPRESS

Track 2 Equivalent Data (Magnetic Strip):
  Primary Account Number: 3712*******1009
  Expiration Date (YYMM): 2010
  Service Code: 201
  Discretionary Data: 15107427500000

Application Primary Account Number (PAN): 3712*******1009F
This part shows my American Express card, its AID, the track 2 data (track 2 is what's normally encoded in the mag stripe of a card, and is what's being transmitted for processing), and my PAN. Note I masked mine, but you should see the full PAN.
Application Interchange Profile: 3C00
  Byte 1:
    DDA supported (b6)
    Cardholder verification is supported (b5)
    Terminal risk management is to be performed (b4)
    Issuer authentication is supported (b3)
  Byte 2:
AIP data here:
  • Dynamic Data Authentication (DDA using 3 layers of RSA key pairs including one for the card itself) is supported, but not Static Data Authentication (SDA only CA and Issuer key pairs) for weak security
  • Cardholder Verification Methods (CVM) are supported (we will see what methods next)
  • Terminal Risk Management can make decisions on its own, ie. offline, to 1) force a transaction to go online; 2) check if recent transaction amounts exceed a floor limit set on the card; 3) if velocity exceeds a threshold set on the card. For the latter 2, terminal can reject the transactions without consulting issuers or networks
  • Issuer Authentication is where Issuer, after authorizes a transaction, sends authorization result as well as an application cryptogram called ARPC (Application ResPonse Cryptogram) back to terminal. The terminal can, if Issuer Authentication is supported on card as indicated by AIP, ask the card to verify the ARPC using the secret key the card shares with issuer.
Application Priority Indicator: 01
This selected AID has the highest priority, if there are multiple AIDs matching between terminal and card.
Card Risk Management Data Object List 1 (CDOL1): 9F02069F03069F1A0295055F2A029A039C019F3704
  9f02 - 6 - Authorised amount of the transaction (excluding adjustments)
  9f03 - 6 - Secondary amount associated with the transaction representing a cashback amount
  9f1a - 2 - Terminal Country Code
  95 - 5 - Terminal Verification Results
  5f2a - 2 - Transaction Currency Code
  9a - 3 - Transaction Date
  9c - 1 - Transaction Type
  9f37 - 4 - Unpredictable Number

Card Risk Management Data Object List 2 (CDOL2): 8A029F02069F03069F1A0295055F2A029A039C019F3704
  8a - 2 - Authorisation Response Code
  9f02 - 6 - Authorised amount of the transaction (excluding adjustments)
  9f03 - 6 - Secondary amount associated with the transaction representing a cashback amount
  9f1a - 2 - Terminal Country Code
  95 - 5 - Terminal Verification Results
  5f2a - 2 - Transaction Currency Code
  9a - 3 - Transaction Date
  9c - 1 - Transaction Type
  9f37 - 4 - Unpredictable Number
Card Risk Management Data Object List (CDOL) are the data elements needed to generate Application Cryptogram (AC). CDOL1 is the requirement to generate Application ReQuest Cryptogram (ARQC) by card and sent to issuer for authorization; CDOL2 is the requirement to generate Application ResPonse Cryptogram (ARPC) by issuer and returned in authorization message.
Cardholder Verification Method (CVM) List: 000000000000000042011E031F0200000000000000000000
  Apply succeeding CV Rule if this CVM is unsucccessful
    Enciphered PIN verified online
  If unattended cash

  Fail cardholder verification if this CVM is unsuccessful
    Signature (paper)
  If terminal supports the CVM

  Fail cardholder verification if this CVM is unsuccessful
    No CVM required
  If not unattended cash and not manual cash and not purchase with cashback

  Fail cardholder verification if this CVM is unsuccessful
    Fail CVM processing
Cardholder Verification Methods (CVM) is a prioritized list of rules.
For example, the first rule says if this card is used in an unattended cash transaction, require encrypted PIN online, if it fails, not the end of the world, try the next verification method that's applicable. The next one in line is "Signature (paper)" if terminal supports it. But most likely an unattended cash transaction wouldn't have the signature capability, for unattended cash, it will likely skip it.
The next one is "No CVM equired" but the condition explicitly excludes unattended cash. The final one is always "Fail CVM processing". So, in nutshell, for unattended cash transaction, one has to successfully pass online encrypted PIN verification.
If the transaction is credit card in store, it will activate "Signature (paper)" rule, the terminal will print a receipt with signature line, and instructs the store clerk to obtain customer signature.
If the transaction is credit card without cashback at a vending machine, it will activate "No CMV Required" rule, which doesn't need cardholder verification.
Certification Authority Public Key Index: 0F

Issuer Public Key Certificate: B0A3DCCD60AEEE9EEF61209A655F2E9646B8E8B8FF0F3315CE61BB942702F7D0ED9E6D512AD92D4AD8480B926553926EE50EF47B17E4428A778E7E7EA1C933FD03272D29B8D07E4C54928F169B672242524383A60836A04A70489F8B7AFA70AFD4C989A6BD1A0E25D7B4521D7D08920FC45E087375BEBD4AC04949A101C0A131CBDE121F7FE7E7A0E9730B9A5D0CE730C359D960420DDA241788D6BEE14D663D29176C9367D215B149208E2AF5D94099

Issuer Public Key Remainder: 24E5B52B
Issuer Public Key Exponent: 03

Application Currency Code: 0840

ICC Public Key Certificate: 83A1898AF7DE8CD7F8FD7BF008A17FB9612158DC1189EC4EF897BFD99271DAD2DD62087958C44FCA05DC069D6E3555BBA4A89B01ED089BC6796E93E2069574EF416F3C9C622D39B2C60A544E7B44F5FA1DD94AA84C6D47FB4C31A71FC5249AAD1DD5891C01BF5FB8E3EA620D6CA6519274F392B431E3F85ACBABBE60CDE3D8CE5ACABAEA5626540B2B79923D222914F8

ICC Public Key Exponent: 03

ICC Public Key Remainder: C14D885E3ADAC2431E49

Dynamic Data Authentication Data Object List (DDOL): 9F3704
&nbsp; 9f37 - 4 - Unpredictable Number

Static Data Authentication Tag List: 82
Certification Authority (CA) Public Keys are loaded on terminals by acquirers. CA in EMV context are card schemes (Visa, MasterCard, AMEX, etc.), each can have multiple public keys. Therefore an index is needed to indicate which public key is used to provision this card. The full list of CA public keys can be found here.
CA Public Key is used by terminal to restore Issuer Public Key from the Issuer Public Key Certificate.
The data structure holding Issuer Public Key is often too small for the complete key, therefore, the remainder in Issuer Public Key Remainder needs to be concatenated to the restored Issuer Public Key for completeness.
Similarly, for cards that support offline Dynamic Data Authentication, the ICC Public Key is also embedded in the card in the format of ICC Public Key Certificate. Issuer Public Key is used to restore ICC Public Key from ICC Public Key Certificate.
Similarly, ICC Public Key Remainder contains the overflow of the key.
Dynamic Data Authentication Data Object List (DDOL) denotes which data elements need to be used to run a Dynamic Data Authentication. In this case it's an unpreditable (random) number.
Static Data Authentication Tag List is the piece of original data together with ICC Public Key that are signed into the ICC Public Key Certificate. It is needed to verify if the ICC Public Key Certificate is authentic.
Application File Locator: 0801010008020201080405001002020018030300
  SFI: 1
  First/Only Record Number: 1
  Last Record Number: 1
  Number of records involved in offline data authentication: 0

  SFI: 1
  First/Only Record Number: 2
  Last Record Number: 2
  Number of records involved in offline data authentication: 1

  SFI: 1
  First/Only Record Number: 4
  Last Record Number: 5
  Number of records involved in offline data authentication: 0

  SFI: 2
  First/Only Record Number: 2
  Last Record Number: 2
  Number of records involved in offline data authentication: 0

  SFI: 3
  First/Only Record Number: 3
  Last Record Number: 3
  Number of records involved in offline data authentication: 0
AFL indicates how to read application data from the card, and which ones are used in data authentication (see above)
Application Usage Control: FF00
  Byte 1:
    Valid at terminals other than ATMs
    Valid at ATMs
    Valid for international services
    Valid for domestic services
    Valid for international goods
    Valid for domestic goods
    Valid for international cash transactions
    Valid for domestic cash transactions
  Byte 2:
The card also dictates which use cases are supported. If a terminal's use case isn't supported in this list, terminal should fail the transaction.

Further Experiment

A sample script doemv.js is also included in the git repository. This script not only dumps the data from EMV cards, but also attempts to
  1. do a Static Data Authentication (SDA)
  2. do a Dynamic Data Authentication (DDA)
  3. generate an Application Cryptogram (AC)
Note that many new EMV cards do not support SDA (like mine). If your dump of AIP says only DDA is supported, please comment out the SDA code invocation in doemv.js:
Also important, the CA Public Keys stored in git repository are incomplete, in fact, it only contains a subset of Visa public keys. So in order to support your card, you may need to supplement it with the public key needed by your card.
To find which CA public key is needed, add a debug print in dataAuthentication.js to print out rid and index:
DataAuthentication.prototype.getSchemePublicKey = function() {
        var rid = this.getRID();
        var index = this.getPubKeyIndex();

        print("rid="+rid+", index="+index);
Then look up the CA Public Key here by rid and index. For example, my AMEX card's rid is A000000025 and index is 0F, so the missing public key is
and key length is 1408.
Add a new XML inside schemepublickey directory (this directory is in parallel to emv.js), similar to the Visa public key XMLs already there. Make sure you replace the followings correctly:
  • <gp:Component Name="MODULUS" Encoding="HEX" Value=""> The value here is the public key looked up above.
  • <gp:KeyInfo Name="RSAPublic" Type="PUBLIC" SubType="RSA" Size="" Mode="PROD"/> The size here is the key length above.
Then, in doemv.js, add the new XML to the public key list:
var d = new DataAuthentication(e);
d.addSchemePublicKey(new ByteString("A000000003", HEX), 1, new Key("schemepublickeys/kp_visa_1024_01.xml"));
d.addSchemePublicKey(new ByteString("A000000003", HEX), 7, new Key("schemepublickeys/kp_visa_1152_07.xml"));
d.addSchemePublicKey(new ByteString("A000000003", HEX), 8, new Key("schemepublickeys/kp_visa_1408_08.xml"));
d.addSchemePublicKey(new ByteString("A000000003", HEX), 9, new Key("schemepublickeys/kp_visa_1984_09.xml"));

// add more ...
// add more ...
// add more ...

Further Reading

What's illustrated and explained in this article is the tip of an iceberg. EMV specification is gigantic and complicated and sometimes confusing.
Here are some useful links:
Have fun!


The Noonification banner

Subscribe to get your daily round-up of top tech stories!