簡體   English   中英

如何使用java從智能卡讀取文件

[英]How to read file from smart card using java

我是智能卡技術的新手。 我想從智能卡讀取文件。 我正在使用javax.smartcardio來讀取值。 我開發了一些代碼來連接系統到卡(這很好)。 我也有卡ATR和其他細節。 但沒有得到適當的APDU命令幫助與智能卡通信。 卡在APDU命令中。

首先:

“不是”所有Java卡都有MFDFEF 這些單詞依次代表主文件專用文件基本文件 它們是ISO7816定義的智能卡系統文件的組件( 參見ISO7816的第4部分 ),因此您的卡可能有也可能沒有此文件系統。

典型的Java卡有一個存儲器,您可以在其中安裝您的applet(在成功驗證之后)並注冊您的applet的名稱(我們稱之為AID,代表Applet IDentifier ,它是一個5到16字節的十六進制序列)在卡的注冊表中(加載/安裝的applet和包含生命周期和特權的包的表 - 閱讀全球平台卡規范 )。

然后:

假設您的讀卡器中插有智能卡,該智能卡已連接到您的計算機。 您可以使用不同的選項在計算機和卡之間進行通信。

1 - 您可以使用可用的工具,例如您的讀者工具(幾乎所有讀者都有一個工具), PyAPDUTool等。

2 - 您可以使用Javax.smartcardio庫編寫Java程序以與智能卡通信:

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-您可以使用PySCard庫編寫Python程序以與智能卡通信:

#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-您可以使用WinSCard庫以C ++ / .Net編寫程序(不確定)與智能卡通信。

以上程序是將APDU命令發送到智能卡的示例程序。 但是它們的命令取決於你的卡和你的[你]安裝的小程序。

例如,假設您正在編寫AID = 01 02 03 04 05 00的applet,當它接收00 00 00 00 00作為APDU命令時返回11 22 33 44 55 您需要做什么才能收到此回復(即11 22 33 44 55 )如下:

  1. 在其數據字段中使用applet的AID發送SELECT APDU命令。
  2. 00 00 00 00 00發送到您的小程序。
  3. 您的applet響應上述命令並帶有預期答案。

如果您的卡已經實現了ISO7816系統文件,則需要文件ID才能選擇它們。 但命令本身在ISO7816-P4中定義。

即使您的卡沒有實現ISO7816系統文件,您也可以編寫一個小程序,就像ISO7816-P系統文件實現的智能卡一樣(不管怎么說都不容易)。

由於MF的ID總是3F00 ,嘗試選擇此文件,將顯示您的卡是否實現了系統文件。

通常,當您的卡啟動時,名為Card Manager的卡中的強制實體會收到您的APDU命令。 通過使用SELECT APDU命令,您請求卡管理器將下一個傳入命令發送到所選的APPLET

市場上有各種各樣的智能卡,每種都使用不同的結構來保存數據。 文件結構在I SO 7816-4中定義:組織,安全性和交換命令

有關智能卡文件結構的更多信息,請參閱link1Link2

卡片人員實體的選擇是否使用這種文件結構來保持芯片內的數據。 印度標准SCOSTA完全符合ISO 7816標准,這意味着任何SCOSTA complient產品都將使用ISO 7816 -4(MF,DF,EF)中定義的結構。

在發送任何命令之前,您應該知道卡的結構。 如選擇MF - >選擇DF - >選擇EF - >讀取記錄命令。

對於java卡(智能卡),並不總是創建文件結構來保存數據,它可以使用數組[即持久存儲器]並在操作期間為其賦值。 此值駐留在智能卡生命周期中。 想要獲取值只是發送一個適當的定義命令,卡將返回數組中的值。 就這些。

這意味着我們可以說所有智能卡都不遵循文件結構規則

要讀取任何智能卡,有一些預先定義的規則,如果卡是結構明智的,我們應該知道結構,否則我們可以得到錯誤狀態字

如果談論命令,它也被定義這里 - 智能卡命令規則,您可以在這里閱讀,以增強您對智能卡命令的了解,以便您可以發送正確的命令。

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

在發送任何命令之前,您應該了解有關您正在使用的智能卡的更多信息。 分享命令響應以檢查確切問題是很好的。 javax.smartcardio是與智能卡通信的非常好的API,也有任何已經共享的各種示例,可以幫助您編寫代碼來訪問任何智能卡。

希望在了解您正在使用的智能卡的深層細節后,一旦您構建了適當的命令,您將不會收到任何錯誤。 希望能幫助到你。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM