Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to read file from smart card using java

I am new in smart card technology. I want to read file from smart card. I am using javax.smartcardio to read value. I developed some code to connecting system to card (That's work fine). I have card ATR and other detail also. But not getting proper help for APDU command for communication with Smart card. Stuck in APDU command.

like image 641
Krunal Indrodiya Avatar asked Apr 18 '16 12:04

Krunal Indrodiya


2 Answers

First of all:

"Not" all Java cards have MF, DF and EF inside! These words stands for Master File, Dedicated File and Elementary File in order. They are components of an ISO7816-defined system file for smart card (refer to part 4 of ISO7816), so your card maybe or maybe not have this file system.

Typical java cards have a storage that you can install your applets in it (after a successful authentication for sure) and register name of your applet (we call it AID, that stands for Applet IDentifier and it is a 5 to 16 byte hexadecimal sequence) in the card's registry table (a table of loaded/installed applets and packages that contain life-cycles and priviledges too - read Global Platform Card Spec).

And then:

Let assume that you have a smart card inserted in your card reader that is connected to your computer. You have different options to have a communication between your computer and the card.

1-You can use available tools such as your reader's tool (almost all readers have one tool), PyAPDUTool, etc.

2-You can use Javax.smartcardio library for writing your Java program to communicate with smart cards:

import java.util.List;
import java.util.Scanner;
import javax.smartcardio.Card;
import javax.smartcardio.CardChannel;
import javax.smartcardio.CardException;
import javax.smartcardio.CardTerminal;
import javax.smartcardio.CommandAPDU;
import javax.smartcardio.ResponseAPDU;
import javax.smartcardio.TerminalFactory;
import javax.xml.bind.DatatypeConverter;

public class TestPCSC {

    public static void main(String[] args) throws CardException {

        TerminalFactory tf = TerminalFactory.getDefault();
        List< CardTerminal> terminals = tf.terminals().list();
        System.out.println("Available Readers:");
        System.out.println(terminals + "\n");

        Scanner scanner = new Scanner(System.in);
        System.out.print("Which reader do you want to send your commands to? (0 or 1 or ...): ");
        String input = scanner.nextLine();
        int readerNum = Integer.parseInt(input);
        CardTerminal cardTerminal = (CardTerminal) terminals.get(readerNum);
        Card connection = cardTerminal.connect("DIRECT");
        CardChannel cardChannel = connection.getBasicChannel();

        System.out.println("Write your commands in Hex form, without '0x' or Space charaters.");
        System.out.println("\n---------------------------------------------------");
        System.out.println("Pseudo-APDU Mode:");
        System.out.println("---------------------------------------------------");
        while (true) {
            System.out.println("Pseudo-APDU command: (Enter 0 to send APDU command)");
            String cmd = scanner.nextLine();
            if (cmd.equals("0")) {
                break;
            }
            System.out.println("Command  : " + cmd);
            byte[] cmdArray = hexStringToByteArray(cmd);
            byte[] resp = connection.transmitControlCommand(CONTROL_CODE(), cmdArray);
            String hex = DatatypeConverter.printHexBinary(resp);
            System.out.println("Response : " + hex + "\n");
        }

        System.out.println("\n---------------------------------------------------");
        System.out.println("APDU Mode:");
        System.out.println("---------------------------------------------------");

        while (true) {
            System.out.println("APDU command: (Enter 0 to exit)");
            String cmd = scanner.nextLine();
            if (cmd.equals("0")) {
                break;
            }
            System.out.println("Command  : " + cmd);
            byte[] cmdArray = hexStringToByteArray(cmd);
            ResponseAPDU resp = cardChannel.transmit(new CommandAPDU(cmdArray));
            byte[] respB = resp.getBytes();
            String hex = DatatypeConverter.printHexBinary(respB);
            System.out.println("Response : " + hex + "\n");
        }

        connection.disconnect(true);

    }

    public static int CONTROL_CODE() {
        String osName = System.getProperty("os.name").toLowerCase();
        if (osName.indexOf("windows") > -1) {
            /* Value used by both MS' CCID driver and SpringCard's CCID driver */
            return (0x31 << 16 | 3500 << 2);
        } else {
            /* Value used by PCSC-Lite */
            return 0x42000000 + 1;
        }

    }

    public static byte[] hexStringToByteArray(String s) {
        int len = s.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                    + Character.digit(s.charAt(i + 1), 16));
        }
        return data;
    }

}

3- You can use PySCard library to write your Python program to communicate with smart cards:

#Importing required modules.
import sys
import time
#--- You may need to change the following "line" based on your pyScard library installation path
sys.path.append("D:\\PythonX\\Lib\\site-packages")
from smartcard.scard import *
import smartcard.util
from smartcard.System import readers


