Search code examples
pythonnfcacr122

Write password to Ntag213 using python and acr122u


I'm trying to write some data into a NFC using the acr 122u card reader. So far, I'm able to do it. My problem is that I need to also make the NFC password protected. I can add the password using a phone app like nfctools, but I need this process to be automated in the future.

For this I am using python smartcard.System to connect and write to the NFC tag. My problem is that I can't find anywhere how to save a password into the tag.

from smartcard.System import readers
from smartcard.CardConnection import CardConnection
from smartcard.scard import SCARD_SHARE_DIRECT

reader = readers()[0]
print(reader)
connection = reader.createConnection()
connection.connect()
command = [0xFF, 0xD6, 0x00, 0x05, 0x04, 0x34, 0x03, 0x3d,0x91]
r, sw1, sw2 = connection.transmit(command)

This works for writing. I've tried this for authentication:

auth= [0xFF, 0x00, 0x00, 0x00, 0x07, 0xd4, 0x42, 0x1b, 0x01, 0x01, 0x01, 0x01]
r, sw1, sw2 = connection.transmit(auth)
print(r)
print(sw1)
print(sw2)

auth2= [0xFF, 0x86, 0x00, 0x00, 0x05, 0x01, 0x00, 0x04, 0x60, 0x00]
r, sw1, sw2 = connection.transmit(auth2)
print(r)
print(sw1)
print(sw2)

And this does not work. As far as I know, this would only authenticate me into the NFC and will not write the password into the NFC itself.

Any tips? Thanks

Edit: I'm using the API file in the acs website http://www.acs.com.hk/download-manual/419/API-ACR122U-2.04.pdf


Solution

  • With the help of @Andrew and some research I was able to find the solution.

    I was using python smartcard to communicate from python to the acr122u like this:

    from smartcard.System import readers
    from smartcard.CardConnection import CardConnection
    from smartcard.scard import SCARD_SHARE_DIRECT
    
    reader = readers()[0]
    connection = reader.createConnection()
    connection.connect()
    

    In order to write normal data to the tag, I was using the Update Binary Blocks from http://www.acs.com.hk/download-manual/419/API-ACR122U-2.04.pdf, like this:

    command = [0xFF, 0xD6, 0x00, 0x05, 0x04, 0x34, 0x03, 0x3d,0x91]
    r, sw1, sw2 = connection.transmit(command)
    if (sw1,sw2) == (0x90,0x00):
        print("Correct command")
    else:
        print("Error")
    

    When it comes to setting a password for the tag, we need to use the Direct Transmit command from the ACS PDF. This command will send our payload to the PN532 chip inside the NFC reader. So, inside our payload we need to have a special command to tell the PN532 to send our command to the NFC tag, that special code is 0x4d,0x42.

    Now we can use any command supported by the Ntag 213 present here https://www.nxp.com/docs/en/data-sheet/NTAG213_215_216.pdf we just need to follow this layout:

    [0xff, 0x00, 0x00, 0x00, Number of bytes to send, Payload]

    where payload is:

    [0xd4,0x42, ntag command] for example a read is [0xd4,0x42,0x30, 0x29]

    In total, our command to use in the direct transmit will look like this: [0xff, 0x00, 0x00, 0x00, 0x4, 0xd4,0x42,0x30, 0x29]

    enter image description here

    In order to complete the password process, we need to follow the steps described in NTAG212 Mifare Ultralight with Authentication like this:

    def createPseudoAPDU(payload, nBytes):
        #nBytes+0x2 to add the 0xd4 and 0x42 two bytes
        return np.concatenate(([0xff, 0x00, 0x00, 0x00, nBytes+0x2,0xd4,0x42], payload), axis=0).tolist() 
    
    
    setPwd = createPseudoAPDU([0xa2, 0x2b,0x32,0x30,0x32,0x32],0x06)
    setPack = createPseudoAPDU([0xa2, 0x2c,0x00,0x00,0x00,0x00],0x06)
    
    setAuthLimAndProt = createPseudoAPDU([0xa2, 0x2a,0x00,0x05,0x00,0x00],0x06)
    
    setauth0 = createPseudoAPDU([0xa2, 0x29,0x04,0x00,0x00,0x00],0x06)
    
    r, sw1, sw2 = connection.transmit(setPwd)
    print(r)
    print(sw1)
    print(sw2)
    
    r, sw1, sw2 = connection.transmit(setPack)
    print(r)
    print(sw1)
    print(sw2)
    
    r, sw1, sw2 = connection.transmit(setAuthLimAndProt)
    print(r)
    print(sw1)
    print(sw2)
    
    r, sw1, sw2 = connection.transmit(setauth0)
    print(r)
    print(sw1)
    print(sw2)