watersa8
watersa8

Reputation: 13

PN532 MiFare Ultralight C Mutual Authentication

Has anyone managed to get Mutual Authentication with an ultralight C card working using this chip? I understand the Authentication procedure but looking at the command set in the chips manual and trying a few things I don't think it is actually possible but thought I would post here before abanding the chip-set and moving back to using a CJS encoder for verification

Thanks in advance

Upvotes: 1

Views: 1052

Answers (2)

Lewis Munene
Lewis Munene

Reputation: 164

Yes, it is possible to perform mutual authentication with Mifare Ultralight C. Use the following procedure:

STEP 1: Send start authentication command. (1A 00) to card

STEP 2: Card generates an 8 byte random number RndB. This random number is DES/3DES enciphered with the diversified key, denoted by ek(RndB), and is then transmitted to the terminal.

STEP 3 The terminal runs a DES/3DES deciphering operation on the received ek(RndB) and thus retrieves RndB. RndB is then rotated left by 8 bits (first byte is moved to the end of RndB), yielding RndB’. Now the terminal itself generates an 8 byte random number RndA. This RndA is concatenated with RndB’ and enciphered using DES/3DES (The ecryption of the two blocks is chained using the Cipher Block Chaining (CBC) send mode). This token ek(RndA + RndB’) is sent to the card.

STEP 4: The card runs an DES/3DES decipherment on the received token and thus gains RndA + RndB’. The card can now verify the sent RndB’ by comparing it with the RndB’ obtained by rotating the original RndB left by 8 bits internally. A successful verification proves to the card that the card and the terminal possess the same secret (key). If the verification fails, the card stops the authentication procedure and returns an error message. As the card also received the random number RndA, generated by the terminal, it can perform a rotate left operation by 8 bits on RndA to gain RndA’, which is enciphered again, resulting in ek(RndA’). This token is sent to the terminal.

STEP 5: The terminal runs a DES/3DES decipherment on the received ek(RndA’) and thus gains RndA’ for comparison with the terminal-internally rotated RndA’. If the comparison fails, the terminal exits the procedure and may halt the card.

STEP 6: The card sets the authentication state as ‘Authenticated’

Same can be found in this NXP datasheet

Upvotes: 1

Lewis Munene
Lewis Munene

Reputation: 164

Sample C source code:

typedef unsigned char byte;

int mutual_authentication( const byte *diversifiedKey )
{
    byte cmd[256], response[256];
    int cmdLen, responseLen;

    //Send 1A00
    cmd[0] = 0x1A;
    cmd[1] = 0x00;
    cmdLen = 2;
    int ret = send_command( cmd, cmdLen, response, &responseLen );

    //Get ekRndB
    byte ekRndB[8], rndB[8];

    memcpy(ekRndB, response, 8);
    //Decrypt ekRndB with diversifiedKey
    des_ISO_decrypt( diversifiedKey, ekRndB, rndB, 8 );

    //PCD Generates RndA
    byte randA[8] = "\x33,\x54,\x2A,\x87,\x21,\x00,\x77,\x98";//random numbers
    byte rndARndBComplement[16], ekRndARndBComplement[16];

    // Append RndA and RndB' ( RndB' is generated by rotating RndB one byte to the left )
    // after the status byte.
    memcpy(&rndARndBComplement[0],rndA,8);
    memcpy(&rndARndBComplement[8],&rndB[1],7);  // bytes 1 to 7
    rndARndBComplement[15] = rndB[0];           // byte 0

    // Apply the DES send operation to the 16 argument bytes before sending the second frame to the PICC
    des_ISO_encrypt(diversifiedKey, rndARndBComplement, ekRndARndBComplement, 16);

    cmd[0] = 0xAF;
    memcpy(&cmd[1], ekRndARndBComplement, 16);
    cmdLen = 17;

    ret = send_command( cmd, cmdLen, response, &responseLen );

    byte ekRndAComplement[8], rndAComplement[8], finalOutput[8];

    memcpy(&ekRndAComplement[0], &response[1], 8);
    des_ISO_decrypt(diversifiedKey, ekRndAComplement, rndAComplement, 8);

    memcpy(&finalOutput[1], &RndAComplement[0], 7);
    finalOutput[0] = rndAComplement[7];

    //compare the received RndA with the one we originally had
    return memcmp(&finalOutput[0], &rndA[0], 8);
}

Note: You should have your own implementation of send_command() (depending on your card reader), des_ISO_decrypt() and des_ISO_encrypt() (depending on your DES library).

Upvotes: 1

Related Questions