layout, text, colors - mfu info, 15 info

This commit is contained in:
iceman1001 2020-04-04 12:17:55 +02:00
commit 34adf411c3
7 changed files with 252 additions and 214 deletions

View file

@ -93,8 +93,6 @@
#define CheckCrc15(data, len) check_crc(CRC_15693, (data), (len)) #define CheckCrc15(data, len) check_crc(CRC_15693, (data), (len))
#define AddCrc15(data, len) compute_crc(CRC_15693, (data), (len), (data)+(len), (data)+(len)+1) #define AddCrc15(data, len) compute_crc(CRC_15693, (data), (len), (data)+(len), (data)+(len)+1)
#define sprintUID(target,uid) Iso15693sprintUID((target), (uid))
static void BuildIdentifyRequest(uint8_t *cmdout); static void BuildIdentifyRequest(uint8_t *cmdout);
//static void BuildReadBlockRequest(uint8_t *cmdout, uint8_t *uid, uint8_t blockNumber ); //static void BuildReadBlockRequest(uint8_t *cmdout, uint8_t *uid, uint8_t blockNumber );
static void BuildInventoryResponse(uint8_t *cmdout, uint8_t *uid); static void BuildInventoryResponse(uint8_t *cmdout, uint8_t *uid);
@ -946,7 +944,7 @@ void BruteforceIso15693Afi(uint32_t speed) {
WDT_HIT(); WDT_HIT();
if (recvlen >= 12) { if (recvlen >= 12) {
Dbprintf("NoAFI UID = %s", sprintUID(NULL, buf + 2)); Dbprintf("NoAFI UID = %s", iso15693_sprintUID(NULL, buf + 2));
} }
// now with AFI // now with AFI
@ -964,7 +962,7 @@ void BruteforceIso15693Afi(uint32_t speed) {
recvlen = SendDataTag(data, datalen, false, speed, buf); recvlen = SendDataTag(data, datalen, false, speed, buf);
WDT_HIT(); WDT_HIT();
if (recvlen >= 12) { if (recvlen >= 12) {
Dbprintf("AFI = %i UID = %s", i, sprintUID(NULL, buf + 2)); Dbprintf("AFI = %i UID = %s", i, iso15693_sprintUID(NULL, buf + 2));
} }
aborted = BUTTON_PRESS(); aborted = BUTTON_PRESS();

View file

@ -50,10 +50,6 @@
#define AddCrc15(data, len) compute_crc(CRC_15693, (data), (len), (data)+(len), (data)+(len)+1) #define AddCrc15(data, len) compute_crc(CRC_15693, (data), (len), (data)+(len), (data)+(len)+1)
#endif #endif
#ifndef sprintUID
# define sprintUID(target, uid) Iso15693sprintUID((target), (uid))
#endif
typedef struct { typedef struct {
uint8_t lock; uint8_t lock;
uint8_t block[4]; uint8_t block[4];
@ -212,8 +208,22 @@ const productName uidmapping[] = {
{ 0, 0, "no tag-info available" } // must be the last entry { 0, 0, "no tag-info available" } // must be the last entry
}; };
#define PUBLIC_ECDA_KEYLEN 33 static int CmdHF15Help(const char *Cmd);
uint8_t nxp_15693_public_keys[][PUBLIC_ECDA_KEYLEN] = {
static int nxp_15693_print_signature(uint8_t *uid, uint8_t *signature) {
#define PUBLIC_ECDA_KEYLEN 33
const ecdsa_publickey_t nxp_15693_public_keys[] = {
{"NXP Mifare Classic MFC1C14_x", "044F6D3F294DEA5737F0F46FFEE88A356EED95695DD7E0C27A591E6F6F65962BAF"},
{"Manufacturer Mifare Classic MFC1C14_x", "046F70AC557F5461CE5052C8E4A7838C11C7A236797E8A0730A101837C004039C2"},
{"NXP ICODE DNA, ICODE SLIX2", "048878A2A2D3EEC336B4F261A082BD71F9BE11C4E2E896648B32EFA59CEA6E59F0"},
{"NXP Public key", "04A748B6A632FBEE2C0897702B33BEA1C074998E17B84ACA04FF267E5D2C91F6DC"},
{"NXP Ultralight Ev1", "0490933BDCD6E99B4E255E3DA55389A827564E11718E017292FAF23226A96614B8"},
{"NXP NTAG21x (2013)", "04494E1A386D3D3CFE3DC10E5DE68A499B1C202DB5B132393E89ED19FE5BE8BC61"},
{"MICRON Public key", "04f971eda742a4a80d32dcf6a814a707cc3dc396d35902f72929fdcd698b3468f2"},
};
/*
uint8_t nxp_15693_public_keys[][PUBLIC_ECDA_KEYLEN] = {
// ICODE SLIX2 / DNA // ICODE SLIX2 / DNA
{ {
0x04, 0x88, 0x78, 0xA2, 0xA2, 0xD3, 0xEE, 0xC3, 0x04, 0x88, 0x78, 0xA2, 0xA2, 0xD3, 0xEE, 0xC3,
@ -249,17 +259,19 @@ uint8_t nxp_15693_public_keys[][PUBLIC_ECDA_KEYLEN] = {
0xcc, 0x3d, 0xc3, 0x96, 0xd3, 0x59, 0x02, 0xf7, 0xcc, 0x3d, 0xc3, 0x96, 0xd3, 0x59, 0x02, 0xf7,
0x29, 0x29, 0xfd, 0xcd, 0x69, 0x8b, 0x34, 0x68, 0xf2 0x29, 0x29, 0xfd, 0xcd, 0x69, 0x8b, 0x34, 0x68, 0xf2
} }
}; };
*/
static int CmdHF15Help(const char *Cmd);
static int nxp_15693_print_signature(uint8_t *uid, uint8_t *signature) {
uint8_t i; uint8_t i;
int res; int res;
bool is_valid = false; bool is_valid = false;
for (i = 0; i< ARRAYLEN(nxp_15693_public_keys); i++) { for (i = 0; i< ARRAYLEN(nxp_15693_public_keys); i++) {
res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP128R1, nxp_15693_public_keys[i], uid, 8, signature, 32, false);
int dl = 0;
uint8_t key[PUBLIC_ECDA_KEYLEN];
param_gethex_to_eol(nxp_15693_public_keys[i].value, 0, key, PUBLIC_ECDA_KEYLEN, &dl);
res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP128R1, key, uid, 8, signature, 32, false);
is_valid = (res == 0); is_valid = (res == 0);
if (is_valid) if (is_valid)
break; break;
@ -271,12 +283,12 @@ static int nxp_15693_print_signature(uint8_t *uid, uint8_t *signature) {
return PM3_ESOFT; return PM3_ESOFT;
} }
PrintAndLogEx(INFO, "\n--- Tag Signature"); PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature"));
PrintAndLogEx(INFO, " IC signature public key name : %s", (i == 0)? "NXP ICODE SLIX2 / DNA" : "unknown, post on forum"); PrintAndLogEx(INFO, " IC signature public key name: %s", nxp_15693_public_keys[i].desc);
PrintAndLogEx(INFO, " IC signature public key value : %s", sprint_hex(nxp_15693_public_keys[i], 33)); PrintAndLogEx(INFO, "IC signature public key value: %s", nxp_15693_public_keys[i].value);
PrintAndLogEx(INFO, " Elliptic curve parameters : NID_secp128r1"); PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp128r1");
PrintAndLogEx(INFO, " TAG IC Signature : %s", sprint_hex(signature, 32)); PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex(signature, 32));
PrintAndLogEx(INFO, " Signature verification " _GREEN_("successful")); PrintAndLogEx(SUCCESS, " Signature verified: " _GREEN_("successful"));
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -577,7 +589,7 @@ static bool prepareHF15Cmd(char **cmd, uint16_t *reqlen, uint8_t *arg1, uint8_t
return false; return false;
} }
memcpy(&req[tmpreqlen], uid, sizeof(uid)); memcpy(&req[tmpreqlen], uid, sizeof(uid));
PrintAndLogEx(SUCCESS, "Detected UID %s", sprintUID(NULL, uid)); PrintAndLogEx(SUCCESS, "Detected UID " _GREEN_("%s"), iso15693_sprintUID(NULL,uid));
tmpreqlen += sizeof(uid); tmpreqlen += sizeof(uid);
break; break;
default: default:
@ -590,7 +602,7 @@ static bool prepareHF15Cmd(char **cmd, uint16_t *reqlen, uint8_t *arg1, uint8_t
uid[7 - i] = temp & 0xff; uid[7 - i] = temp & 0xff;
} }
PrintAndLogEx(SUCCESS, "Using UID %s", sprintUID(NULL, uid)); PrintAndLogEx(SUCCESS, "Using UID " _GREEN_("%s"), iso15693_sprintUID(NULL,uid));
memcpy(&req[tmpreqlen], uid, sizeof(uid)); memcpy(&req[tmpreqlen], uid, sizeof(uid));
tmpreqlen += sizeof(uid); tmpreqlen += sizeof(uid);
break; break;
@ -870,8 +882,8 @@ static int NxpSysInfo(uint8_t *uid) {
*/ */
static int CmdHF15Info(const char *Cmd) { static int CmdHF15Info(const char *Cmd) {
char cmdp = param_getchar(Cmd, 0); char cmdp = tolower(param_getchar(Cmd, 0));
if (strlen(Cmd) < 1 || cmdp == 'h' || cmdp == 'H') return usage_15_info(); if (strlen(Cmd) < 1 || cmdp == 'h') return usage_15_info();
PacketResponseNG resp; PacketResponseNG resp;
uint8_t *recv; uint8_t *recv;
@ -890,11 +902,8 @@ static int CmdHF15Info(const char *Cmd) {
AddCrc15(req, reqlen); AddCrc15(req, reqlen);
reqlen += 2; reqlen += 2;
// PrintAndLogEx(NORMAL, "cmd %s", sprint_hex(req, reqlen) );
clearCommandBuffer(); clearCommandBuffer();
SendCommandOLD(CMD_HF_ISO15693_COMMAND, reqlen, arg1, 1, req, reqlen); SendCommandOLD(CMD_HF_ISO15693_COMMAND, reqlen, arg1, 1, req, reqlen);
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
PrintAndLogEx(WARNING, "iso15693 card select failed"); PrintAndLogEx(WARNING, "iso15693 card select failed");
DropField(); DropField();
@ -918,11 +927,12 @@ static int CmdHF15Info(const char *Cmd) {
} }
memcpy(uid, recv + 2, sizeof(uid)); memcpy(uid, recv + 2, sizeof(uid));
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(SUCCESS, " UID : %s", sprintUID(NULL, uid)); PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") "---------");
PrintAndLogEx(SUCCESS, " TYPE : %s", getTagInfo_15(recv + 2)); PrintAndLogEx(INFO, "-------------------------------------------------------------");
PrintAndLogEx(SUCCESS, " SYSINFO : %s", sprint_hex(recv, status - 2)); PrintAndLogEx(SUCCESS, " TYPE: " _YELLOW_("%s"), getTagInfo_15(recv + 2));
PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), iso15693_sprintUID(NULL,uid));
PrintAndLogEx(SUCCESS, " SYSINFO: %s", sprint_hex(recv, status - 2));
// DSFID // DSFID
if (recv[1] & 0x01) if (recv[1] & 0x01)
@ -953,7 +963,7 @@ static int CmdHF15Info(const char *Cmd) {
} }
// Check if SLIX2 and attempt to get NXP System Information // Check if SLIX2 and attempt to get NXP System Information
PrintAndLogEx(INFO, "4 & 08 :: %02x 7 == 1 :: %u 8 == 4 :: %u", recv[4], recv[7], recv[8]); PrintAndLogEx(DEBUG, "4 & 08 :: %02x 7 == 1 :: %u 8 == 4 :: %u", recv[4], recv[7], recv[8]);
if (recv[8] == 0x04 && recv[7] == 0x01 && recv[4] & 0x80) { if (recv[8] == 0x04 && recv[7] == 0x01 && recv[4] & 0x80) {
return NxpSysInfo(uid); return NxpSysInfo(uid);
} }
@ -993,7 +1003,7 @@ static int CmdHF15Sim(const char *Cmd) {
return PM3_EINVARG; return PM3_EINVARG;
} }
PrintAndLogEx(SUCCESS, "Starting simulating UID %s", sprint_hex(uid, sizeof(uid))); PrintAndLogEx(SUCCESS, "Starting simulating UID " _YELLOW_("%s"), iso15693_sprintUID(NULL,uid));
clearCommandBuffer(); clearCommandBuffer();
SendCommandOLD(CMD_HF_ISO15693_SIMULATE, 0, 0, 0, uid, 8); SendCommandOLD(CMD_HF_ISO15693_SIMULATE, 0, 0, 0, uid, 8);
@ -1191,7 +1201,7 @@ static int CmdHF15Dump(const char *Cmd) {
} }
// detect blocksize from card :) // detect blocksize from card :)
PrintAndLogEx(SUCCESS, "Reading memory from tag UID " _YELLOW_("%s"), sprintUID(NULL, uid)); PrintAndLogEx(SUCCESS, "Reading memory from tag UID " _YELLOW_("%s"), iso15693_sprintUID(NULL,uid));
int blocknum = 0; int blocknum = 0;
uint8_t *recv = NULL; uint8_t *recv = NULL;
@ -1752,7 +1762,7 @@ static int CmdHF15CSetUID(const char *Cmd) {
return PM3_EINVARG; return PM3_EINVARG;
} }
PrintAndLogEx(SUCCESS, "Input new UID | %s", sprint_hex(uid, sizeof(uid))); PrintAndLogEx(SUCCESS, "Input new UID | " _YELLOW_("%s"), iso15693_sprintUID(NULL,uid));
if (!getUID(oldUid)) { if (!getUID(oldUid)) {
PrintAndLogEx(FAILED, "Can't get old/current UID."); PrintAndLogEx(FAILED, "Can't get old/current UID.");
@ -1823,8 +1833,8 @@ static int CmdHF15CSetUID(const char *Cmd) {
PrintAndLogEx(FAILED, "Setting UID on tag failed."); PrintAndLogEx(FAILED, "Setting UID on tag failed.");
return PM3_ESOFT; return PM3_ESOFT;
} else { } else {
PrintAndLogEx(SUCCESS, "old UID : %02X %02X %02X %02X %02X %02X %02X %02X", oldUid[7], oldUid[6], oldUid[5], oldUid[4], oldUid[3], oldUid[2], oldUid[1], oldUid[0]); PrintAndLogEx(SUCCESS, "Old: %s", iso15693_sprintUID(NULL, oldUid));
PrintAndLogEx(SUCCESS, "new UID : %02X %02X %02X %02X %02X %02X %02X %02X", newUid[7], newUid[6], newUid[5], newUid[4], newUid[3], newUid[2], newUid[1], newUid[0]); PrintAndLogEx(SUCCESS, "New: " _GREEN_("%s"), iso15693_sprintUID(NULL, newUid));
return PM3_SUCCESS; return PM3_SUCCESS;
} }
} }
@ -1873,7 +1883,7 @@ bool readHF15Uid(bool verbose) {
return false; return false;
} }
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(SUCCESS, " UID : %s", sprintUID(NULL, uid)); PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), iso15693_sprintUID(NULL, uid));
PrintAndLogEx(SUCCESS, " TYPE : %s", getTagInfo_15(uid)); PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("%s"), getTagInfo_15(uid));
return true; return true;
} }

