Use PN532 board. Simplify work with Arduino based host, use this library.
Define connection.
#include <Arduino.h>
#include <SPI.h>
#include <PN532_SPI.h>
#include <PN532.h>
PN532_SPI intfc(SPI,5);
PN532 nfc(intfc);
Check if card/phone is present :
success = nfc.inListPassiveTarget();
if (success) { ...
Define comm buffer:
uint8_t apdubuffer[255] = {};
uint8_t apdulen;
and send SELECT PPSE command:
apdulen = 255;
success2 = sendAPDU(0x00, 0xA4, 0x04, 0x00, "2PAY.SYS.DDF01", 0x00, &apdubuffer[0], &apdulen);
if succedded, then:
//fromHEX("A0000000031010") - VISA
//fromHEX("A0000000041010") - MC
success2 = sendAPDU(0x00, 0xA4, 0x04, 0x00, fromHEX("A0000000031010"), 0x00, &apdubuffer[0], &apdulen);
and you're good to read card's internal files (SFI/RECs), eg.:
success2 = sendAPDU(0x00, 0xB2, rec_num, (sfi_num << 3)+4, 0x00, &apdubuffer[0], &apdulen);
It'll be best to find PAN/ICC public key, indeed, as unique to card, but there will be many bytes presented before PAN/ICC, imho quite unique and sufficient to perform authentication
Afterall, you'd need this overloads:
bool sendAPDU(byte cla, byte ins, byte p1, byte p2, String aid, byte le, uint8_t *response, uint8_t *resp_len)
{
uint8_t cmdbuf[255];
memset(&cmdbuf[0],0,255);
cmdbuf[0] = cla;
cmdbuf[1] = ins;
cmdbuf[2] = p1;
cmdbuf[3] = p2;
cmdbuf[4] = aid.length();
int i;
for (i=0;i<aid.length();i++)
cmdbuf[5+i] = aid[i];
cmdbuf[6+i] = le;
//printbuf((char*)&cmdbuf[0],5+aid.length());
return nfc.inDataExchange(&cmdbuf[0], 5+aid.length(), response, resp_len);
}
bool sendAPDU(byte cla, byte ins, byte p1, byte p2, uint8_t* aid, byte le, uint8_t *response, uint8_t *resp_len)
{
uint8_t cmdbuf[255];
memset(&cmdbuf[0],0,255);
cmdbuf[0] = cla;
cmdbuf[1] = ins;
cmdbuf[2] = p1;
cmdbuf[3] = p2;
cmdbuf[4] = aid[0];
int i;
for (i=0;i<aid[0];i++)
cmdbuf[5+i] = aid[i+1];
cmdbuf[6+i] = le;
//printbuf((char*)&cmdbuf[0],5+cmdbuf[4]);
return nfc.inDataExchange(&cmdbuf[0], 5+cmdbuf[4], response, resp_len);
}
bool sendAPDU(byte cla, byte ins, byte p1, byte p2, byte le, uint8_t *response, uint8_t *resp_len)
{
uint8_t cmdbuf[255];
memset(&cmdbuf[0],0,255);
cmdbuf[0] = cla;
cmdbuf[1] = ins;
cmdbuf[2] = p1;
cmdbuf[3] = p2;
cmdbuf[4] = le;
//printbuf((char*)&cmdbuf[0],5);
return nfc.inDataExchange(&cmdbuf[0], 5, response, resp_len);
}
and this, too:
/*
Funny, non-C approach to return array from a function
Returns ptr to global static buf...
Just to improve readability of sendAPDU() function...
Not really needed in real app,
*/
uint8_t fromHexBuf[255];
uint8_t* fromHEX(String hexs) {
int i = hexs.length()/2;
fromHexBuf[0] = i;
int x=0;
while (i) {
char buf[3];
char *tmp;
buf[0] = hexs[2*x];
buf[1] = hexs[2*x+1];
buf[2] = 0;
uint8_t v = strtol(&buf[0], &tmp, 16);
//Serial.printf("-> %s = %x\n", buf, v);
fromHexBuf[x+1] = v;
x=x+1;
i--;
}
return &fromHexBuf[0];
}