#---This is the list of commands that we want to send device
cmds =[[,0xFF,0x69,0x44,0x42,0x05,0x68,0x92,0x00,0x04,0x00],]


#--- Let's to make a connection to the card reader
r=readers()
print "Available Readers :",r
print
target_reader = input("--- Select Reader (0, 1 , ...): ")
print

while(True):
    try:
        print "Using :",r[target_reader]
        reader = r[target_reader]
        connection=reader.createConnection()
        connection.connect()
        break
    except:
        print "--- Exception occured! (Wrong reader or No card present)"
        ans = raw_input("--- Try again? (0:Exit/1:Again/2:Change Reader)")
        if int(ans)==0:
            exit()
        elif int(ans)==2:
            target_reader = input("Select Reader (0, 1 , ...): ")

#--- An struct for APDU responses consist of Data, SW1 and SW2
class stru:
    def __init__(self):
        self.data = list()
        self.sw1 = 0
        self.sw2 = 0

resp = stru()

def send(cmds):
    for cmd in cmds:

        #--- Following 5 line added to have a good format of command in the output.
        temp = stru() ;
        temp.data[:]=cmd[:]
        temp.sw1=12
        temp.sw2=32
        modifyFormat(temp)
        print "req: ", temp.data

        resp.data,resp.sw1,resp.sw2 = connection.transmit(cmd)
        modifyFormat(resp)
        printResponse(resp)

def modifyFormat(resp):
    resp.sw1=hex(resp.sw1)
    resp.sw2=hex(resp.sw2)   
    if (len(resp.sw2)<4):
        resp.sw2=resp.sw2[0:2]+'0'+resp.sw2[2]
    for i in range(0,len(resp.data)):
        resp.data[i]=hex(resp.data[i])
        if (len(resp.data[i])<4):
            resp.data[i]=resp.data[i][0:2]+'0'+resp.data[i][2]

def printResponse(resp):
    print "res: ", resp.data,resp.sw1,resp.sw2


send(cmds)
connection.disconnect()

4- You can use WinSCard library to write your program in C++/.Net (Not sure) to communicate with smart cards.

Above programs are sample programs to send APDU commands to smart cards. But the commands themselve are depend on your card and the applets that [your] are installed on it.

For example let assume that you are write an applet with AID = 01 02 03 04 05 00 that returns 11 22 33 44 55 when it receive 00 00 00 00 00 as APDU command. What you need to do to receive this response (i.e. 11 22 33 44 55) is as below:

  1. Send a SELECT APDU command with you applet's AID in its data field.
  2. Sending 00 00 00 00 00 to your applet.
  3. Your applet response to the above command with expected answer.

If your card have been implemented ISO7816 system file, you need ID of files to select them. but the commands themselves are defined in ISO7816-P4.

Even if your cards doesn't implemented ISO7816 system file, you can write an applet to act like a ISO7816-P system file implemented smart card (Not easy anyway).

As the ID of MF is 3F00 always, trying to select this file, will show you if your card implemented the system-file or not.

Typically when your card powers on, a mandatory entity in the card named Card Manager, receive your APDU commands. By using SELECT APDU command, you request the card manager to send next incoming commands to the selected APPLET

like image 105
Ebrahim Ghasemi Avatar answered Nov 20 '22 08:11

Ebrahim Ghasemi


There are various kind of smart card in the market, Each are using different structure to keeping data inside. File structure is defined in ISO 7816-4: Organization, security and commands for interchange

You can see link1 and Link2 for more about smart card file structure.

It is the choice of card personlisation entity whether they use this file structure or not to keeping data inside chip. Indian standard SCOSTA is fully complient with ISO 7816 standard , it means any product that is SCOSTA complient will use the structure defined in ISO 7816 -4 ( MF, DF, EF).

Here you should know the structure of the card before sending any command to it. Like Select MF -> Select DF -> Select EF -> Read Record Command.

In case of java card ( smart card) , there are not always File Structure created to keeping data, it can be use arrays [i.e. Persistent memory] and assign values to it during operations. This value reside in smart card lifetime. Want to get the value just send an appropriate defined command and card will return you the value from the array. that is all.

It means we can say all smart card does not follow File structure rule

To read any smart card there are some pre-defined rules , If card is structure wise, we should know the structure otherwise we can get Error status word.

If talk about command , it is also defined Here -Smart Card Command Rules you can read here to enhance your knowledge about smart card commands so that you could send right command.

But not getting proper help for APDU command for communication with Smart card. Stuck in APDU command.

Here you should know more about Smart card you are using before sending any command to it. It is good to share Command Response to check the exact issue. javax.smartcardio is very good API to communicate with smart card, also there any various example already shared that helps you to write code to access any smart card.

Hope after knowing the deep detail of the smart card you are using and once you build appropriate command you will not get any error. Hope it helps.

like image 1
Arjun Avatar answered Nov 20 '22 08:11

Arjun