Go Down

Topic: nfc.inDataExchange messing with response apdu? (Read 742 times) previous topic - next topic

Nov 26, 2013, 05:18 am Last Edit: Nov 26, 2013, 05:56 am by MisterFrench Reason: 1
Hi,

I'm working on an app that uses Host Card Emulation to send data to a Adafruit NFC shield. The app receives the SELECT AID apdu and then returns a 32 bytes md5 hash to be used by the Arduino.

My problem is it seems the response apdu's last 9 characters get changed to "ÿ" (255).

I've already tested the outgoing apdu on the app side and all the characters are there so I'm assuming something is happening on the arduino side of things.

Here is the relevant part of my sketch:

Code: [Select]
           uint8_t response[32];
           
           uint8_t responseLength = sizeof(response);
           
           if (nfc.inDataExchange(message, sizeof(message), response, &responseLength)) {
               
               Serial.print("TYPECASTED RAW: ");
               for (int i = 0; i < sizeof(response); i++) {
                   Serial.print((char)response[i]);
               }
             
               Serial.println(" ");
                         
               unlockDrawer(message);
               
           }


And the serial output from that is:

Code: [Select]
TYPECASTED RAW: e68d3f574009cbbe0111502ÿÿÿÿÿÿÿÿÿ

Any help appreciated. Thank you.

UPDATE

Went into the Adafruit NFC library and enabled debug mode and I get

'Status code indicates an error'

If that points anyone in the right direction...

Digging in the Adafruit NFC library, here's the part that throws this error:

