我已经开发了成功的解决方案来读取克罗地亚公共服务中使用的 DESFire 智能卡,两者都用于:
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 文件,例如,即使未加密也是如此。
我找到了解决办法。所以,如果有人遇到类似的问题 代码是这样的。顺便说一句,关键在于
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();
}