gpt4 book ai didi

javacard - 如何在没有卡的情况下向智能卡读卡器(而不是智能卡)发送命令?

转载 作者:行者123 更新时间:2023-12-03 14:24:54 24 4
gpt4 key购买 nike

前言:

我有一个双接口(interface)智能卡读卡器,它具有一些扩展功能(除了向卡发送 APDU 命令和接收 APDU 响应)。

例如,在其文档中提到您可以使用以下命令获取阅读器的固件版本:

GET_FIRMWARE_VERSION:FF 69 44 42 05 68 92 00 05 00
在其工具中,有一个用于此功能的按钮,并且可以正常工作:

enter image description here

我什至嗅探了 USB 端口,看看我的 PC 和我的阅读器之间的连接中究竟交换了什么来实现这个功能:

命令:
enter image description here

回复:
enter image description here

问题:

我想使用其他工具或通过代码获取我的读卡器版本(并且可能发送其他扩展命令),但我必须在读卡器中插入一张卡才能发送命令,否则我会收到 No Card Present 异常,而我不想要向卡发送命令! (读卡器工具成功响应 GET_FIRMWARE_VERSION 读卡器插槽中没有任何可用卡)

到目前为止我做了什么:

1.我尝试了一些工具,包括 OpenSCTool 、 PyAPDUTool 和另一个读者的工具。
2.我编写了以下python脚本来发送扩展命令。

#--- Importing required modules.
import sys
import time
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()

输出:
>>> ================================ RESTART ================================
Available Readers : ['CREATOR CRT-603 (CZ1) CCR RF 0', 'CREATOR CRT-603 (CZ1) CCR SAM 0']

--- Select Reader (0, 1 , ...): 0

Using : CREATOR CRT-603 (CZ1) CCR RF 0
--- Exception occured! (Wrong reader or No card present)
--- Try again? (0:Exit/1:Again/2:Change Reader)

>>> ================================ RESTART ================================
Available Readers : ['CREATOR CRT-603 (CZ1) CCR RF 0', 'CREATOR CRT-603 (CZ1) CCR SAM 0']

--- Select Reader (0, 1 , ...): 1

Using : CREATOR CRT-603 (CZ1) CCR SAM 0
--- Exception occured! (Wrong reader or No card present)
--- Try again? (0:Exit/1:Again/2:Change Reader)

但两者都有提到的问题!

问题:

1-如何在没有可用卡的情况下向读卡器发送扩展命令?

2- 为什么我在嗅探数据中看不到命令​​头? (请注意,由于 header 是所有扩展命令的预先指定的固定值,我认为阅读器工具不会使用 GET_FIRMWARE_VERSION 命令发送 header ,它只发送数据!但它是如何工作的?)

更新:

通过反复试验,我发现了一些有用的东西。

假设:
  • 伪 APDU 固定 header = FF 69 44 42
  • GET_READER_FIRMWARE_VERSION 的伪 APDU 数据字段 = 68 92 00 04 00
  • CHANGE_SAM_SLOT = 68 92 01 00 03 XX 00 00 的伪 APDU 数据字段
    (我的阅读器有两个 SAM 插槽,所以 XX 可以是 0102 )
  • 选择 APDU 命令 = 00 A4 04 00 00

  • 好的,我编写了以下 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;
    }

    }

    在上面的程序中,我可以使用 connection.transmitControlCommandcardChannel.transmit() 方法向我的阅读器发送命令。关键是,使用第一种方法发送给阅读器的所有命令都假定为 Pseudo-APDU 命令,我不应该为它们使用 Psedo-APDU header !并且所有使用第二种方法发送给阅读器的命令都被假定为常规 APDU 命令,所以如果我需要通过第二种方法发送 Pseudo-APDU 命令,我必须向它添加 Pseudo-APDU header 。

    让我们看看非接触式阅读器的输出:
    run:
    Available Readers:
    [PC/SC terminal ACS ACR122 0,
    PC/SC terminal CREATOR CRT-603 (CZ1) CCR RF 0,
    PC/SC terminal CREATOR CRT-603 (CZ1) CCR SAM 0]

    Which reader do you want to send your commands to? (0 or 1 or ...): 1
    Write your commands in Hex form, without '0x' or Space charaters.

    ---------------------------------------------------
    Pseudo-APDU Mode:
    ---------------------------------------------------
    Pseudo-APDU command: (Enter 0 to send APDU command)
    00A4040000
    Command : 00A4040000
    Response : 6800
    //Based on reader's documents, 0x6800 means "Class byte is not correct"
    //As I have a regular java card in the RF field of my reader, I conclude that
    //this response is Reader's response (and not card response)

    Pseudo-APDU command: (Enter 0 to send APDU command)
    6892000400
    Command : 6892000400
    Response : 433630335F435A375F425F31353038323100039000

    Pseudo-APDU command: (Enter 0 to send APDU command)
    FF694442056892000400
    Command : FF694442056892000400
    Response : 6800
    //Pseudo-APDU commands doesn't work in Pseudo-APDU mode if I add the Pseudo-APDU header to them.

    Pseudo-APDU command: (Enter 0 to send APDU command)
    00A4040000
    Command : 00A4040000
    Response : 6800

    Pseudo-APDU command: (Enter 0 to send APDU command)
    0

    ---------------------------------------------------
    APDU Mode:
    ---------------------------------------------------
    APDU command: (Enter 0 to exit)
    00A4040000
    Command : 00A4040000
    Response : 6F198408A000000018434D00A50D9F6E061291921101009F6501FF9000

    APDU command: (Enter 0 to exit)
    6892000400
    Command : 6892000400
    Response : 6E00
    //This is the response of my card. I can't receive Firmware version in APDU mode using this command without Pseudo-APDU header.

    APDU command: (Enter 0 to exit)
    FF694442056892000400
    Command : FF694442056892000400
    Response : 433630335F435A375F425F31353038323100099000
    //I successfully received Firmware version in APDU mode using the fixed Pseudo-APDU header.

    APDU command: (Enter 0 to exit)
    00A4040000
    Command : 00A4040000
    Response : 6F198408A000000018434D00A50D9F6E061291921101009F6501FF9000

    APDU command: (Enter 0 to exit)
    0
    BUILD SUCCESSFUL (total time: 1 minute 36 seconds)

    还有问题吗?

    是的,有两个问题!:

    1-上述程序仅在第一次运行时工作正常。我的意思是,如果我停止运行并重新运行它,第二种方法会引发异常:
    run:
    Available Readers:
    [PC/SC terminal ACS ACR122 0, PC/SC terminal CREATOR CRT-603 (CZ1) CCR RF 0, PC/SC terminal CREATOR CRT-603 (CZ1) CCR SAM 0]

    Which reader do you want to send your commands to? (0 or 1 or ...): 1
    Write your commands in Hex form, without '0x' or Space charaters.

    ---------------------------------------------------
    Pseudo-APDU Mode:
    ---------------------------------------------------

    Pseudo-APDU command: (Enter 0 to send APDU command)
    00A4040000
    Command : 00A4040000
    Response : 6800

    Pseudo-APDU command: (Enter 0 to send APDU command)
    FF694442056892000400
    Command : FF694442056892000400
    Response : 6800

    Pseudo-APDU command: (Enter 0 to send APDU command)
    6892000400
    Command : 6892000400
    Response : 433630335F435A375F425F31353038323100049000

    Pseudo-APDU command: (Enter 0 to send APDU command)
    00A4040000
    Command : 00A4040000
    Response : 6800

    Pseudo-APDU command: (Enter 0 to send APDU command)
    0

    ---------------------------------------------------
    APDU Mode:
    ---------------------------------------------------
    APDU command: (Enter 0 to exit)
    00A4040000
    Command : 00A4040000
    Exception in thread "main" javax.smartcardio.CardException: sun.security.smartcardio.PCSCException: Unknown error 0x16
    at sun.security.smartcardio.ChannelImpl.doTransmit(ChannelImpl.java:219)
    at sun.security.smartcardio.ChannelImpl.transmit(ChannelImpl.java:90)
    at TestPCSC.main(TestPCSC.java:58)
    Caused by: sun.security.smartcardio.PCSCException: Unknown error 0x16
    at sun.security.smartcardio.PCSC.SCardTransmit(Native Method)
    at sun.security.smartcardio.ChannelImpl.doTransmit(ChannelImpl.java:188)
    ... 2 more
    Java Result: 1
    BUILD SUCCESSFUL (total time: 39 seconds)

    正如您在上面看到的,我不能再使用第二种方法了,我需要关闭阅读器并再次打开它以使其再次正常工作。

    2-联系界面(我的意思是SAM阅读器)总是抛出以前的异常!我的意思是第二种方法根本不起作用(第一次运行,第二次和第三次都没有......)

    请注意,我尝试了不同的阅读器,似乎不仅限于此阅读器。一些 ACS 阅读器在重新运行时也有类似或完全相同的问题

    有谁有想法吗?

    作为一个附带问题,Python 是否有任何相同的方法可以像 Java 一样发送 Pseudo-APDU?

    最后,从 Reader 的角度来看, connection.transmitControlCommandcardChannel.transmit() 方法有什么区别?

    最佳答案

    当您停止“智能卡”服务时,该工具是否仍返回固件版本?如果是,那么该工具可能会使用原始 IOCTL命令 (DeviceIoControl) 与驱动程序通信。

    也看看this question .作者说要设置SCARD_PROTOCOL_UNDEFINED作为协议(protocol)参数:

    SCardConnect(hSC,
    readerState.szReader,
    SCARD_SHARE_DIRECT,
    SCARD_PROTOCOL_UNDEFINED,
    &hCH,
    &dwAP
    );

    我刚刚尝试过,它似乎至少适用于 Windows 10。没有插卡就可以通讯。不过,我没有测试其他 Windows 版本。

    关于javacard - 如何在没有卡的情况下向智能卡读卡器(而不是智能卡)发送命令?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35389657/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com