【发布时间】:2022-12-17 23:03:35
【问题描述】:
在用户vlp 提供了非常有用的提示后,我终于能够通过 java 智能卡 API (original thread) 与我的 ACR39 card reader 连接到 AT24C16 I2C card。
由于我要读取的免费存储卡不是智能卡,我需要使用伪 APDU 命令通过Card.transmitControlCommand 与卡通信。读卡器附带一个很棒的documentation,其中包含我需要的所有命令(基本上我只需要读取卡上的数据)。
虽然一切似乎都工作正常,但我没有从卡或读卡器(查询固件时)得到任何响应。
我有这个:
package com.Smaca;
import java.util.List;
import javax.smartcardio.*;
public class SReader {
public static void readCard() {
TerminalFactory factory = TerminalFactory.getDefault();
// GET_READER_INFORMATION
// I believe this is the correct command - the manual specifies 11h as the last byte
// I tried both
byte[] GET_R_INFO = new byte[] { (byte)0xFF,(byte)0x09,(byte)0x00,(byte)0x00,(byte)0xB};
//byte[] GET_R_INFO = new byte[] { (byte)0xFF,(byte)0x09,(byte)0x00,(byte)0x00,(byte)0x11};
//SELECT_CARD_TYPE
byte[] SELECT_CARD_TYPE = new byte[] { (byte)0xFF, (byte)0xA4, (byte)0x00, (byte)0x00, (byte)0x01, (byte)0x01 };
//SELECT_PAGE_SIZE
byte[] SELECT_PAGE_SIZE = new byte[] { (byte)0xFF, (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x01, (byte)0x04 };
//READ_MEMORY_CARD
byte[] READ = new byte[] { (byte)0xFF, (byte)0xB0, (byte)0xFF, (byte)0x00, (byte)0xFF };
int SCARD_CTL_CODE = 3500;
try {
List terminals = factory.terminals().list();
CardTerminal ter = (CardTerminal)terminals.get(0);
ter.waitForCardPresent(3000000);
if(ter.isCardPresent())
{
System.out.println("Card present");
Card ca = ter.connect("direct");
System.out.println(ca);
byte[] response_info = ca.transmitControlCommand(SCARD_CTL_CODE(SCARD_CTL_CODE), GET_R_INFO);
System.out.println("Reader info: "+ bytesToHex(response_info));
byte[] response = ca.transmitControlCommand(SCARD_CTL_CODE(SCARD_CTL_CODE), SELECT_CARD_TYPE);
System.out.println("Select card: "+bytesToHex(response));
byte[] response_ps = ca.transmitControlCommand(SCARD_CTL_CODE(SCARD_CTL_CODE), SELECT_PAGE_SIZE);
System.out.println("Select page size: "+ bytesToHex(response_ps));
byte[] response_read = ca.transmitControlCommand(SCARD_CTL_CODE(SCARD_CTL_CODE), READ);
System.out.println("Data read: "+ bytesToHex(response_read));
}
System.out.println( "is Card Present: " + ((CardTerminal)terminals.get(0)).isCardPresent());
} catch (CardException e) {
e.printStackTrace();
}
}
public static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte hashByte : bytes) {
int intVal = 0xff & hashByte;
if (intVal < 0x10) {
sb.append('0');
}
sb.append(Integer.toHexString(intVal));
}
return sb.toString();
}
public static final int SCARD_CTL_CODE(int command)
{
boolean isWindows = System.getProperty("os.name").startsWith("Windows");
if (isWindows) {
return 0x00310000 | (command << 2);
} else {
return 0x42000000 | command;
}
}
public static void main(String[] args) {
readCard();
}
}
这是输出:
Card present
PC/SC card in ACS ACR39U ICC Reader, protocol Unknown protocol 4, state OK
Reader info:
Select card:
Select page size:
Data read:
is Card Present: true
谁能看到我做错了什么?至少 GET_READER_INFORMATION 命令应该有效?!
更新:
我想我知道问题出在哪里。我只传输了命令的原始数据,但它们需要作为 PC_to_RDR_XfrBlock 命令 (Chapter 7.1.4.) 的有效载荷传输。
不过,我在格式化命令时仍然遇到问题。 如果有人知道该怎么做,请告诉我。一个具体的例子会很棒。
谢谢! 汤姆
【问题讨论】:
-
试试
transmit而不是transmitControlCommand... -
Card ca = ter.connect("direct"); ca.beginExclusive(); CardChannel channel = ca.getBasicChannel(); CommandAPDU apdu = new CommandAPDU(SELECT_CARD_TYPE); channel.transmit(apdu); -
javax.smartcardio.CardException: sun.security.smartcardio.PCSCException: SCARD_E_NOT_TRANSACTED 在 java.smartcardio/sun.security.smartcardio.ChannelImpl.doTransmit(ChannelImpl.java:226) 在 java.smartcardio/sun.security.smartcardio.ChannelImpl.transmit (ChannelImpl.java:89) 在 Smaca/com.Smaca.SReader.readCard(SReader.java:50) 在 Smaca/com.Smaca.SReader.main(SReader.java:109) 引起:sun.security.smartcardio。 PCSCException:SCARD_E_NOT_TRANSACTED 在 java.smartcardio/sun.security.smartcardio.PCSC.SCardTransmit(本机方法)在 java.smartcardio/sun.security.smartcardio.ChannelImp...
标签: i2c apdu eeprom acr smartcardio