【发布时间】:2017-01-25 21:04:09
【问题描述】:
我拼凑了以下代码示例,以使用 javax.smartcardio 库检测 Mifare 智能卡。此代码适用于列出的 Mifare 类型。
public class DetectCardTester {
private static final String PROTOCOL = "T=1";
static Map<String,String> KNOWN_CARD_TYPES = ImmutableMap.<String, String>builder()
.put("00-01", "Mifare 1K")
.put("00-02", "Mifare 4K")
.put("00-03", "Mifare Ultralight")
.put("00-26", "Mifare Mini")
.build();
public static void main(String... args) {
try {
final TerminalFactory terminalFactory = SmartcardTerminalFactory.create();
System.out.println("Place card on the reader");
final Card card = awaitCard(terminalFactory, 3, SECONDS);
final ATR atr = card.getATR();
final byte[] bytes = atr.getBytes();
System.out.println("ATR=" + String.valueOf(Hex.encodeHex(bytes, false)));
if (bytes != null && bytes.length > 13) {
String typeCode = String.format("%02X-%02X", bytes[13], bytes[14]);
if (KNOWN_CARD_TYPES.containsKey(typeCode)) {
System.out.println("Known Type:" + KNOWN_CARD_TYPES.get(typeCode));
} else {
System.out.println("Unknown Type:" + typeCode);
}
}
// TODO: Detect Desfire Card
} catch (Throwable t) {
t.printStackTrace();
}
}
public static Card awaitCard(final TerminalFactory terminalFactory, final int qty, final TemporalUnit unit) throws CardException {
LocalDateTime timeout = now().plus(qty, unit);
while (now().isBefore(timeout)) {
Optional<CardTerminal> cardTerminal = getCardPresentTerminal(terminalFactory);
if (cardTerminal.isPresent()) {
return cardTerminal.get().connect(PROTOCOL);
}
}
throw new CardNotPresentException("Timed out waiting for card");
}
private static Optional<CardTerminal> getCardPresentTerminal(final TerminalFactory terminalFactory) throws CardException {
List<CardTerminal> terminals = terminalFactory.terminals().list();
for (CardTerminal cardTerminal : terminals) {
if (cardTerminal.isCardPresent()) {
return Optional.of(cardTerminal);
}
}
for (CardTerminal cardTerminal : terminals) {
// waitForCardPresent / Absent doesn't work with some Jacax.smartcard.io implementations
// i.e. OSX http://bugs.java.com/view_bug.do?bug_id=7195480
// This is why we have the imediate check above
if (cardTerminal.waitForCardPresent(250)) {
return Optional.of(cardTerminal);
}
}
return Optional.empty();
}
}
我使用以下资源将这段代码放在一起:
- http://downloads.acs.com.hk/drivers/en/API-ACR122U-2.02.pdf
- How to get SAK to Identify smart card type using JAVA?
我想实现 TODO 注释来检测 Desfire 卡。如果我将 Desfire 卡放在读取此代码上,则只会输出:
Place card on the reader
ATR=3B8180018080
我发现这个问题Determine card type from ATR 有点帮助,但我错过了一些东西。有问题的卡的 HistoricalByte 是 0x80,我找不到任何信息。
如果可能的话,我将非常感谢扩展上述代码示例,使其可以检测 Desfire 卡类型。
【问题讨论】:
-
为您的卡片定制 ATS 怎么样?还是发送 GetVersion?或者在本机 DESFire 中发送一些命令而不是包装。我没有其他选择,因为它是 ISO14443-4A。即使使用 SAK(Java 中不可用),您也可能会发现冲突。
-
感谢您的建议。我不确定如何使用 Java 发送 ATS,也不确定如何使用它来确保卡是 Desfire 卡。我确实想过使用 GetVersion,但感觉就像是 hack!
-
ATS 将专门用于您的卡,而不是 DESFire,或者至少我认为是这样。然后,这是您在卡上配置的内容。关于 GetVersion 作为 hack,我认为考虑到它是 4A 类型的卡,否则会很困难。实际上,有人可以在 JavaCard 上实现类似的命令,并假装它是 DESFire 卡:(
-
smartcard-atr.appspot.com by Ludovic Rousseau 非常适合将 ATR 映射到卡片;仍然有非常不同的卡,具有相同的 ATR,因此不足以识别您的卡。