使用适用于 Java(而非 Android)的 TapLinx SDK 来读取 MIFARE DESFire 非接触式智能卡

问题描述 投票:0回答:1

我已经开发了成功的解决方案来读取克罗地亚公共服务中使用的 DESFire 智能卡,两者都用于:

  1. 点网。多平台,使用 pcsc-sharp 和“原始”APDU 方法。
  2. 安卓。使用适用于 Android 的 TapLinx SDK 和高级方法。例如:
    myDesFire.getUID()
    而不是原始 APDU 命令。

现在,我正在尝试使用 TapLinx SDK for Java 和高级方法用 Java 开发多平台解决方案。

我依靠

javax.smartcardio
轮询连接的卡终端来查看智能卡何时插入或移除,并且它工作得很好。在我的测试应用程序(JavaFX,如果重要的话)中,在
onCardInserted
事件中,我正在调用我自己的
cardLogic
方法。该方法尝试连接到智能卡。

在Android中,非常简单:

public static Card cardLogic(final Intent intent, NxpNfcLib nxpNfcLib, MyCardKeys keys) {

//... some code ommited for brevity

desFireEV = DESFireFactory.getInstance().getDESFireEV2(nxpNfcLib.getCustomModules());

desFireEV.getReader().connect();

byte[] uid = desFireEV.getUID();

// ...and so on.

在Java中,我的类似方法是:

public static Card cardLogic(CardTerminal terminal, MyCardKeys keys) {

//... some code ommited for brevity

javax.smartcardio.Card javaCard = terminal.connect("*");

desFire = DESFireFactory.getInstance().getDESFireEV2(TapLinx.getCustomModules());

// **NOW WHAT!???**

desFire.getReader().connect(); // **This does not work, of course. HOW TO connect context of javaCard object with getting a concrete reader, so that...**

byte[] uid = desFire.getUID(); // **... I can do this without raising an exception?**

所以,问题就是上述代码片段的注释中的问题。我完全被困住了。可能缺少一些明显的东西。但我无法找出解决方案,即使在阅读两个示例桌面应用程序的代码时也是如此。

请帮忙。

我还尝试了不使用 TapLinx SDK 的原始 APDU 方法,仅使用

javax.smartcardio
,但由于
smartcardio
实际上是为了支持接触式卡而开发的,因此无法针对非接触式卡进行更复杂的操作。因此,我可以读取 DESFire 的 UID、选择身份应用程序、读取应用程序 ID,但我无法读取 BER TLV 文件,例如,即使未加密也是如此。

java sdk mifare desfire taplinx
1个回答
0
投票

我找到了解决办法。所以,如果有人遇到类似的问题 代码是这样的。顺便说一句,关键在于

setTransceive
方法!?!?!!! 而且,似乎我最初错误地将这个答案放到了一些类似的线程中。

MyApp.TapLinx.getCustomModules().setTransceive(new MyCardApduHandler(new MyCardReader(terminal)));
desFire = DESFireFactory.getInstance().getDESFireEV2(MyApp.TapLinx.getCustomModules());
desFire.getReader().connect();

// Read UID.
byte[] uid = desFire.getUID();
// To do anything further, and unlike Android , you have to set Command Set to ISO.
desFire.setCommandSet(IDESFireEV1.CommandSet.ISO);
// Select ID app...
desFire.selectApplication(0);
// ...and so on

MyCardApduHandler
是准系统:

public class MyCardApduHandler implements IApduHandler {
    IReader reader;

    public SCardApduHandler(IReader reader) {
        this.reader = reader;
    }

    @Override
    public byte[] apduExchange(byte[] bytes) {
        return reader.transceive(bytes);
    }

    @Override
    public IReader getReader() {
        return reader;
    }
}

MyCardReader
如下:

public class MyCardReader implements IReader {
    CardTerminal mTerminal;
    CardChannel mKanal;
    Card mJavaCard;
    ProtocolDetails mProtokol;
    boolean isConnected = false;

    public SCardReader(CardTerminal terminal) {
        mTerminal = terminal;
    }

    @Override
    public byte[] transceive(byte[] bytes) {
        ResponseAPDU res;
        try {
            res = mKanal.transmit(new CommandAPDU(bytes));
        } catch (CardException e) {
            throw new NxpNfcLibException(e, e.getMessage());
        }
        return res.getBytes();
    }

    @Override
    public void connect() {
        if (!isConnected) {
            try {
                mTerminal.waitForCardPresent(0);
                mJavaCard = mTerminal.connect("*");
                mKanal = mJavaCard.getBasicChannel();
                mProtokol = new ProtocolDetails();
                mProtokol.uid = Commands.uid(mKanal);
                // TODO: Other components of the protocol.
                isConnected = true;
            } catch (CardException e) {
                throw new NxpNfcLibException(e, e.getMessage());
            }
        }
    }

    @Override
    public void close() {
        if (isConnected) {
            try {
                if (mKanal.getChannelNumber() != 0) mKanal.close();
                mJavaCard.disconnect(false);
                isConnected = false;
            } catch (Exception e) {
                throw new NxpNfcLibException(e, e.getMessage());
            }
        }
    }

    @Override
    public boolean isConnected() {
        return isConnected;
    }

    @Override
    public void setTimeout(long l) {
        throw new NotSupportedException("SCardReader: metoda setTimeout nije podržana. ");
    }

    @Override
    public long getTimeout() {
        throw new NotSupportedException("SCardReader: metoda getTimeout nije podržana. ");
    }

    @Override
    public ProtocolDetails getProtocolDetails() {
        return mProtokol;
    }
}

而且,

Commands.uid(mKanal)
是通过原始APDU实现的:

public static byte[] uid(CardChannel kanal) throws CardException, RuntimeException {
    CommandAPDU cmd = new CommandAPDU(new byte[] { (byte) 0xFF, (byte) 0xCA, (byte) 0x00, (byte) 0x00, (byte) 0x00 });
    ResponseAPDU res = kanal.transmit(cmd);
    if (res.getSW1() != 0x90 && res.getSW2() != 0x00) throw new RuntimeException(String.format("uid: greška SW1 SW2 = %02X %02X", res.getSW1(), res.getSW2()));
    return res.getData();
}
© www.soinside.com 2019 - 2024. All rights reserved.