Unkown error 0x16 on smartcard reader access

孤街醉人 提交于 2020-01-01 16:56:11

问题


I am trying to change the buzzer duration on the ACR1252U.

Link to API: http://www.acs.com.hk/download-manual/6402/API-ACR1252U-1.09.pdf

According to the API documentation I need the 'E0000028010A' command to change the buzzer status, whereby '0A' marks the duration as 0A*10ms (Page 44).

Following Java code is used:

public static void main(String[] args) {
    try {
        byte[] send = new byte[6];

        send[0] = (byte) 0xE0; // Commandclass
        send[1] = (byte) 0x00; // Protocoll
        send[2] = (byte) 0x00; // Param 1
        send[3] = (byte) 0x28; // Param 2: Buzzerstatus
        send[4] = (byte) 0x01; // Change Flag
        send[5] = (byte) 0x0A; // Duration: 0A*10ms => 100ms

        Card card = getCard("DIRECT"); // Works!
        CardChannel channel = card.getBasicChannel(); // Works!
        CommandAPDU command = new CommandAPDU(send); // Works!
        channel.transmit(command); // EXCEPTION!
    } catch (Exception ex) {
        ex.printStackTrace();
    }
}

public static Card getCard(String target) throws Exception {
    TerminalFactory factory = TerminalFactory.getDefault();
    List<CardTerminal> terminals = factory.terminals().list();
    for (CardTerminal t : terminals) {
        if (t.getName().equals("ACS ACR1252 Dual Reader PICC 0")) {
            Card card = t.connect(target);
            return card;
        }
    }
    throw new Exception();
}

But this results in the following stacktrace indicating the "unkown error 0x16":

javax.smartcardio.CardException: sun.security.smartcardio.PCSCException: Unknown error 0x16
    at sun.security.smartcardio.ChannelImpl.doTransmit(ChannelImpl.java:219)
    at sun.security.smartcardio.ChannelImpl.transmit(ChannelImpl.java:90)
    at readerconfig.TagConfig.main(TagConfig.java:24)
Caused by: sun.security.smartcardio.PCSCException: Unknown error 0x16
    at sun.security.smartcardio.PCSC.SCardTransmit(Native Method)
    at sun.security.smartcardio.ChannelImpl.doTransmit(ChannelImpl.java:188)
    ... 2 more

I've spent hours on searching for anything in this direction however I couldn't find anything. I have even tried another device, which still generated this error.

Either I have completely gone blind or something is not set up correctly with my computer. All I can say is, that I have already successfully written and read from NFC tags using this reader. But I just can't change the config of the reader itself.

EDIT:

I've also found this alternative way to send the command:

byte[] send = new byte[5];
send[0] = (byte) 0xE0;
send[1] = (byte) 0x0;
send[2] = (byte) 0x0;
send[3] = (byte) 0x18; // Tries to read firmware version
send[4] = (byte) 0x0;

Card card = CardUtils.getCard("DIRECT"); // Works!
card.transmitControlCommand(3500, send);

But this results in the "unknown error 0x1":

javax.smartcardio.CardException: transmitControlCommand() failed
    at sun.security.smartcardio.CardImpl.transmitControlCommand(CardImpl.java:236)
    at readerconfig.ReaderConfig.main(ReaderConfig.java:28)
Caused by: sun.security.smartcardio.PCSCException: Unknown error 0x1
    at sun.security.smartcardio.PCSC.SCardControl(Native Method)
    at sun.security.smartcardio.CardImpl.transmitControlCommand(CardImpl.java:232)
    ... 1 more

回答1:


There are two ways to interact with this reader over the Java Smartcard IO API:

  1. The first is to open a regular APDU transmission channel (from a PC/SC point of view this maps to T=0 or T=1 protocol). You can do this using

    Card card = getCard("*");
    

    However, this will require the reader to report the presence of a card. Otherwise you can't open a connection that way.

    You can then transmit APDU commands to the card (on the basic channel or a logical channel) and you can send special commands to the reader on the basic channel. These special commands have their class byte set to 0xFF to indicate that the command is intended to be interpreted by the reader (instead of being forwarded to the card). So this is not applicable for the "peripherals control" commands that start with 0xE0.

  2. Those "peripherals control" commands have to be sent to the reader using control commands with the control code SCARD_CTL_CODE(3500). As with opening a connection to the card, you can use getCard("*") if there is a card present on the reader. However, if you want to be able to send those commands to the reader even if there is no card present, you have to open a connection in "direct" mode:

    Card card = getCard("DIRECT");
    

    You can then send control commands using the method card.transmitControlCommand(). This method takes the control code as the first argument and the command (as byte array) as the second argument. Exchanging commands on the basic channel or any logical channel using channel.transmit() will usually not work in "direct" mode (hence the error code 0x16).

    The control code is calculated as

    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;
        }
    }
    

    Note the difference between Windows and other platforms.

    For instance, to send the buzzer control command, you would use

    byte[] command = new byte[] { (byte)0xE0, (byte)0x00, (byte)0x00, (byte)0x28, (byte)0x01, (byte)0x0A };
    byte[] response = card.transmitControlCommand(SCARD_CTL_CODE(3500), command);
    

    Finally, be aware that sending IOCTL control codes over PC/SC requires special driver support. Specifically, the standard CCID driver provided by Microsoft does not support sending escape commands by default (see USB CCID Class Driver Details). This driver supports escape commands only after enabling them through the registry value "EscapeCommandEnable". The error 0x1 that you showed in your question is a typical result of this missing support for escape commands.

    To reliably support all features of the reader (including escape commands) you need to use the "PC/SC Drivers" package provided by ACS on their website.




回答2:


Try to use

card.transmitControlCommand(int controlCode, byte[] command)

instead of transmit. According to section 5.8 (page 41 of the pdf you linked to) controlcode is 3500, although it is unclear to me, if that is a hex or an int, so compare to SCARD_CTL_CODE, if you are able to. At least, I interpret the documentation this.

Usually you use transmitControlCommand to talk to the reader and transmit to talk to the card.

Fixed typo in ControlCode. Kudos to Torhan Bartel for telling me.



来源:https://stackoverflow.com/questions/41851527/unkown-error-0x16-on-smartcard-reader-access

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!