diff --git a/CHANGELOG.md b/CHANGELOG.md index d0cdd77d7..4c4ec4c2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file. This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... ## [unreleased][unreleased] + - Added Mifare MAD Card Holder Information decoding (@lukaskuzmiak) - Change Better precision for HF and LF voltage measurements and Add theremin.py script (@rosco) - Added Mifare MAD Info Byte decoding. Easier to identify Card Publisher (@lukaskuzmiak) - Change use system Bzip2 library instead of Zlib for hardnested tables, tables are now 7x smaller (@doegox) diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c index 9cd0b282e..ae0c26a76 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -4500,6 +4500,7 @@ static int CmdHF14AMfMAD(const char *Cmd) { arg_str0("kK", "key", "key for printing sectors", NULL), arg_lit0("bB", "keyb", "use key B for access printing sectors (by default: key A)"), arg_lit0("", "be", "(optional, BigEndian)"), + arg_lit0("", "dch", "decode Card Holder information"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -4512,11 +4513,12 @@ static int CmdHF14AMfMAD(const char *Cmd) { CLIGetHexWithReturn(ctx, 3, key, &keylen); bool keyB = arg_get_lit(4); bool swapmad = arg_get_lit(5); + bool decodeholder = arg_get_lit(6); CLIParserFree(ctx); - if (aidlen != 2 && keylen > 0) { - PrintAndLogEx(WARNING, "do not need a key without aid"); + if (aidlen != 2 && !decodeholder && keylen > 0) { + PrintAndLogEx(WARNING, "do not need a key without aid/decode card holder"); } uint8_t sector0[16 * 4] = {0}; @@ -4549,10 +4551,7 @@ static int CmdHF14AMfMAD(const char *Cmd) { MAD2DecodeAndPrint(sector10, swapmad, verbose); } - if (aidlen == 2) { - uint16_t aaid = (aid[0] << 8) + aid[1]; - PrintAndLogEx(INFO, "-------------- " _CYAN_("AID 0x%04x") " ---------------", aaid); - + if (aidlen == 2 || decodeholder) { uint16_t mad[7 + 8 + 8 + 8 + 8] = {0}; size_t madlen = 0; if (MADDecode(sector0, sector10, mad, &madlen, swapmad)) { @@ -4566,19 +4565,53 @@ static int CmdHF14AMfMAD(const char *Cmd) { memcpy(akey, key, 6); } - for (int i = 0; i < madlen; i++) { - if (aaid == mad[i]) { - uint8_t vsector[16 * 4] = {0}; - if (mfReadSector(i + 1, keyB ? MF_KEY_B : MF_KEY_A, akey, vsector)) { - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(ERR, "error, read sector %d", i + 1); - return PM3_ESOFT; - } + if (aidlen == 2) { + uint16_t aaid = (aid[0] << 8) + aid[1]; + PrintAndLogEx(INFO, "-------------- " _CYAN_("AID 0x%04x") " ---------------", aaid); - for (int j = 0; j < (verbose ? 4 : 3); j ++) - PrintAndLogEx(NORMAL, " [%03d] %s", (i + 1) * 4 + j, sprint_hex(&vsector[j * 16], 16)); + for (int i = 0; i < madlen; i++) { + if (aaid == mad[i]) { + uint8_t vsector[16 * 4] = {0}; + if (mfReadSector(i + 1, keyB ? MF_KEY_B : MF_KEY_A, akey, vsector)) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(ERR, "error, read sector %d", i + 1); + return PM3_ESOFT; + } + + for (int j = 0; j < (verbose ? 4 : 3); j ++) + PrintAndLogEx(NORMAL, " [%03d] %s", (i + 1) * 4 + j, sprint_hex(&vsector[j * 16], 16)); + } } } + + if (decodeholder) { + uint16_t aaid = 0x0004; + PrintAndLogEx(INFO, "-------- " _CYAN_("Card Holder Info 0x%04x") " --------", aaid); + + uint8_t data[4096] = {0}; + int datalen = 0; + + for (int i = 0; i < madlen; i++) { + if (aaid == mad[i]) { + uint8_t vsector[16 * 4] = {0}; + if (mfReadSector(i + 1, keyB ? MF_KEY_B : MF_KEY_A, akey, vsector)) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(ERR, "error, read sector %d", i + 1); + return PM3_ESOFT; + } + + memcpy(&data[datalen], vsector, 16 * 3); + datalen += 16 * 3; + } + } + + if (!datalen) { + PrintAndLogEx(WARNING, "no Card Holder Info data"); + return PM3_SUCCESS; + } + + MADCardHolderInfoDecode(data, datalen, verbose); + } } return PM3_SUCCESS; diff --git a/client/src/mifare/mad.c b/client/src/mifare/mad.c index c4569b274..dad6d6ea6 100644 --- a/client/src/mifare/mad.c +++ b/client/src/mifare/mad.c @@ -232,15 +232,27 @@ int MADDecode(uint8_t *sector0, uint8_t *sector10, uint16_t *mad, size_t *madlen return PM3_SUCCESS; } -static const char *aid_admin[] = { - "free", - "defect", - "reserved", - "additional directory info", - "card holder info", - "not applicable" +static const char *holder_info_type[] = { + "Surname", + "Given name", + "Sex", + "Other" }; +int MADCardHolderInfoDecode(uint8_t *data, size_t dataLen, bool verbose) { + size_t idx = 0; + while (idx < dataLen) { + uint8_t len = data[idx] & 0x3f; + uint8_t type = data[idx] >> 6; + idx++; + if (len > 0) { + PrintAndLogEx(INFO, "%s: %.*s", holder_info_type[type], len, &data[idx]); + idx += len; + } else break; + } + return PM3_SUCCESS; +} + static int MADInfoByteDecode(uint8_t *sector, bool swapmad, int MADver, bool verbose) { uint8_t InfoByte; if (MADver == 1) { @@ -269,6 +281,15 @@ static int MADInfoByteDecode(uint8_t *sector, bool swapmad, int MADver, bool ver } } +static const char *aid_admin[] = { + "free", + "defect", + "reserved", + "additional directory info", + "card holder info", + "not applicable" +}; + int MAD1DecodeAndPrint(uint8_t *sector, bool swapmad, bool verbose, bool *haveMAD2) { open_mad_file(&mad_known_aids, verbose); diff --git a/client/src/mifare/mad.h b/client/src/mifare/mad.h index e5f23ea0f..bb1b3800c 100644 --- a/client/src/mifare/mad.h +++ b/client/src/mifare/mad.h @@ -17,6 +17,6 @@ int MADCheck(uint8_t *sector0, uint8_t *sector10, bool verbose, bool *haveMAD2); int MADDecode(uint8_t *sector0, uint8_t *sector10, uint16_t *mad, size_t *madlen, bool swapmad); int MAD1DecodeAndPrint(uint8_t *sector, bool swapmad, bool verbose, bool *haveMAD2); int MAD2DecodeAndPrint(uint8_t *sector, bool swapmad, bool verbose); - +int MADCardHolderInfoDecode(uint8_t *data, size_t dataLen, bool verbose); #endif // _MAD_H_