text , but the ultralight detect in 14a info is a bit confusing. This PR was intended to make it more clear. We still need to improve the text output

This commit is contained in:
iceman1001 2025-05-30 01:38:55 +02:00
commit 83837699e1
4 changed files with 146 additions and 36 deletions

View file

@ -1827,14 +1827,17 @@ static int detect_nxp_card_print(uint8_t sak, uint16_t atqa, uint64_t select_sta
const char *product_type_str = ""; const char *product_type_str = "";
const char *major_product_version_str = ""; const char *major_product_version_str = "";
const char *storage_size_str = ""; const char *storage_size_str = "";
if (version_hw_available) { if (version_hw_available) {
switch (version_hw->product_type & 0x0F) { switch (version_hw->product_type & 0x0F) {
case 0x1: case 0x1: {
product_type_str = "MIFARE DESFire"; product_type_str = "MIFARE DESFire";
// special cases, override product_type_str when needed // special cases, override product_type_str when needed
if (version_hw->product_type == 0x91) { if (version_hw->product_type == 0x91) {
product_type_str = "Apple Wallet DESFire Applet"; product_type_str = "Apple Wallet DESFire Applet";
} }
// general rule // general rule
switch (version_hw->major_product_version & 0x0F) { switch (version_hw->major_product_version & 0x0F) {
case 0x01: case 0x01:
@ -1847,6 +1850,7 @@ static int detect_nxp_card_print(uint8_t sak, uint16_t atqa, uint64_t select_sta
major_product_version_str = "EV3"; major_product_version_str = "EV3";
break; break;
} }
// special cases, override major_product_version_str when needed // special cases, override major_product_version_str when needed
switch (version_hw->major_product_version) { switch (version_hw->major_product_version) {
case 0x00: case 0x00:
@ -1860,7 +1864,8 @@ static int detect_nxp_card_print(uint8_t sak, uint16_t atqa, uint64_t select_sta
break; break;
} }
break; break;
case 0x2: }
case 0x2: {
product_type_str = "MIFARE Plus"; product_type_str = "MIFARE Plus";
switch (version_hw->major_product_version) { switch (version_hw->major_product_version) {
case 0x11: case 0x11:
@ -1870,15 +1875,23 @@ static int detect_nxp_card_print(uint8_t sak, uint16_t atqa, uint64_t select_sta
major_product_version_str = "EV2"; major_product_version_str = "EV2";
break; break;
default: default:
major_product_version_str = "Unknown"; major_product_version_str = "n/a";
} }
break; break;
case 0x3: }
case 0x3: {
product_type_str = "MIFARE Ultralight"; product_type_str = "MIFARE Ultralight";
switch (version_hw->major_product_version) { switch (version_hw->major_product_version) {
case 0x01: case 0x01: {
major_product_version_str = "EV1"; major_product_version_str = "EV1";
if (version_hw->storage_size == 0x0B) {
storage_size_str = "48b";
} else if (version_hw->storage_size == 0x0E) {
storage_size_str = "128b";
}
break; break;
}
case 0x02: case 0x02:
major_product_version_str = "Nano"; major_product_version_str = "Nano";
break; break;
@ -1886,10 +1899,11 @@ static int detect_nxp_card_print(uint8_t sak, uint16_t atqa, uint64_t select_sta
major_product_version_str = "AES"; major_product_version_str = "AES";
break; break;
default: default:
major_product_version_str = "Unknown"; major_product_version_str = "n/a";
} }
break; break;
case 0x4: }
case 0x4: {
product_type_str = "NTAG"; product_type_str = "NTAG";
switch (version_hw->major_product_version) { switch (version_hw->major_product_version) {
case 0x01: case 0x01:
@ -1909,37 +1923,66 @@ static int detect_nxp_card_print(uint8_t sak, uint16_t atqa, uint64_t select_sta
major_product_version_str = "4xx"; major_product_version_str = "4xx";
break; break;
default: default:
major_product_version_str = "Unknown"; major_product_version_str = "n/a";
} }
break; break;
case 0x7: }
case 0x7: {
product_type_str = "NTAG I2C"; product_type_str = "NTAG I2C";
break; break;
case 0x8: }
case 0x8: {
product_type_str = "MIFARE DESFire Light"; product_type_str = "MIFARE DESFire Light";
break; break;
case 0x9: }
case 0x9: {
product_type_str = "MIFARE Hospitality"; product_type_str = "MIFARE Hospitality";
switch (version_hw->major_product_version) { switch (version_hw->major_product_version) {
case 0x01: case 0x01:
major_product_version_str = "AES"; major_product_version_str = "AES";
break; break;
default: default:
major_product_version_str = "Unknown"; major_product_version_str = "n/a";
} }
break; break;
default: }
default: {
product_type_str = "Unknown NXP tag"; product_type_str = "Unknown NXP tag";
break;
} }
uint32_t size = 1 << (version_hw->storage_size >> 1); }
if (storage_size_str == NULL) {
static char size_str[16]; static char size_str[16];
if (size < 1024) { uint16_t usize = 1 << ((version_hw->storage_size >> 1) + 1);
snprintf(size_str, sizeof(size_str), "%s%uB", (version_hw->storage_size & 0x01) == 0 ? "" : "~", size); uint16_t lsize = 1 << (version_hw->storage_size >> 1);
// is LSB set?
if ((version_hw->storage_size & 0x01) == 1) {
// if set, its a range between upper size and lower size
if (lsize < 1024) {
snprintf(size_str, sizeof(size_str), "%u - %uB", usize, lsize);
} else { } else {
snprintf(size_str, sizeof(size_str), "%s%uK", (version_hw->storage_size & 0x01) == 0 ? "" : "~", size / 1024); snprintf(size_str, sizeof(size_str), "%u - %uK", (usize / 1024), (lsize / 1024));
} }
} else {
// if not set, it's lower size
if (lsize < 1024) {
snprintf(size_str, sizeof(size_str), "%uB", lsize);
} else {
snprintf(size_str, sizeof(size_str), "%uK", lsize / 1024);
}
}
storage_size_str = size_str; storage_size_str = size_str;
} }
}
char tag_info[128]; char tag_info[128];
if ((sak & 0x44) == 0x40) { if ((sak & 0x44) == 0x40) {
@ -1951,25 +1994,36 @@ static int detect_nxp_card_print(uint8_t sak, uint16_t atqa, uint64_t select_sta
} }
type |= MTISO18092; type |= MTISO18092;
} }
if ((sak & 0x02) == 0x00) { // SAK b2=0 if ((sak & 0x02) == 0x00) { // SAK b2=0
if ((sak & 0x08) == 0x08) { // SAK b2=0 b4=1 if ((sak & 0x08) == 0x08) { // SAK b2=0 b4=1
if ((sak & 0x10) == 0x10) { // SAK b2=0 b4=1 b5=1 if ((sak & 0x10) == 0x10) { // SAK b2=0 b4=1 b5=1
if ((sak & 0x01) == 0x01) { // SAK b2=0 b4=1 b5=1 b1=1, SAK=0x19 if ((sak & 0x01) == 0x01) { // SAK b2=0 b4=1 b5=1 b1=1, SAK=0x19
printTag("MIFARE Classic 2K"); printTag("MIFARE Classic 2K");
type |= MTCLASSIC; type |= MTCLASSIC;
} else { // SAK b2=0 b4=1 b5=1 b1=0 } else { // SAK b2=0 b4=1 b5=1 b1=0
if ((sak & 0x20) == 0x20) { // SAK b2=0 b4=1 b5=1 b1=0 b6=1, SAK=0x38 if ((sak & 0x20) == 0x20) { // SAK b2=0 b4=1 b5=1 b1=0 b6=1, SAK=0x38
printTag("SmartMX with MIFARE Classic 4K"); printTag("SmartMX with MIFARE Classic 4K");
type |= MTCLASSIC; type |= MTCLASSIC;
} else { // SAK b2=0 b4=1 b5=1 b1=0 b6=0 } else { // SAK b2=0 b4=1 b5=1 b1=0 b6=0
if (select_status == 4) { // SAK b2=0 b4=1 b5=1 b1=0 b6=0 ATS if (select_status == 4) { // SAK b2=0 b4=1 b5=1 b1=0 b6=0 ATS
if (version_hw_available) { // SAK b2=0 b4=1 b5=1 b1=0 b6=0 ATS GetVersion if (version_hw_available) { // SAK b2=0 b4=1 b5=1 b1=0 b6=0 ATS GetVersion
snprintf(tag_info, sizeof(tag_info), "%s %s %s in SL1", product_type_str, major_product_version_str, storage_size_str); snprintf(tag_info, sizeof(tag_info), "%s %s %s in SL1", product_type_str, major_product_version_str, storage_size_str);
printTag(tag_info); printTag(tag_info);
type |= MTPLUS; type |= MTPLUS;
} else { // SAK b2=0 b4=1 b5=1 b1=0 b6=0 ATS No_GetVersion } else { // SAK b2=0 b4=1 b5=1 b1=0 b6=0 ATS No_GetVersion
if (ats_hist_len > 0) { if (ats_hist_len > 0) {
if ((ats_hist_len == 9) && (memcmp(ats_hist, "\xC1\x05\x2F\x2F", 4) == 0)) { if ((ats_hist_len == 9) && (memcmp(ats_hist, "\xC1\x05\x2F\x2F", 4) == 0)) {
if (memcmp(ats_hist + 4, "\x00\x35\xC7", 3) == 0) { if (memcmp(ats_hist + 4, "\x00\x35\xC7", 3) == 0) {
printTag("MIFARE Plus S 4K in SL1"); printTag("MIFARE Plus S 4K in SL1");
} else if (memcmp(ats_hist + 4, "\x01\xBC\xD6", 3) == 0) { } else if (memcmp(ats_hist + 4, "\x01\xBC\xD6", 3) == 0) {
@ -1988,7 +2042,9 @@ static int detect_nxp_card_print(uint8_t sak, uint16_t atqa, uint64_t select_sta
} }
} }
} }
} else { // SAK b2=0 b4=1 b5=1 b1=0 b6=0 no_ATS, SAK=0x18 } else { // SAK b2=0 b4=1 b5=1 b1=0 b6=0 no_ATS, SAK=0x18
if ((atqa & 0x0040) == 0x0040) { if ((atqa & 0x0040) == 0x0040) {
printTag("MIFARE Classic 4K CL2"); printTag("MIFARE Classic 4K CL2");
} else { } else {
@ -2000,28 +2056,38 @@ static int detect_nxp_card_print(uint8_t sak, uint16_t atqa, uint64_t select_sta
} }
} else { // SAK b2=0 b4=1 b5=0 } else { // SAK b2=0 b4=1 b5=0
if ((sak & 0x01) == 0x01) { // SAK b2=0 b4=1 b5=0 b1=1, SAK=0x09 if ((sak & 0x01) == 0x01) { // SAK b2=0 b4=1 b5=0 b1=1, SAK=0x09
if ((atqa & 0x0040) == 0x0040) { if ((atqa & 0x0040) == 0x0040) {
printTag("MIFARE Mini 0.3K CL2"); printTag("MIFARE Mini 0.3K CL2");
} else { } else {
printTag("MIFARE Mini 0.3K"); printTag("MIFARE Mini 0.3K");
} }
type |= MTMINI; type |= MTMINI;
} else { // SAK b2=0 b4=1 b5=0 b1=0 } else { // SAK b2=0 b4=1 b5=0 b1=0
if ((sak & 0x20) == 0x20) { // SAK b2=0 b4=1 b5=0 b1=0 b6=1, SAK=0x28 if ((sak & 0x20) == 0x20) { // SAK b2=0 b4=1 b5=0 b1=0 b6=1, SAK=0x28
printTag("SmartMX with MIFARE Classic 1K"); printTag("SmartMX with MIFARE Classic 1K");
printTag("FM1208-10 with MIFARE Classic 1K"); printTag("FM1208-10 with MIFARE Classic 1K");
printTag("FM1216-137 with MIFARE Classic 1K"); printTag("FM1216-137 with MIFARE Classic 1K");
type |= MTCLASSIC; type |= MTCLASSIC;
} else { // SAK b2=0 b4=1 b5=0 b1=0 b6=0 } else { // SAK b2=0 b4=1 b5=0 b1=0 b6=0
if (select_status == 4) { // SAK b2=0 b4=1 b5=0 b1=0 b6=0 ATS if (select_status == 4) { // SAK b2=0 b4=1 b5=0 b1=0 b6=0 ATS
if (version_hw_available) { // SAK b2=0 b4=1 b5=0 b1=0 b6=0 ATS GetVersion if (version_hw_available) { // SAK b2=0 b4=1 b5=0 b1=0 b6=0 ATS GetVersion
snprintf(tag_info, sizeof(tag_info), "%s %s %s in SL1", product_type_str, major_product_version_str, storage_size_str); snprintf(tag_info, sizeof(tag_info), "%s %s %s in SL1", product_type_str, major_product_version_str, storage_size_str);
printTag(tag_info); printTag(tag_info);
type |= MTPLUS; type |= MTPLUS;
} else { // SAK b2=0 b4=1 b5=0 b1=0 b6=0 ATS No_GetVersion } else { // SAK b2=0 b4=1 b5=0 b1=0 b6=0 ATS No_GetVersion
if (ats_hist_len > 0) { if (ats_hist_len > 0) {
if ((ats_hist_len == 9) && (memcmp(ats_hist, "\xC1\x05\x2F\x2F", 4) == 0)) { if ((ats_hist_len == 9) && (memcmp(ats_hist, "\xC1\x05\x2F\x2F", 4) == 0)) {
if (memcmp(ats_hist + 4, "\x00\x35\xC7", 3) == 0) { if (memcmp(ats_hist + 4, "\x00\x35\xC7", 3) == 0) {
printTag("MIFARE Plus S 2K in SL1"); printTag("MIFARE Plus S 2K in SL1");
} else if (memcmp(ats_hist + 4, "\x01\xBC\xD6", 3) == 0) { } else if (memcmp(ats_hist + 4, "\x01\xBC\xD6", 3) == 0) {
@ -2030,7 +2096,9 @@ static int detect_nxp_card_print(uint8_t sak, uint16_t atqa, uint64_t select_sta
printTag("Unrecognized MIFARE Plus??"); printTag("Unrecognized MIFARE Plus??");
} }
type |= MTPLUS; type |= MTPLUS;
} else if ((ats_hist_len == 9) && (memcmp(ats_hist, "\xC1\x05\x21\x30", 4) == 0)) { } else if ((ats_hist_len == 9) && (memcmp(ats_hist, "\xC1\x05\x21\x30", 4) == 0)) {
if (memcmp(ats_hist + 4, "\x00\xF6\xD1", 3) == 0) { if (memcmp(ats_hist + 4, "\x00\xF6\xD1", 3) == 0) {
printTag("MIFARE Plus SE 1K 17pF"); printTag("MIFARE Plus SE 1K 17pF");
} else if (memcmp(ats_hist + 4, "\x10\xF6\xD1", 3) == 0) { } else if (memcmp(ats_hist + 4, "\x10\xF6\xD1", 3) == 0) {
@ -2039,7 +2107,9 @@ static int detect_nxp_card_print(uint8_t sak, uint16_t atqa, uint64_t select_sta
printTag("Unrecognized MIFARE Plus SE??"); printTag("Unrecognized MIFARE Plus SE??");
} }
type |= MTPLUS; type |= MTPLUS;
} else { } else {
if ((atqa & 0x0040) == 0x0040) { if ((atqa & 0x0040) == 0x0040) {
printTag("MIFARE Classic 1K CL2 with ATS!"); printTag("MIFARE Classic 1K CL2 with ATS!");
} else { } else {
@ -2060,8 +2130,11 @@ static int detect_nxp_card_print(uint8_t sak, uint16_t atqa, uint64_t select_sta
} }
} }
} }
} else { // SAK b2=0 b4=0 } else { // SAK b2=0 b4=0
if ((sak & 0x10) == 0x10) { // SAK b2=0 b4=0 b5=1 if ((sak & 0x10) == 0x10) { // SAK b2=0 b4=0 b5=1
if ((sak & 0x01) == 0x01) { // SAK b2=0 b4=0 b5=1 b1=1, SAK=0x11 if ((sak & 0x01) == 0x01) { // SAK b2=0 b4=0 b5=1 b1=1, SAK=0x11
printTag("MIFARE Plus 4K in SL2"); printTag("MIFARE Plus 4K in SL2");
type |= MTPLUS; type |= MTPLUS;
@ -2069,33 +2142,48 @@ static int detect_nxp_card_print(uint8_t sak, uint16_t atqa, uint64_t select_sta
printTag("MIFARE Plus 2K in SL2"); printTag("MIFARE Plus 2K in SL2");
type |= MTPLUS; type |= MTPLUS;
} }
} else { // SAK b2=0 b4=0 b5=0 } else { // SAK b2=0 b4=0 b5=0
if ((sak & 0x01) == 0x01) { // SAK b2=0 b4=0 b5=0 b1=1 if ((sak & 0x01) == 0x01) { // SAK b2=0 b4=0 b5=0 b1=1
printTag("TNP3xxx (TagNPlay, Activision Game Appliance)"); printTag("TNP3xxx (TagNPlay, Activision Game Appliance)");
type |= MTCLASSIC; type |= MTCLASSIC;
} else { // SAK b2=0 b4=0 b5=0 b1=0 } else { // SAK b2=0 b4=0 b5=0 b1=0
if ((sak & 0x20) == 0x20) { // SAK b2=0 b4=0 b5=0 b1=0 b6=1, SAK=0x20 if ((sak & 0x20) == 0x20) { // SAK b2=0 b4=0 b5=0 b1=0 b6=1, SAK=0x20
if (select_status == 1) { // SAK b2=0 b4=0 b5=0 b1=0 b6=1 ATS if (select_status == 1) { // SAK b2=0 b4=0 b5=0 b1=0 b6=1 ATS
if (version_hw_available) { // SAK b2=0 b4=0 b5=0 b1=0 b6=1 ATS GetVersion if (version_hw_available) { // SAK b2=0 b4=0 b5=0 b1=0 b6=1 ATS GetVersion
if ((version_hw->product_type & 0x7F) == 0x02) { if ((version_hw->product_type & 0x7F) == 0x02) {
snprintf(tag_info, sizeof(tag_info), "%s %s %s in SL0/SL3", product_type_str, major_product_version_str, storage_size_str); snprintf(tag_info, sizeof(tag_info), "%s %s %s in SL0/SL3", product_type_str, major_product_version_str, storage_size_str);
type |= MTPLUS; type |= MTPLUS;
} else if (((version_hw->product_type & 0x7F) == 0x01) || } else if (((version_hw->product_type & 0x7F) == 0x01) ||
(version_hw->product_type == 0x08) || (version_hw->product_type == 0x08) ||
(version_hw->product_type == 0x91)) { (version_hw->product_type == 0x91)) {
snprintf(tag_info, sizeof(tag_info), "%s %s %s", product_type_str, major_product_version_str, storage_size_str); snprintf(tag_info, sizeof(tag_info), "%s %s %s", product_type_str, major_product_version_str, storage_size_str);
type |= MTDESFIRE; type |= MTDESFIRE;
} else if (version_hw->product_type == 0x04) { } else if (version_hw->product_type == 0x04) {
snprintf(tag_info, sizeof(tag_info), "%s %s %s", product_type_str, major_product_version_str, storage_size_str); snprintf(tag_info, sizeof(tag_info), "%s %s %s", product_type_str, major_product_version_str, storage_size_str);
type |= (MTDESFIRE | MT424); type |= (MTDESFIRE | MT424);
} else { } else {
snprintf(tag_info, sizeof(tag_info), "%s %s %s", product_type_str, major_product_version_str, storage_size_str); snprintf(tag_info, sizeof(tag_info), "%s %s %s", product_type_str, major_product_version_str, storage_size_str);
} }
printTag(tag_info); printTag(tag_info);
} else { // SAK b2=0 b4=0 b5=0 b1=0 b6=1 ATS No GetVersion } else { // SAK b2=0 b4=0 b5=0 b1=0 b6=1 ATS No GetVersion
if (ats_hist_len > 0) { if (ats_hist_len > 0) {
if ((ats_hist_len == 9) && (memcmp(ats_hist, "\xC1\x05\x2F\x2F", 4) == 0)) { if ((ats_hist_len == 9) && (memcmp(ats_hist, "\xC1\x05\x2F\x2F", 4) == 0)) {
if (memcmp(ats_hist + 4, "\x00\x35\xC7", 3) == 0) { if (memcmp(ats_hist + 4, "\x00\x35\xC7", 3) == 0) {
if ((atqa & 0xFF0F) == 0x0004) { if ((atqa & 0xFF0F) == 0x0004) {
printTag("MIFARE Plus S 2K in SL0/SL3"); printTag("MIFARE Plus S 2K in SL0/SL3");
} else if ((atqa & 0xFF0F) == 0x0002) { } else if ((atqa & 0xFF0F) == 0x0002) {
@ -2103,21 +2191,28 @@ static int detect_nxp_card_print(uint8_t sak, uint16_t atqa, uint64_t select_sta
} else { } else {
printTag("Unrecognized MIFARE Plus??"); printTag("Unrecognized MIFARE Plus??");
} }
} else if (memcmp(ats_hist + 4, "\x01\xBC\xD6", 3) == 0) { } else if (memcmp(ats_hist + 4, "\x01\xBC\xD6", 3) == 0) {
printTag("MIFARE Plus X 2K/4K in SL0/SL3"); printTag("MIFARE Plus X 2K/4K in SL0/SL3");
} else if (memcmp(ats_hist + 4, "\x00\xF6\xD1", 3) == 0) { } else if (memcmp(ats_hist + 4, "\x00\xF6\xD1", 3) == 0) {
printTag("MIFARE Plus SE 1K 17pF"); printTag("MIFARE Plus SE 1K 17pF");
} else if (memcmp(ats_hist + 4, "\x10\xF6\xD1", 3) == 0) { } else if (memcmp(ats_hist + 4, "\x10\xF6\xD1", 3) == 0) {
printTag("MIFARE Plus SE 1K 70pF"); printTag("MIFARE Plus SE 1K 70pF");
} else { } else {
printTag("Unrecognized MIFARE Plus??"); printTag("Unknown MIFARE Plus");
} }
type |= MTPLUS; type |= MTPLUS;
} else { } else {
if ((atqa == 0x0001) || (atqa == 0x0004)) { if ((atqa == 0x0001) || (atqa == 0x0004)) {
printTag("HID SEOS (smartmx / javacard)"); printTag("HID SEOS (smartmx / javacard)");
type |= HID_SEOS; type |= HID_SEOS;
} }
if (atqa == 0x0004) { if (atqa == 0x0004) {
printTag("EMV"); printTag("EMV");
type |= MTEMV; type |= MTEMV;
@ -2128,11 +2223,15 @@ static int detect_nxp_card_print(uint8_t sak, uint16_t atqa, uint64_t select_sta
} else { } else {
printTag("Unknown tag claims to support RATS in SAK but does not..."); printTag("Unknown tag claims to support RATS in SAK but does not...");
} }
} else { // SAK b2=0 b4=0 b5=0 b1=0 b6=0, SAK=0x00 } else { // SAK b2=0 b4=0 b5=0 b1=0 b6=0, SAK=0x00
if (version_hw_available) { // SAK b2=0 b4=0 b5=0 b1=0 b6=0 GetVersion if (version_hw_available) { // SAK b2=0 b4=0 b5=0 b1=0 b6=0 GetVersion
snprintf(tag_info, sizeof(tag_info), "%s %s %s", product_type_str, major_product_version_str, storage_size_str); snprintf(tag_info, sizeof(tag_info), "%s %s %s", product_type_str, major_product_version_str, storage_size_str);
printTag(tag_info); printTag(tag_info);
} else { // SAK b2=0 b4=0 b5=0 b1=0 b6=0 No_GetVersion } else { // SAK b2=0 b4=0 b5=0 b1=0 b6=0 No_GetVersion
int status = mfuc_test_authentication_support(); int status = mfuc_test_authentication_support();
if (status == PM3_SUCCESS) { if (status == PM3_SUCCESS) {
// TODO: read page 2/3, then ?? // TODO: read page 2/3, then ??
@ -2141,6 +2240,7 @@ static int detect_nxp_card_print(uint8_t sak, uint16_t atqa, uint64_t select_sta
} else { } else {
printTag("MIFARE Ultralight"); printTag("MIFARE Ultralight");
} }
} }
type |= MTULTRALIGHT; type |= MTULTRALIGHT;
} }
@ -2148,20 +2248,25 @@ static int detect_nxp_card_print(uint8_t sak, uint16_t atqa, uint64_t select_sta
} }
} }
} else { // SAK b2=1 } else { // SAK b2=1
if (sak == 0x0A) { if (sak == 0x0A) {
if (atqa == 0x0003) { if (atqa == 0x0003) {
// Uses Shanghai algo // Uses Shanghai algo
printTag("FM11RF005SH (FUDAN Shanghai Metro)"); printTag("FM11RF005SH (FUDAN Shanghai Metro)");
type |= MTFUDAN; type |= MTFUDAN;
} else if (atqa == 0x0005) { } else if (atqa == 0x0005) {
printTag("FM11RF005M (FUDAN ISO14443A w Crypto-1 algo)"); printTag("FM11RF005M (FUDAN ISO14443A w Crypto-1 algo)");
type |= MTFUDAN; type |= MTFUDAN;
} }
} else if (sak == 0x53) { } else if (sak == 0x53) {
printTag("FM11RF08SH (FUDAN)"); printTag("FM11RF08SH (FUDAN)");
type |= MTFUDAN; type |= MTFUDAN;
} }
} }
if (type == MTNONE) { if (type == MTNONE) {
PrintAndLogEx(WARNING, " failed to fingerprint"); PrintAndLogEx(WARNING, " failed to fingerprint");
} }
@ -2803,10 +2908,11 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
} }
DropField(); DropField();
if (verbose == false && found) if (verbose == false && found) {
PrintAndLogEx(INFO, "----------------------------------------------------"); PrintAndLogEx(INFO, "----------------------------------------------------");
} }
} }
}
} else { } else {
@ -2814,7 +2920,9 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
PrintAndLogEx(INFO, "proprietary iso18092 card found"); PrintAndLogEx(INFO, "proprietary iso18092 card found");
} else { } else {
PrintAndLogEx(INFO, "proprietary non iso14443-4 card found, RATS not supported"); PrintAndLogEx(INFO, "");
PrintAndLogEx(INFO, "Proprietary non iso14443-4 card found");
PrintAndLogEx(INFO, "RATS not supported");
if ((card.sak & 0x20) == 0x20) { if ((card.sak & 0x20) == 0x20) {
PrintAndLogEx(INFO, "--> SAK incorrectly claims that card supports RATS <--"); PrintAndLogEx(INFO, "--> SAK incorrectly claims that card supports RATS <--");
} }
@ -2829,7 +2937,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
return PM3_EFAILED; return PM3_EFAILED;
} }
PrintAndLogEx(INFO, ""); // PrintAndLogEx(INFO, "");
uint16_t isMagic = 0; uint16_t isMagic = 0;

View file

@ -10167,7 +10167,8 @@ static int CmdHF14AMfInfo(const char *Cmd) {
&& card.sak == 0x08 && memcmp(blockdata + 5, "\x88\x04\x00\x45", 4) == 0) { && card.sak == 0x08 && memcmp(blockdata + 5, "\x88\x04\x00\x45", 4) == 0) {
PrintAndLogEx(SUCCESS, "NXP MF1ICS5004"); PrintAndLogEx(SUCCESS, "NXP MF1ICS5004");
} else if (fKeyType == MF_KEY_BD) { } else if (fKeyType == MF_KEY_BD) {
PrintAndLogEx(SUCCESS, _RED_("Unknown card with backdoor, please report details!")); PrintAndLogEx(SUCCESS, _RED_("Unknown card with backdoor"));
PrintAndLogEx(INFO, "Please report details!");
} else } else
// other cards // other cards
if (card.sak == 0x08 && memcmp(blockdata + 5, "\x88\x04\x00\x46", 4) == 0) { if (card.sak == 0x08 && memcmp(blockdata + 5, "\x88\x04\x00\x46", 4) == 0) {
@ -10181,7 +10182,7 @@ static int CmdHF14AMfInfo(const char *Cmd) {
} else if (card.sak == 0x08 && memcmp(blockdata + 5, "\x88\x04\x00\xc0", 4) == 0) { } else if (card.sak == 0x08 && memcmp(blockdata + 5, "\x88\x04\x00\xc0", 4) == 0) {
PrintAndLogEx(SUCCESS, "NXP MF1ICS5035"); PrintAndLogEx(SUCCESS, "NXP MF1ICS5035");
} else { } else {
PrintAndLogEx(SUCCESS, "unknown"); PrintAndLogEx(SUCCESS, "n/a");
} }
if (keycnt > 1 && e_sector != NULL && e_sector[1].foundKey[MF_KEY_A] && (e_sector[1].Key[MF_KEY_A] == 0x2A2C13CC242A)) { if (keycnt > 1 && e_sector != NULL && e_sector[1].foundKey[MF_KEY_A] && (e_sector[1].Key[MF_KEY_A] == 0x2A2C13CC242A)) {

View file

@ -299,7 +299,7 @@ static const char *getUlev1CardSizeStr(uint8_t fsize) {
// is LSB set? // is LSB set?
if (fsize & 1) if (fsize & 1)
snprintf(buf, sizeof(buf), "%02X, (%u <-> %u bytes)", fsize, usize, lsize); snprintf(buf, sizeof(buf), "%02X, (%u - %u bytes)", fsize, usize, lsize);
else else
snprintf(buf, sizeof(buf), "%02X, (%u bytes)", fsize, lsize); snprintf(buf, sizeof(buf), "%02X, (%u bytes)", fsize, lsize);
return buf; return buf;
@ -3925,17 +3925,17 @@ static int CmdHF14AMfUAESAuth(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfu aesauth", CLIParserInit(&ctx, "hf mfu aesauth",
"Tests AES key on Mifare Ultralight AES tags.\n" "Tests AES key on Mifare Ultralight AES tags.\n"
"If key is not specified, null key will be tried.\n" "If no key is specified, null key will be tried.\n"
"Key index 0: DataProtKey (default)\n" "Key index 0: DataProtKey (default)\n"
"Key index 1: UIDRetrKey\n" "Key index 1: UIDRetrKey\n"
"Key index 2: OriginalityKey\n", "Key index 2: OriginalityKey\n",
"hf mfu aesauth\n" "hf mfu aesauth\n"
"hf mfu aesauth --key <32 hex chars> --index <0..2>" "hf mfu aesauth --key <16 hex bytes> --index <0..2>"
); );
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_str0(NULL, "key", "<hex>", "Authentication key (16 bytes in hex)"), arg_str0(NULL, "key", "<hex>", "AES key (16 hex bytes)"),
arg_int0("i", "index", "<0..2>", "Key index, default: 0"), arg_int0("i", "index", "<0..2>", "Key index, default: 0"),
arg_lit0("k", NULL, "Keep field on (only if a key is provided)"), arg_lit0("k", NULL, "Keep field on (only if a key is provided)"),
arg_param_end arg_param_end

View file

@ -3742,9 +3742,10 @@
"-i <dec> tearoff delay increment (in us) - default 10", "-i <dec> tearoff delay increment (in us) - default 10",
"-e <dec> tearoff delay end (in us) must be a higher value than the start delay", "-e <dec> tearoff delay end (in us) must be a higher value than the start delay",
"--loop <dec> number of times to loop per tearoff time", "--loop <dec> number of times to loop per tearoff time",
"--sleep <ms> Sleep between each tear" "--sleep <ms> Sleep between each tear",
"--arm Runs the commands on device side and tries to stabilize tears"
], ],
"usage": "hf iclass tear [-hv] [-k <hex>] [--ki <dec>] --blk <dec> -d <hex> [-m <hex>] [--credit] [--elite] [--raw] [--nr] [--shallow] -s <dec> [-i <dec>] [-e <dec>] [--loop <dec>] [--sleep <ms>]" "usage": "hf iclass tear [-hv] [-k <hex>] [--ki <dec>] --blk <dec> -d <hex> [-m <hex>] [--credit] [--elite] [--raw] [--nr] [--shallow] -s <dec> [-i <dec>] [-e <dec>] [--loop <dec>] [--sleep <ms>] [--arm]"
}, },
"hf iclass unhash": { "hf iclass unhash": {
"command": "hf iclass unhash", "command": "hf iclass unhash",
@ -7078,15 +7079,15 @@
}, },
"hf mfu aesauth": { "hf mfu aesauth": {
"command": "hf mfu aesauth", "command": "hf mfu aesauth",
"description": "Tests AES key on Mifare Ultralight AES tags. If key is not specified, null key will be tried. Key index 0: DataProtKey (default) Key index 1: UIDRetrKey Key index 2: OriginalityKey", "description": "Tests AES key on Mifare Ultralight AES tags. If no key is specified, null key will be tried. Key index 0: DataProtKey (default) Key index 1: UIDRetrKey Key index 2: OriginalityKey",
"notes": [ "notes": [
"hf mfu aesauth", "hf mfu aesauth",
"hf mfu aesauth --key <32 hex chars> --index <0..2>" "hf mfu aesauth --key <16 hex bytes> --index <0..2>"
], ],
"offline": false, "offline": false,
"options": [ "options": [
"-h, --help This help", "-h, --help This help",
"--key <hex> Authentication key (16 bytes in hex)", "--key <hex> AES key (16 hex bytes)",
"-i, --index <0..2> Key index, default: 0", "-i, --index <0..2> Key index, default: 0",
"-k Keep field on (only if a key is provided)" "-k Keep field on (only if a key is provided)"
], ],
@ -13371,6 +13372,6 @@
"metadata": { "metadata": {
"commands_extracted": 768, "commands_extracted": 768,
"extracted_by": "PM3Help2JSON v1.00", "extracted_by": "PM3Help2JSON v1.00",
"extracted_on": "2025-05-28T18:50:22" "extracted_on": "2025-05-29T23:30:20"
} }
} }