Mifare Ultralight C Authentication on Android

2019-07-13 18:13发布

问题:

I have some Mifare Ultralight C tags for testing authentication.

The first time I read it with the app NXP TagInfo, I could see the following info:

(...)
Page 04 - Page 27: FULL OF 0s **(empty tag)**
Page 28: 00 00 -- --
Page 29: 00 00 -- --
Page 2A: 30 -- -- --
Page 2B: 00 -- -- --
Page 2C: 42 52 45 41
PAGE 2D: 4B 4D 45 49
PAGE 2E: 46 59 4F 55
PAGE 2F: 43 41 4E 21

The page 2C - 2F means that it had the default key "BREAKMEIFYOUCAN!" (425245414b4d454946594f5543414e21).

Then I ran my Android app which basically did this:

  1. Write 49454D4B41455242214E4143554F5946 starting from page 2C till page 2F (for authenticating).

  2. Write 0x04 at page 2A (42); meaning all the pages from 2A on need authentication.

  3. Write 0x00 at page 2B (43); meaning authentication is needed both for reading and writing.

//Start authenticating
byte[] result1 = mifare.transceive(new byte[] {
                (byte)0xA2,  /* CMD = WRITE */
                (byte)0x2C,  /* PAGE = 44    */
                (byte)0x49, (byte)0x45, (byte)0x4D, (byte)0x4B  /* 49 45 4D 4B */
        });

byte[] result2 = mifare.transceive(new byte[] {
                (byte)0xA2,  /* CMD = WRITE */
                (byte)0x2D,  /* PAGE = 45    */
                (byte)0x41, (byte)0x45, (byte)0x52, (byte)0x42  /* 41 45 52 42 */
        });

byte[] result3 = mifare.transceive(new byte[] {
                (byte)0xA2,  /* CMD = WRITE */
                (byte)0x2E,  /* PAGE = 46    */
                (byte)0x21, (byte)0x4E, (byte)0X41, (byte)0X43  /* 21 4E 41 43 */
        });

byte[] result4 = mifare.transceive(new byte[] {
                (byte)0xA2,  /* CMD = WRITE */
                (byte)0x2F,  /* PAGE = 47    */
                (byte)0X55, (byte)0X4F, (byte)0X59, (byte)0X46  /* 55 4F 59 46 */
        });
//Finish authenticating

//Say the pages the card needs authentication
byte[] result5 = mifare.transceive(new byte[] {
                (byte)0xA2,  /* CMD = WRITE */
                (byte)0x2A,  /* PAGE = 42    */
                (byte)0x04, (byte)0x00, (byte)0x00, (byte)0x00  /* Message = All pages after 04 needs authentication */
        });

byte[] result6 = mifare.transceive(new byte[] {
                (byte)0xA2,  /* CMD = WRITE */
                (byte)0x2B,  /* PAGE = 43    */
                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00  /* Message = authentication is required both for reading and writing */
        });
//Finish "card activition"

After doing this, I read the tag again using the NXP TagInfo app, and as expected, I couldn't see the tag info anymore. Instead of that, it indicated .p XX XX XX XX on all fields (from 04 on), which indicates it needs password for reading the data.

After that (and here is where I can't see my mistake) I tried to authenticate the tag again (by writing to pages 2C - 2F), but I get this error at the beginning of the authentication part:

System.err: java.io.IOException: Transceive failed
System.err:     at android.nfc.TransceiveResult.getResponseOrThrow(TransceiveResult.java:52)
        at android.nfc.tech.BasicTagTechnology.transceive(BasicTagTechnology.java:151)
        at android.nfc.tech.MifareUltralight.transceive(MifareUltralight.java:215)**

I can't see what I'm doing wrong...

回答1:

What you are doing wrong is that you did not actually implement the MIFARE Ultralight C authentication. On MIFARE Ultralight C tags, writing to pages 0x2C..0x2F does exactly what the command says: It writes to that pages, but it does not perform any authentication.

Instead, MIFARE Ultralight C implements a three-way mutual challenge-response authentication protocol. This protocol is started by sending an AUTHENTICATE command:

byte[] result1 = mifare.transceive(new byte[] {
            (byte)0xA1,  /* CMD = AUTHENTICATE */
            (byte)0x00
});

In response to that command, you will get a challenge that you need to decrypt using the authentication key, manipulate, encrypt and send back to the tag to proof that you actually posess the authentication key. You can find some code that implements MIFARE Ultralight C authentication in this Q/A: Android: Authenticating with NXP MiFare Ultralight C.