【问题标题】:How can you use javax.smartcardio to detect a desfire card?如何使用 javax.smartcardio 检测 desfire 卡?
【发布时间】: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();
    }
}

我使用以下资源将这段代码放在一起:

我想实现 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,因此不足以识别您的卡。

标签: java smartcard mifare


【解决方案1】:

重置答案 (ATR) 可能很好地表明您拥有什么卡。您所追求的 SPEC 称为“7816-3”第 8 节。它实际上是付费的规范,但如果您用谷歌搜索得好...

无论如何,SIM 规范很难理解,它们的定义很明确,但您需要深入到比特级别才能完全理解它。

ATR 以字节为单位解码,让我们解码您的特定 ATR:

Byte1 称为“TS”,定义为 3B 或 3F,其中 3F 表示使用“逆约定”,3B 表示“直接约定”

Byte2 称为“T0”,定义为“格式字符”。该字节的第一个半字节“8”指的是一个 Y1 参数,第二个半字节指的是一个“K”参数。 您的“T0”第一个半字节 Y1 = 8 和第二个半字节 K = 1 Y1 参数 8 = (二进制) 1000 意味着后面只有一个 TA1 参数。 如果是 9 = (二进制) 1001 表示 TA1 开启 (1) TB1 关闭 (0) TC1 关闭 (0) 并且 TD1 开启 (1)。 K 定义了历史字节的数量,即在您的情况下为 1 个历史字节。

长话短说,是的,“80”是您的历史字节(在 7816-4 规范中定义)。 80 是您可以拥有的最基本的历史字节。 80 是“类别/状态指标”,所有 80 都被定义为:

A status indicator (one, two or three bytes) may be present in an optional COMPACT-TLV data object

关键字是“可能存在”,即在您的情况下,他们决定不包含任何进一步的信息。

回到您的问题,检查与确切值“3B8180018080”匹配的 ATR 应该足以识别 DESfire 卡。然而,在我的应用程序中,我还使用了特定文件的存在(即仅在 desfire 卡上找到)、文件的内容或 AID 提供的特定于卡的应用程序来更准确地对卡进行分类。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-12
    • 1970-01-01
    • 2017-05-11
    • 1970-01-01
    相关资源
    最近更新 更多