I have an NFC application built on android that sends a hash as an apdu answer. This is the code I use in my Android app to send the hash:
@Override
public byte[] processCommandApdu(byte[] arg0, Bundle arg1) {
String hash = "e68d3f574009cbbe011150263634c5c0";
return hash.getBytes(Charset.forName("UTF-8"));
}
Now when I receive it on the Arduino side of things I get this RAW data:
10154561005110253555248485799989810148494949534850255255255255255255255255255
How do I get the hash back from that?
This is what I have right now but it's obviously not working:
uint8_t response[32];
uint8_t responseLength = sizeof(response);
if (nfc.inDataExchange(message, sizeof(message), response, &responseLength)) {
Serial.print("RAW: ");
for (int i = 0; i < sizeof(response); i++) {
Serial.print(response[i]);
}
Serial.println(" ");
char buffer[32];
itoa((int)response,buffer,8);
Serial.print("ITOA: ");
for (int i = 0; i < sizeof(buffer); i++) {
Serial.print(buffer[i]);
}
Serial.println(" ");
}
And this is the serial output of the code above:
RAW: 10154561005110253555248485799989810148494949534850255255255255255255255255255
ITOA: 4253 µ +
3ü R
Halp!!!
Three suggestions, though none of them really explains why the last few bytes get truncated:
Don't convert the hexadecimal hash representation to a character string to later send those characters in UTF-8 encoding. It would be much more efficient (and less decoding effort) to directly send the hash as bytes:
@Override
public byte[] processCommandApdu(byte[] arg0, Bundle arg1) {
byte[] hash = {
(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
};
return hash;
}
If you already have the hash as a hexadecimal string, I suggest you convert it to its byte representation on the Android side first.
When using HCE, you should stick to ISO/IEC 7816-4 APDUs instead of just sending random data. A command APDU (short format) consists of the following:
+----------+----------+----------+----------+----------+------------+----------+
| CLA | INS | P1 | P2 | Lc | DATA | Le |
| (1 Byte) | (1 Byte) | (1 Byte) | (1 Byte) | (1 Byte) | (Lc Bytes) | (1 Byte) |
+----------+----------+----------+----------+----------+------------+----------+
Where Lc encodes the number of bytes of DATA. If DATA is empty, Lc is empty too. Le encodes the number of bytes expected as response (with the special case of Le = 0x00, which means 256 response bytes expected.
A response APDU (that's what you send as a return value in processCommandApdu
) looks like this:
+----------+----------+----------+
| DATA | SW1 | SW2 |
| (n Byte) | (1 Byte) | (1 Byte) |
+----------+----------+----------+
DATA is the response data. SW1 & SW2 form the response status word (typically SW1 = 0x90, SW2 = 0x00 for success). Note that SW1 and SW2 are mandatory.
When iterating through the response of inDataExchange
use the response length provided by that function (responseLength
) instead of your maximum buffer length:
for (int i = 0; i < responseLength; ++i) {
...
}
Moreover, I suggest that you provide a buffer with more than the maximum expected response length. (Particularly in your case where you use UTF-8 encoding for a 32 character string, which might (for some characters) result in more that 32 bytes.)
OK so I figured out my answer. I don't need itoa. I can just typecast the RAW input to char and get what I need:
Serial.print("TYPECASTED RAW: ");
for (int i = 0; i < sizeof(response); i++) {
Serial.print((char)response[i]);
}
Serial.println(" ");
And that outputed:
e68d3f574009cbbe0111502ÿÿÿÿÿÿÿÿÿ
Now I just wonder why the last 9 characters are being replaced with 255?