I am trying to read data from ISO-7816-4 eVCR (electronic vehicle registration card) using
javax.smartcardio. Whenever I try to select file from card I get SW code 6A86 which
translates to 'Incorrect P1 or P2 parameter'. I tried many combinations of values for
P1 and P2 and got same result.
Card itself works fine with other programs and sample code works fine with other cards.
Card I have problem with is same card as in this question.
This is code I use:
Card card = terminal.connect("*");
System.out.println("ATR: " + Utils.bytes2HexString(card.getATR().getBytes()));
byte aid[] = {(byte)0xA0, 0x00, 0x00, 0x00, 0x77, 0x01, 0x08, 0x00, 0x07,
0x00, 0x00, (byte) 0xFE, 0x00, 0x00, (byte) 0xAD, (byte) 0xF2};
ResponseAPDU response = null;
CardChannel channel = card.getBasicChannel();
response = channel.transmit(new CommandAPDU(0x00, 0xA4, 0x04, 0x0C, aid));
System.out.println("AID: " + response);
response = channel.transmit(new CommandAPDU(0x00, 0xA4, 0x02, 0x00, new byte[]{(byte)0xD0, 0x01}));
System.out.println("SELECT: " + response);
And output is:
ATR: 3B:DB:96:00:80:B1:FE:45:1F:83:00:31:C0:64:1A:18:01:00:0F:90:00:52
AID: ResponseAPDU: 2 bytes, SW=9000
SELECT: ResponseAPDU: 2 bytes, SW=6a86
I can't see what am I doing wrong. Do some cards require extra initialization steps or some extra parameters for select?
You could use 0x0C as P2 (instead of 0x00)? Maybe the file ID is correct, but it cannot give back any file information (0x0C means: don't give back file information).
It depends on the card operating system and/or application if this would influence the returned status word.
Related
I'm developing a Java application that connects to HID Omnikey 5022 card reader. What I need is reading PACS bits (raw Wiegand data).
I have exactly the same problem with this question, I also can see the data with PACS Probe application:
How to read Smart Card data
Unfortunately the provided answer to that is not working for me.
This is what I get from PACS Probe:
Card Reader: HID Global OMNIKEY 5022 Smart Card Reader 0
Card type: PicoPass 32KS (8x2 + 16)
Card serial number (CSN, UID): 32966202F8FF12E0 (hex)
PACS bits (raw Wiegand) data: 000000310BC53938 (hex)
I have already tried the command I found in Omnikey 5023 guide, surprisingly it returns some data but it's not what I need.
That command is:
commandAPDU = new CommandAPDU(new byte[] { (byte) 0xFF, (byte) 0x70, (byte) 0x07, (byte) 0x6B, (byte) 0x07,
(byte) 0xA0, (byte) 0x05, (byte) 0xBE, (byte) 0x03, (byte) 0x80, (byte) 0x01, (byte) 0x04, (byte) 0x00 }); // Read PACS 5023
It returns this:
9E020003
// I need 000000310BC53938
Any help is appreciated since I am new to smart card development.
Thanks in advance.
The response APDU you are getting from the reader is an error code for unsupported proprietary command.
You will need a secure session to access PACS bit data using OMNIKEY 5022 or OMNIKEY 5023 readers.
Unless you have the appropriate documentation for this reader, I would probably stick to the card serial number (UID, CSN) and use a Java wrapper for PC/SC (or pcsclite) to connect to reader and card.
Then issue (via SCardTransmit(FFCA0000 APDU) to get the UID (32966202F8FF12E0) shown in your the sample output from https://PACSprobe.com
As for Java: use smartcardio lib. That's a good wrapper for native PC/SC
It's a lot of work porting the secure channel protocols to Java. Calling a third-party library may be easier.
I was able to use javax.smartcardio, and get the Wiegand data using code like below. At the end you can see the facility code and card number are printed.
TerminalFactory terminalFactory = TerminalFactory.getDefault();
CardTerminals cardTerminals = terminalFactory.terminals();
List<CardTerminal> terminalList = cardTerminals.list();
CardTerminal cardTerminal = terminalList.get(0);
cardTerminal.waitForCardPresent(10 * 1000); // wait 10 seconds
Card card = cardTerminal.connect("*");
System.out.println("Card: " + card);
CardChannel channel = card.getBasicChannel();
byte[] aid = { (byte) 0xA0, (byte) 0x05, (byte) 0xA1, (byte) 0x03, (byte) 0x80, (byte) 0x01, (byte) 0x04 };
CommandAPDU apdu = new CommandAPDU(0xFF, (byte) 112, (byte) 7, (byte) 107, aid, 256);
ResponseAPDU r = channel.transmit(apdu);
byte[] bytesOut = r.getBytes();
int num1 = (int) bytesOut[3];
if (bytesOut.length - 6 != num1)
System.out.println("problem");
int numberOfBitsShifted = (int) bytesOut[4];
int num2 = num1 - 1;
byte[] newBytesArr = Arrays.copyOfRange(bytesOut, 5, 5 + num2);
if (newBytesArr.length != num2)
System.out.println("problem");
ByteBuffer wrapped = ByteBuffer.wrap(newBytesArr);
int num = wrapped.getInt();
int first26 = num >> 6;
int withoutParity = first26 >> 1;
int cardNumber = withoutParity & 0xffff;
int facilityCode = (withoutParity >> 16) & 0xff;
System.out.println(facilityCode);
System.out.println(cardNumber);
In the following programs, command is a byte array field in Apdu class. The problem is that my IDE (Netbeans) mark the line of
apdu.command = {(byte) 0x00, (byte)0xa4, (byte) 0x00, (byte) 0x00};
As error, with the message illegal start of expression, while it is okay to use the following instead:
byte[] bytes = {(byte) 0x00, (byte) 0xa4, (byte) 0x00, (byte) 0x00};
apdu.command = bytes;
What's wrong with the first programs?
First program:
Second Program:
You need to initialize the array variable with :
apdu.command = new byte[] {(byte) 0x00, (byte)0xa4, (byte) 0x00, (byte) 0x00};
The initialization you tried is only valid in array declaration expressions.
array syntax {} can only be used for initialization not for assignment.
you need to use apdu.command =new byte[] {(byte) 0x00, (byte)0xa4, (byte) 0x00, (byte) 0x00};.
I am trying to write hexadecimal data into my serial port using java, but now I cant convert the hexadecimal data into the byte array.
Here is the code which shows the error message:
static byte[] bytearray = {0x02, 0x08, 0x16, 0x0, 0x00, 0x33, 0xC6, 0x1B};
This is the code writing into the serial port:
try {
outputStream = serialPort.getOutputStream();
// Write the stream of data conforming to PC to reader protocol
outputStream.write(bytearray);
outputStream.flush();
System.out.println("The following bytes are being written");
for(int i=0; i<bytearray.length; i++){
System.out.println(bytearray[i]);
System.out.println("Tag will be read when its in the field of the reader");
}
} catch (IOException e) {}
Can I know how can I solve this problem. Currently I am using the javax.comm plugin. Thank you.
If you look at the error message:
Main.java:10: error: incompatible types: possible lossy conversion from int to byte
static byte[] bytearray = {0x02, 0x08, 0x16, 0x0, 0x00, 0x33, 0xC6, 0x1B};
^
There is a small caret pointing to the value 0xC6. The reason for the issue is that java's byte is signed, meaning that its range is from -0x80 to 0x7F. You can fix this by casting:
static byte[] bytearray = {0x02, 0x08, 0x16, 0x0, 0x00, 0x33, (byte) 0xC6, 0x1B};
Or, you can use the negative, in-range value of -0x3A (which is equivalent to 0x36 in two's-complement notation).
Try to cast 0xC6 like this as byte range is from -0x80 to 0x7F:
static byte[] bytearray = {0x02, 0x08, 0x16, 0x0, 0x00, 0x33, (byte) 0xC6, 0x1B};
I'm trying to convert int to hex with format 0x12 0x2B and so on. Is there anything similar like python: https://docs.python.org/2/library/functions.html#hex
to accomplish this or i will need to work around this with many unnecessary steps?
I need to get something like this below:
int []hexInt={0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01};
You could declare a String which will be equal to "0x" + Integer.toHexString(int)
public static String intToHexStr(int i){
return "0x"+String.format("%2s", Integer.toHexString(i)).replace(' ', '0');
}
Maybe this is very late but here is the answer to your question:
Integer.parseInt(String.format("%X", intValue),16)
As the title says; is there a APDU command for retrieving the UID of a tag? I am using Java, with an ACR122-u cardreader and the javax.smartcardio.* package and I want to get the UID from a tag on the scanner. The smartcardio library can send CommandAPDU's but I need to figure out what APDU to send. Google has not been very friendly to me on this one, providing me with thousands of unhelpful datasheets of some sort...
Any help would be great :)
Better late than never but there is actually an APDU to JUST retrieve the UID: (byte) 0xFF, (byte) 0xCA, (byte) 0x00, (byte) 0x00, (byte) 0x00
FF CA 00 00 00
In Java: byte[] getuid = new byte[] { (byte) 0xFF, (byte) 0xCA, (byte) 0x00,
(byte) 0x00, (byte) 0x00 };
If you send this APDU, the response data will be just the UID of the card :) (Much easier than having more info and having to set an offset to get just the info you need...)
The APDU Command for Read UID is
byte[] baReadUID = new byte[5];
baReadUID = new byte[] { (byte) 0xFF, (byte) 0xCA, (byte) 0x00,
(byte) 0x00, (byte) 0x00 };
All Complete code is here....