Authenticating Ultralight EV1 with PC/SC reader - java

I have a problem trying to authenticate an Ultralight EV1 card using a PC/SC reader (specifically an ACR1222L) in Java. I'm able to write and read on an unprotected tag using the corresponding APDUs for ISO 14443-3 tags. However, I can't find a way to run the PWD_AUTH command since it is not part of the 14443-3 standard (or any native command for that matter). Is it possible to run this command (or any native command for that matter)?
I have tried sending the following APDU {e0 00 00 24 07 1b ff ff ff ff 63 00} where 1b is the native command, ff ff ff ff is the password and 63 00 is the CRC_A of the command plus password. I have also tried without the CRC, switching the order of the parameters, etc., but so far I could not get it working.
I also tried wrapping the APDU (as described in https://stackoverflow.com/a/41729534/3613883). I got it working with a Desfire EV1 card but it doesn’t work with the ultralight EV1 (since it doesn’t support ISO7816-4 obviously).
So, is there a way to authenticate a Ultralight EV1 card using a PC/SC reader?

First of all, MIFARE Ultralight EV1 does not speak APDUs. Instead it uses commands based directly on the framing defined in ISO/IEC 14443-3. Since ISO/IEC 14443-3 only defines the framing and the anti-collision/enumeration commands, any protocol on top of that (e.g. the MIFARE Ultralight/NTAG command sets) is proprietary.
The correct command for password authentication using the password FF FF FF FF would be:
byte[] tagCommand = new byte[] { (byte)0x1B, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF };
Note that the CRC will typically be handled by the contactless frontend chip so you don't need to apped it manually.
With the ACR1222L, there are multiple different ways to exchange such proprietary commands:
You can use PC_to_RDR_Escape (note that that's only available if you installed the original ACR driver package for the reader). Assuming that you are using the Java Smartcard IO API, you would do that using the method Card.transmitControlCommand():
byte[] response = card.transmitControlCommand(SCARD_CTL_CODE(3500), command);
The definition of the method SCARD_CTL_CODE can be found in this post.
The command needs to be a byte array that contains an APDU header for the pseudo-APDU that passes raw commands to the contactless frontend chip and the actual command for the contactless frontend chip. Since the ACR1222L is based on an NXP PN532(?), the command for the contactless frontend chip would be the InDataExchange command (see the user manual):
byte[] interfaceCommandHeader = new byte[] { (byte)0xD4, (byte)0x40, (byte)0x01 };
byte[] interfaceCommand = Arrays.copyOf(interfaceCommandHeader, interfaceCommandHeader.length + tagCommand.length);
System.arraycopy(tagCommand, 0, interfaceCommand, interfaceCommandHeader.length, tagCommand.length);
Depending on how the reader actually activates the card, you might need to use the InCommunicateThru command instead of InDataExchange:
byte[] interfaceCommandHeader = new byte[] { (byte)0xD4, (byte)0x42 };
byte[] interfaceCommand = Arrays.copyOf(interfaceCommandHeader, interfaceCommandHeader.length + tagCommand.length);
System.arraycopy(tagCommand, 0, interfaceCommand, interfaceCommandHeader.length, tagCommand.length);
The pseudo APDU header can be added by:
byte[] commandHeader = new byte[] { (byte)0xE0, (byte)0x00, (byte)0x00, (byte)0x24, (byte)0x00 };
byte[] command = Arrays.copyOf(commandHeader, commandHeader.length + interfaceCommand.length);
System.arraycopy(interfaceCommand, 0, command, commandHeader.length, interfaceCommand.length);
command[4] = (byte)(interfaceCommand.length & 0x0FF); // update Lc field
Another option is to send commands directly using PC_to_RDR_XfrBlock. This maps to CardChannel.transmit() in the Java Smartcard IO API:
ResponseAPDU responseApdu = cardChannel.transmit(commandAPDU);
The manual of your reader is not quite clear if the same pseudo APDU header can be used over that interface. However, if you look into appendix H, you'll find a different header from wrapping into a pseudo APDU (the ACR122U legacy mode). So you could use the following:
CommandAPDU commandAPDU = new CommandAPDU(0xFF, 0x00, 0x00, 0x00, interfaceCommand);
Note that, again, you have to wrap the tag command into the InDataExchange command for the contactless frontend chip.

Related

Sending APDU commands to Write Data to a smartCard Reader using java smartcardio functions

I am trying to write data to contactless card in HID Omnikey 5122 device using java smartcardIO functions.
The Data that I need to insert to the card is {00 01 02 03}.
APDU command I am trying to send through channel.transmit function is {FF D6 00 04 04 00 01 02 03}
where:
FF is CLS
D6 is INS
00 is P1
04 is P2
04 is Number of bytes to update
00 01 02 03 is the data that I need to insert.
I am not able to correctly build the APDU command through below function. Can some one help me with this. I am using functions available in java smartcardio library.
ResponseAPDU respApdu = channel.transmit(
new CommandAPDU(0xFF,0xD6,0x00,0x04,0x04,
new byte[] {(byte) 0x00,
(byte) 0x01,
(byte)0x02,
(byte)0x03}));
I am getting syntax error like constructor command is having invalid arguments.
It looks like you are trying to send an UPDATE BINARY APDU to update the transparent file at offset 4 (this is what you provide in P1-P2). You have to use a CLA byte of 00h (if that file operation doesn't require the use of Secure Messaging).
Since P1-P2 doesn't specify a short file identifier in your case, your currently selected file has
to be compatible with the READ/UPDATE BINARY commands
to have file size >=9 byres.

Read write data in SLE4442 smart card with java commandAPDU?

I want to read and write data in SLE4442 smart card
i have ACR38U-i1 smart card reader
For write I am use this commandAPDU
byte[] cmdApduPutCardUid = new byte[]{(byte)0xFF, (byte)0xD0, (byte)0x40,(byte)0x00, (byte)4,(byte)6,(byte)2,(byte)6,(byte)2};
And for read data
byte[] cmdApduGetCardUid = new byte[]{(byte)0xFF,(byte)0xB0,(byte)0x40,(byte)0x00,(byte)0xFF};
both are execute and send SW= 9000
but no one data receive in responseAPDU
Like I write 6262 data but it not receive
I am also use Select command to before write and read command
The select command is
byte[] cmdApduSlcCardUid = new byte[]{(byte)0xFF,(byte)0xA4,(byte)0x00,(byte)0x00,(byte)0x01,(byte)0x06};
Have anyone Proper java code to read and write in SLE4442 smart card ?
APDU Commands related to work with Memory Cards could be different for different readers and implemented support. Here is an example for OmniKey reader.
Take a look to your ACR reader specification and use specific Pseudo-APDU command to work with SLE 4442.
For your question:
4.6.1 SELECT_CARD_TYPE: "FF A4 00 00 01 06", where 0x06 in the data meant "Infineon SLE 4432 and SLE 4442".
4.6.2 READ_MEMORY_CARD: "FF B0 00 [Bytes Address] [MEM_L]", where
[Bytes Address]: is the memory address location of memory card
[MEM_L]: Length of data to be read from the memory card
4.6.5 WRITE_MEMORY_CARD: "FF D0 00 [Bytes Address] [MEM_L] [Data]"
[Data]: data to be written to the memory card
You used P1 = 0x40 and this could be an issue.

How can I read smart card id? [duplicate]

Which APDU command gets 7 bytes of the card ID?
I use T=CL (ISO7816) protocol with ISO14443 layer. On detect card I can see only 4 bytes of the card ID.
I found that this should be the APDU command to get a card ID.
For example its:
0xFF, 0xCA, 0x00, 0x00, 0x00
but result of this command is: 6E 00, that on specifications of APDU answers tell that "Class not supported"
Then I found that its APDU command may be as:
0x00, 0xCA, 0x00, 0x00, 0x00
this command return 6A 88
where 6A XX - "Wrong parameter(s) P1-P2" and 88 - "Referenced data not found"
What you think about it?
Thank you!
P.S. All command as: CLA, INS, P1, P2, LenData, Data
Other my command work normaly (such as sellect aplet and work with it), problem only at getting card ID
The answer given before is wrong. This is because we are not talking about a ISO 7816 command here but a internal command of the PC/SC API.
The APDU "0xFF 0xCA 0x00 0x00 0x00" is in fact correct and I have cards for which I get a 7 byte answer. Please note that this will only work with contactless (RFID) cards because this UID is part of the radio protocol. Please note further that some chips will return a new random UID after each power up. This is for example true for my passport chip as well as my german national identity card and a countermeasure to prevent tracking of card holders. In theory such random UIDs shall begin with 0x08 but this is not always the case.
As the UID is a "internal" value of the protocol, the APDU in question is NOT sent to the card but is only a internal command (of the PC/SC Interface) to get the UID from the card reader driver. CLA 0xFF is generally not in normal use as it is only used for reserved for "Protocol Parameter Selection" (PPS). PC/SC abuses this CLA for internal commands.
The command here is the PC/SC internal "Get Data" Command, specified in Part 3, Section 3.2.2.1.3 of the PC/SC specification. Here P1 and P2 have special predefined meanings, so there is no point in trying different values. The standard only defineds P1=0,P2=0 for getting the UID and P1=1,P2=0 for "all historical bytes from the ATS of a ISO 14443 A card without CRC". Other values are not supported.
Interestingly the answer 0x6A 0x88 is not defined in the standard. 0x6a 0x81 would mean "Function not supported" which would be the case which cards which don't have a UID (standard mentions 7816-10 contact card). The two other defined answers (0x62 0x82 and 0x6C 0xXX) define a mismatch between the requested answer length and the actual amount of data and won't occur here, because we simply request any length data by specifying 0 in the last byte of the request.
So why it isn't working for the submitter I don't know. For me it works, some cards return 4 bytes, other return 7 bytes.
See the PC/SC standard, part 3 in particular, here: http://www.pcscworkgroup.com/specifications/specdownload.php
0xCA is the GET DATA command. You must supply a TLV Tag in P1-P2.
ISO 7816 part 6 "Interindustry data elements for interchange" has a list of these tags, but none of them corresponds unambiguously to "card ID". I suggest that you try all values of P2, with P1 equal to 0x00, 0x5F, or 0x7F, to find out which data elements are supported by your card.
I think your second command is correct, but the card has not been programmed with an application Id.
For 6A88 the BasicCard manual says: "The built-in command GET APPLICATION ID returns this error code if no application ID was configured in the BasicCard".
This is a very often discussed problem.
0xFF, 0xCA, 0x00, 0x00, 0x00 is the correct pcsc command to get th card uid.
If you get a 6E00 response, then your driver has a bug. Update the driver or try another reader.
I tried :
byte data[] = new byte[]{};
CommandApdu((byte)0xA0, (byte)0xC0, (byte)0x00, (byte)0x00, data)
I got SW1=(byte)0x9F SW2=(byte)0xXX
9FXX = "Command successfully executed; ‘xx’ bytes of data are available and can be
requested using GET RESPONSE."
Except 9F00 and 9F04 which means
9F00=PIN blocked and Unblock Try Counter is 3
9F04=PIN not succesfully verified, PIN blocked and Unblock Try Counter is 3

Reading phantom NFC tags via javax.smartcardio

I have an an old NFC reader for the tikitag web service (which was later renamed touchatag, and finally abandoned around 2012). Since the website is no longer available, I could no longer find the original tikitag/touchatag drivers. After some searching, I found this NFC reader is a generic ACS ACR122U USB reader, and installed a suitable driver from here. My system is Windows 7 (64-bits).
First, I tried the NFC Tools library for high-level read and write access to NFC tags. I got an error saying an unsupported tag was encountered; although no tag was present on the reader, or even remotely nearby. It seems other developers also encountered the same error with this library, as shown here. Note this tag is detected ad infinitum (so, it does not just disappear after being detected once).
I copied the required low-level code into a separate class (i.e., independent from the NFC Tools library). You can find this code below (similar code can also be found in tutorials):
import java.util.List;
import javax.smartcardio.Card;
import javax.smartcardio.CardTerminal;
import javax.smartcardio.TerminalFactory;
import org.nfctools.utils.NfcUtils;
public class NdefTest {
public static void main(String[] args) throws Exception {
TerminalFactory factory = TerminalFactory.getDefault();
List<CardTerminal> terminals = factory.terminals().list();
CardTerminal terminal = terminals.get(0);
if (terminal.waitForCardPresent(5000)) {
Card card = terminal.connect("T=0");
System.out.println(NfcUtils.convertBinToASCII(card.getATR().getHistoricalBytes()));
}
}
}
This code detects the exact same "phantom" tag as when using the NFC Tools library. Therefore, this issue seems unrelated to the NFC Tools library (as implied by the library developer in response to the error report). Either I'm missing something, or the issue is either related to the installed driver, the NFC reader hardware, or some unfixed bug in javax.smartcardio (listed in order of likelihood).
I have tried uninstalling the aforementioned driver and letting Windows 7 install a suitable driver on its own (called "Microsoft Usbccid Smartcard Reader (WUDF)"), which results in the same errors as described above. I have not tried another reader, since I only have the one.
(Note: the name of this NFC reader in the Windows device overview is "CCID USB Reader", instead of "ACS ACR122" or something related. Don't know whether this is important, just thought I would mention it.).
Has anyone encountered this issue, and managed to resolve it?
UPDATE
Ok, I've tried sending a CLF command to the reader after the simulated tag has been detected; namely, getting the ATS of the connected PICC (p. 11 of the ACR122U manual):
TerminalFactory factory = TerminalFactory.getDefault();
List<CardTerminal> terminals = factory.terminals().list();
// (this is the correct terminal)
CardTerminal terminal = terminals.get(0);
if (terminal.waitForCardPresent(5000)) {
Card card = terminal.connect("*");
CardChannel channel = card.getBasicChannel();
// (I tried both 0x00 and 0x01 as P1, as well as 0x05 for Le)
CommandAPDU getAts = new CommandAPDU(0xFF, 0xCA, 0x00, 0x00, 0x04);
ResponseAPDU response = channel.transmit(getAts);
System.out.println(response.getSW1());
System.out.println(response.getSW2());
}
But I keep getting an error response code (0x63 0x00). Any ideas on what I could be doing wrong?
The problem you encounter is that this version of the ACR122U reader uses PC/SC (CCID) in a somewhat non-standard way.
The "card" that you detect with the PC/SC API is actually either a dummy card simulated by the reader (to allow the PC/SC API to open a connection even if no card is present) or a smartcard chip in the reader's SAM slot (contact card present inside the reader's casing).
In either case, this reader uses PC/SC only as a transport protocol for native commands of the contactless frontend chip used within this reader (NXP PN532). Thus, if you want to use the reader's contactless functionality, you have to use the CLF's native command set. See the ACR122U API documentation or the libnfc implementation for further details.
(all credit goes to Michael Roland; this post is meant as a solution summary)
Ok Michael, given the example in your last comment, I finally understand what you mean by using the PC/SC protocol for tunneling CLF commands. I tested some of the commands in the PN532 documentation, and they return valid results. (However, the command you gave as an example didn't work and crashed the reader; it had to be reset.)
For instance, to get the firmware version:
CommandAPDU commApdu = new CommandAPDU(0xFF, 0x00, 0x00, 0x00,
new byte[] { (byte)0xD4, (byte)0x02 });
InDataExchange command:
CommandAPDU commApdu = new CommandAPDU(0xFF, 0x00, 0x00, 0x00,
new byte[] { (byte)0xD4, (byte)0x40, 0x01 });
I found the NFCIP library, which supports sending byte arrays between peers (examples are ACS ACR122 and Nokia 6131) using the InDataExchange command. When reading the PN532 documentation (p. 131), it seems that this command allows reading tags as well. Michael, do you happen to know of any library that handles uses these low-level commands with the goal of reading (different types of) tags?

Get hex values from socket and convert to decimal

I have data that I read from a socket and I know it has the following format:
[2bytes][8bytes][2bytes] = 12 bytes
That I want to read separately; and the values are in Hex. I actually captured that data a while ago in PHP and saved it to files and I can view it properly using od (unix):
$ od -h myFile
$ 0000000 02eb 02fe fe02 fefe 02fe 02fe 000a
$ 0000015
That, has a CR and LF at the end, resulting in 14 bytes. How can I obtain those values in Java reading from a socket? For instance how do I get that "02eb" (2 bytes) and convert it to a decimal value?
I am already reading from the socket, last thing I tried was:
mMessage = mBRin.readLine();
byte[] bytes = mMessage.trim().getBytes()
But that gives me 18 bytes in the array.
If it helps, in PHP to get that first part I did:
$input = socket_read($value,13,PHP_BINARY_READ);
$trim_input = trim($input);
$float_head = hexdec(bin2hex(substr($input,0,2)));
I think I am not understanding this, which may be the answer
I have data that I read from a socket and I know it has the following
format:
[2bytes][8bytes][2bytes] = 12 bytes
If you already have code to read bytes from a socket, you can use a ByteBuffer to convert the bytes to short, int, long etc. values.
Socket s = .....;
InputStream in = s.getInputStream();
byte [] buf = new byte[12];
// read 12 bytes from socket into bytes
in.read(buf);
ByteBuffer bb = ByteBuffer.allocate(buf.length);
bb.order(ByteOrder.LITTLE_ENDIAN);
bb.put(buf);
bb.flip();
short short1 = bb.getShort();
long long1 = bb.getLong();
short short2 = bb.getShort();
Note the call to set the byte buffer to little endian.
When you did the od command you got output similar to the following (this output comes from a file I created on my system to mimic yours). The od -h command reads the bytes from the file, puts them together as 2-byte shorts in little endian mode then prints out the short values in hex.
$ od -h binary.dat
0000000 02eb 02fe fe02 fefe 02fe 02fe 000a
0000015
However if you use the -tx1 you see the bytes in the real order they appear in the file.
$ od -tx1 binary.dat
$ 0000000 eb 02 fe 02 02 fe fe fe fe 02 fe 02 0a
$ 0000015
If you run this on your file I think you will see that it is really 13 bytes not 14 bytes and is terminated by a single LF, not CRLF. The "extra" byte you saw was a "present" from od -h is does not actually exist in file.
Anyhow, The first byte is value 235 (EB in hex). The second byte is 2. The question is - what is the correct value for that first short want. If, according to your socket protocol, the data is serialized in little endian mode, the value of those two bytes concatenated into a short is 02EB hex or 747. If the socket protocol uses big endian, then the value is EB02 hex or 60162.
The ByteBuffer approach gives you flexibility and allows you to read/write in either big-endian or little endian. It also allows you to separate the reading of data off the socket (into byte arrays) then later converting the data into numbers. This may make it easier for unit testing since you can create byte arrays for various test cases and make sure your parsing code works as expected.
The DataInputStream approach in sharadendu's answer will also work - but only if the socket protocol is big-endian. DataInputStream is hard-coded to big-endian.
Socket socket = ......;
DataInputStream dis = new DataInputStream(socket.getInputStream());
short f1 = dis.readShort();
long f2 = dis.readLong();
sort f3 = dis.readShort();
To print the values in hex use String.format("%x",f1);
Hope it helps ...

Categories