upgrade code to work with develoment version of libnfc (upcomming 1.4.0)

Update code to match with the new API;
Sync nfc-utils.[ch] from libnfc's repo;
Update ./configure to detect libnfc 1.4.0;
This commit is contained in:
Romuald Conty 2010-11-02 09:36:39 +00:00
parent 2072e323bb
commit 0320ded902
5 changed files with 554 additions and 45 deletions

View file

@ -13,7 +13,7 @@ AM_INIT_AUTOMAKE
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
# Checks for pkg-config modules. # Checks for pkg-config modules.
LIBNFC_REQUIRED_VERSION=1.3.9 LIBNFC_REQUIRED_VERSION=1.4.0
PKG_CHECK_MODULES([LIBNFC], [libnfc >= $LIBNFC_REQUIRED_VERSION], [], [AC_MSG_ERROR([libnfc >= $LIBNFC_REQUIRED_VERSION is mandatory.])]) PKG_CHECK_MODULES([LIBNFC], [libnfc >= $LIBNFC_REQUIRED_VERSION], [], [AC_MSG_ERROR([libnfc >= $LIBNFC_REQUIRED_VERSION is mandatory.])])
PKG_CONFIG_REQUIRES="libnfc" PKG_CONFIG_REQUIRES="libnfc"

View file

