diff --git a/src/Makefile.am b/src/Makefile.am index 699d7fa..d57ba0d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 diff --git a/src/mfcuk_finger.c b/src/mfcuk_finger.c index 109183e..7017914 100644 --- a/src/mfcuk_finger.c +++ b/src/mfcuk_finger.c @@ -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; diff --git a/src/mfcuk_finger.h b/src/mfcuk_finger.h index 58b06aa..8b17d1b 100644 --- a/src/mfcuk_finger.h +++ b/src/mfcuk_finger.h @@ -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(); diff --git a/src/mfcuk_keyrecovery_darkside.c b/src/mfcuk_keyrecovery_darkside.c index 049ecad..5eefb01 100644 --- a/src/mfcuk_keyrecovery_darkside.c +++ b/src/mfcuk_keyrecovery_darkside.c @@ -131,13 +131,23 @@ #include #endif +// NFC #include +#include + +// 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 + +// 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 #include -#include +#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); diff --git a/src/mifare.c b/src/mifare.c new file mode 100644 index 0000000..28db72c --- /dev/null +++ b/src/mifare.c @@ -0,0 +1,85 @@ +#include "mifare.h" + +#include + +#include + +/** + * @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; +} diff --git a/src/mifare.h b/src/mifare.h new file mode 100644 index 0000000..1b98b22 --- /dev/null +++ b/src/mifare.h @@ -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 + * + * + * @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 + +// 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_ diff --git a/src/mirror-subr.c b/src/mirror-subr.c new file mode 100644 index 0000000..4685293 --- /dev/null +++ b/src/mirror-subr.c @@ -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 + */ + + /** + * @file mirror-subr.c + * @brief + */ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif // HAVE_CONFIG_H + +#include + +#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 + * + * + * @file mirror-subr.h + * @brief + */ + +#ifndef _LIBNFC_MIRROR_SUBR_H_ +#define _LIBNFC_MIRROR_SUBR_H_ + +#include + +#include + + +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_ diff --git a/src/nfc-utils.c b/src/nfc-utils.c new file mode 100644 index 0000000..33063c8 --- /dev/null +++ b/src/nfc-utils.c @@ -0,0 +1,179 @@ +#include + +#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; szByteNr0) { + 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 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; +} + diff --git a/src/nfc-utils.h b/src/nfc-utils.h new file mode 100644 index 0000000..c0c6f68 --- /dev/null +++ b/src/nfc-utils.h @@ -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 + * + * + * @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 +#include + +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