所以,我有一台非接触式万事达卡和一张Visa paywave手机。 我使用非接触式HID Omnikey 5427 CK。
这是我的代码:`
static boolean cardReading = true;
public static void main(String[] args) throws CardException, UnsupportedEncodingException {
while (cardReading == true) {
try {
TerminalFactory factory = TerminalFactory.getDefault();
List<CardTerminal> terminals = factory.terminals().list();
CardTerminal terminal = terminals.get(0);
if (!terminal.isCardPresent()) {
continue;
}
System.out.println("Terminals: " + terminals);
System.out.println("Used terminal: " + terminal);
Card card = terminal.connect("T=0");
System.out.println("\n\nInserted card: " + card);
CardChannel channel = card.getBasicChannel();
String pse = "00A404000E325041592E5359532E444446303100";
CommandAPDU apdu = new CommandAPDU(pse.getBytes());
ResponseAPDU r = channel.transmit(apdu);
System.out.println("Response: " + toHex(r.getData().toString()) + " " + r);
System.out.println("ADPU: " + toHex(apdu.getBytes().toString()) + " " + r.getSW() + " " + r.getSW1() + " " + r.getSW2() + " " + r.getNr());
apdu = new CommandAPDU((byte)0x00, (byte)0xB2, (byte)0x01, (byte)0x0C, (byte)0x00);
r = channel.transmit(apdu);
cardReading = false;
Toolkit.getDefaultToolkit().beep();
System.out.println("Terminals: " + terminals);
System.out.println("Used terminal: " + terminal);
System.out.println("\n\nInserted card: " + card);
System.out.println("Response: " + toHex(r.getData().toString()) + " " + r);
System.out.println("ADPU: " + toHex(apdu.getBytes().toString()) + " " + r.getSW() + " " + r.getSW1() + " " + r.getSW2() + " " + r.getNr());
System.exit(1);
} catch(Exception e) {
continue;
}
}
}
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;
}
public static String toHex(String arg) {
return String.format("%040x", new BigInteger(1, arg.getBytes()));
}
`
所以输出是:
Terminals: [PC/SC terminal HID OMNIKEY 5427 CK 0]
Used terminal: PC/SC terminal HID OMNIKEY 5427 CK 0
Inserted card: PC/SC card in HID OMNIKEY 5427 CK 0, protocol T=0, state OK
Response: 0000000000000000005b42403163343630306630 ResponseAPDU: 65 bytes, SW=9000
ADPU: 000000000000000000005b424035623665663230 36864 144 0 63
Terminals: [PC/SC terminal HID OMNIKEY 5427 CK 0]
Used terminal: PC/SC terminal HID OMNIKEY 5427 CK 0
Inserted card: PC/SC card in HID OMNIKEY 5427 CK 0, protocol T=0, state OK
Response: 0000000000000000005b42403565616235383039 ResponseAPDU: 14 bytes, SW=9000
ADPU: 0000000000000000005b42403433323065373664 36864 144 0 12
我不明白为什么回复0000000000000000005b42403565616235383039 ... 请帮忙。
此致,弗拉德。
答案 0 :(得分:2)
正如Michael Roland所说 - 你对十六进制字符串的处理是错误的。
元错误1:使用&#39; byte []。toString()&#39;
r.getData().toString()
byte[].toString
使用默认的Object.toString()
实现,该实现返回类名后跟@
和Object.hashCode()
的值(例如"[B@312b1dae"
) - 其中不是你想要进一步处理的东西。
您可以使用Arrays.toString()
方法(不执行十六进制转储)或any other method。
元错误2:使用&#39; String.getBytes()&#39;
String pse = "00A404000E325041592E5359532E444446303100";
CommandAPDU apdu = new CommandAPDU(pse.getBytes());
不创建所需的APDU对象,因为方法String.getBytes()
不执行十六进制转换,而是在平台的默认字符集中进行字符集转换,例如:"1234".getBytes()
给出{{1} (而不是你所期望的{ 0x31, 0x32, 0x33, 0x34 }
)。
下面是一个简单的代码示例,它几乎与您的代码相同:
{ 0x12, 0x34 }
请注意一些有趣的部分:
此代码使用Apache Commons Codec进行十六进制转换
参数package test.java.so;
import java.util.List;
import javax.smartcardio.Card;
import javax.smartcardio.CardChannel;
import javax.smartcardio.CardTerminal;
import javax.smartcardio.CommandAPDU;
import javax.smartcardio.ResponseAPDU;
import javax.smartcardio.TerminalFactory;
import org.apache.commons.codec.binary.Hex;
@SuppressWarnings("restriction")
public class So39543402 {
public static void main(String[] args) throws Exception {
TerminalFactory factory = TerminalFactory.getDefault();
List<CardTerminal> terminals = factory.terminals().list();
CardTerminal terminal = terminals.get(0);
Card card = terminal.connect("*");
CardChannel channel = card.getBasicChannel();
String pse = "00A404000E325041592E5359532E444446303100";
CommandAPDU apdu = new CommandAPDU(Hex.decodeHex(pse.toCharArray()));
exchangeApdu(channel, apdu);
apdu = new CommandAPDU(0x00, 0xB2, 0x01, 0x0C, 256);
exchangeApdu(channel, apdu);
}
private static ResponseAPDU exchangeApdu(CardChannel channel, CommandAPDU apdu) throws javax.smartcardio.CardException {
System.out.println("APDU: " + Hex.encodeHexString(apdu.getBytes()));
ResponseAPDU r = channel.transmit(apdu);
System.out.println("Response: " + Hex.encodeHexString(r.getBytes()));
return r;
}
}
用于"*"
,它比总是请求CardTerminal.connect()
协议更具通用性
您的T=0
APDU被修改为期望256字节的响应数据 - this is how this particular constructor works(您的代码会生成ISO案例1 Command-APDU,这可能不是您想要的)< / p>
另外一个注意事项:
READ RECORD
方法(即使您希望将单个字符转换为字节)。始终指定所需的字符集(例如&#34; US-ASCII&#34;,&#34; UTF-8&#34;)