View file

@ -27,7 +27,6 @@ uint8_t key_ones_data[16] = { 0x01 };
uint8_t key_defa_data[16] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; uint8_t key_defa_data[16] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
uint8_t key_picc_data[16] = { 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f }; uint8_t key_picc_data[16] = { 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f };
typedef enum { typedef enum {
UNKNOWN = 0, UNKNOWN = 0,
MF3ICD40, MF3ICD40,
@ -122,10 +121,20 @@ static int get_desfire_freemem(uint32_t *free_mem) {
// --- GET SIGNATURE // --- GET SIGNATURE
static int desfire_print_signature(uint8_t *uid, uint8_t *signature, size_t signature_len, desfire_cardtype_t card_type) { static int desfire_print_signature(uint8_t *uid, uint8_t *signature, size_t signature_len, desfire_cardtype_t card_type) {
#define PUBLIC_DESFIRE_ECDA_KEYLEN 57
// DESFire Ev3 - wanted // DESFire Ev3 - wanted
// ref: MIFARE Desfire Originality Signature Validation // ref: MIFARE Desfire Originality Signature Validation
#define PUBLIC_DESFIRE_ECDA_KEYLEN 57
const ecdsa_publickey_t nxp_desfire_public_keys[] = {
{"NTAG42x 1-3 NTAG 424 DNA TagTamper, NTAG426 TT, NTAG424DNA, DESFire EV2", "048A9B380AF2EE1B98DC417FECC263F8449C7625CECE82D9B916C992DA209D68422B81EC20B65A66B5102A61596AF3379200599316A00A1410"},
{"NTAG42x 4, NTAG426, DESFire Ev2", "04B304DC4C615F5326FE9383DDEC9AA892DF3A57FA7FFB3276192BC0EAA252ED45A865E3B093A3D0DCE5BE29E92F1392CE7DE321E3E5C52B3A"},
{"NTAG42x 3, NTAG 424 DNA, DESFire Light EV1", "040E98E117AAA36457F43173DC920A8757267F44CE4EC5ADD3C54075571AEBBF7B942A9774A1D94AD02572427E5AE0A2DD36591B1FB34FCF3D"},
{"NTAG413DNA, DESFire EV1", "04BB5D514F7050025C7D0F397310360EEC91EAF792E96FC7E0F496CB4E669D414F877B7B27901FE67C2E3B33CD39D1C797715189AC951C2ADD"},
{"Mifare Plus", "044409ADC42F91A8394066BA83D872FB1D16803734E911170412DDF8BAD1A4DADFD0416291AFE1C748253925DA39A5F39A1C557FFACD34C62E"},
{"NTAG424DNA, NTAG424DNATT (Tag Tamper), DESFire Light EV2", "04B304DC4C615F5326FE9383DDEC9AA892DF3A57FA7FFB3276192BC0EAA252ED45A865E3B093A3D0DCE5BE29E92F1392CE7DE321E3E5C52B3B"},
};
/*
uint8_t nxp_desfire_keys[][PUBLIC_DESFIRE_ECDA_KEYLEN] = { uint8_t nxp_desfire_keys[][PUBLIC_DESFIRE_ECDA_KEYLEN] = {
// NTAG42x 3 - NTAG 424 DNA, DESFire Light // NTAG42x 3 - NTAG 424 DNA, DESFire Light
{ {
@ -170,17 +179,30 @@ static int desfire_print_signature(uint8_t *uid, uint8_t *signature, size_t sign
0xDC, 0xE5, 0xBE, 0x29, 0xE9, 0x2F, 0x13, 0x92, 0xDC, 0xE5, 0xBE, 0x29, 0xE9, 0x2F, 0x13, 0x92,
0xCE, 0x7D, 0xE3, 0x21, 0xE3, 0xE5, 0xC5, 0x2B, 0x3A 0xCE, 0x7D, 0xE3, 0x21, 0xE3, 0xE5, 0xC5, 0x2B, 0x3A
}, },
// Unknown - needs identification
{
0x04, 0xBB, 0x5D, 0x51, 0x4F, 0x70, 0x50, 0x02,
0x5C, 0x7D, 0x0F, 0x39, 0x73, 0x10, 0x36, 0x0E,
0xEC, 0x91, 0xEA, 0xF7, 0x92, 0xE9, 0x6F, 0xC7,
0xE0, 0xF4, 0x96, 0xCB, 0x4E, 0x66, 0x9D, 0x41,
0x4F, 0x87, 0x7B, 0x7B, 0x27, 0x90, 0x1F, 0xE6,
0x7C, 0x2E, 0x3B, 0x33, 0xCD, 0x39, 0xD1, 0xC7,
0x97, 0x71, 0x51, 0x89, 0xAC, 0x95, 0x1C, 0x2A, 0xDD
}
}; };
*/
uint8_t i; uint8_t i;
int res; int res;
bool is_valid = false; bool is_valid = false;
for (i = 0; i< ARRAYLEN(nxp_desfire_keys); i++) { for (i = 0; i< ARRAYLEN(nxp_desfire_public_keys); i++) {
res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP224R1, nxp_desfire_keys[i], uid, 7, signature, signature_len, false); int dl = 0;
uint8_t key[PUBLIC_DESFIRE_ECDA_KEYLEN];
param_gethex_to_eol(nxp_desfire_public_keys[i].value, 0, key, PUBLIC_DESFIRE_ECDA_KEYLEN, &dl);
res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP224R1, key, uid, 7, signature, signature_len, false);
is_valid = (res == 0); is_valid = (res == 0);
if (is_valid) if (is_valid)
break; break;
@ -190,6 +212,7 @@ static int desfire_print_signature(uint8_t *uid, uint8_t *signature, size_t sign
return PM3_ESOFT; return PM3_ESOFT;
} }
/*
char *publickeyname; char *publickeyname;
switch(i) { switch(i) {
case 0: case 0:
@ -205,19 +228,20 @@ static int desfire_print_signature(uint8_t *uid, uint8_t *signature, size_t sign
publickeyname = "Unknown DESFire, post on forum"; publickeyname = "Unknown DESFire, post on forum";
break; break;
} }
*/
PrintAndLogEx(INFO, " Tag Signature"); PrintAndLogEx(INFO, "--- Tag Signature");
PrintAndLogEx(INFO, " IC signature public key name : %s", publickeyname); PrintAndLogEx(INFO, "IC signature public key name : %s", nxp_desfire_public_keys[i].desc);
PrintAndLogEx(INFO, " IC signature public key value : %s", sprint_hex(nxp_desfire_keys[i], 16)); PrintAndLogEx(INFO, "IC signature public key value : %.16s", nxp_desfire_public_keys[i].value);
PrintAndLogEx(INFO, " : %s", sprint_hex(nxp_desfire_keys[i] + 16, 16)); PrintAndLogEx(INFO, " : %.16s", nxp_desfire_public_keys[i].value + 16);
PrintAndLogEx(INFO, " : %s", sprint_hex(nxp_desfire_keys[i] + 32, 16)); PrintAndLogEx(INFO, " : %.16s", nxp_desfire_public_keys[i].value + 32);
PrintAndLogEx(INFO, " : %s", sprint_hex(nxp_desfire_keys[i] + 48, PUBLIC_DESFIRE_ECDA_KEYLEN - 48)); PrintAndLogEx(INFO, " : %.16s", nxp_desfire_public_keys[i].value + 48);
PrintAndLogEx(INFO, " Elliptic curve parameters : NID_secp224r1"); PrintAndLogEx(INFO, " Elliptic curve parameters : NID_secp224r1");
PrintAndLogEx(INFO, " TAG IC Signature : %s", sprint_hex(signature, 16)); PrintAndLogEx(INFO, " TAG IC Signature : %s", sprint_hex(signature, 16));
PrintAndLogEx(INFO, " : %s", sprint_hex(signature + 16, 16)); PrintAndLogEx(INFO, " : %s", sprint_hex(signature + 16, 16));
PrintAndLogEx(INFO, " : %s", sprint_hex(signature + 32, 16)); PrintAndLogEx(INFO, " : %s", sprint_hex(signature + 32, 16));
PrintAndLogEx(INFO, " : %s", sprint_hex(signature + 48, signature_len - 48)); PrintAndLogEx(INFO, " : %s", sprint_hex(signature + 48, signature_len - 48));
PrintAndLogEx( (is_valid) ? SUCCESS : WARNING, " Signature verified " _GREEN_("successful")); PrintAndLogEx( (is_valid) ? SUCCESS : WARNING, "Signature verified " _GREEN_("successful"));
PrintAndLogEx(INFO, "-------------------------------------------------------------"); PrintAndLogEx(INFO, "-------------------------------------------------------------");
return PM3_SUCCESS; return PM3_SUCCESS;
} }

View file

@ -8,9 +8,7 @@
// High frequency MIFARE ULTRALIGHT (C) commands // High frequency MIFARE ULTRALIGHT (C) commands
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include "cmdhfmfu.h" #include "cmdhfmfu.h"
#include <ctype.h> #include <ctype.h>
#include "cmdparser.h" #include "cmdparser.h"
#include "commonutil.h" #include "commonutil.h"
#include "crypto/libpcrypto.h" #include "crypto/libpcrypto.h"
@ -535,7 +533,7 @@ static int ul_print_default(uint8_t *data) {
sprint_bin(data + 10, 2) sprint_bin(data + 10, 2)
); );
PrintAndLogEx(SUCCESS, "OneTimePad : %s - %s\n", PrintAndLogEx(SUCCESS, "OneTimePad: %s - %s\n",
sprint_hex(data + 12, 4), sprint_hex(data + 12, 4),
sprint_bin(data + 12, 4) sprint_bin(data + 12, 4)
); );
@ -609,23 +607,24 @@ static int ndef_print_CC(uint8_t *data) {
} }
PrintAndLogEx(NORMAL, "--- NDEF Message"); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Capability Container: %s", sprint_hex(data, 4)); PrintAndLogEx(INFO, "--- " _CYAN_("NDEF Message"));
PrintAndLogEx(NORMAL, " %02X : NDEF Magic Number", data[0]); PrintAndLogEx(SUCCESS, "Capability Container: %s", sprint_hex(data, 4));
PrintAndLogEx(SUCCESS, " %02X: NDEF Magic Number", data[0]);
// PrintAndLogEx(NORMAL, " %02X : version %d.%d supported by tag", data[1], (data[1] & 0xF0) >> 4, data[1] & 0x0F); // PrintAndLogEx(SUCCESS, " %02X : version %d.%d supported by tag", data[1], (data[1] & 0xF0) >> 4, data[1] & 0x0F);
PrintAndLogEx(NORMAL, " %02X : version %d.%d supported by tag", data[1], cc_major, cc_minor); PrintAndLogEx(SUCCESS, " %02X: version %d.%d supported by tag", data[1], cc_major, cc_minor);
PrintAndLogEx(NORMAL, " : %s / %s", rStr, wStr); PrintAndLogEx(SUCCESS, " : %s / %s", rStr, wStr);
PrintAndLogEx(NORMAL, " %02X : Physical Memory Size: %d bytes", data[2], data[2] * 8); PrintAndLogEx(SUCCESS, " %02X: Physical Memory Size: %d bytes", data[2], data[2] * 8);
if (data[2] == 0x06) if (data[2] == 0x06)
PrintAndLogEx(NORMAL, " %02X : NDEF Memory Size: %d bytes", data[2], 48); PrintAndLogEx(SUCCESS, " %02X: NDEF Memory Size: %d bytes", data[2], 48);
else if (data[2] == 0x12) else if (data[2] == 0x12)
PrintAndLogEx(NORMAL, " %02X : NDEF Memory Size: %d bytes", data[2], 144); PrintAndLogEx(SUCCESS, " %02X: NDEF Memory Size: %d bytes", data[2], 144);
else if (data[2] == 0x3E) else if (data[2] == 0x3E)
PrintAndLogEx(NORMAL, " %02X : NDEF Memory Size: %d bytes", data[2], 496); PrintAndLogEx(SUCCESS, " %02X: NDEF Memory Size: %d bytes", data[2], 496);
else if (data[2] == 0x6D) else if (data[2] == 0x6D)
PrintAndLogEx(NORMAL, " %02X : NDEF Memory Size: %d bytes", data[2], 872); PrintAndLogEx(SUCCESS, " %02X: NDEF Memory Size: %d bytes", data[2], 872);
uint8_t msb3 = (data[3] & 0xE0) >> 5; uint8_t msb3 = (data[3] & 0xE0) >> 5;
uint8_t sf = (data[3] & 0x10) >> 4; uint8_t sf = (data[3] & 0x10) >> 4;
@ -633,14 +632,14 @@ static int ndef_print_CC(uint8_t *data) {
uint8_t mlrule = (data[3] & 0x06) >> 1; uint8_t mlrule = (data[3] & 0x06) >> 1;
uint8_t mbread = (data[3] & 0x01); uint8_t mbread = (data[3] & 0x01);
PrintAndLogEx(NORMAL, " Additional feature information"); PrintAndLogEx(SUCCESS, " Additional feature information");
PrintAndLogEx(NORMAL, " %02X", data[3]); PrintAndLogEx(SUCCESS, " %02X", data[3]);
PrintAndLogEx(NORMAL, " 00000000"); PrintAndLogEx(SUCCESS, " 00000000");
PrintAndLogEx(NORMAL, " xxx - %02X : RFU ( %s)", msb3, (msb3 == 0) ? _GREEN_("ok") : _RED_("fail")); PrintAndLogEx(SUCCESS, " xxx - %02X: RFU ( %s)", msb3, (msb3 == 0) ? _GREEN_("ok") : _RED_("fail"));
PrintAndLogEx(NORMAL, " x - %02X : %s special frame", sf, (sf) ? "support" : "don\'t support"); PrintAndLogEx(SUCCESS, " x - %02X: %s special frame", sf, (sf) ? "support" : "don\'t support");
PrintAndLogEx(NORMAL, " x - %02X : %s lock block", lb, (lb) ? "support" : "don\'t support"); PrintAndLogEx(SUCCESS, " x - %02X: %s lock block", lb, (lb) ? "support" : "don\'t support");
PrintAndLogEx(NORMAL, " xx - %02X : RFU ( %s)", mlrule, (mlrule == 0) ? _GREEN_("ok") : _RED_("fail")); PrintAndLogEx(SUCCESS, " xx - %02X: RFU ( %s)", mlrule, (mlrule == 0) ? _GREEN_("ok") : _RED_("fail"));
PrintAndLogEx(NORMAL, " x - %02X : IC %s multiple block reads", mbread, (mbread) ? "support" : "don\'t support"); PrintAndLogEx(SUCCESS, " x - %02X: IC %s multiple block reads", mbread, (mbread) ? "support" : "don\'t support");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -710,31 +709,31 @@ int ul_print_type(uint32_t tagtype, uint8_t spaces) {
} }
static int ulc_print_3deskey(uint8_t *data) { static int ulc_print_3deskey(uint8_t *data) {
PrintAndLogEx(NORMAL, " deskey1 [44/0x2C] : %s [%s]", sprint_hex(data, 4), sprint_ascii(data, 4)); PrintAndLogEx(NORMAL, " deskey1 [44/0x2C]: %s [%s]", sprint_hex(data, 4), sprint_ascii(data, 4));
PrintAndLogEx(NORMAL, " deskey1 [45/0x2D] : %s [%s]", sprint_hex(data + 4, 4), sprint_ascii(data + 4, 4)); PrintAndLogEx(NORMAL, " deskey1 [45/0x2D]: %s [%s]", sprint_hex(data + 4, 4), sprint_ascii(data + 4, 4));
PrintAndLogEx(NORMAL, " deskey2 [46/0x2E] : %s [%s]", sprint_hex(data + 8, 4), sprint_ascii(data + 8, 4)); PrintAndLogEx(NORMAL, " deskey2 [46/0x2E]: %s [%s]", sprint_hex(data + 8, 4), sprint_ascii(data + 8, 4));
PrintAndLogEx(NORMAL, " deskey2 [47/0x2F] : %s [%s]", sprint_hex(data + 12, 4), sprint_ascii(data + 12, 4)); PrintAndLogEx(NORMAL, " deskey2 [47/0x2F]: %s [%s]", sprint_hex(data + 12, 4), sprint_ascii(data + 12, 4));
PrintAndLogEx(NORMAL, "\n 3des key : %s", sprint_hex(SwapEndian64(data, 16, 8), 16)); PrintAndLogEx(NORMAL, "\n 3des key: %s", sprint_hex(SwapEndian64(data, 16, 8), 16));
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int ulc_print_configuration(uint8_t *data) { static int ulc_print_configuration(uint8_t *data) {
PrintAndLogEx(NORMAL, "--- UL-C Configuration"); PrintAndLogEx(NORMAL, "\n--- " _CYAN_("UL-C Configuration"));
PrintAndLogEx(NORMAL, " Higher Lockbits [40/0x28] : %s - %s", sprint_hex(data, 4), sprint_bin(data, 2)); PrintAndLogEx(NORMAL, " Higher Lockbits [40/0x28]: %s - %s", sprint_hex(data, 4), sprint_bin(data, 2));
PrintAndLogEx(NORMAL, " Counter [41/0x29] : %s - %s", sprint_hex(data + 4, 4), sprint_bin(data + 4, 2)); PrintAndLogEx(NORMAL, " Counter [41/0x29]: %s - %s", sprint_hex(data + 4, 4), sprint_bin(data + 4, 2));
bool validAuth = (data[8] >= 0x03 && data[8] <= 0x30); bool validAuth = (data[8] >= 0x03 && data[8] <= 0x30);
if (validAuth) if (validAuth)
PrintAndLogEx(NORMAL, " Auth0 [42/0x2A] : %s page %d/0x%02X and above need authentication", sprint_hex(data + 8, 4), data[8], data[8]); PrintAndLogEx(NORMAL, " Auth0 [42/0x2A]: %s page %d/0x%02X and above need authentication", sprint_hex(data + 8, 4), data[8], data[8]);
else { else {
if (data[8] == 0) { if (data[8] == 0) {
PrintAndLogEx(NORMAL, " Auth0 [42/0x2A] : %s default", sprint_hex(data + 8, 4)); PrintAndLogEx(NORMAL, " Auth0 [42/0x2A]: %s default", sprint_hex(data + 8, 4));
} else { } else {
PrintAndLogEx(NORMAL, " Auth0 [42/0x2A] : %s auth byte is out-of-range", sprint_hex(data + 8, 4)); PrintAndLogEx(NORMAL, " Auth0 [42/0x2A]: %s auth byte is out-of-range", sprint_hex(data + 8, 4));
} }
} }
PrintAndLogEx(NORMAL, " Auth1 [43/0x2B] : %s %s", PrintAndLogEx(NORMAL, " Auth1 [43/0x2B]: %s %s",
sprint_hex(data + 12, 4), sprint_hex(data + 12, 4),
(data[12] & 1) ? "write access restricted" : "read and write access restricted" (data[12] & 1) ? "write access restricted" : "read and write access restricted"
); );
@ -743,7 +742,8 @@ static int ulc_print_configuration(uint8_t *data) {
static int ulev1_print_configuration(uint32_t tagtype, uint8_t *data, uint8_t startPage) { static int ulev1_print_configuration(uint32_t tagtype, uint8_t *data, uint8_t startPage) {
PrintAndLogEx(NORMAL, "\n--- Tag Configuration"); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Configuration"));
bool strg_mod_en = (data[0] & 2); bool strg_mod_en = (data[0] & 2);
uint8_t authlim = (data[4] & 0x07); uint8_t authlim = (data[4] & 0x07);
@ -753,7 +753,7 @@ static int ulev1_print_configuration(uint32_t tagtype, uint8_t *data, uint8_t st
bool prot = (data[4] & 0x80); bool prot = (data[4] & 0x80);
uint8_t vctid = data[5]; uint8_t vctid = data[5];
PrintAndLogEx(NORMAL, " cfg0 [%u/0x%02X] : %s", startPage, startPage, sprint_hex(data, 4)); PrintAndLogEx(INFO, " cfg0 [%u/0x%02X]: %s", startPage, startPage, sprint_hex(data, 4));
if ((tagtype & (NTAG_213_F | NTAG_216_F))) { if ((tagtype & (NTAG_213_F | NTAG_216_F))) {
uint8_t mirror_conf = (data[0] & 0xC0); uint8_t mirror_conf = (data[0] & 0xC0);
@ -764,35 +764,35 @@ static int ulev1_print_configuration(uint32_t tagtype, uint8_t *data, uint8_t st
switch (mirror_conf) { switch (mirror_conf) {
case 0: case 0:
PrintAndLogEx(NORMAL, " - no ASCII mirror"); PrintAndLogEx(INFO, " - no ASCII mirror");
break; break;
case 1: case 1:
PrintAndLogEx(NORMAL, " - UID ASCII mirror"); PrintAndLogEx(INFO, " - UID ASCII mirror");
break; break;
case 2: case 2:
PrintAndLogEx(NORMAL, " - NFC counter ASCII mirror"); PrintAndLogEx(INFO, " - NFC counter ASCII mirror");
break; break;
case 3: case 3:
PrintAndLogEx(NORMAL, " - UID and NFC counter ASCII mirror"); PrintAndLogEx(INFO, " - UID and NFC counter ASCII mirror");
break; break;
default: default:
break; break;
} }
PrintAndLogEx(NORMAL, " - SLEEP mode %s", (sleep_en) ? "enabled" : "disabled"); PrintAndLogEx(INFO, " - SLEEP mode %s", (sleep_en) ? "enabled" : "disabled");
switch (fdp_conf) { switch (fdp_conf) {
case 0: case 0:
PrintAndLogEx(NORMAL, " - no field detect"); PrintAndLogEx(INFO, " - no field detect");
break; break;
case 1: case 1:
PrintAndLogEx(NORMAL, " - enabled by first State-of-Frame (start of communication)"); PrintAndLogEx(INFO, " - enabled by first State-of-Frame (start of communication)");
break; break;
case 2: case 2:
PrintAndLogEx(NORMAL, " - enabled by selection of the tag"); PrintAndLogEx(INFO, " - enabled by selection of the tag");
break; break;
case 3: case 3:
PrintAndLogEx(NORMAL, " - enabled by field presence"); PrintAndLogEx(INFO, " - enabled by field presence");
break; break;
default: default:
break; break;
@ -801,54 +801,54 @@ static int ulev1_print_configuration(uint32_t tagtype, uint8_t *data, uint8_t st
if (tagtype & NTAG_213_F) { if (tagtype & NTAG_213_F) {
switch (mirror_conf) { switch (mirror_conf) {
case 1: case 1:
{ PrintAndLogEx(NORMAL, " mirror start block %02X | byte pos %02X - %s", data[2], mirror_byte, (data[2] >= 0x4 && data[2] <= 0x24) ? "OK" : "Invalid value"); break;} { PrintAndLogEx(INFO, " mirror start block %02X | byte pos %02X - %s", data[2], mirror_byte, (data[2] >= 0x4 && data[2] <= 0x24) ? "OK" : "Invalid value"); break;}
case 2: case 2:
{ PrintAndLogEx(NORMAL, " mirror start block %02X | byte pos %02X - %s", data[2], mirror_byte, (data[2] >= 0x4 && data[2] <= 0x26) ? "OK" : "Invalid value"); break;} { PrintAndLogEx(INFO, " mirror start block %02X | byte pos %02X - %s", data[2], mirror_byte, (data[2] >= 0x4 && data[2] <= 0x26) ? "OK" : "Invalid value"); break;}
case 3: case 3:
{ PrintAndLogEx(NORMAL, " mirror start block %02X | byte pos %02X - %s", data[2], mirror_byte, (data[2] >= 0x4 && data[2] <= 0x22) ? "OK" : "Invalid value"); break;} { PrintAndLogEx(INFO, " mirror start block %02X | byte pos %02X - %s", data[2], mirror_byte, (data[2] >= 0x4 && data[2] <= 0x22) ? "OK" : "Invalid value"); break;}
default: default:
break; break;
} }
} else if (tagtype & NTAG_216_F) { } else if (tagtype & NTAG_216_F) {
switch (mirror_conf) { switch (mirror_conf) {
case 1: case 1:
{ PrintAndLogEx(NORMAL, " mirror start block %02X | byte pos %02X - %s", data[2], mirror_byte, (data[2] >= 0x4 && data[2] <= 0xDE) ? "OK" : "Invalid value"); break;} { PrintAndLogEx(INFO, " mirror start block %02X | byte pos %02X - %s", data[2], mirror_byte, (data[2] >= 0x4 && data[2] <= 0xDE) ? "OK" : "Invalid value"); break;}
case 2: case 2:
{ PrintAndLogEx(NORMAL, " mirror start block %02X | byte pos %02X - %s", data[2], mirror_byte, (data[2] >= 0x4 && data[2] <= 0xE0) ? "OK" : "Invalid value"); break;} { PrintAndLogEx(INFO, " mirror start block %02X | byte pos %02X - %s", data[2], mirror_byte, (data[2] >= 0x4 && data[2] <= 0xE0) ? "OK" : "Invalid value"); break;}
case 3: case 3:
{ PrintAndLogEx(NORMAL, " mirror start block %02X | byte pos %02X - %s", data[2], mirror_byte, (data[2] >= 0x4 && data[2] <= 0xDC) ? "OK" : "Invalid value"); break;} { PrintAndLogEx(INFO, " mirror start block %02X | byte pos %02X - %s", data[2], mirror_byte, (data[2] >= 0x4 && data[2] <= 0xDC) ? "OK" : "Invalid value"); break;}
default: default:
break; break;
} }
} }
} }
PrintAndLogEx(NORMAL, " - strong modulation mode %s", (strg_mod_en) ? "enabled" : "disabled"); PrintAndLogEx(INFO, " - strong modulation mode %s", (strg_mod_en) ? "enabled" : "disabled");
if (data[3] < 0xff) if (data[3] < 0xff)
PrintAndLogEx(NORMAL, " - page %d and above need authentication", data[3]); PrintAndLogEx(INFO, " - page %d and above need authentication", data[3]);
else else
PrintAndLogEx(NORMAL, " - pages don't need authentication"); PrintAndLogEx(INFO, " - pages don't need authentication");
PrintAndLogEx(NORMAL, " cfg1 [%u/0x%02X] : %s", startPage + 1, startPage + 1, sprint_hex(data + 4, 4)); PrintAndLogEx(INFO, " cfg1 [%u/0x%02X]: %s", startPage + 1, startPage + 1, sprint_hex(data + 4, 4));
if (authlim == 0) if (authlim == 0)
PrintAndLogEx(NORMAL, " - Unlimited password attempts"); PrintAndLogEx(INFO, " - " _GREEN_("Unlimited password attempts"));
else else
PrintAndLogEx(NORMAL, " - Max number of password attempts is " _YELLOW_("%d"), authlim); PrintAndLogEx(INFO, " - Max number of password attempts is " _YELLOW_("%d"), authlim);
PrintAndLogEx(NORMAL, " - NFC counter %s", (nfc_cnf_en) ? "enabled" : "disabled"); PrintAndLogEx(INFO, " - NFC counter %s", (nfc_cnf_en) ? "enabled" : "disabled");
PrintAndLogEx(NORMAL, " - NFC counter %s", (nfc_cnf_prot_pwd) ? "not protected" : "password protection enabled"); PrintAndLogEx(INFO, " - NFC counter %s", (nfc_cnf_prot_pwd) ? "not protected" : "password protection enabled");
PrintAndLogEx(NORMAL, " - user configuration %s", cfglck ? "permanently locked" : "writeable"); PrintAndLogEx(INFO, " - user configuration %s", cfglck ? "permanently locked" : "writeable");
PrintAndLogEx(NORMAL, " - %s access is protected with password", prot ? "read and write" : "write"); PrintAndLogEx(INFO, " - %s access is protected with password", prot ? "read and write" : "write");
PrintAndLogEx(NORMAL, " - %02X, Virtual Card Type Identifier is %s default", vctid, (vctid == 0x05) ? "" : "not"); PrintAndLogEx(INFO, " - %02X, Virtual Card Type Identifier is %sdefault", vctid, (vctid == 0x05) ? "" : "not ");
PrintAndLogEx(NORMAL, " PWD [%u/0x%02X] : %s- (cannot be read)", startPage + 2, startPage + 2, sprint_hex(data + 8, 4)); PrintAndLogEx(INFO, " PWD [%u/0x%02X]: %s- (cannot be read)", startPage + 2, startPage + 2, sprint_hex(data + 8, 4));
PrintAndLogEx(NORMAL, " PACK [%u/0x%02X] : %s - (cannot be read)", startPage + 3, startPage + 3, sprint_hex(data + 12, 2)); PrintAndLogEx(INFO, " PACK [%u/0x%02X]: %s - (cannot be read)", startPage + 3, startPage + 3, sprint_hex(data + 12, 2));
PrintAndLogEx(NORMAL, " RFU [%u/0x%02X] : %s- (cannot be read)", startPage + 3, startPage + 3, sprint_hex(data + 14, 2)); PrintAndLogEx(INFO, " RFU [%u/0x%02X]: %s- (cannot be read)", startPage + 3, startPage + 3, sprint_hex(data + 14, 2));
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int ulev1_print_counters() { static int ulev1_print_counters() {
PrintAndLogEx(NORMAL, "--- Tag Counters"); PrintAndLogEx(INFO, "--- " _CYAN_("Tag Counters"));
uint8_t tear[1] = {0}; uint8_t tear[1] = {0};
uint8_t counter[3] = {0, 0, 0}; uint8_t counter[3] = {0, 0, 0};
uint16_t len = 0; uint16_t len = 0;
@ -856,8 +856,8 @@ static int ulev1_print_counters() {
ulev1_readTearing(i, tear, sizeof(tear)); ulev1_readTearing(i, tear, sizeof(tear));
len = ulev1_readCounter(i, counter, sizeof(counter)); len = ulev1_readCounter(i, counter, sizeof(counter));
if (len == 3) { if (len == 3) {
PrintAndLogEx(NORMAL, " [%0d] : %s", i, sprint_hex(counter, 3)); PrintAndLogEx(INFO, " [%0d]: %s", i, sprint_hex(counter, 3));
PrintAndLogEx(NORMAL, " - %02X tearing %s", tear[0], (tear[0] == 0xBD) ? "Ok" : "failure"); PrintAndLogEx(SUCCESS, " - %02X tearing %s", tear[0], (tear[0] == 0xBD) ? "Ok" : "failure");
} }
} }
return len; return len;
@ -866,10 +866,20 @@ static int ulev1_print_counters() {
static int ulev1_print_signature(TagTypeUL_t tagtype, uint8_t *uid, uint8_t *signature, size_t signature_len) { static int ulev1_print_signature(TagTypeUL_t tagtype, uint8_t *uid, uint8_t *signature, size_t signature_len) {
#define PUBLIC_ECDA_KEYLEN 33 #define PUBLIC_ECDA_KEYLEN 33
// known public keys for the originality check (source: https://github.com/alexbatalov/node-nxp-originality-verifier) // known public keys for the originality check (source: https://github.com/alexbatalov/node-nxp-originality-verifier)
// ref: AN11350 NTAG 21x Originality Signature Validation // ref: AN11350 NTAG 21x Originality Signature Validation
// ref: AN11341 MIFARE Ultralight EV1 Originality Signature Validation // ref: AN11341 MIFARE Ultralight EV1 Originality Signature Validation
const ecdsa_publickey_t nxp_mfu_public_keys[] = {
{"NXP Mifare Classic MFC1C14_x", "044F6D3F294DEA5737F0F46FFEE88A356EED95695DD7E0C27A591E6F6F65962BAF"},
{"Manufacturer Mifare Classic MFC1C14_x", "046F70AC557F5461CE5052C8E4A7838C11C7A236797E8A0730A101837C004039C2"},
{"NXP ICODE DNA, ICODE SLIX2", "048878A2A2D3EEC336B4F261A082BD71F9BE11C4E2E896648B32EFA59CEA6E59F0"},
{"NXP Public key", "04A748B6A632FBEE2C0897702B33BEA1C074998E17B84ACA04FF267E5D2C91F6DC"},
{"NXP Ultralight Ev1", "0490933BDCD6E99B4E255E3DA55389A827564E11718E017292FAF23226A96614B8"},
{"NXP NTAG21x (2013)", "04494E1A386D3D3CFE3DC10E5DE68A499B1C202DB5B132393E89ED19FE5BE8BC61"},
{"MICRON Public key", "04f971eda742a4a80d32dcf6a814a707cc3dc396d35902f72929fdcd698b3468f2"},
};
/*
uint8_t nxp_mfu_public_keys[6][PUBLIC_ECDA_KEYLEN] = { uint8_t nxp_mfu_public_keys[6][PUBLIC_ECDA_KEYLEN] = {
// UL, NTAG21x and NDEF // UL, NTAG21x and NDEF
{ {
@ -914,61 +924,49 @@ static int ulev1_print_signature(TagTypeUL_t tagtype, uint8_t *uid, uint8_t *sig
0x29, 0x29, 0xfd, 0xcd, 0x69, 0x8b, 0x34, 0x68, 0xf2 0x29, 0x29, 0xfd, 0xcd, 0x69, 0x8b, 0x34, 0x68, 0xf2
} }
}; };
*/
uint8_t i; uint8_t i;
int res; int res;
bool is_valid = false; bool is_valid = false;
for (i = 0; i< ARRAYLEN(nxp_mfu_public_keys); i++) { for (i = 0; i< ARRAYLEN(nxp_mfu_public_keys); i++) {
res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP128R1, nxp_mfu_public_keys[i], uid, 7, signature, signature_len, false); int dl = 0;
uint8_t key[PUBLIC_ECDA_KEYLEN];
param_gethex_to_eol(nxp_mfu_public_keys[i].value, 0, key, PUBLIC_ECDA_KEYLEN, &dl);
res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP128R1, key, uid, 7, signature, signature_len, false);
is_valid = (res == 0); is_valid = (res == 0);
if (is_valid) if (is_valid)
break; break;
} }
PrintAndLogEx(NORMAL, "");
if (is_valid == false) { if (is_valid == false) {
PrintAndLogEx(SUCCESS, "Signature verification " _RED_("failed")); PrintAndLogEx(SUCCESS, "Signature verification " _RED_("failed"));
return PM3_ESOFT; return PM3_ESOFT;
} }
char *publickeyname; PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature"));
switch(i) { PrintAndLogEx(INFO, " IC signature public key name: %s", nxp_mfu_public_keys[i].desc);
case 0: PrintAndLogEx(INFO, "IC signature public key value: %s", nxp_mfu_public_keys[i].value);
publickeyname = "NXP NTAG21x (2013)"; PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp128r1");
break; PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, signature_len));
case 1: PrintAndLogEx(SUCCESS, " Signature verified: " _GREEN_("successful"));
publickeyname = "NXP Ev1";
break;
case 4:
publickeyname = "Manufacturer, post on forum";
break;
case 5:
publickeyname = "MIKRON";
break;
default:
publickeyname = "Unknown, post on forum";
break;
}
PrintAndLogEx(INFO, "\n--- Tag Signature");
PrintAndLogEx(INFO, "IC signature public key name : %s", publickeyname);
PrintAndLogEx(INFO, "IC signature public key value : %s", sprint_hex(nxp_mfu_public_keys[i], PUBLIC_ECDA_KEYLEN));
PrintAndLogEx(INFO, " Elliptic curve parameters : NID_secp128r1");
PrintAndLogEx(INFO, " TAG IC Signature : %s", sprint_hex(signature, signature_len));
PrintAndLogEx(SUCCESS, "Signature verified " _GREEN_("successful"));
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int ulev1_print_version(uint8_t *data) { static int ulev1_print_version(uint8_t *data) {
PrintAndLogEx(NORMAL, "\n--- Tag Version"); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, " Raw bytes: %s", sprint_hex(data, 8)); PrintAndLogEx(INFO, "--- " _CYAN_("Tag Version"));
PrintAndLogEx(NORMAL, " Vendor ID: %02X, %s", data[1], getTagInfo(data[1])); PrintAndLogEx(INFO, " Raw bytes: %s", sprint_hex(data, 8));
PrintAndLogEx(NORMAL, " Product type: %s", getProductTypeStr(data[2])); PrintAndLogEx(INFO, " Vendor ID: %02X, %s", data[1], getTagInfo(data[1]));
PrintAndLogEx(NORMAL, " Product subtype: %02X, %s", data[3], (data[3] == 1) ? "17 pF" : "50pF"); PrintAndLogEx(INFO, " Product type: %s", getProductTypeStr(data[2]));
PrintAndLogEx(NORMAL, " Major version: %02X", data[4]); PrintAndLogEx(INFO, " Product subtype: %02X, %s", data[3], (data[3] == 1) ? "17 pF" : "50pF");
PrintAndLogEx(NORMAL, " Minor version: %02X", data[5]); PrintAndLogEx(INFO, " Major version: %02X", data[4]);
PrintAndLogEx(NORMAL, " Size: %s", getUlev1CardSizeStr(data[6])); PrintAndLogEx(INFO, " Minor version: %02X", data[5]);
PrintAndLogEx(NORMAL, " Protocol type: %02X %s", data[7], (data[7] == 0x3) ? "(ISO14443-3 Compliant)" : ""); PrintAndLogEx(INFO, " Size: %s", getUlev1CardSizeStr(data[6]));
PrintAndLogEx(INFO, " Protocol type: %02X%s", data[7], (data[7] == 0x3) ? ", ISO14443-3 Compliant" : "");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -1188,8 +1186,9 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
TagTypeUL_t tagtype = GetHF14AMfU_Type(); TagTypeUL_t tagtype = GetHF14AMfU_Type();
if (tagtype == UL_ERROR) return PM3_ESOFT; if (tagtype == UL_ERROR) return PM3_ESOFT;
PrintAndLogEx(NORMAL, "\n--- Tag Information ---------"); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "-------------------------------------------------------------"); PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") "---------");
PrintAndLogEx(INFO, "-------------------------------------------------------------");
ul_print_type(tagtype, 6); ul_print_type(tagtype, 6);
// Swap endianness // Swap endianness
@ -1339,7 +1338,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
// hasAuthKey, if we was called with key, skip test. // hasAuthKey, if we was called with key, skip test.
if (!authlim && !hasAuthKey) { if (!authlim && !hasAuthKey) {
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(SUCCESS, _GREEN_("--- Known EV1/NTAG passwords ---")); PrintAndLogEx(SUCCESS, "--- " _CYAN_("Known EV1/NTAG passwords"));
// test pwd gen A // test pwd gen A
num_to_bytes(ul_ev1_pwdgenA(card.uid), 4, key); num_to_bytes(ul_ev1_pwdgenA(card.uid), 4, key);
len = ulev1_requestAuthentication(key, pack, sizeof(pack)); len = ulev1_requestAuthentication(key, pack, sizeof(pack));
@ -1790,7 +1789,7 @@ void printMFUdumpEx(mfu_dump_t *card, uint16_t pages, uint8_t startpage) {
// Read and Dump Card Contents, using auto detection of tag size. // Read and Dump Card Contents, using auto detection of tag size.
static int CmdHF14AMfUDump(const char *Cmd) { static int CmdHF14AMfUDump(const char *Cmd) {
uint8_t fileNameLen = 0; int fileNameLen = 0;
char filename[FILE_PATH_SIZE] = {0x00}; char filename[FILE_PATH_SIZE] = {0x00};
char *fptr = filename; char *fptr = filename;
@ -1834,6 +1833,8 @@ static int CmdHF14AMfUDump(const char *Cmd) {
break; break;
case 'f': case 'f':
fileNameLen = param_getstr(Cmd, cmdp + 1, filename, sizeof(filename)); fileNameLen = param_getstr(Cmd, cmdp + 1, filename, sizeof(filename));
if (fileNameLen > FILE_PATH_SIZE - 5)
fileNameLen = FILE_PATH_SIZE - 5;
cmdp += 2; cmdp += 2;
break; break;
case 'p': //set start page case 'p': //set start page

View file

@ -11,18 +11,18 @@
// returns a string representation of the UID // returns a string representation of the UID
// UID is transmitted and stored LSB first, displayed MSB first // UID is transmitted and stored LSB first, displayed MSB first
// target char* buffer, where to put the UID, if NULL a static buffer is returned // dest char* buffer, where to put the UID, if NULL a static buffer is returned
// uid[] the UID in transmission order // uid[] the UID in transmission order
// return: ptr to string // return: ptr to string
char *Iso15693sprintUID(char *target, uint8_t *uid) { char *iso15693_sprintUID(char *dest, uint8_t *uid) {
static char tempbuf[3 * 8 + 1] = {0}; static char tempbuf[3 * 8 + 1] = {0};
if (target == NULL) if (dest == NULL)
target = tempbuf; dest = tempbuf;
sprintf(target, "%02X %02X %02X %02X %02X %02X %02X %02X", sprintf(dest, "%02X %02X %02X %02X %02X %02X %02X %02X",
uid[7], uid[6], uid[5], uid[4], uid[7], uid[6], uid[5], uid[4],
uid[3], uid[2], uid[1], uid[0] uid[3], uid[2], uid[1], uid[0]
); );
return target; return dest;
} }

View file

@ -142,6 +142,6 @@ static const int Iso15693FrameEOF[] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
}; };
char *Iso15693sprintUID(char *target, uint8_t *uid); char *iso15693_sprintUID(char *dest, uint8_t *uid);
#endif #endif

View file

@ -267,6 +267,11 @@ typedef struct {
uint8_t AIA[8]; uint8_t AIA[8];
} PACKED iclass_reader_t; } PACKED iclass_reader_t;
typedef struct {
const char *desc;
const char *value;
} PACKED ecdsa_publickey_t;
// For the bootloader // For the bootloader
#define CMD_DEVICE_INFO 0x0000 #define CMD_DEVICE_INFO 0x0000
//#define CMD_SETUP_WRITE 0x0001 //#define CMD_SETUP_WRITE 0x0001