Java smartcardio // transmitControlCommand response is always empty // ACR 39

444 Views Asked by At

after very useful tips from user vlp, I have finally been able to connect to an AT24C16 I2C card with my ACR39 card reader through the java smartcard API (original thread).

Since the free memory card I want to read is not a smart card, I need to use pseudo APDU commands to talk to the card via Card.transmitControlCommand. The card reader came with a great documentation that contains all the commands I need (basically I just need to read the data on the card).

While everything seems to work fine, I don't get any response from the card or from the reader (when querying the firmware).

I have this:

package com.Smaca;

import java.util.List;
import javax.smartcardio.*;

public class SReader {

    public static void readCard() {

        TerminalFactory factory = TerminalFactory.getDefault();

        // GET_READER_INFORMATION
        // I believe this is the correct command - the manual specifies 11h as the last byte
        // I tried both
        byte[] GET_R_INFO = new byte[] { (byte)0xFF,(byte)0x09,(byte)0x00,(byte)0x00,(byte)0xB};
        //byte[] GET_R_INFO = new byte[] { (byte)0xFF,(byte)0x09,(byte)0x00,(byte)0x00,(byte)0x11};


        //SELECT_CARD_TYPE
        byte[] SELECT_CARD_TYPE = new byte[] { (byte)0xFF, (byte)0xA4, (byte)0x00, (byte)0x00, (byte)0x01, (byte)0x01 };
        
        //SELECT_PAGE_SIZE
        byte[] SELECT_PAGE_SIZE = new byte[] { (byte)0xFF, (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x01, (byte)0x04 };

        //READ_MEMORY_CARD
        byte[] READ = new byte[] { (byte)0xFF, (byte)0xB0, (byte)0xFF, (byte)0x00, (byte)0xFF };

        int SCARD_CTL_CODE = 3500;

        try {
            List terminals = factory.terminals().list();
            CardTerminal ter = (CardTerminal)terminals.get(0);

            ter.waitForCardPresent(3000000);

            if(ter.isCardPresent())
            {
                System.out.println("Card present");

                Card ca = ter.connect("direct");
                System.out.println(ca);

                byte[] response_info = ca.transmitControlCommand(SCARD_CTL_CODE(SCARD_CTL_CODE), GET_R_INFO);
                System.out.println("Reader info: "+ bytesToHex(response_info));

                byte[] response = ca.transmitControlCommand(SCARD_CTL_CODE(SCARD_CTL_CODE), SELECT_CARD_TYPE);
                System.out.println("Select card: "+bytesToHex(response));

                byte[] response_ps = ca.transmitControlCommand(SCARD_CTL_CODE(SCARD_CTL_CODE), SELECT_PAGE_SIZE);
                System.out.println("Select page size: "+ bytesToHex(response_ps));

                byte[] response_read = ca.transmitControlCommand(SCARD_CTL_CODE(SCARD_CTL_CODE), READ);
                System.out.println("Data read: "+ bytesToHex(response_read));


            }

            System.out.println( "is Card Present: " + ((CardTerminal)terminals.get(0)).isCardPresent());


        } catch (CardException e) {
            e.printStackTrace();
        }
    }

    public static String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte hashByte : bytes) {
            int intVal = 0xff & hashByte;
            if (intVal < 0x10) {
                sb.append('0');
            }
            sb.append(Integer.toHexString(intVal));
        }
        return sb.toString();
    }   


    public static final int SCARD_CTL_CODE(int command) 
    {
        boolean isWindows = System.getProperty("os.name").startsWith("Windows");
        if (isWindows) {
            return 0x00310000 | (command << 2);
        } else {
            return 0x42000000 | command;
        }
    }



    public static void main(String[] args) {
        readCard();
    }
}

And this is the output:

Card present
PC/SC card in ACS ACR39U ICC Reader, protocol Unknown protocol 4, state OK
Reader info: 
Select card: 
Select page size: 
Data read: 
is Card Present: true

Can anyone see what I'm doing wrong? At the very least the GET_READER_INFORMATION command should work?!

UPDATE:

I think I know what the problem is. I only transmitted the raw data of the commands but they need to be transmitted as payload of the PC_to_RDR_XfrBlock command (Chapter 7.1.4.).

I'm still having problems formatting the command, though. If anyone has any idea how to do that, please let me know. A concrete example would be great.

Thanks! Tom

0

There are 0 best solutions below