首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用java从智能卡读取文件

如何使用java从智能卡读取文件
EN

Stack Overflow用户
提问于 2016-04-18 12:03:08
回答 2查看 19.9K关注 0票数 6

我是智能卡技术方面的新手。我想从智能卡上读取文件。我正在使用javax.smartcardio读取值。我开发了一些代码来连接系统到卡(这很好)。我也有卡片ATR和其他细节。但没有得到与智能卡通信的APDU命令的适当帮助。被困在APDU指挥部。

EN

回答 2

Stack Overflow用户

发布于 2016-04-18 12:24:38

首先:

“不是”所有的Java卡都有MFDFEF!这些词代表主文件,专用文件和基本文件的顺序。它们是not 7816定义的智能卡系统文件(请参阅ISO7816第4部分)的组件,因此您的卡可能有或可能没有此文件系统。

典型的java卡有一个存储空间,您可以在其中安装小程序(经过成功的身份验证),并注册小程序的名称(我们称之为AID,表示applet IDentifier,它是一个5到16字节的十六进制序列)在卡片的注册表中(一个包含生命周期和特权的加载/安装小程序和包表- 阅读全球平台卡规范)。

,然后:

假设您在您的读卡器中插入了一张连接到计算机的智能卡。在计算机和卡之间进行通信时,您有不同的选择。

1-您可以使用可用的工具,如您的读者工具(几乎所有的读者都有一个工具),PyAPDUTool等。

2-您可以使用Javax.smartcardio库编写您的Java程序,以便与智能卡通信:

代码语言:javascript
复制
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程序:

代码语言:javascript
复制
#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,当它作为APDU命令接收到00 00 00 00 00时返回11 22 33 44 55。要接收此响应(即11 22 33 44 55),您需要做的如下:

  1. 在其数据字段中,与applet的AID一起发送一个SELECT APDU命令。
  2. 00 00 00 00 00发送到您的applet。
  3. 您的applet对上述命令的响应具有预期的答案。

如果您的卡已实现ISO7816系统文件,则需要文件ID来选择它们。但是命令本身是在ISO7816-P4中定义的。

即使您的卡片没有实现ISO7816系统文件,您也可以编写一个小程序来执行一个if 7816-P系统文件实现的智能卡(无论如何都不容易)。

由于MF的ID始终是3F00,尝试选择此文件,将显示您的卡是否实现了系统文件。

通常,当您的卡启动时,卡中的强制实体“卡管理器”接收您的APDU命令。通过使用SELECT APDU命令,您可以请求卡片管理器向选定的APPLET发送下一个传入命令。

票数 4
EN

Stack Overflow用户

发布于 2016-04-22 09:49:27

市场上有各种各样的智能卡,每种智能卡都采用不同的结构来保存数据。文件结构是在i中定义的,所以是7816-4:交换的组织、安全性和命令。

有关智能卡文件结构的更多信息,您可以看到link1Link2

使用这种文件结构或不使用这种文件结构来保存芯片内的数据,是卡人格化实体的选择。印度标准SCOSTA完全符合ISO 7816标准,这意味着任何符合标准的产品都将使用ISO7816-4( MF、DF、EF)中定义的结构。

在此,您应该知道卡的结构,然后再向它发送任何命令。类似于选择MF ->,选择DF ->选择EF ->读取记录命令。

对于java卡(智能卡),并不总是为保存数据而创建文件结构,它可以使用数组,即持久化内存,并在操作期间为其赋值。此值驻留在智能卡生存期中。要获得值,只需发送一个适当的定义命令,卡片就会从数组中返回值。仅此而已。

,这意味着我们可以说所有智能卡都不遵循文件结构规则

任何智能卡的读取都有一些预定义的规则,如果智能卡的结构是合理的,我们就应该知道它的结构,否则就可以得到错误状态字

如果谈到命令,您也可以在这里阅读在这里,-Smart卡命令规则,以增强您对智能卡命令的了解,以便您能够发送正确的命令。

代码语言:javascript
复制
But not getting proper help for APDU command for communication with Smart card. Stuck in APDU command.

在这里,您应该了解更多关于智能卡的使用,然后再发送任何命令给它。共享命令响应来检查确切的问题是很好的。javax.smartcardio是很好的与智能卡进行通信的API,还有任何帮助您编写代码访问任何智能卡的共享示例。

希望在知道您正在使用的智能卡的详细信息之后,一旦您构建了适当的命令,您将不会收到任何错误。希望能帮上忙。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36693453

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档