@ -158,11 +158,11 @@ int main(int argc, char * const argv[]) {
mf_init(&t, &r); mf_init(&t, &r);
// Configure reader settings // Configure reader settings
mf_configure(r.pdi); mf_configure(r.pdi);
mf_select_tag(r.pdi, &t.ti); mf_select_tag(r.pdi, &(t.nt));
// Save tag uid and info about block size (b4K) // Save tag uid and info about block size (b4K)
t.b4K = (t.ti.nai.abtAtqa[1] == 0x02); t.b4K = (t.nt.nti.nai.abtAtqa[1] == 0x02);
t.uid = (uint32_t) bytes_to_num(t.ti.nai.abtUid, 4); t.uid = (uint32_t) bytes_to_num(t.nt.nti.nai.abtUid, 4);
t.num_blocks = (t.b4K) ? 0xff : 0x3f; t.num_blocks = (t.b4K) ? 0xff : 0x3f;
t.num_sectors = t.b4K ? NR_TRAILERS_4k : NR_TRAILERS_1k; t.num_sectors = t.b4K ? NR_TRAILERS_4k : NR_TRAILERS_1k;
@ -191,7 +191,7 @@ int main(int argc, char * const argv[]) {
} }
// Test if a compatible MIFARE tag is used // Test if a compatible MIFARE tag is used
if ((t.ti.nai.btSak & 0x08) == 0) { if ((t.nt.nti.nai.btSak & 0x08) == 0) {
printf("Error: inserted tag is not a MIFARE Classic card\n"); printf("Error: inserted tag is not a MIFARE Classic card\n");
nfc_disconnect(r.pdi); nfc_disconnect(r.pdi);
exit(1); exit(1);
@ -206,7 +206,7 @@ int main(int argc, char * const argv[]) {
// Try to authenticate to all sectors with default keys // Try to authenticate to all sectors with default keys
// Set the authentication information (uid) // Set the authentication information (uid)
memcpy(mp.mpa.abtUid, t.ti.nai.abtUid, sizeof(mp.mpa.abtUid)); memcpy(mp.mpa.abtUid, t.nt.nti.nai.abtUid, sizeof(mp.mpa.abtUid));
// Iterate over all keys (n = number of keys) // Iterate over all keys (n = number of keys)
n = sizeof(defaultKeys)/sizeof(defaultKeys[0]); n = sizeof(defaultKeys)/sizeof(defaultKeys[0]);
for (key = 0; key < n; key++) { for (key = 0; key < n; key++) {
@ -276,7 +276,7 @@ int main(int argc, char * const argv[]) {
for (m = 0; m < 2; ++m) { for (m = 0; m < 2; ++m) {
if (e_sector == -1) break; // All keys are default, I am skipping recovery mode if (e_sector == -1) break; // All keys are default, I am skipping recovery mode
for (j = 0; j < (t.num_sectors); ++j) { for (j = 0; j < (t.num_sectors); ++j) {
memcpy(mp.mpa.abtUid, t.ti.nai.abtUid, sizeof(mp.mpa.abtUid)); memcpy(mp.mpa.abtUid, t.nt.nti.nai.abtUid, sizeof(mp.mpa.abtUid));
if ((dumpKeysA && !t.sectors[j].foundKeyA) || (!dumpKeysA && !t.sectors[j].foundKeyB)) { if ((dumpKeysA && !t.sectors[j].foundKeyA) || (!dumpKeysA && !t.sectors[j].foundKeyB)) {
// First, try already broken keys // First, try already broken keys
@ -407,7 +407,7 @@ int main(int argc, char * const argv[]) {
fprintf(stdout, "Block %02d, type %c, key %012llx :", block, 'A', bytes_to_num(t.sectors[i].KeyA, 6)); fprintf(stdout, "Block %02d, type %c, key %012llx :", block, 'A', bytes_to_num(t.sectors[i].KeyA, 6));
print_hex(mp.mpd.abtData, 16); print_hex(mp.mpd.abtData, 16);
mf_configure(r.pdi); mf_configure(r.pdi);
mf_select_tag(r.pdi, &t.ti); mf_select_tag(r.pdi, &(t.nt));
failure = false; failure = false;
} else { } else {
// Error, now try read() with B key // Error, now try read() with B key
@ -424,7 +424,7 @@ int main(int argc, char * const argv[]) {
fprintf(stdout, "Block %02d, type %c, key %012llx :", block, 'B', bytes_to_num(t.sectors[i].KeyB, 6)); fprintf(stdout, "Block %02d, type %c, key %012llx :", block, 'B', bytes_to_num(t.sectors[i].KeyB, 6));
print_hex(mp.mpd.abtData, 16); print_hex(mp.mpd.abtData, 16);
mf_configure(r.pdi); mf_configure(r.pdi);
mf_select_tag(r.pdi, &t.ti); mf_select_tag(r.pdi, &(t.nt));
failure = false; failure = false;
} else { } else {
mf_configure(r.pdi); mf_configure(r.pdi);
@ -440,7 +440,7 @@ int main(int argc, char * const argv[]) {
memcpy(mtDump.amb[block].mbt.abtKeyB,t.sectors[i].KeyB,6); memcpy(mtDump.amb[block].mbt.abtKeyB,t.sectors[i].KeyB,6);
if (!failure) memcpy(mtDump.amb[block].mbt.abtAccessBits,mp.mpd.abtData+6,4); if (!failure) memcpy(mtDump.amb[block].mbt.abtAccessBits,mp.mpd.abtData+6,4);
} else if (!failure) memcpy(mtDump.amb[block].mbd.abtData, mp.mpd.abtData,16); } else if (!failure) memcpy(mtDump.amb[block].mbd.abtData, mp.mpd.abtData,16);
memcpy(mp.mpa.abtUid,t.ti.nai.abtUid,4); memcpy(mp.mpa.abtUid,t.nt.nti.nai.abtUid,4);
} }
// Finally save all keys + data to file // Finally save all keys + data to file
@ -506,9 +506,13 @@ void mf_configure(nfc_device_t* pdi) {
nfc_configure(pdi,NDO_ACTIVATE_FIELD,true); nfc_configure(pdi,NDO_ACTIVATE_FIELD,true);
} }
void mf_select_tag(nfc_device_t* pdi, nfc_target_info_t* ti) { void mf_select_tag(nfc_device_t* pdi, nfc_target_t* pnt) {
// Poll for a ISO14443A (MIFARE) tag // Poll for a ISO14443A (MIFARE) tag
if (!nfc_initiator_select_passive_target(pdi,NM_ISO14443A_106,NULL,0,ti)) { const nfc_modulation_t nm = {
.nmt = NMT_ISO14443A,
.nbr = NBR_106,
};
if (!nfc_initiator_select_passive_target(pdi, nm, NULL, 0, pnt)) {
fprintf(stderr, "!Error connecting to the MIFARE Classic tag\n"); fprintf(stderr, "!Error connecting to the MIFARE Classic tag\n");
nfc_disconnect(pdi); nfc_disconnect(pdi);
exit(1); exit(1);
@ -547,7 +551,11 @@ int find_exploit_sector(mftag t) {
} }
void mf_anticollision(mftag t, mfreader r) { void mf_anticollision(mftag t, mfreader r) {
if (!nfc_initiator_select_passive_target(r.pdi, NM_ISO14443A_106, NULL, 0, &t.ti)) { const nfc_modulation_t nm = {
.nmt = NMT_ISO14443A,
.nbr = NBR_106,
};
if (!nfc_initiator_select_passive_target(r.pdi, nm, NULL, 0, &t.nt)) {
fprintf(stderr, "\n\n!Error: tag has been removed\n"); fprintf(stderr, "\n\n!Error: tag has been removed\n");
exit(1); exit(1);
} }
@ -581,7 +589,7 @@ int mf_enhanced_auth(int e_sector, int a_sector, mftag t, mfreader r, denonce *d
// Prepare AUTH command // Prepare AUTH command
Auth[0] = (t.sectors[e_sector].foundKeyA) ? 0x60 : 0x61; Auth[0] = (t.sectors[e_sector].foundKeyA) ? 0x60 : 0x61;
append_iso14443a_crc(Auth,2); iso14443a_crc_append (Auth,2);
// fprintf(stdout, "\nAuth command:\t"); // fprintf(stdout, "\nAuth command:\t");
// print_hex(Auth, 4); // print_hex(Auth, 4);
@ -724,7 +732,7 @@ int mf_enhanced_auth(int e_sector, int a_sector, mftag t, mfreader r, denonce *d
// Again, prepare the Auth command with MC_AUTH_A, recover the block and CRC // Again, prepare the Auth command with MC_AUTH_A, recover the block and CRC
Auth[0] = dumpKeysA ? 0x60 : 0x61; Auth[0] = dumpKeysA ? 0x60 : 0x61;
Auth[1] = a_sector; Auth[1] = a_sector;
append_iso14443a_crc(Auth,2); iso14443a_crc_append (Auth,2);
// Encryption of the Auth command, sending the Auth command // Encryption of the Auth command, sending the Auth command
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {

View file

@ -40,7 +40,7 @@ typedef struct {
} denonce; // Revealed information about nonce } denonce; // Revealed information about nonce
typedef struct { typedef struct {
nfc_target_info_t ti; nfc_target_t nt;
sector * sectors; // Allocate later, we do not know the number of sectors yet sector * sectors; // Allocate later, we do not know the number of sectors yet
sector e_sector; // Exploit sector sector e_sector; // Exploit sector
uint32_t num_sectors; uint32_t num_sectors;
@ -72,7 +72,7 @@ typedef struct {
void usage(FILE * stream, int errno); void usage(FILE * stream, int errno);
void mf_init(mftag *t, mfreader *r); void mf_init(mftag *t, mfreader *r);
void mf_configure(nfc_device_t* pdi); void mf_configure(nfc_device_t* pdi);
void mf_select_tag(nfc_device_t* pdi, nfc_target_info_t* ti); void mf_select_tag(nfc_device_t* pdi, nfc_target_t* pnt);
int trailer_block(uint32_t block); int trailer_block(uint32_t block);
int find_exploit_sector(mftag t); int find_exploit_sector(mftag t);
void mf_anticollision(mftag t, mfreader r); void mf_anticollision(mftag t, mfreader r);

View file

@ -1,4 +1,5 @@
#include <nfc/nfc.h> #include <nfc/nfc.h>
#include <err.h>
#include "nfc-utils.h" #include "nfc-utils.h"
@ -97,34 +98,409 @@ print_hex_par (const byte_t * pbtData, const size_t szBits, const byte_t * pbtDa
printf ("\n"); printf ("\n");
} }
#define SAK_UID_NOT_COMPLETE 0x04
#define SAK_ISO14443_4_COMPLIANT 0x20 #define SAK_ISO14443_4_COMPLIANT 0x20
#define SAK_ISO18092_COMPLIANT 0x40 #define SAK_ISO18092_COMPLIANT 0x40
void void
print_nfc_iso14443a_info (const nfc_iso14443a_info_t nai) print_nfc_iso14443a_info (const nfc_iso14443a_info_t nai, bool verbose)
{ {
printf (" ATQA (SENS_RES): "); printf (" ATQA (SENS_RES): ");
print_hex (nai.abtAtqa, 2); print_hex (nai.abtAtqa, 2);
if (verbose) {
printf("* UID size: ");
switch ((nai.abtAtqa[1] & 0xc0)>>6) {
case 0:
printf("single\n");
break;
case 1:
printf("double\n");
break;
case 2:
printf("triple\n");
break;
case 3:
printf("RFU\n");
break;
}
printf("* bit frame anticollision ");
switch (nai.abtAtqa[1] & 0x1f) {
case 0x01:
case 0x02:
case 0x04:
case 0x08:
case 0x10:
printf("supported\n");
break;
default:
printf("not supported\n");
break;
}
}
printf (" UID (NFCID%c): ", (nai.abtUid[0] == 0x08 ? '3' : '1')); printf (" UID (NFCID%c): ", (nai.abtUid[0] == 0x08 ? '3' : '1'));
print_hex (nai.abtUid, nai.szUidLen); print_hex (nai.abtUid, nai.szUidLen);
if (verbose) {
if (nai.abtUid[0] == 0x08) {
printf ("* Random UID\n");
}
}
printf (" SAK (SEL_RES): "); printf (" SAK (SEL_RES): ");
print_hex (&nai.btSak, 1); print_hex (&nai.btSak, 1);
if (verbose) {
if (nai.btSak & SAK_UID_NOT_COMPLETE) {
printf ("* Warning! Cascade bit set: UID not complete\n");
}
if (nai.btSak & SAK_ISO14443_4_COMPLIANT) {
printf ("* Compliant with ISO/IEC 14443-4\n");
} else {
printf ("* Not compliant with ISO/IEC 14443-4\n");
}
if (nai.btSak & SAK_ISO18092_COMPLIANT) {
printf ("* Compliant with ISO/IEC 18092\n");
} else {
printf ("* Not compliant with ISO/IEC 18092\n");
}
}
if (nai.szAtsLen) { if (nai.szAtsLen) {
printf (" ATS (ATR): "); printf (" ATS: ");
print_hex (nai.abtAts, nai.szAtsLen); print_hex (nai.abtAts, nai.szAtsLen);
} }
if ((nai.btSak & SAK_ISO14443_4_COMPLIANT) || (nai.btSak & SAK_ISO18092_COMPLIANT)) { if (nai.szAtsLen && verbose) {
printf (" Compliant with: "); // Decode ATS according to ISO/IEC 14443-4 (5.2 Answer to select)
if (nai.btSak & SAK_ISO14443_4_COMPLIANT) const int iMaxFrameSizes[] = { 16, 24, 32, 40, 48, 64, 96, 128, 256 };
printf ("ISO/IEC 14443-4 "); printf ("* Max Frame Size accepted by PICC: %d bytes\n", iMaxFrameSizes[nai.abtAts[0] & 0x0F]);
if (nai.btSak & SAK_ISO18092_COMPLIANT)
printf ("ISO/IEC 18092"); size_t offset = 1;
printf ("\n"); if (nai.abtAts[0] & 0x10) { // TA(1) present
byte_t TA = nai.abtAts[offset];
offset++;
printf ("* Bit Rate Capability:\n");
if (TA == 0) {
printf (" * PICC supports only 106 kbits/s in both directions\n");
}
if (TA & 1<<7) {
printf (" * Same bitrate in both directions mandatory\n");
}
if (TA & 1<<4) {
printf (" * PICC to PCD, DS=2, bitrate 212 kbits/s supported\n");
}
if (TA & 1<<5) {
printf (" * PICC to PCD, DS=4, bitrate 424 kbits/s supported\n");
}
if (TA & 1<<6) {
printf (" * PICC to PCD, DS=8, bitrate 847 kbits/s supported\n");
}
if (TA & 1<<0) {
printf (" * PCD to PICC, DR=2, bitrate 212 kbits/s supported\n");
}
if (TA & 1<<1) {
printf (" * PCD to PICC, DR=4, bitrate 424 kbits/s supported\n");
}
if (TA & 1<<2) {
printf (" * PCD to PICC, DR=8, bitrate 847 kbits/s supported\n");
}
if (TA & 1<<3) {
printf (" * ERROR unknown value\n");
}
}
if (nai.abtAts[0] & 0x20) { // TB(1) present
byte_t TB= nai.abtAts[offset];
offset++;
printf ("* Frame Waiting Time: %.4g ms\n",256.0*16.0*(1<<((TB & 0xf0) >> 4))/13560.0);
if ((TB & 0x0f) == 0) {
printf ("* No Start-up Frame Guard Time required\n");
} else {
printf ("* Start-up Frame Guard Time: %.4g ms\n",256.0*16.0*(1<<(TB & 0x0f))/13560.0);
}
}
if (nai.abtAts[0] & 0x40) { // TC(1) present
byte_t TC = nai.abtAts[offset];
offset++;
if (TC & 0x1) {
printf("* Node ADdress supported\n");
} else {
printf("* Node ADdress not supported\n");
}
if (TC & 0x2) {
printf("* Card IDentifier supported\n");
} else {
printf("* Card IDentifier not supported\n");
}
}
if (nai.szAtsLen > offset) {
printf ("* Historical bytes Tk: " );
print_hex (nai.abtAts + offset, (nai.szAtsLen - offset));
byte_t CIB = nai.abtAts[offset];
offset++;
if (CIB != 0x00 && CIB != 0x10 && (CIB & 0xf0) != 0x80) {
printf(" * Proprietary format\n");
if (CIB == 0xc1) {
printf(" * Tag byte: Mifare or virtual cards of various types\n");
byte_t L = nai.abtAts[offset];
offset++;
if (L != (nai.szAtsLen - offset)) {
printf(" * Warning: Type Identification Coding length (%i)", L);
printf(" not matching Tk length (%zi)\n", (nai.szAtsLen - offset));
}
if ((nai.szAtsLen - offset - 2) > 0) { // Omit 2 CRC bytes
byte_t CTC = nai.abtAts[offset];
offset++;
printf(" * Chip Type: ");
switch (CTC & 0xf0) {
case 0x00:
printf("(Multiple) Virtual Cards\n");
break;
case 0x10:
printf("Mifare DESFire\n");
break;
case 0x20:
printf("Mifare Plus\n");
break;
default:
printf("RFU\n");
break;
}
printf(" * Memory size: ");
switch (CTC & 0x0f) {
case 0x00:
printf("<1 kbyte\n");
break;
case 0x01:
printf("1 kbyte\n");
break;
case 0x02:
printf("2 kbyte\n");
break;
case 0x03:
printf("4 kbyte\n");
break;
case 0x04:
printf("8 kbyte\n");
break;
case 0x0f:
printf("Unspecified\n");
break;
default:
printf("RFU\n");
break;
}
}
if ((nai.szAtsLen - offset) > 0) { // Omit 2 CRC bytes
byte_t CVC = nai.abtAts[offset];
offset++;
printf(" * Chip Status: ");
switch (CVC & 0xf0) {
case 0x00:
printf("Engineering sample\n");
break;
case 0x20:
printf("Released\n");
break;
default:
printf("RFU\n");
break;
}
printf(" * Chip Generation: ");
switch (CVC & 0x0f) {
case 0x00:
printf("Generation 1\n");
break;
case 0x01:
printf("Generation 2\n");
break;
case 0x02:
printf("Generation 3\n");
break;
case 0x0f:
printf("Unspecified\n");
break;
default:
printf("RFU\n");
break;
}
}
if ((nai.szAtsLen - offset) > 0) { // Omit 2 CRC bytes
byte_t VCS = nai.abtAts[offset];
offset++;
printf(" * Specifics (Virtual Card Selection):\n");
if ((VCS & 0x09) == 0x00) {
printf(" * Only VCSL supported\n");
} else if ((VCS & 0x09) == 0x01) {
printf(" * VCS, VCSL and SVC supported\n");
}
if ((VCS & 0x0e) == 0x00) {
printf(" * SL1, SL2(?), SL3 supported\n");
} else if ((VCS & 0x0e) == 0x02) {
printf(" * SL3 only card\n");
} else if ((VCS & 0x0f) == 0x0e) {
printf(" * No VCS command supported\n");
} else if ((VCS & 0x0f) == 0x0f) {
printf(" * Unspecified\n");
} else {
printf(" * RFU\n");
}
}
}
} else {
if (CIB == 0x00) {
printf(" * Tk after 0x00 consist of optional consecutive COMPACT-TLV data objects\n");
printf(" followed by a mandatory status indicator (the last three bytes, not in TLV)\n");
printf(" See ISO/IEC 7816-4 8.1.1.3 for more info\n");
}
if (CIB == 0x10) {
printf(" * DIR data reference: %02x\n", nai.abtAts[offset]);
}
if (CIB == 0x80) {
if (nai.szAtsLen == offset) {
printf(" * No COMPACT-TLV objects found, no status found\n");
} else {
printf(" * Tk after 0x80 consist of optional consecutive COMPACT-TLV data objects;\n");
printf(" the last data object may carry a status indicator of one, two or three bytes.\n");
printf(" See ISO/IEC 7816-4 8.1.1.3 for more info\n");
}
}
}
}
}
if (verbose) {
printf("Fingerprinting based on ATQA & SAK values:\n");
uint32_t atqasak = 0;
atqasak += (((uint32_t)nai.abtAtqa[0] & 0xff)<<16);
atqasak += (((uint32_t)nai.abtAtqa[1] & 0xff)<<8);
atqasak += ((uint32_t)nai.btSak & 0xff);
bool found_possible_match = false;
switch (atqasak) {
case 0x000218:
printf("* Mifare Classic 4K\n");
found_possible_match = true;
break;
case 0x000408:
printf("* Mifare Classic 1K\n");
printf("* Mifare Plus (4-byte UID) 2K SL1\n");
found_possible_match = true;
break;
case 0x000409:
printf("* Mifare MINI\n");
found_possible_match = true;
break;
case 0x000410:
printf("* Mifare Plus (4-byte UID) 2K SL2\n");
found_possible_match = true;
break;
case 0x000411:
printf("* Mifare Plus (4-byte UID) 4K SL2\n");
found_possible_match = true;
break;
case 0x000418:
printf("* Mifare Plus (4-byte UID) 4K SL1\n");
found_possible_match = true;
break;
case 0x000420:
printf("* Mifare Plus (4-byte UID) 2K/4K SL3\n");
found_possible_match = true;
break;
case 0x004400:
printf("* Mifare Ultralight\n");
printf("* Mifare UltralightC\n");
found_possible_match = true;
break;
case 0x004208:
case 0x004408:
printf("* Mifare Plus (7-byte UID) 2K SL1\n");
found_possible_match = true;
break;
case 0x004218:
case 0x004418:
printf("* Mifare Plus (7-byte UID) 4K SL1\n");
found_possible_match = true;
break;
case 0x004210:
case 0x004410:
printf("* Mifare Plus (7-byte UID) 2K SL2\n");
found_possible_match = true;
break;
case 0x004211:
case 0x004411:
printf("* Mifare Plus (7-byte UID) 4K SL2\n");
found_possible_match = true;
break;
case 0x004220:
case 0x004420:
printf("* Mifare Plus (7-byte UID) 2K/4K SL3\n");
found_possible_match = true;
break;
case 0x034420:
printf("* Mifare DESFire / Desfire EV1\n");
found_possible_match = true;
break;
}
// Other matches not described in
// AN MIFARE Type Identification Procedure
// but seen in the field:
switch (atqasak) {
case 0x000488:
printf("* Mifare Classic 1K Infineon\n");
found_possible_match = true;
break;
case 0x000298:
printf("* Gemplus MPCOS\n");
found_possible_match = true;
break;
case 0x030428:
printf("* JCOP31\n");
found_possible_match = true;
break;
case 0x004820:
printf("* JCOP31 v2.4.1\n");
printf("* JCOP31 v2.2\n");
found_possible_match = true;
break;
case 0x000428:
printf("* JCOP31 v2.3.1\n");
found_possible_match = true;
break;
case 0x000453:
printf("* Fudan FM1208SH01\n");
found_possible_match = true;
break;
case 0x000820:
printf("* Fudan FM1208\n");
found_possible_match = true;
break;
case 0x000238:
printf("* MFC 4K emulated by Nokia 6212 Classic\n");
found_possible_match = true;
break;
case 0x000838:
printf("* MFC 4K emulated by Nokia 6131 NFC\n");
found_possible_match = true;
break;
}
if ((nai.abtAtqa[0] & 0xf0) == 0) {
switch (nai.abtAtqa[1]) {
case 0x02:
printf("* SmartMX with Mifare 4K emulation\n");
found_possible_match = true;
break;
case 0x04:
printf("* SmartMX with Mifare 1K emulation\n");
found_possible_match = true;
break;
case 0x48:
printf("* SmartMX with 7-byte UID\n");
found_possible_match = true;
break;
}
}
if (! found_possible_match) {
printf("* Unknown card, sorry\n");
}
} }
} }
void void
print_nfc_felica_info (const nfc_felica_info_t nfi) print_nfc_felica_info (const nfc_felica_info_t nfi, bool verbose)
{ {
printf (" ID (NFCID2): "); printf (" ID (NFCID2): ");
print_hex (nfi.abtId, 8); print_hex (nfi.abtId, 8);
@ -133,18 +509,85 @@ print_nfc_felica_info (const nfc_felica_info_t nfi)
} }
void void
print_nfc_iso14443b_info (const nfc_iso14443b_info_t nbi) print_nfc_jewel_info (const nfc_jewel_info_t nji, bool verbose)
{ {
printf (" ATQB: "); printf (" ATQA (SENS_RES): ");
print_hex (nbi.abtAtqb, 12); print_hex (nji.btSensRes, 2);
printf (" ID: "); printf (" 4-LSB JEWELID: ");
print_hex (nbi.abtId, 4); print_hex (nji.btId, 4);
printf (" CID: %02x\n", nbi.btCid); }
if (nbi.szInfLen > 0) {
printf (" INF: "); #define PI_ISO14443_4_SUPPORTED 0x01
print_hex (nbi.abtInf, nbi.szInfLen); #define PI_NAD_SUPPORTED 0x01
#define PI_CID_SUPPORTED 0x02
void
print_nfc_iso14443b_info (const nfc_iso14443b_info_t nbi, bool verbose)
{
const int iMaxFrameSizes[] = { 16, 24, 32, 40, 48, 64, 96, 128, 256 };
printf (" PUPI: ");
print_hex (nbi.abtPupi, 4);
printf (" Application Data: ");
print_hex (nbi.abtApplicationData, 4);
printf (" Protocol Info: ");
print_hex (nbi.abtProtocolInfo, 3);
if (verbose) {
printf ("* Bit Rate Capability:\n");
if (nbi.abtProtocolInfo[0] == 0) {
printf (" * PICC supports only 106 kbits/s in both directions\n");
}
if (nbi.abtProtocolInfo[0] & 1<<7) {
printf (" * Same bitrate in both directions mandatory\n");
}
if (nbi.abtProtocolInfo[0] & 1<<4) {
printf (" * PICC to PCD, 1etu=64/fc, bitrate 212 kbits/s supported\n");
}
if (nbi.abtProtocolInfo[0] & 1<<5) {
printf (" * PICC to PCD, 1etu=32/fc, bitrate 424 kbits/s supported\n");
}
if (nbi.abtProtocolInfo[0] & 1<<6) {
printf (" * PICC to PCD, 1etu=16/fc, bitrate 847 kbits/s supported\n");
}
if (nbi.abtProtocolInfo[0] & 1<<0) {
printf (" * PCD to PICC, 1etu=64/fc, bitrate 212 kbits/s supported\n");
}
if (nbi.abtProtocolInfo[0] & 1<<1) {
printf (" * PCD to PICC, 1etu=32/fc, bitrate 424 kbits/s supported\n");
}
if (nbi.abtProtocolInfo[0] & 1<<2) {
printf (" * PCD to PICC, 1etu=16/fc, bitrate 847 kbits/s supported\n");
}
if (nbi.abtProtocolInfo[0] & 1<<3) {
printf (" * ERROR unknown value\n");
}
if( (nbi.abtProtocolInfo[1] & 0xf0) <= 0x80 ) {
printf ("* Maximum frame sizes: %d bytes\n", iMaxFrameSizes[((nbi.abtProtocolInfo[1] & 0xf0) >> 4)]);
}
if((nbi.abtProtocolInfo[1] & 0x0f) == PI_ISO14443_4_SUPPORTED) {
printf ("* Protocol types supported: ISO/IEC 14443-4\n");
}
printf ("* Frame Waiting Time: %.4g ms\n",256.0*16.0*(1<<((nbi.abtProtocolInfo[2] & 0xf0) >> 4))/13560.0);
if((nbi.abtProtocolInfo[2] & (PI_NAD_SUPPORTED|PI_CID_SUPPORTED)) != 0) {
printf ("* Frame options supported: ");
if ((nbi.abtProtocolInfo[2] & PI_NAD_SUPPORTED) != 0) printf ("NAD ");
if ((nbi.abtProtocolInfo[2] & PI_CID_SUPPORTED) != 0) printf ("CID ");
printf("\n");
}
}
}
void
print_nfc_dep_info (const nfc_dep_info_t ndi, bool verbose)
{
printf (" NFCID3: ");
print_hex (ndi.abtNFCID3, 10);
printf (" BS: %02x\n", ndi.btBS);
printf (" BR: %02x\n", ndi.btBR);
printf (" TO: %02x\n", ndi.btTO);
printf (" PP: %02x\n", ndi.btPP);
if (ndi.szGB) {
printf ("General Bytes: ");
print_hex (ndi.abtGB, ndi.szGB);
} }
printf (" PARAMS: %02x %02x %02x %02x\n", nbi.btParam1, nbi.btParam2, nbi.btParam3, nbi.btParam4);
} }
/** /**
@ -152,7 +595,7 @@ print_nfc_iso14443b_info (const nfc_iso14443b_info_t nbi)
* @return Returns the list of found device descriptions. * @return Returns the list of found device descriptions.
*/ */
nfc_device_desc_t * nfc_device_desc_t *
parse_device_desc (int argc, const char *argv[], size_t * szFound) parse_args (int argc, const char *argv[], size_t * szFound, bool * verbose)
{ {
nfc_device_desc_t *pndd = 0; nfc_device_desc_t *pndd = 0;
int arg; int arg;
@ -162,7 +605,7 @@ parse_device_desc (int argc, const char *argv[], size_t * szFound)
for (arg = 1; arg < argc; arg++) { for (arg = 1; arg < argc; arg++) {
if (0 == strcmp (argv[arg], "--device")) { if (0 == strcmp (argv[arg], "--device")) {
// FIXME: this device selection by command line options is terrible & does not support USB/PCSC drivers
if (argc > arg + 1) { if (argc > arg + 1) {
char buffer[256]; char buffer[256];
@ -182,10 +625,64 @@ parse_device_desc (int argc, const char *argv[], size_t * szFound)
sscanf (strtok (NULL, ":"), "%u", &pndd->uiSpeed); sscanf (strtok (NULL, ":"), "%u", &pndd->uiSpeed);
*szFound = 1; *szFound = 1;
} else {
errx (1, "usage: %s [--device driver:port:speed]", argv[0]);
} }
break; }
if ((0 == strcmp (argv[arg], "-v")) || (0 == strcmp (argv[arg], "--verbose"))) {
*verbose = true;
} }
} }
return pndd; return pndd;
} }
const char *
str_nfc_baud_rate (const nfc_baud_rate_t nbr)
{
switch(nbr) {
case NBR_UNDEFINED:
return "undefined baud rate";
break;
case NBR_106:
return "106 kbps";
break;
case NBR_212:
return "212 kbps";
break;
case NBR_424:
return "424 kbps";
break;
case NBR_847:
return "847 kbps";
break;
}
return "";
}
void
print_nfc_target (const nfc_target_t nt, bool verbose)
{
switch(nt.nm.nmt) {
case NMT_ISO14443A:
printf ("ISO/IEC 14443A (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
print_nfc_iso14443a_info (nt.nti.nai, verbose);
break;
case NMT_JEWEL:
printf ("Innovision Jewel (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
print_nfc_jewel_info (nt.nti.nji, verbose);
break;
case NMT_FELICA:
printf ("FeliCa (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
print_nfc_felica_info (nt.nti.nfi, verbose);
break;
case NMT_ISO14443B:
printf ("ISO/IEC 14443-4B (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
print_nfc_iso14443b_info (nt.nti.nbi, verbose);
break;
case NMT_DEP:
printf ("D.E.P. (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
print_nfc_dep_info (nt.nti.ndi, verbose);
break;
}
}

View file

@ -34,10 +34,14 @@ void print_hex (const byte_t * pbtData, const size_t szLen);
void print_hex_bits (const byte_t * pbtData, const size_t szBits); void print_hex_bits (const byte_t * pbtData, const size_t szBits);
void print_hex_par (const byte_t * pbtData, const size_t szBits, const byte_t * pbtDataPar); void print_hex_par (const byte_t * pbtData, const size_t szBits, const byte_t * pbtDataPar);
void print_nfc_iso14443a_info (const nfc_iso14443a_info_t nai); void print_nfc_iso14443a_info (const nfc_iso14443a_info_t nai, bool verbose);
void print_nfc_iso14443b_info (const nfc_iso14443b_info_t nbi); void print_nfc_iso14443b_info (const nfc_iso14443b_info_t nbi, bool verbose);
void print_nfc_felica_info (const nfc_felica_info_t nfi); void print_nfc_felica_info (const nfc_felica_info_t nfi, bool verbose);
void print_nfc_jewel_info (const nfc_jewel_info_t nji, bool verbose);
void print_nfc_dep_info (const nfc_dep_info_t ndi, bool verbose);
nfc_device_desc_t *parse_device_desc (int argc, const char *argv[], size_t * szFound); void print_nfc_target (const nfc_target_t nt, bool verbose);
nfc_device_desc_t *parse_args (int argc, const char *argv[], size_t * szFound, bool * verbose);
#endif #endif