Authenticating Ultralight EV1 with PC/SC reader

∥☆過路亽.° 提交于 2019-12-04 12:00:46
Michael Roland

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:

  1. 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
    
  2. 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.

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