Attempt to make it work with libnfc 1.3.9

This commit is contained in:
rconty@il4p.fr 2010-09-06 11:24:05 +00:00
parent b628fa2e6e
commit 26006db05e
12 changed files with 644 additions and 69 deletions

View File

@ -1,7 +1,17 @@
bin_PROGRAMS = mfcuk_keyrecovery_darkside
# set the include path found by configure
mfcuk_keyrecovery_darkside_SOURCES = mfcuk_keyrecovery_darkside.c mfcuk_mifare.c mfcuk_utils.c mfcuk_finger.c crapto1.c crypto1.c
mfcuk_keyrecovery_darkside_SOURCES = \
crapto1.c \
crypto1.c \
mfcuk_finger.c \
mfcuk_keyrecovery_darkside.c \
mfcuk_mifare.c \
mfcuk_utils.c \
mifare.c \
mirror-subr.c \
nfc-utils.c
mfcuk_keyrecovery_darkside_LDADD = -lnfc -lusb -lpcsclite
# dist_man_MANS = mfcuk_keyrecovery_darkside.1

View File

@ -47,7 +47,7 @@ mfcuk_finger_tmpl_entry mfcuk_finger_db[] =
int mfcuk_finger_db_entries = sizeof(mfcuk_finger_db)/sizeof(mfcuk_finger_db[0]);
int mfcuk_finger_default_decoder(mifare_tag *dump)
int mfcuk_finger_default_decoder(mifare_classic_tag *dump)
{
if (!dump)
{
@ -62,7 +62,7 @@ int mfcuk_finger_default_decoder(mifare_tag *dump)
}
// Yes, I know C++ class inheritance would perfectly fit the decoders/comparators... Though C is more to my heart. Anyone to rewrite in C++?
int mfcuk_finger_skgt_decoder(mifare_tag *dump)
int mfcuk_finger_skgt_decoder(mifare_classic_tag *dump)
{
unsigned char *dump_ptr = NULL;
unsigned short car_number = 0;
@ -85,7 +85,7 @@ int mfcuk_finger_skgt_decoder(mifare_tag *dump)
return 1;
}
int mfcuk_finger_default_comparator(mifare_tag *dump, mfcuk_finger_template *tmpl, float *score)
int mfcuk_finger_default_comparator(mifare_classic_tag *dump, mfcuk_finger_template *tmpl, float *score)
{
int max_bytes = 0;
int i;
@ -140,8 +140,8 @@ int mfcuk_finger_default_comparator(mifare_tag *dump, mfcuk_finger_template *tmp
int mfcuk_finger_load()
{
int i;
mifare_tag mask;
mifare_tag values;
mifare_classic_tag mask;
mifare_classic_tag values;
FILE *fp = NULL;
size_t result = 0;
mfcuk_finger_template *tmpl_new = NULL;

View File

@ -47,13 +47,13 @@
// Wrapping an ugly template into an externally pleasant name. To implement proper template later.
typedef struct _mfcuk_finger_template_
{
mifare_tag mask;
mifare_tag values;
mifare_classic_tag mask;
mifare_classic_tag values;
} mfcuk_finger_template;
// Function type definition, to be used for custom decoders/comparators
typedef int (*mfcuk_finger_comparator) (mifare_tag *dump, mfcuk_finger_template *tmpl, float *score);
typedef int (*mfcuk_finger_decoder) (mifare_tag *dump);
typedef int (*mfcuk_finger_comparator) (mifare_classic_tag *dump, mfcuk_finger_template *tmpl, float *score);
typedef int (*mfcuk_finger_decoder) (mifare_classic_tag *dump);
// Naive implementation of a self-contained fingerprint database entry
typedef struct _mfcuk_finger_tmpl_entry_
@ -65,9 +65,9 @@ typedef struct _mfcuk_finger_tmpl_entry_
mfcuk_finger_template *tmpl_data;
} mfcuk_finger_tmpl_entry;
int mfcuk_finger_default_comparator(mifare_tag *dump, mfcuk_finger_template *tmpl, float *score);
int mfcuk_finger_default_decoder(mifare_tag *dump);
int mfcuk_finger_skgt_decoder(mifare_tag *dump);
int mfcuk_finger_default_comparator(mifare_classic_tag *dump, mfcuk_finger_template *tmpl, float *score);
int mfcuk_finger_default_decoder(mifare_classic_tag *dump);
int mfcuk_finger_skgt_decoder(mifare_classic_tag *dump);
// "Housekeeping" functions
int mfcuk_finger_load();

View File

@ -131,13 +131,23 @@
#include <sys/types.h>
#endif
// NFC
#include <nfc/nfc.h>
#include <nfc/nfc-types.h>
// Crapto1
#include "crapto1.h"
// FIXME: For some reason (reason=I am dumb perhaps), these two prototypes are not visible form crapto1.h, so I put them here
struct Crypto1State* lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8]);
uint32_t lfsr_rollback_word(struct Crypto1State* s, uint32_t in, int fb);
// :FIXME
#include <nfc/mifaretag.h>
// imported from libnfc's examples
#include "mifare.h"
#include "nfc-utils.h"
#include "mirror-subr.h"
// internal
#include "mfcuk_mifare.h"
#include "mfcuk_utils.h"
#include "mfcuk_finger.h"
@ -215,6 +225,9 @@ uint32_t mfcuk_verify_key_block(nfc_device_t* pnd, uint32_t uiUID, uint64_t ui64
return MFCUK_FAIL_COMM;
}
// We need to disable EASY_FRAMING feature to talk in "raw" mode
nfc_configure (pnd, NDO_EASY_FRAMING, false);
// Request plain tag-nonce
if (!nfc_initiator_transceive_bytes(pnd,abtAuth,4,abtRx,&szRx))
{
@ -222,7 +235,7 @@ uint32_t mfcuk_verify_key_block(nfc_device_t* pnd, uint32_t uiUID, uint64_t ui64
}
// Save the tag nonce (nt)
nt = swap_endian32(abtRx);
nt = mirror_bytes(abtRx, 4);
nt_orig = nt;
// Init cipher with key
@ -372,7 +385,7 @@ uint32_t mfcuk_key_recovery_block(nfc_device_t* pnd, uint32_t uiUID, uint64_t ui
//print_hex(abtRx,4);
// Save the tag nonce (nt)
nt = swap_endian32(abtRx);
nt = mirror_bytes(abtRx, 4);
// zveriu
//printf("INFO - Nonce distance %d (from 0x%08x, to 0x%08x)\n", nonce_distance(nt, nt_orig), nt, nt_orig);
@ -672,9 +685,9 @@ void print_usage(FILE *fp)
fprintf(fp, "\n");
fprintf(fp, "Usage:\n");
fprintf(fp, "-C - require explicit connection to the reader. Without this option, the connection is not made and recovery will not occur\n");
fprintf(fp, "-i mifare.dmp - load input mifare_tag type dump\n");
fprintf(fp, "-I mifare_ext.dmp - load input extended dump specific to this tool, has several more fields on top of mifare_tag type dump\n");
fprintf(fp, "-o mifare.dmp - output the resulting mifare_tag dump to a given file\n");
fprintf(fp, "-i mifare.dmp - load input mifare_classic_tag type dump\n");
fprintf(fp, "-I mifare_ext.dmp - load input extended dump specific to this tool, has several more fields on top of mifare_classic_tag type dump\n");
fprintf(fp, "-o mifare.dmp - output the resulting mifare_classic_tag dump to a given file\n");
fprintf(fp, "-O mifare_ext.dmp - output the resulting extended dump to a given file\n");
fprintf(fp, "-V sector[:A/B/any_other_alphanum[:fullkey]] - verify key for specified sector, -1 means all sectors\n");
fprintf(fp, "\tAfter first semicolon key-type can specified: A verifies only keyA, B verifies only keyB, anything else verifies both keys\n");
@ -707,11 +720,11 @@ void print_identification()
void print_mifare_tag_actions(const char *title, mifare_tag *tag)
void print_mifare_classic_tag_actions(const char *title, mifare_classic_tag *tag)
{
uint32_t i, max_blocks, trailer_block;
byte_t bTagType;
mifare_block_trailer *ptr_trailer = NULL;
mifare_classic_block_trailer *ptr_trailer = NULL;
if (!tag)
{
@ -751,7 +764,7 @@ void print_mifare_tag_actions(const char *title, mifare_tag *tag)
break;
}
ptr_trailer = (mifare_block_trailer *) ((char *)tag + (trailer_block * MIFARE_CLASSIC_BYTES_PER_BLOCK) );
ptr_trailer = (mifare_classic_block_trailer *) ((char *)tag + (trailer_block * MIFARE_CLASSIC_BYTES_PER_BLOCK) );
printf("%d\t| %02x%02x%02x%02x%02x%02x\t| %c %c | %c %c\t| %02x%02x%02x%02x%02x%02x\t| %c %c | %c %c\n",
get_sector_for_block(bTagType, trailer_block),
@ -846,7 +859,7 @@ bool mfcuk_darkside_select_tag(nfc_device_t* pnd, int iSleepAtFieldOFF, int iSle
sleep(iSleepAfterFieldON);
// Poll for a ISO14443A (MIFARE) tag
if (!nfc_initiator_select_tag(pnd,NM_ISO14443A_106,NULL,0,&ti_tmp))
if (!nfc_initiator_select_passive_target(pnd,NM_ISO14443A_106,NULL,0,&ti_tmp))
{
fprintf(stderr, "ERROR: connecting to MIFARE Classic tag\n");
//nfc_disconnect(pnd);
@ -866,8 +879,8 @@ int main(int argc, char* argv[])
//char extendedDescription[MFCUK_EXTENDED_DESCRIPTION_LENGTH] = {0}; // Initialize with '\0' character
byte_t keyOpt[MIFARE_CLASSIC_KEY_BYTELENGTH] = {0};
byte_t uidOpt[MIFARE_CLASSIC_UID_BYTELENGTH] = {0};
mifare_block_trailer *ptr_trailer = NULL;
mifare_block_trailer *ptr_trailer_dump = NULL;
mifare_classic_block_trailer *ptr_trailer = NULL;
mifare_classic_block_trailer *ptr_trailer_dump = NULL;
int sector = 0;
uint32_t block = 0;
byte_t action = 0;
@ -891,13 +904,13 @@ int main(int argc, char* argv[])
uint64_t ui64Key = 0xc1e51c63b8f5;//0xffffffffffff;
uint32_t uiErrCode = MFCUK_SUCCESS;
uint64_t ui64KeyRecovered;
mifare_tag_ext dump_loaded_tag;
mifare_tag_ext tag_on_reader;
mifare_tag_ext tag_recover_verify;
mifare_classic_tag_ext dump_loaded_tag;
mifare_classic_tag_ext tag_on_reader;
mifare_classic_tag_ext tag_recover_verify;
mifare_key_type bKeyType = keyA;
// fingerprint options related
mifare_tag finger_tag;
mifare_classic_tag finger_tag;
float finger_score;
float finger_score_highest;
int finger_index_highest;
@ -1059,7 +1072,7 @@ int main(int argc, char* argv[])
if (st >= MIFARE_CLASSIC_UID_BYTELENGTH)
{
tag_recover_verify.uid = swap_endian32(uidOpt);
tag_recover_verify.uid = mirror_bytes(uidOpt, 4);
memcpy( tag_recover_verify.tag_basic.amb[0].mbm.abtUID, uidOpt, MIFARE_CLASSIC_UID_BYTELENGTH );
bfOpts[ch] = true;
}
@ -1125,7 +1138,7 @@ int main(int argc, char* argv[])
{
// TODO: proper error handling for block and ptr_trailer
block = get_trailer_block_for_sector(MIFARE_CLASSIC_4K, i);
ptr_trailer = (mifare_block_trailer *) ((char *)(&tag_recover_verify.tag_basic) + (block * MIFARE_CLASSIC_BYTES_PER_BLOCK) );
ptr_trailer = (mifare_classic_block_trailer *) ((char *)(&tag_recover_verify.tag_basic) + (block * MIFARE_CLASSIC_BYTES_PER_BLOCK) );
ptr_trailer->abtAccessBits[ACTIONS_KEY_A] |= action;
ptr_trailer->abtAccessBits[ACTIONS_KEY_B] |= action;
@ -1146,7 +1159,7 @@ int main(int argc, char* argv[])
{
// TODO: proper error handling for block and ptr_trailer
block = get_trailer_block_for_sector(MIFARE_CLASSIC_4K, i);
ptr_trailer = (mifare_block_trailer *) ((char *)(&tag_recover_verify.tag_basic) + (block * MIFARE_CLASSIC_BYTES_PER_BLOCK) );
ptr_trailer = (mifare_classic_block_trailer *) ((char *)(&tag_recover_verify.tag_basic) + (block * MIFARE_CLASSIC_BYTES_PER_BLOCK) );
ptr_trailer->abtAccessBits[ACTIONS_KEY_B * (1 - (token[0]-'A'))] &= (~action);
}
@ -1159,7 +1172,7 @@ int main(int argc, char* argv[])
{
// TODO: proper error handling for block and ptr_trailer
block = get_trailer_block_for_sector(MIFARE_CLASSIC_4K, i);
ptr_trailer = (mifare_block_trailer *) ((char *)(&tag_recover_verify.tag_basic) + (block * MIFARE_CLASSIC_BYTES_PER_BLOCK) );
ptr_trailer = (mifare_classic_block_trailer *) ((char *)(&tag_recover_verify.tag_basic) + (block * MIFARE_CLASSIC_BYTES_PER_BLOCK) );
ptr_trailer->abtAccessBits[ACTIONS_KEY_A] |= action;
ptr_trailer->abtAccessBits[ACTIONS_KEY_B] |= action;
@ -1200,7 +1213,7 @@ int main(int argc, char* argv[])
{
// TODO: proper error handling for block and ptr_trailer
block = get_trailer_block_for_sector(MIFARE_CLASSIC_4K, i);
ptr_trailer = (mifare_block_trailer *) ((char *)(&tag_recover_verify.tag_basic) + (block * MIFARE_CLASSIC_BYTES_PER_BLOCK) );
ptr_trailer = (mifare_classic_block_trailer *) ((char *)(&tag_recover_verify.tag_basic) + (block * MIFARE_CLASSIC_BYTES_PER_BLOCK) );
if ( !specific_key_type || specific_key_type == keyA )
{
@ -1224,7 +1237,7 @@ int main(int argc, char* argv[])
}
break;
case 'i':
// Input simple dump file of type mifare_tag, Options i and I are autoexclusive
// Input simple dump file of type mifare_classic_tag, Options i and I are autoexclusive
if (!bfOpts['i'] && !bfOpts['I'])
{
if ( !mfcuk_load_tag_dump(optarg, &(dump_loaded_tag.tag_basic)) )
@ -1238,7 +1251,7 @@ int main(int argc, char* argv[])
}
break;
case 'I':
// // Input extended dump file of type mifare_tag_ext, Options i and I are autoexclusive
// // Input extended dump file of type mifare_classic_tag_ext, Options i and I are autoexclusive
if (!bfOpts['i'] && !bfOpts['I'])
{
if ( !mfcuk_load_tag_dump_ext(optarg, &(dump_loaded_tag)) )
@ -1405,7 +1418,7 @@ int main(int argc, char* argv[])
{
if (bfOpts['v'] && (verboseLevel > 0))
{
print_mifare_tag_keys("LOADED TAG DUMP", &(dump_loaded_tag.tag_basic));
print_mifare_classic_tag_keys("LOADED TAG DUMP", &(dump_loaded_tag.tag_basic));
}
// Overwrite from the loaded dump only the keys for sectors and keys which were not specified on command line
@ -1413,8 +1426,8 @@ int main(int argc, char* argv[])
{
// TODO: proper error handling for block and ptr_trailer
block = get_trailer_block_for_sector(MIFARE_CLASSIC_4K, i);
ptr_trailer = (mifare_block_trailer *) ((char *)(&tag_recover_verify.tag_basic) + (block * MIFARE_CLASSIC_BYTES_PER_BLOCK) );
ptr_trailer_dump = (mifare_block_trailer *) ((char *)(&dump_loaded_tag.tag_basic) + (block * MIFARE_CLASSIC_BYTES_PER_BLOCK) );
ptr_trailer = (mifare_classic_block_trailer *) ((char *)(&tag_recover_verify.tag_basic) + (block * MIFARE_CLASSIC_BYTES_PER_BLOCK) );
ptr_trailer_dump = (mifare_classic_block_trailer *) ((char *)(&dump_loaded_tag.tag_basic) + (block * MIFARE_CLASSIC_BYTES_PER_BLOCK) );
// If no command line keyA is set, copy from loaded dump
if ( !(ptr_trailer->abtAccessBits[ACTIONS_KEY_A] & ACTIONS_KEYSET) )
@ -1434,12 +1447,12 @@ int main(int argc, char* argv[])
// If no command line UID supplied and not tag-type specified, copy the manufacturer block from the loaded dump
if ( !bfOpts['U'] && !bfOpts['M'] )
{
ptr_trailer = (mifare_block_trailer *) ((char *)(&tag_recover_verify.tag_basic) + (0 * MIFARE_CLASSIC_BYTES_PER_BLOCK) );
ptr_trailer_dump = (mifare_block_trailer *) ((char *)(&dump_loaded_tag.tag_basic) + (0 * MIFARE_CLASSIC_BYTES_PER_BLOCK) );
ptr_trailer = (mifare_classic_block_trailer *) ((char *)(&tag_recover_verify.tag_basic) + (0 * MIFARE_CLASSIC_BYTES_PER_BLOCK) );
ptr_trailer_dump = (mifare_classic_block_trailer *) ((char *)(&dump_loaded_tag.tag_basic) + (0 * MIFARE_CLASSIC_BYTES_PER_BLOCK) );
memcpy( ptr_trailer, ptr_trailer_dump, sizeof(*ptr_trailer) );
tag_recover_verify.type = tag_recover_verify.tag_basic.amb[0].mbm.btUnknown;
tag_recover_verify.uid = swap_endian32(tag_recover_verify.tag_basic.amb[0].mbm.abtUID);
tag_recover_verify.uid = mirror_bytes(tag_recover_verify.tag_basic.amb[0].mbm.abtUID, 4);
}
}
@ -1490,19 +1503,19 @@ int main(int argc, char* argv[])
}
// Tag on the reader UID
tag_on_reader.uid = swap_endian32(ti.nai.abtUid);
tag_on_reader.uid = mirror_bytes(ti.nai.abtUid, 4);
memcpy( tag_on_reader.tag_basic.amb[0].mbm.abtUID, ti.nai.abtUid, MIFARE_CLASSIC_UID_BYTELENGTH);
// No command line tag UID specified, take it from the tag on the reader
if ( !bfOpts['U'] )
{
tag_recover_verify.uid = swap_endian32(ti.nai.abtUid);
tag_recover_verify.uid = mirror_bytes(ti.nai.abtUid, 4);
memcpy( tag_recover_verify.tag_basic.amb[0].mbm.abtUID, ti.nai.abtUid, MIFARE_CLASSIC_UID_BYTELENGTH);
}
if (bfOpts['v'] && (verboseLevel > 0))
{
print_mifare_tag_actions("\n\nINITIAL ACTIONS MATRIX", &(tag_recover_verify.tag_basic));
print_mifare_classic_tag_actions("\n\nINITIAL ACTIONS MATRIX", &(tag_recover_verify.tag_basic));
}
max_sectors = (IS_MIFARE_CLASSIC_1K(tag_recover_verify.type)?MIFARE_CLASSIC_1K_MAX_SECTORS:MIFARE_CLASSIC_4K_MAX_SECTORS);
@ -1531,7 +1544,7 @@ int main(int argc, char* argv[])
// TODO: proper error handling
block = get_trailer_block_for_sector(crntVerifTagType, i);
ptr_trailer = (mifare_block_trailer *) ((char *)(&tag_recover_verify.tag_basic) + (block * MIFARE_CLASSIC_BYTES_PER_BLOCK) );
ptr_trailer = (mifare_classic_block_trailer *) ((char *)(&tag_recover_verify.tag_basic) + (block * MIFARE_CLASSIC_BYTES_PER_BLOCK) );
// If DEFAULT KEYS option was specified, crntNumVerifKeys is already taking care of them
// Also, perform verification ontly if the sector has been marked for verification of key and not valid verification yet occured in the loop
@ -1552,7 +1565,7 @@ int main(int argc, char* argv[])
fprintf(stderr, "WARN: mfcuk_key_arr_to_uint64() failed, verification key will be %012llx\n", crntVerifKey);
}
/*
/*
// TODO: make this kind of key verification as part of option -a - advanced verification of keys with crapto1 rollback for double verification
// TEST
nfc_disconnect(pnd);
@ -1591,12 +1604,11 @@ int main(int argc, char* argv[])
// Reset advanced settings
mfcuk_darkside_reset_advanced(pnd);
*/
*/
memcpy(mp.mpa.abtUid, tag_recover_verify.tag_basic.amb[0].mbm.abtUID, MIFARE_CLASSIC_UID_BYTELENGTH);
memcpy(mp.mpa.abtKey, &(current_default_keys[j][0]), MIFARE_CLASSIC_KEY_BYTELENGTH);
if ( !nfc_initiator_select_tag(pnd, NM_ISO14443A_106, NULL, 0, &ti) )
if ( !nfc_initiator_select_passive_target(pnd, NM_ISO14443A_106, NULL, 0, &ti) )
{
fprintf(stderr, "ERROR: tag was removed or cannot be selected\n");
}
@ -1621,7 +1633,7 @@ int main(int argc, char* argv[])
if ( bfOpts['v'] && (verboseLevel > 0) )
{
print_mifare_tag_actions("\n\nACTION RESULTS MATRIX AFTER VERIFY", &(tag_recover_verify.tag_basic));
print_mifare_classic_tag_actions("\n\nACTION RESULTS MATRIX AFTER VERIFY", &(tag_recover_verify.tag_basic));
}
// RECOVER KEYS CODE-BLOCK
@ -1632,7 +1644,7 @@ int main(int argc, char* argv[])
ui64KeyRecovered = 0;
block = get_trailer_block_for_sector(MIFARE_CLASSIC_4K, i);
ptr_trailer = (mifare_block_trailer *) ((char *)(&tag_recover_verify.tag_basic) + (block * MIFARE_CLASSIC_BYTES_PER_BLOCK) );
ptr_trailer = (mifare_classic_block_trailer *) ((char *)(&tag_recover_verify.tag_basic) + (block * MIFARE_CLASSIC_BYTES_PER_BLOCK) );
printf(" %x", i);
fflush(stdout);
@ -1723,7 +1735,7 @@ int main(int argc, char* argv[])
if ( bfOpts['v'] && (verboseLevel > 0) )
{
print_mifare_tag_actions("\n\nACTION RESULTS MATRIX AFTER RECOVER", &(tag_recover_verify.tag_basic));
print_mifare_classic_tag_actions("\n\nACTION RESULTS MATRIX AFTER RECOVER", &(tag_recover_verify.tag_basic));
}
// DUMP DATA CODE-BLOCK
@ -1732,7 +1744,7 @@ int main(int argc, char* argv[])
for (i=0; i<max_sectors; i++)
{
block = get_trailer_block_for_sector(MIFARE_CLASSIC_4K, i);
ptr_trailer = (mifare_block_trailer *) ((char *)(&tag_recover_verify.tag_basic) + (block * MIFARE_CLASSIC_BYTES_PER_BLOCK) );
ptr_trailer = (mifare_classic_block_trailer *) ((char *)(&tag_recover_verify.tag_basic) + (block * MIFARE_CLASSIC_BYTES_PER_BLOCK) );
//nfc_initiator_mifare_cmd()
}

View File

@ -357,7 +357,7 @@ void test_mifare_classic_blocks_sectors_functions(byte_t bTagType)
}
bool mfcuk_save_tag_dump(char *filename, mifare_tag *tag)
bool mfcuk_save_tag_dump(char *filename, mifare_classic_tag *tag)
{
FILE *fp;
size_t result;
@ -382,7 +382,7 @@ bool mfcuk_save_tag_dump(char *filename, mifare_tag *tag)
return true;
}
bool mfcuk_save_tag_dump_ext(char *filename, mifare_tag_ext *tag_ext)
bool mfcuk_save_tag_dump_ext(char *filename, mifare_classic_tag_ext *tag_ext)
{
FILE *fp;
size_t result;
@ -407,7 +407,7 @@ bool mfcuk_save_tag_dump_ext(char *filename, mifare_tag_ext *tag_ext)
return true;
}
bool mfcuk_load_tag_dump(char *filename, mifare_tag *tag)
bool mfcuk_load_tag_dump(char *filename, mifare_classic_tag *tag)
{
FILE *fp;
size_t result;
@ -432,7 +432,7 @@ bool mfcuk_load_tag_dump(char *filename, mifare_tag *tag)
return true;
}
bool mfcuk_load_tag_dump_ext(char *filename, mifare_tag_ext *tag_ext)
bool mfcuk_load_tag_dump_ext(char *filename, mifare_classic_tag_ext *tag_ext)
{
FILE *fp;
size_t result;
@ -457,11 +457,11 @@ bool mfcuk_load_tag_dump_ext(char *filename, mifare_tag_ext *tag_ext)
return true;
}
void print_mifare_tag_keys(const char *title, mifare_tag *tag)
void print_mifare_classic_tag_keys(const char *title, mifare_classic_tag *tag)
{
uint32_t i, max_blocks, trailer_block;
byte_t bTagType;
mifare_block_trailer *ptr_trailer = NULL;
mifare_classic_block_trailer *ptr_trailer = NULL;
if (!tag)
{
@ -501,7 +501,7 @@ void print_mifare_tag_keys(const char *title, mifare_tag *tag)
break;
}
ptr_trailer = (mifare_block_trailer *) ((char *)tag + (trailer_block * MIFARE_CLASSIC_BYTES_PER_BLOCK) );
ptr_trailer = (mifare_classic_block_trailer *) ((char *)tag + (trailer_block * MIFARE_CLASSIC_BYTES_PER_BLOCK) );
printf("%d\t| %02x%02x%02x%02x%02x%02x\t| %02x%02x%02x%02x\t| %02x%02x%02x%02x%02x%02x\n",
get_sector_for_block(bTagType, trailer_block),

View File

@ -57,7 +57,7 @@
#include <stdlib.h>
#include <nfc/nfc.h>
#include <nfc/mifaretag.h>
#include "mifare.h"
#define MIFARE_CLASSIC_UID_BYTELENGTH 4 // Length of a Mifare Classic UID in bytes
#define MIFARE_CLASSIC_KEY_BYTELENGTH 6 // Length of a Mifare Classic key in bytes
@ -104,8 +104,8 @@ typedef struct {
byte_t type; // ATS/SAK from ti.tia.btSak, example 0x08h for Mifare 1K, 0x18h for Mifare 4K
char datetime[14]; // non-zero-terminated date-time of dump in format YYYYMMDDH24MISS, example 20091114231541 - 14 Nov 2009, 11:15:41 PM
char description[MFCUK_EXTENDED_DESCRIPTION_LENGTH]; // a description of the tag dump, example "RATB_DUMP_BEFORE_PAY"
mifare_tag tag_basic;
} mifare_tag_ext;
mifare_classic_tag tag_basic;
} mifare_classic_tag_ext;
// Define type of keys (A or B) in NXP notation
typedef enum {
@ -134,11 +134,11 @@ bool is_last_sector(byte_t bTagType, uint32_t uiSector);
bool is_last_big_sector(byte_t bTagType, uint32_t uiSector);
bool is_last_small_sector(byte_t bTagType, uint32_t uiSector);
void test_mifare_classic_blocks_sectors_functions(byte_t bTagType);
bool mfcuk_save_tag_dump(char *filename, mifare_tag *tag);
bool mfcuk_save_tag_dump_ext(char *filename, mifare_tag_ext *tag_ext);
bool mfcuk_load_tag_dump(char *filename, mifare_tag *tag);
bool mfcuk_load_tag_dump_ext(char *filename, mifare_tag_ext *tag_ext);
void print_mifare_tag_keys(const char *title, mifare_tag *tag);
bool mfcuk_save_tag_dump(char *filename, mifare_classic_tag *tag);
bool mfcuk_save_tag_dump_ext(char *filename, mifare_classic_tag_ext *tag_ext);
bool mfcuk_load_tag_dump(char *filename, mifare_classic_tag *tag);
bool mfcuk_load_tag_dump_ext(char *filename, mifare_classic_tag_ext *tag_ext);
void print_mifare_classic_tag_keys(const char *title, mifare_classic_tag *tag);
bool mfcuk_key_uint64_to_arr(const uint64_t *ui64Key, byte_t *arr6Key);
bool mfcuk_key_arr_to_uint64(const byte_t *arr6Key, uint64_t *ui64Key);

85
src/mifare.c Normal file
View File

@ -0,0 +1,85 @@
#include "mifare.h"
#include <string.h>
#include <nfc/nfc.h>
/**
* @brief Execute a MIFARE Classic Command
* @return Returns true if action was successfully performed; otherwise returns false.
* @param pmp Some commands need additional information. This information should be supplied in the mifare_param union.
*
* The specified MIFARE command will be executed on the tag. There are different commands possible, they all require the destination block number.
* @note There are three different types of information (Authenticate, Data and Value).
*
* First an authentication must take place using Key A or B. It requires a 48 bit Key (6 bytes) and the UID.
* They are both used to initialize the internal cipher-state of the PN53X chip (http://libnfc.org/hardware/pn53x-chip).
* After a successful authentication it will be possible to execute other commands (e.g. Read/Write).
* The MIFARE Classic Specification (http://www.nxp.com/acrobat/other/identification/M001053_MF1ICS50_rev5_3.pdf) explains more about this process.
*/
bool nfc_initiator_mifare_cmd(nfc_device_t* pnd, const mifare_cmd mc, const uint8_t ui8Block, mifare_param* pmp)
{
byte_t abtRx[265];
size_t szRxLen;
size_t szParamLen;
byte_t abtCmd[265];
// Make sure we are dealing with a active device
if (!pnd->bActive) return false;
abtCmd[0] = mc; // The MIFARE Classic command
abtCmd[1] = ui8Block; // The block address (1K=0x00..0x39, 4K=0x00..0xff)
switch (mc)
{
// Read and store command have no parameter
case MC_READ:
case MC_STORE:
szParamLen = 0;
break;
// Authenticate command
case MC_AUTH_A:
case MC_AUTH_B:
szParamLen = sizeof(mifare_param_auth);
break;
// Data command
case MC_WRITE:
szParamLen = sizeof(mifare_param_data);
break;
// Value command
case MC_DECREMENT:
case MC_INCREMENT:
case MC_TRANSFER:
szParamLen = sizeof(mifare_param_value);
break;
// Please fix your code, you never should reach this statement
default:
return false;
break;
}
// When available, copy the parameter bytes
if (szParamLen) memcpy(abtCmd+2,(byte_t*)pmp,szParamLen);
// Fire the mifare command
if (!nfc_initiator_transceive_bytes(pnd,abtCmd,2+szParamLen,abtRx,&szRxLen)) {
nfc_perror (pnd, "nfc_initiator_transceive_bytes");
return false;
}
// When we have executed a read command, copy the received bytes into the param
if (mc == MC_READ) {
if(szRxLen == 16) {
memcpy(pmp->mpd.abtData,abtRx,16);
} else {
return false;
}
}
// Command succesfully executed
return true;
}

127
src/mifare.h Normal file
View File

@ -0,0 +1,127 @@
/**
* Public platform independent Near Field Communication (NFC) library
*
* Copyright (C) 2009, Roel Verdult, 2010, Romuald Conty
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*
* @file mifaretag.h
* @brief provide samples structs and functions to manipulate MIFARE Classic and Ultralight tags using libnfc
*/
#ifndef _LIBNFC_MIFARE_H_
#define _LIBNFC_MIFARE_H_
#include <nfc/nfc-types.h>
// Compiler directive, set struct alignment to 1 byte_t for compatibility
#pragma pack(1)
typedef enum {
MC_AUTH_A = 0x60,
MC_AUTH_B = 0x61,
MC_READ = 0x30,
MC_WRITE = 0xA0,
MC_TRANSFER = 0xB0,
MC_DECREMENT = 0xC0,
MC_INCREMENT = 0xC1,
MC_STORE = 0xC2
} mifare_cmd;
// MIFARE command params
typedef struct {
byte_t abtKey[6];
byte_t abtUid[4];
} mifare_param_auth;
typedef struct {
byte_t abtData[16];
} mifare_param_data;
typedef struct {
byte_t abtValue[4];
} mifare_param_value;
typedef union {
mifare_param_auth mpa;
mifare_param_data mpd;
mifare_param_value mpv;
} mifare_param;
// Reset struct alignment to default
#pragma pack()
bool nfc_initiator_mifare_cmd(nfc_device_t* pnd, const mifare_cmd mc, const uint8_t ui8Block, mifare_param* pmp);
// Compiler directive, set struct alignment to 1 byte_t for compatibility
#pragma pack(1)
// MIFARE Classic
typedef struct {
byte_t abtUID[4];
byte_t btBCC;
byte_t btUnknown;
byte_t abtATQA[2];
byte_t abtUnknown[8];
} mifare_classic_block_manufacturer;
typedef struct {
byte_t abtData[16];
} mifare_classic_block_data;
typedef struct {
byte_t abtKeyA[6];
byte_t abtAccessBits[4];
byte_t abtKeyB[6];
} mifare_classic_block_trailer;
typedef union {
mifare_classic_block_manufacturer mbm;
mifare_classic_block_data mbd;
mifare_classic_block_trailer mbt;
} mifare_classic_block;
typedef struct {
mifare_classic_block amb[256];
} mifare_classic_tag;
// MIFARE Ultralight
typedef struct {
byte_t sn0[3];
byte_t btBCC0;
byte_t sn1[4];
byte_t btBCC1;
byte_t internal;
byte_t lock[2];
byte_t otp[4];
} mifareul_block_manufacturer;
typedef struct {
byte_t abtData[16];
} mifareul_block_data;
typedef union {
mifareul_block_manufacturer mbm;
mifareul_block_data mbd;
} mifareul_block;
typedef struct {
mifareul_block amb[4];
} mifareul_tag;
// Reset struct alignment to default
#pragma pack()
#endif // _LIBNFC_MIFARE_H_

82
src/mirror-subr.c Normal file
View File

@ -0,0 +1,82 @@
/*-
* Public platform independent Near Field Communication (NFC) library
*
* Copyright (C) 2009, Roel Verdult
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
/**
* @file mirror-subr.c
* @brief
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include <stdio.h>
#include "mirror-subr.h"
static const byte_t ByteMirror[256] = {
0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30,
0xb0, 0x70, 0xf0, 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 0x18, 0x98,
0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64,
0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, 0x0c, 0x8c, 0x4c, 0xcc,
0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 0x02,
0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2,
0x72, 0xf2, 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a,
0xda, 0x3a, 0xba, 0x7a, 0xfa, 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, 0x0e, 0x8e, 0x4e, 0xce, 0x2e,
0xae, 0x6e, 0xee, 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 0x01, 0x81,
0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71,
0xf1, 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9,
0x39, 0xb9, 0x79, 0xf9, 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 0x15,
0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad,
0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 0x03, 0x83, 0x43,
0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, 0x3b,
0xbb, 0x7b, 0xfb, 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97,
0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f,
0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
};
byte_t mirror(byte_t bt)
{
return ByteMirror[bt];
}
void mirror_bytes(byte_t *pbts, size_t szLen)
{
size_t szByteNr;
for (szByteNr=0; szByteNr<szLen; szByteNr++)
{
*pbts = ByteMirror[*pbts];
pbts++;
}
}
uint32_t mirror32(uint32_t ui32Bits)
{
mirror_bytes((byte_t*)&ui32Bits,4);
return ui32Bits;
}
uint64_t mirror64(uint64_t ui64Bits)
{
mirror_bytes((byte_t*)&ui64Bits,8);
return ui64Bits;
}

37
src/mirror-subr.h Normal file
View File

@ -0,0 +1,37 @@
/**
* Public platform independent Near Field Communication (NFC) library
*
* Copyright (C) 2009, Roel Verdult
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*
* @file mirror-subr.h
* @brief
*/
#ifndef _LIBNFC_MIRROR_SUBR_H_
#define _LIBNFC_MIRROR_SUBR_H_
#include <stdint.h>
#include <nfc/nfc-types.h>
byte_t mirror(byte_t bt);
uint32_t mirror32(uint32_t ui32Bits);
uint64_t mirror64(uint64_t ui64Bits);
void mirror_byte_ts(byte_t *pbts, size_t szLen);
#endif // _LIBNFC_MIRROR_SUBR_H_

179
src/nfc-utils.c Normal file
View File

@ -0,0 +1,179 @@
#include <nfc/nfc.h>
#include "nfc-utils.h"
static const byte_t OddParity[256] = {
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1
};
byte_t oddparity(const byte_t bt)
{
return OddParity[bt];
}
void oddparity_bytes_ts(const byte_t* pbtData, const size_t szLen, byte_t* pbtPar)
{
size_t szByteNr;
// Calculate the parity bits for the command
for (szByteNr=0; szByteNr<szLen; szByteNr++)
{
pbtPar[szByteNr] = OddParity[pbtData[szByteNr]];
}
}
void print_hex(const byte_t* pbtData, const size_t szBytes)
{
size_t szPos;
for (szPos=0; szPos < szBytes; szPos++)
{
printf("%02x ",pbtData[szPos]);
}
printf("\n");
}
void print_hex_bits(const byte_t* pbtData, const size_t szBits)
{
uint8_t uRemainder;
size_t szPos;
size_t szBytes = szBits/8;
for (szPos=0; szPos < szBytes; szPos++)
{
printf("%02x ",pbtData[szPos]);
}
uRemainder = szBits % 8;
// Print the rest bits
if (uRemainder != 0)
{
if (uRemainder < 5)
printf("%01x (%d bits)",pbtData[szBytes], uRemainder);
else
printf("%02x (%d bits)",pbtData[szBytes], uRemainder);
}
printf("\n");
}
void print_hex_par(const byte_t* pbtData, const size_t szBits, const byte_t* pbtDataPar)
{
uint8_t uRemainder;
size_t szPos;
size_t szBytes = szBits/8;
for (szPos=0; szPos < szBytes; szPos++)
{
printf("%02x",pbtData[szPos]);
if (OddParity[pbtData[szPos]] != pbtDataPar[szPos])
{
printf("! ");
} else {
printf(" ");
}
}
uRemainder = szBits % 8;
// Print the rest bits, these cannot have parity bit
if (uRemainder != 0)
{
if (uRemainder < 5)
printf("%01x (%d bits)",pbtData[szBytes], uRemainder);
else
printf("%02x (%d bits)",pbtData[szBytes], uRemainder);
}
printf("\n");
}
#define SAK_ISO14443_4_COMPLIANT 0x20
#define SAK_ISO18092_COMPLIANT 0x40
void print_nfc_iso14443a_info(const nfc_iso14443a_info_t nai)
{
printf(" ATQA (SENS_RES): "); print_hex(nai.abtAtqa,2);
printf(" UID (NFCID%c): ",(nai.abtUid[0]==0x08?'3':'1')); print_hex(nai.abtUid, nai.szUidLen);
printf(" SAK (SEL_RES): "); print_hex(&nai.btSak,1);
if (nai.szAtsLen) {
printf(" ATS (ATR): ");
print_hex(nai.abtAts, nai.szAtsLen);
}
if ( (nai.btSak & SAK_ISO14443_4_COMPLIANT) || (nai.btSak & SAK_ISO18092_COMPLIANT) ) {
printf(" Compliant with: ");
if (nai.btSak & SAK_ISO14443_4_COMPLIANT) printf("ISO/IEC 14443-4 ");
if (nai.btSak & SAK_ISO18092_COMPLIANT) printf("ISO/IEC 18092");
printf("\n");
}
}
void print_nfc_felica_info(const nfc_felica_info_t nfi)
{
printf(" ID (NFCID2): "); print_hex(nfi.abtId,8);
printf(" Parameter (PAD): "); print_hex(nfi.abtPad,8);
}
void print_nfc_iso14443b_info(const nfc_iso14443b_info_t nbi)
{
printf(" ATQB: "); print_hex(nbi.abtAtqb,12);
printf(" ID: "); print_hex(nbi.abtId,4);
printf(" CID: %02x\n",nbi.btCid);
if (nbi.szInfLen>0) {
printf(" INF: "); print_hex(nbi.abtInf,nbi.szInfLen);
}
printf(" PARAMS: %02x %02x %02x %02x\n",nbi.btParam1,nbi.btParam2,nbi.btParam3,nbi.btParam4);
}
/**
* @brief Tries to parse arguments to find device descriptions.
* @return Returns the list of found device descriptions.
*/
nfc_device_desc_t* parse_device_desc(int argc, const char *argv[], size_t* szFound)
{
nfc_device_desc_t* pndd = 0;
int arg;
*szFound = 0;
// Get commandline options
for (arg=1;arg<argc;arg++) {
if (0 == strcmp(argv[arg], "--device")) {
if (argc > arg+1) {
char buffer[256];
pndd = malloc(sizeof(nfc_device_desc_t));
strncpy(buffer, argv[++arg], 256);
// Driver.
pndd->pcDriver = (char *)malloc(256);
strcpy(pndd->pcDriver, strtok(buffer, ":"));
// Port.
pndd->pcPort = (char *)malloc(256);
strcpy(pndd->pcPort, strtok(NULL, ":"));
// Speed.
sscanf(strtok(NULL, ":"), "%u", &pndd->uiSpeed);
*szFound = 1;
}
break;
}
}
return pndd;
}

43
src/nfc-utils.h Normal file
View File

@ -0,0 +1,43 @@
/**
* Public platform independent Near Field Communication (NFC) library
*
* Copyright (C) 2010, Romuald Conty
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*
* @file nfc-utils.h
* @brief Provide some examples shared functions like print, parity calculation, options parsing.
*/
#ifndef _EXAMPLES_NFC_UTILS_H_
#define _EXAMPLES_NFC_UTILS_H_
#include <stdlib.h>
#include <string.h>
byte_t oddparity(const byte_t bt);
void oddparity_byte_ts(const byte_t* pbtData, const size_t szLen, byte_t* pbtPar);
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_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_iso14443b_info(const nfc_iso14443b_info_t nbi);
void print_nfc_felica_info(const nfc_felica_info_t nfi);
nfc_device_desc_t* parse_device_desc(int argc, const char *argv[], size_t* szFound);
#endif