簡體   English   中英

如何使用javax.smartcardio檢測失火卡?

[英]How can you use javax.smartcardio to detect a desfire card?

我整理了以下代碼示例,以使用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

我發現了這個問題,可以從ATR確定卡類型,這有幫助,但是我遺漏了一些東西。 該卡的HistoricalByte為0x80,我無法找到其任何信息。

如果可能的話,我將不勝感激上面擴展的代碼示例,以便它可以檢測Desfire卡類型。

重設答案(ATR)可能很好地表明您擁有的卡。 您追求的SPEC稱為“ 7816-3”第8節。它實際上是按規格收費的,但是如果您對Google感興趣的話...

無論如何,SIM規范很難理解,定義得很好,但是您需要深入了解它。

ATR以字節為單位解碼,讓我們解碼您的特定ATR:

字節1稱為“ TS”,它定義為3B或3F,其中3F表示使用“逆約定”,而3B表示“直接約定”

字節2稱為“ 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卡。 但是,在我的應用程序中,我還使用了特定文件的存在(即僅在除火卡上找到),文件的內容,或者通過AID可以使用特定於卡的特定應用程序來更准確地對卡進行分類。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM