Using TapLinx SDK for Java, NOT Android

取消
显示结果 
显示  仅  | 搜索替代 
您的意思是: 
已解决

Using TapLinx SDK for Java, NOT Android

跳至解决方案
1,542 次查看
IkarovoPero
Contributor II

Greetings!

I have developed successful solutions for reading DESFire smart cards used in Croatian public services, both for:

  1. Dot Net. Multi platform, using pcsc-sharp and "raw" APDU approach.
  2. Android. Using TapLinx SDK for Android and high level-approach. For example: myDesFire.getUID() instead of raw APDU commands.

Right now, I'm trying to develop a multi platform solution in Java, using TapLinx SDK for Java and high-level approach.

I rely on javax.smartcardio for polling connected card terminals to detect when smart card is inserted or removed, and it works perfectly. In my testing app (JavaFX if that matters), in onCardInserted event, I call my own cardLogic method. That method tries to connect to smart card.

In Android, it is very simple:

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.

In Java, similar method of mine is:

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());

// WHAT NOW, I WONDER ???

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

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

So, questions are those in comments of the above code snippets. I'm totally stucked. Probably missing something obvious. but I can not figure out the solution, not even when reading code of both sample apps.

I also tried raw APDU approach in Java, without TapLinx SDK at all, using just javax.smartcardio, but since smartcardio was actually developed to support contact cards, one can not make more complex operations targeting contactless cards. So, I can read DESFire's UID, select identity app, read app IDs, but I can not read BER TLV files, for example, even if not encrypted.

Please help.

标签 (1)
1 解答
1,521 次查看
IkarovoPero
Contributor II

I've found the solution. So, in case someone encounters similar problem
code goes like this. BTW, the key is in the setTransceive method!?!?!!!


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 is barebone:


public class MyCardApduHandler implements IApduHandler {
IReader reader;

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

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

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

 

MyCardReader is as follows:


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

public MyCardReader(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;
}
}

And, Commands.uid(mKanal) is achieved with raw 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();
}

Too bad that most of that is not anywhere near the sample apps...

在原帖中查看解决方案

1 回复
1,522 次查看
IkarovoPero
Contributor II

I've found the solution. So, in case someone encounters similar problem
code goes like this. BTW, the key is in the setTransceive method!?!?!!!


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 is barebone:


public class MyCardApduHandler implements IApduHandler {
IReader reader;

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

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

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

 

MyCardReader is as follows:


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

public MyCardReader(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;
}
}

And, Commands.uid(mKanal) is achieved with raw 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();
}

Too bad that most of that is not anywhere near the sample apps...