Code: [Select]
if (pn532_packetbuffer[5]==PN532_PN532TOHOST && pn532_packetbuffer[6]==PN532_RESPONSE_INDATAEXCHANGE) {
      if ((pn532_packetbuffer[7] & 0x3f)!=0) {
        #ifdef PN532DEBUG
          Serial.println("Status code indicates an error");
        #endif
        return false;
      }


Does that mean anything to anyone?

michinyon

Is your response actually 32 bytes long ?

If it is some kind of character array,  it might not be full of characters.

If you only read 20 characters,   and then try and print 32 characters,  of course you will get some kind of garbage
printed at the end of it.

You need to learn about zero-terminating character arrays.  So your 32 byte array will only have 31 useful characters in it.

You need also to learn about what the function strlen()  and the pseudo-function sizeof()  actually do.

PaulS


Is your response actually 32 bytes long ?

If it is some kind of character array,  it might not be full of characters.

If you only read 20 characters,   and then try and print 32 characters,  of course you will get some kind of garbage
printed at the end of it.

You need to learn about zero-terminating character arrays.  So your 32 byte array will only have 31 useful characters in it.

You need also to learn about what the function strlen()  and the pseudo-function sizeof()  actually do.

I'm not sure of the relevance of any of these comments, given that the function tells you how many characters are in the response. Ignoring that, and trying to guess how long the response was is silly.

A little bit of update, guy on stackoverflow gave me some pointers although I haven't solved my problem yet. Here's how I send the response APDU:

Code: [Select]
    byte[] hashBuffer = {
                (byte)0xe6, (byte)0x8d, (byte)0x3f, (byte)0x57,
                (byte)0x40, (byte)0x09, (byte)0xcb, (byte)0xbe,
                (byte)0x01, (byte)0x11, (byte)0x50, (byte)0x26,
                (byte)0x36, (byte)0x34, (byte)0xc5, (byte)0xc0
        };
        byte[] SW1 = {(byte)0x90};
        byte[] SW2 = {(byte)0x00};
        byte[] responseApdu = new byte[18];
        System.arraycopy(hashBuffer, 0, responseApdu, 0, 16);
        System.arraycopy(SW1, 0, responseApdu, 16, 1);
        System.arraycopy(SW2, 0, responseApdu, 17, 1);

        return responseApdu;


(I know I could make this way shorter up there but I like to separate my code).

Now this is what I get as the raw data on the arduino end of things:

Code: [Select]
2301416387649203190117803854521971921440

How do I get the hex values back from that? Basically uint8_t to hex conversion?

This is what I have right now but it's not working:

Code: [Select]
        Serial.print("HEX: ");
                char buffer[65];
                for (int i = 0; i < sizeof(buffer); i++) {
                    sprintf(buffer, "%02X", (uint8_t)response[i]); 
                }
               
                for (int i = 0; i < sizeof(buffer); i++) {
                    Serial.print(buffer[i]);
                }
               
                Serial.println(" ");


And it outputs a bunch of gibberish.

PaulS

Code: [Select]
                for (int i = 0; i < sizeof(buffer); i++) {
                    sprintf(buffer, "%02X", (uint8_t)response[i]); 
                }

You are overwriting the buffer on every pass through the loop. Why is the size of the output buffer relevant to the number of times to iterate? Pay some attention to what is INPUT and what is OUTPUT, and use the relevant measures.

#6
Nov 26, 2013, 07:58 pm Last Edit: Nov 26, 2013, 09:06 pm by MisterFrench Reason: 1
Finally got it working.

Code: [Select]
               String respBuffer;

               for (int i = 0; i < 16; i++) {
                    if (response[i] < 0x10) respBuffer = respBuffer + "0"; //Adds leading zeros if hex value is smaller than 0x10
                   respBuffer = respBuffer + String(response[i], HEX);                        
               }
               
               Serial.print(respBuffer);

#7
Dec 26, 2013, 10:50 pm Last Edit: Mar 25, 2014, 11:18 pm by Traveller99 Reason: 1

A little bit of update, guy on stackoverflow gave me some pointers although I haven't solved my problem yet. Here's how I send the response APDU:

Code: [Select]
    byte[] hashBuffer = {
                (byte)0xe6, (byte)0x8d, (byte)0x3f, (byte)0x57,
                (byte)0x40, (byte)0x09, (byte)0xcb, (byte)0xbe,
                (byte)0x01, (byte)0x11, (byte)0x50, (byte)0x26,
                (byte)0x36, (byte)0x34, (byte)0xc5, (byte)0xc0
        };
        byte[] SW1 = {(byte)0x90};
        byte[] SW2 = {(byte)0x00};
        byte[] responseApdu = new byte[18];
        System.arraycopy(hashBuffer, 0, responseApdu, 0, 16);
        System.arraycopy(SW1, 0, responseApdu, 16, 1);
        System.arraycopy(SW2, 0, responseApdu, 17, 1);

        return responseApdu;


(I know I could make this way shorter up there but I like to separate my code).

(...)


Why do you use the SW1 and SW2 bytes? Is it mandatory?

My HCE Service is being well selected on Android but on Arduino side I always get false in the nfc.inDataExchange(...)

My Arduino code:
Code: [Select]
void loop()
{
  bool success;
 
  uint8_t responseLength;
 
 
  Serial.println("Waiting for an ISO14443A card");
 
  success = nfc.inListPassiveTarget();

  if(success) {
   
     Serial.println("Found something!");
                 
    uint8_t selectApdu[] = { 0x00, /* CLA */
                              0xA4, /* INS */
                              0x04, /* P1  */
                              0x00, /* P2  */
                              0x07, /* Length of AID  */
                              0xF0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* AID */
                              0x00  /* Le  */ };
                             
    uint8_t response[32]; 
     
    success = nfc.inDataExchange(selectApdu, sizeof(selectApdu), response, &responseLength);
   
    if(success) {
     
     Serial.print("responseLength: "); Serial.println(responseLength);
       
      nfc.PrintHexChar(response, responseLength);
     
      uint8_t i = 0;
      for( ; i < 5; i++) {
        uint8_t apdu[] = { 0x52, 0x52, 0x52, 0x52 };
        uint8_t back[32];
        uint8_t length;
       
        nfc.inDataExchange(apdu, sizeof(apdu), back, &length);
       
        Serial.print("responseLength: "); Serial.println(length);
         
        nfc.PrintHexChar(back, length);
      }
    }
    else {
     
      Serial.println("Failed sending SELECT AID");
    }
  }
  else {
   
    Serial.println("Didn't find anything!");
  }

 
  delay(1000);
}


Should I set the responseLength before call inDataExchange(...)?

EDIT: The problem above was that I wasn't setting the value of responseLength. This must be the size of the responseBuffer. Sry, I forget to share the solution earlier.
For those who came after, you have now a working example in the library repository.

Go Up