This commit is contained in:
iceman1001
2020-04-02 06:39:40 +02:00
6 changed files with 356 additions and 74 deletions

View File

@@ -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... 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] ## [unreleased][unreleased]
- Added `hf mfu ndef` - read and decode NDEF Type2 messages (@iceman1001)
- Added `data ndef` - decode NDEF messages (@iceman1001) - Added `data ndef` - decode NDEF messages (@iceman1001)
- Change - usb write's now waits for shiftregisters (@pwpiwi) - Change - usb write's now waits for shiftregisters (@pwpiwi)
- Change - NDEF supports more signatures now (@iceman1001) - Change - NDEF supports more signatures now (@iceman1001)

View File

@@ -2309,8 +2309,9 @@ static int CmdDataNDEF(const char *Cmd) {
int datalen = 0; int datalen = 0;
uint8_t data[MAX_NDEF_LEN] = {0}; uint8_t data[MAX_NDEF_LEN] = {0};
CLIGetHexWithReturn(1, data, &datalen); CLIGetHexWithReturn(1, data, &datalen);
CLIParserFree(); CLIParserFree();
if (datalen == 0)
return PM3_EINVARG;
PrintAndLogEx(INFO, "Parsed NDEF Records"); PrintAndLogEx(INFO, "Parsed NDEF Records");
return NDEFRecordsDecodeAndPrint(data, datalen); return NDEFRecordsDecodeAndPrint(data, datalen);

View File

@@ -208,7 +208,8 @@ 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
}; };
uint8_t nxp_public_keys[][33] = { #define PUBLIC_ECDA_KEYLEN 33
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,
@@ -216,10 +217,67 @@ uint8_t nxp_public_keys[][33] = {
0xF9, 0xBE, 0x11, 0xC4, 0xE2, 0xE8, 0x96, 0x64, 0xF9, 0xBE, 0x11, 0xC4, 0xE2, 0xE8, 0x96, 0x64,
0x8B, 0x32, 0xEF, 0xA5, 0x9C, 0xEA, 0x6E, 0x59, 0xF0 0x8B, 0x32, 0xEF, 0xA5, 0x9C, 0xEA, 0x6E, 0x59, 0xF0
}, },
// unknown. Needs identification
{
0x04, 0x4F, 0x6D, 0x3F, 0x29, 0x4D, 0xEA, 0x57,
0x37, 0xF0, 0xF4, 0x6F, 0xFE, 0xE8, 0x8A, 0x35,
0x6E, 0xED, 0x95, 0x69, 0x5D, 0xD7, 0xE0, 0xC2,
0x7A, 0x59, 0x1E, 0x6F, 0x6F, 0x65, 0x96, 0x2B, 0xAF
},
// unknown. Needs identification
{
0x04, 0xA7, 0x48, 0xB6, 0xA6, 0x32, 0xFB, 0xEE,
0x2C, 0x08, 0x97, 0x70, 0x2B, 0x33, 0xBE, 0xA1,
0xC0, 0x74, 0x99, 0x8E, 0x17, 0xB8, 0x4A, 0xCA,
0x04, 0xFF, 0x26, 0x7E, 0x5D, 0x2C, 0x91, 0xF6, 0xDC
},
// manufacturer public key
{
0x04, 0x6F, 0x70, 0xAC, 0x55, 0x7F, 0x54, 0x61,
0xCE, 0x50, 0x52, 0xC8, 0xE4, 0xA7, 0x83, 0x8C,
0x11, 0xC7, 0xA2, 0x36, 0x79, 0x7E, 0x8A, 0x07,
0x30, 0xA1, 0x01, 0x83, 0x7C, 0x00, 0x40, 0x39, 0xC2
},
// MIKRON public key.
{
0x04, 0xf9, 0x71, 0xed, 0xa7, 0x42, 0xa4, 0xa8,
0x0d, 0x32, 0xdc, 0xf6, 0xa8, 0x14, 0xa7, 0x07,
0xcc, 0x3d, 0xc3, 0x96, 0xd3, 0x59, 0x02, 0xf7,
0x29, 0x29, 0xfd, 0xcd, 0x69, 0x8b, 0x34, 0x68, 0xf2
}
}; };
static int CmdHF15Help(const char *Cmd); static int CmdHF15Help(const char *Cmd);
static int nxp_15693_print_signature(uint8_t *uid, uint8_t *signature) {
uint8_t i;
int res;
bool is_valid = false;
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);
is_valid = (res == 0);
if (is_valid)
break;
}
PrintAndLogEx(NORMAL, "");
if (is_valid == false) {
PrintAndLogEx(SUCCESS, "Signature verification " _RED_("failed"));
return PM3_ESOFT;
}
PrintAndLogEx(INFO, "\n--- 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 value : %s", sprint_hex(nxp_15693_public_keys[i], 33));
PrintAndLogEx(INFO, " Elliptic curve parameters : NID_secp128r1");
PrintAndLogEx(INFO, " TAG IC Signature : %s", sprint_hex(signature, 32));
PrintAndLogEx(INFO, " Signature verification " _GREEN_("successful"));
return PM3_SUCCESS;
}
// fast method to just read the UID of a tag (collision detection not supported) // fast method to just read the UID of a tag (collision detection not supported)
// *buf should be large enough to fit the 64bit uid // *buf should be large enough to fit the 64bit uid
// returns 1 if succeeded // returns 1 if succeeded
@@ -796,16 +854,8 @@ static int NxpSysInfo(uint8_t *uid) {
uint8_t signature[32] = {0x00}; uint8_t signature[32] = {0x00};
memcpy(signature, recv + 1, 32); memcpy(signature, recv + 1, 32);
int res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP128R1, nxp_public_keys[0], uid, 8, signature, 32, false); nxp_15693_print_signature(uid, signature);
bool is_valid = (res == 0);
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, " Tag Signature");
PrintAndLogEx(NORMAL, " IC signature public key name : NXP ICODE SLIX2 / DNA");
PrintAndLogEx(NORMAL, " IC signature public key value : %s", sprint_hex(nxp_public_keys[0], 33));
PrintAndLogEx(NORMAL, " Elliptic curve parameters : NID_secp128r1");
PrintAndLogEx(NORMAL, " TAG IC Signature : %s", sprint_hex(signature, 32));
PrintAndLogEx(NORMAL, " Signature verification %s", (is_valid) ? _GREEN_("successful") : _RED_("failed"));
} }
} }
@@ -901,10 +951,16 @@ 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]);
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);
} }
// if (recv[8] == 0x04 && recv[7] == 0x02 && recv[4] & 0x80) {
return NxpSysInfo(uid);
//}
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS; return PM3_SUCCESS;

View File

@@ -12,6 +12,7 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include "commonutil.h" // ARRAYLEN
#include "cmdparser.h" // command_t #include "cmdparser.h" // command_t
#include "comms.h" #include "comms.h"
#include "ui.h" #include "ui.h"
@@ -121,18 +122,10 @@ 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) {
uint8_t public_key;
if (card_type == LIGHT)
public_key = 0;
else if (card_type == EV2)
public_key = 1;
else
return PM3_EINVARG;
#define PUBLIC_DESFIRE_ECDA_KEYLEN 57 #define PUBLIC_DESFIRE_ECDA_KEYLEN 57
// ref: MIFARE Desfire Originality Signature Validation // ref: MIFARE Desfire Originality Signature Validation
uint8_t nxp_desfire_keys[2][PUBLIC_DESFIRE_ECDA_KEYLEN] = { uint8_t nxp_desfire_keys[][PUBLIC_DESFIRE_ECDA_KEYLEN] = {
// DESFire Light // DESFire Light
{ {
0x04, 0x0E, 0x98, 0xE1, 0x17, 0xAA, 0xA3, 0x64, 0x04, 0x0E, 0x98, 0xE1, 0x17, 0xAA, 0xA3, 0x64,
@@ -143,7 +136,11 @@ static int desfire_print_signature(uint8_t *uid, uint8_t *signature, size_t sign
0xD0, 0x25, 0x72, 0x42, 0x7E, 0x5A, 0xE0, 0xA2, 0xD0, 0x25, 0x72, 0x42, 0x7E, 0x5A, 0xE0, 0xA2,
0xDD, 0x36, 0x59, 0x1B, 0x1F, 0xB3, 0x4F, 0xCF, 0x3D 0xDD, 0x36, 0x59, 0x1B, 0x1F, 0xB3, 0x4F, 0xCF, 0x3D
}, },
// DESFire Ev2
// DESFire Ev2 - wanted
// DESFire Ev3 - wanted
// Unknown - needs identification
{ {
0x04, 0x8A, 0x9B, 0x38, 0x0A, 0xF2, 0xEE, 0x1B, 0x04, 0x8A, 0x9B, 0x38, 0x0A, 0xF2, 0xEE, 0x1B,
0x98, 0xDC, 0x41, 0x7F, 0xEC, 0xC2, 0x63, 0xF8, 0x98, 0xDC, 0x41, 0x7F, 0xEC, 0xC2, 0x63, 0xF8,
@@ -152,26 +149,59 @@ static int desfire_print_signature(uint8_t *uid, uint8_t *signature, size_t sign
0x42, 0x2B, 0x81, 0xEC, 0x20, 0xB6, 0x5A, 0x66, 0x42, 0x2B, 0x81, 0xEC, 0x20, 0xB6, 0x5A, 0x66,
0xB5, 0x10, 0x2A, 0x61, 0x59, 0x6A, 0xF3, 0x37, 0xB5, 0x10, 0x2A, 0x61, 0x59, 0x6A, 0xF3, 0x37,
0x92, 0x00, 0x59, 0x93, 0x16, 0xA0, 0x0A, 0x14, 0x10 0x92, 0x00, 0x59, 0x93, 0x16, 0xA0, 0x0A, 0x14, 0x10
} },
// Unknown - needs identification
{
0x04, 0x44, 0x09, 0xAD, 0xC4, 0x2F, 0x91, 0xA8,
0x39, 0x40, 0x66, 0xBA, 0x83, 0xD8, 0x72, 0xFB,
0x1D, 0x16, 0x80, 0x37, 0x34, 0xE9, 0x11, 0x17,
0x04, 0x12, 0xDD, 0xF8, 0xBA, 0xD1, 0xA4, 0xDA,
0xDF, 0xD0, 0x41, 0x62, 0x91, 0xAF, 0xE1, 0xC7,
0x48, 0x25, 0x39, 0x25, 0xDA, 0x39, 0xA5, 0xF3,
0x9A, 0x1C, 0x55, 0x7F, 0xFA, 0xCD, 0x34, 0xC6, 0x2E
}
}; };
uint8_t i;
int res;
bool is_valid = false;
int res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP224R1, nxp_desfire_keys[public_key], uid, 7, signature, signature_len, false); for (i = 0; i< ARRAYLEN(nxp_desfire_keys); i++) {
bool is_valid = (res == 0);
res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP224R1, nxp_desfire_keys[i], uid, 7, signature, signature_len, false);
is_valid = (res == 0);
if (is_valid)
break;
}
if (is_valid == false) {
PrintAndLogEx(SUCCESS, "Signature verification " _RED_("failed"));
return PM3_ESOFT;
}
char *publickeyname;
switch(i) {
case 0:
publickeyname = "NXP DESFire Light";
break;
default:
publickeyname = "Unknown DESFire, post on forum";
break;
}
PrintAndLogEx(INFO, " Tag Signature"); PrintAndLogEx(INFO, " Tag Signature");
PrintAndLogEx(INFO, " IC signature public key name : %s", (card_type == LIGHT) ? "NXP DESFire Light" : "NXP DESFire Ev2"); PrintAndLogEx(INFO, " IC signature public key name : %s", publickeyname);
PrintAndLogEx(INFO, " IC signature public key value : %s", sprint_hex(nxp_desfire_keys[public_key], 16)); PrintAndLogEx(INFO, " IC signature public key value : %s", sprint_hex(nxp_desfire_keys[i], 16));
PrintAndLogEx(INFO, " : %s", sprint_hex(nxp_desfire_keys[public_key] + 16, 16)); PrintAndLogEx(INFO, " : %s", sprint_hex(nxp_desfire_keys[i] + 16, 16));
PrintAndLogEx(INFO, " : %s", sprint_hex(nxp_desfire_keys[public_key] + 32, 16)); PrintAndLogEx(INFO, " : %s", sprint_hex(nxp_desfire_keys[i] + 32, 16));
PrintAndLogEx(INFO, " : %s", sprint_hex(nxp_desfire_keys[public_key] + 48, PUBLIC_DESFIRE_ECDA_KEYLEN - 48)); PrintAndLogEx(INFO, " : %s", sprint_hex(nxp_desfire_keys[i] + 48, PUBLIC_DESFIRE_ECDA_KEYLEN - 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 %s", (is_valid) ? _GREEN_("successful") : _RED_("failed")); PrintAndLogEx( (is_valid) ? SUCCESS : WARNING, " Signature verified " _GREEN_("successful"));
PrintAndLogEx(INFO, "-------------------------------------------------------------"); PrintAndLogEx(INFO, "-------------------------------------------------------------");
return PM3_SUCCESS; return PM3_SUCCESS;
} }

View File

@@ -21,6 +21,9 @@
#include "fileutils.h" #include "fileutils.h"
#include "protocols.h" #include "protocols.h"
#include "generator.h" #include "generator.h"
#include "mifare/ndef.h"
#include "cliparser/cliparser.h"
#define MAX_UL_BLOCKS 0x0F #define MAX_UL_BLOCKS 0x0F
#define MAX_ULC_BLOCKS 0x2B #define MAX_ULC_BLOCKS 0x2B
@@ -259,29 +262,6 @@ uint8_t default_pwd_pack[][4] = {
{0xFF, 0xFF, 0xFF, 0xFF}, // PACK 0x00,0x00 -- factory default {0xFF, 0xFF, 0xFF, 0xFF}, // PACK 0x00,0x00 -- factory default
}; };
#define PUBLIC_ECDA_KEYLEN 33
// known public keys for the originality check (source: https://github.com/alexbatalov/node-nxp-originality-verifier)
// ref: AN11350 NTAG 21x Originality Signature Validation
// ref: AN11341 MIFARE Ultralight EV1 Originality Signature Validation
uint8_t public_keys[2][PUBLIC_ECDA_KEYLEN] = {
// UL, NTAG21x and NDEF
{
0x04, 0x49, 0x4e, 0x1a, 0x38, 0x6d, 0x3d, 0x3c,
0xfe, 0x3d, 0xc1, 0x0e, 0x5d, 0xe6, 0x8a, 0x49,
0x9b, 0x1c, 0x20, 0x2d, 0xb5, 0xb1, 0x32, 0x39,
0x3e, 0x89, 0xed, 0x19, 0xfe, 0x5b, 0xe8, 0xbc, 0x61
},
// UL EV1
{
0x04, 0x90, 0x93, 0x3b, 0xdc, 0xd6, 0xe9, 0x9b,
0x4e, 0x25, 0x5e, 0x3d, 0xa5, 0x53, 0x89, 0xa8,
0x27, 0x56, 0x4e, 0x11, 0x71, 0x8e, 0x01, 0x72,
0x92, 0xfa, 0xf2, 0x32, 0x26, 0xa9, 0x66, 0x14, 0xb8
}
};
uint32_t UL_TYPES_ARRAY[] = { uint32_t UL_TYPES_ARRAY[] = {
UNKNOWN, UL, UL_C, UL_EV1_48, UL_EV1_128, NTAG, UNKNOWN, UL, UL_C, UL_EV1_48, UL_EV1_128, NTAG,
NTAG_203, NTAG_210, NTAG_212, NTAG_213, NTAG_215, NTAG_216, NTAG_203, NTAG_210, NTAG_212, NTAG_213, NTAG_215, NTAG_216,
@@ -563,6 +543,22 @@ static int ul_print_default(uint8_t *data) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int ndef_get_maxsize(uint8_t *data) {
// no NDEF message
if (data[0] != 0xE1)
return 0;
if (data[2] == 0x06)
return 48;
else if (data[2] == 0x12)
return 144;
else if (data[2] == 0x3E)
return 496;
else if (data[2] == 0x6D)
return 872;
return 0;
}
static int ndef_print_CC(uint8_t *data) { static int ndef_print_CC(uint8_t *data) {
// no NDEF message // no NDEF message
if (data[0] != 0xE1) if (data[0] != 0xE1)
@@ -868,19 +864,98 @@ 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) {
uint8_t public_key = 0;
if (tagtype == UL_EV1_48 || tagtype == UL_EV1_128) { #define PUBLIC_ECDA_KEYLEN 33
public_key = 1;
// known public keys for the originality check (source: https://github.com/alexbatalov/node-nxp-originality-verifier)
// ref: AN11350 NTAG 21x Originality Signature Validation
// ref: AN11341 MIFARE Ultralight EV1 Originality Signature Validation
uint8_t nxp_mfu_public_keys[6][PUBLIC_ECDA_KEYLEN] = {
// UL, NTAG21x and NDEF
{
0x04, 0x49, 0x4e, 0x1a, 0x38, 0x6d, 0x3d, 0x3c,
0xfe, 0x3d, 0xc1, 0x0e, 0x5d, 0xe6, 0x8a, 0x49,
0x9b, 0x1c, 0x20, 0x2d, 0xb5, 0xb1, 0x32, 0x39,
0x3e, 0x89, 0xed, 0x19, 0xfe, 0x5b, 0xe8, 0xbc, 0x61
},
// UL EV1
{
0x04, 0x90, 0x93, 0x3b, 0xdc, 0xd6, 0xe9, 0x9b,
0x4e, 0x25, 0x5e, 0x3d, 0xa5, 0x53, 0x89, 0xa8,
0x27, 0x56, 0x4e, 0x11, 0x71, 0x8e, 0x01, 0x72,
0x92, 0xfa, 0xf2, 0x32, 0x26, 0xa9, 0x66, 0x14, 0xb8
},
// unknown. Needs identification
{
0x04, 0x4F, 0x6D, 0x3F, 0x29, 0x4D, 0xEA, 0x57,
0x37, 0xF0, 0xF4, 0x6F, 0xFE, 0xE8, 0x8A, 0x35,
0x6E, 0xED, 0x95, 0x69, 0x5D, 0xD7, 0xE0, 0xC2,
0x7A, 0x59, 0x1E, 0x6F, 0x6F, 0x65, 0x96, 0x2B, 0xAF
},
// unknown. Needs identification
{
0x04, 0xA7, 0x48, 0xB6, 0xA6, 0x32, 0xFB, 0xEE,
0x2C, 0x08, 0x97, 0x70, 0x2B, 0x33, 0xBE, 0xA1,
0xC0, 0x74, 0x99, 0x8E, 0x17, 0xB8, 0x4A, 0xCA,
0x04, 0xFF, 0x26, 0x7E, 0x5D, 0x2C, 0x91, 0xF6, 0xDC
},
// manufacturer public key
{
0x04, 0x6F, 0x70, 0xAC, 0x55, 0x7F, 0x54, 0x61,
0xCE, 0x50, 0x52, 0xC8, 0xE4, 0xA7, 0x83, 0x8C,
0x11, 0xC7, 0xA2, 0x36, 0x79, 0x7E, 0x8A, 0x07,
0x30, 0xA1, 0x01, 0x83, 0x7C, 0x00, 0x40, 0x39, 0xC2
},
// MIKRON public key.
{
0x04, 0xf9, 0x71, 0xed, 0xa7, 0x42, 0xa4, 0xa8,
0x0d, 0x32, 0xdc, 0xf6, 0xa8, 0x14, 0xa7, 0x07,
0xcc, 0x3d, 0xc3, 0x96, 0xd3, 0x59, 0x02, 0xf7,
0x29, 0x29, 0xfd, 0xcd, 0x69, 0x8b, 0x34, 0x68, 0xf2
}
};
uint8_t i;
int res;
bool is_valid = false;
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);
is_valid = (res == 0);
if (is_valid)
break;
}
if (is_valid == false) {
PrintAndLogEx(SUCCESS, "Signature verification " _RED_("failed"));
return PM3_ESOFT;
}
char *publickeyname;
switch(i) {
case 0:
publickeyname = "NXP NTAG21x (2013)";
break;
case 1:
publickeyname = "NXP Ev1";
break;
case 4:
publickeyname = "Manufacturer, post on forum";
break;
case 5:
publickeyname = "MIKRON";
break;
default:
publickeyname = "Unknown, post on forum";
break;
} }
int res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP128R1, public_keys[public_key], uid, 7, signature, signature_len, false);
bool is_valid = (res == 0);
PrintAndLogEx(INFO, "\n--- Tag Signature"); PrintAndLogEx(INFO, "\n--- Tag Signature");
PrintAndLogEx(INFO, "IC signature public key name : NXP NTAG21x (2013)"); PrintAndLogEx(INFO, "IC signature public key name : %s", publickeyname);
PrintAndLogEx(INFO, "IC signature public key value : %s", sprint_hex(public_keys[public_key], PUBLIC_ECDA_KEYLEN)); 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, " Elliptic curve parameters : NID_secp128r1");
PrintAndLogEx(INFO, " TAG IC Signature : %s", sprint_hex(signature, signature_len)); PrintAndLogEx(INFO, " TAG IC Signature : %s", sprint_hex(signature, signature_len));
PrintAndLogEx(SUCCESS, "Signature verified %s", (is_valid) ? _GREEN_("successful") : _RED_("failed")); PrintAndLogEx(SUCCESS, "Signature verified " _GREEN_("successful"));
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@@ -2633,6 +2708,100 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int CmdHF14MfuNDEF(const char *Cmd) {
int keylen;
int maxsize = 16, status;
bool hasAuthKey = false;
bool swapEndian = false;
iso14a_card_select_t card;
uint8_t data[16] = {0x00};
uint8_t key[16] = {0x00};
uint8_t *p_key = key;
uint8_t pack[4] = {0, 0, 0, 0};
CLIParserInit("hf mfu ndef",
"Prints NFC Data Exchange Format (NDEF)",
"Usage:\n\thf mfu ndef -> shows NDEF data\n"
"\thf mfu ndef -k ffffffff -> shows NDEF data with key\n");
void *argtable[] = {
arg_param_begin,
arg_str0("kK", "key", "replace default key for NDEF", NULL),
arg_lit0("lL", "key", "(optional) swap entered key's endianness"),
arg_param_end
};
CLIExecWithReturn(Cmd, argtable, true);
CLIGetHexWithReturn(1, key, &keylen);
swapEndian = arg_get_lit(2);
CLIParserFree();
switch(keylen) {
case 0:
break;
case 4:
case 16:
hasAuthKey = true;
break;
default:
PrintAndLogEx(WARNING, "ERROR: Key is incorrect length\n");
return PM3_EINVARG;
}
// Get tag type
TagTypeUL_t tagtype = GetHF14AMfU_Type();
if (tagtype == UL_ERROR) return PM3_ESOFT;
// Is tag UL/NTAG?
// Swap endianness
if (swapEndian && hasAuthKey) p_key = SwapEndian64(key, keylen, (keylen == 16) ? 8 : 4);
// Select and Auth
if (ul_auth_select(&card, tagtype, hasAuthKey, p_key, pack, sizeof(pack)) == PM3_ESOFT) return PM3_ESOFT;
// read pages 0,1,2,3 (should read 4pages)
status = ul_read(0, data, sizeof(data));
if (status == -1) {
DropField();
PrintAndLogEx(ERR, "Error: tag didn't answer to READ");
return PM3_ESOFT;
} else if (status == 16) {
status = ndef_print_CC(data + 12);
if (status == PM3_ESOFT) {
DropField();
PrintAndLogEx(ERR, "Error: tag didn't contain a NDEF Container");
return PM3_ESOFT;
}
// max datasize;
maxsize = ndef_get_maxsize(data + 12);
}
// allocate mem
uint8_t *records = calloc(maxsize, sizeof(uint8_t));
if (records == NULL) {
DropField();
return PM3_EMALLOC;
}
// read NDEF records.
for(uint16_t i = 0, j = 0; i < maxsize; i += 16, j += 4) {
status = ul_read(4 + j, records + i, 16);
if (status == -1) {
DropField();
PrintAndLogEx(ERR, "Error: tag didn't answer to READ");
return PM3_ESOFT;
}
}
DropField();
status = NDEFDecodeAndPrint(records, (size_t)maxsize, true);
free(records);
return status;
}
//------------------------------------ //------------------------------------
// Menu Stuff // Menu Stuff
//------------------------------------ //------------------------------------
@@ -2651,6 +2820,7 @@ static command_t CommandTable[] = {
{"gen", CmdHF14AMfUGenDiverseKeys, AlwaysAvailable, "Generate 3des mifare diversified keys"}, {"gen", CmdHF14AMfUGenDiverseKeys, AlwaysAvailable, "Generate 3des mifare diversified keys"},
{"pwdgen", CmdHF14AMfUPwdGen, AlwaysAvailable, "Generate pwd from known algos"}, {"pwdgen", CmdHF14AMfUPwdGen, AlwaysAvailable, "Generate pwd from known algos"},
{"otptear", CmdHF14AMfuOtpTearoff, IfPm3Iso14443a, "Tear-off test on OTP bits"}, {"otptear", CmdHF14AMfuOtpTearoff, IfPm3Iso14443a, "Tear-off test on OTP bits"},
{"ndef", CmdHF14MfuNDEF, IfPm3Iso14443a, "Prints NDEF records from card"},
{NULL, NULL, NULL, NULL} {NULL, NULL, NULL, NULL}
}; };

View File

@@ -308,15 +308,15 @@ static int ndefDecodePayload(NDEFHeader_t *ndef) {
switch (ndef->TypeNameFormat) { switch (ndef->TypeNameFormat) {
case tnfWellKnownRecord: case tnfWellKnownRecord:
PrintAndLogEx(INFO, "Well Known Record"); PrintAndLogEx(INFO, "Well Known Record");
PrintAndLogEx(NORMAL, "\ttype: %.*s", (int)ndef->TypeLen, ndef->Type); PrintAndLogEx(INFO, "\ttype : %.*s", (int)ndef->TypeLen, ndef->Type);
if (!strncmp((char *)ndef->Type, "T", ndef->TypeLen)) { if (!strncmp((char *)ndef->Type, "T", ndef->TypeLen)) {
PrintAndLogEx(NORMAL, "\ttext : %.*s", (int)ndef->PayloadLen, ndef->Payload); PrintAndLogEx(INFO, "\ttext : " _GREEN_("%.*s"), (int)ndef->PayloadLen, ndef->Payload);
} }
if (!strncmp((char *)ndef->Type, "U", ndef->TypeLen)) { if (!strncmp((char *)ndef->Type, "U", ndef->TypeLen)) {
PrintAndLogEx(NORMAL PrintAndLogEx(INFO
, "\turi : %s%.*s" , "\turi : " _GREEN_("%s%.*s")
, (ndef->Payload[0] <= 0x23 ? URI_s[ndef->Payload[0]] : "[err]") , (ndef->Payload[0] <= 0x23 ? URI_s[ndef->Payload[0]] : "[err]")
, (int)(ndef->PayloadLen - 1) , (int)(ndef->PayloadLen - 1)
, &ndef->Payload[1] , &ndef->Payload[1]
@@ -330,14 +330,28 @@ static int ndefDecodePayload(NDEFHeader_t *ndef) {
break; break;
case tnfAbsoluteURIRecord: case tnfAbsoluteURIRecord:
PrintAndLogEx(INFO, "Absolute URI Record"); PrintAndLogEx(INFO, "Absolute URI Record");
PrintAndLogEx(NORMAL, "\ttype: %.*s", (int)ndef->TypeLen, ndef->Type); PrintAndLogEx(INFO, "\ttype : %.*s", (int)ndef->TypeLen, ndef->Type);
PrintAndLogEx(NORMAL, "\tpayload: %.*s", (int)ndef->PayloadLen, ndef->Payload); PrintAndLogEx(INFO, "\tpayload : %.*s", (int)ndef->PayloadLen, ndef->Payload);
break; break;
case tnfEmptyRecord: case tnfEmptyRecord:
PrintAndLogEx(INFO, "Empty Record");
PrintAndLogEx(INFO, "\t -to be impl-");
break;
case tnfMIMEMediaRecord: case tnfMIMEMediaRecord:
PrintAndLogEx(INFO, "MIME Media Record");
PrintAndLogEx(INFO, "\t -to be impl-");
break;
case tnfExternalRecord: case tnfExternalRecord:
PrintAndLogEx(INFO, "External Record");
PrintAndLogEx(INFO, "\t -to be impl-");
break;
case tnfUnchangedRecord: case tnfUnchangedRecord:
PrintAndLogEx(INFO, "Unchanged Record");
PrintAndLogEx(INFO, "\t -to be impl-");
break;
case tnfUnknownRecord: case tnfUnknownRecord:
PrintAndLogEx(INFO, "Unknown Record");
PrintAndLogEx(INFO, "\t -to be impl-");
break; break;
} }
return PM3_SUCCESS; return PM3_SUCCESS;
@@ -372,8 +386,11 @@ static int ndefRecordDecodeAndPrint(uint8_t *ndefRecord, size_t ndefRecordLen) {
int NDEFRecordsDecodeAndPrint(uint8_t *ndefRecord, size_t ndefRecordLen) { int NDEFRecordsDecodeAndPrint(uint8_t *ndefRecord, size_t ndefRecordLen) {
bool firstRec = true; bool firstRec = true;
size_t len = 0; size_t len = 0;
size_t counter = 0;
while (len < ndefRecordLen) { while (len < ndefRecordLen) {
counter++;
NDEFHeader_t NDEFHeader = {0}; NDEFHeader_t NDEFHeader = {0};
int res = ndefDecodeHeader(&ndefRecord[len], ndefRecordLen - len, &NDEFHeader); int res = ndefDecodeHeader(&ndefRecord[len], ndefRecordLen - len, &NDEFHeader);
if (res != PM3_SUCCESS) if (res != PM3_SUCCESS)
@@ -381,7 +398,7 @@ int NDEFRecordsDecodeAndPrint(uint8_t *ndefRecord, size_t ndefRecordLen) {
if (firstRec) { if (firstRec) {
if (!NDEFHeader.MessageBegin) { if (!NDEFHeader.MessageBegin) {
PrintAndLogEx(ERR, "NDEF first record have MessageBegin=false!"); PrintAndLogEx(ERR, "NDEF first record have MessageBegin = false!");
return PM3_ESOFT; return PM3_ESOFT;
} }
firstRec = false; firstRec = false;
@@ -392,6 +409,9 @@ int NDEFRecordsDecodeAndPrint(uint8_t *ndefRecord, size_t ndefRecordLen) {
return PM3_ESOFT; return PM3_ESOFT;
} }
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(SUCCESS, "Record " _YELLOW_("%zu"), counter);
PrintAndLogEx(INFO, "-----------------------------------------------------");
ndefRecordDecodeAndPrint(&ndefRecord[len], NDEFHeader.RecLen); ndefRecordDecodeAndPrint(&ndefRecord[len], NDEFHeader.RecLen);
len += NDEFHeader.RecLen; len += NDEFHeader.RecLen;
@@ -407,22 +427,26 @@ int NDEFDecodeAndPrint(uint8_t *ndef, size_t ndefLen, bool verbose) {
size_t indx = 0; size_t indx = 0;
PrintAndLogEx(INFO, "NDEF decoding:"); PrintAndLogEx(INFO, "");
PrintAndLogEx(INFO, "NDEF parsing");
while (indx < ndefLen) { while (indx < ndefLen) {
PrintAndLogEx(INFO, "-----------------------------------------------------");
switch (ndef[indx]) { switch (ndef[indx]) {
case 0x00: { case 0x00: {
indx++; indx++;
uint16_t len = ndefTLVGetLength(&ndef[indx], &indx); uint16_t len = ndefTLVGetLength(&ndef[indx], &indx);
PrintAndLogEx(INFO, "-- NDEF NULL block.");
PrintAndLogEx(SUCCESS, "-- NDEF NULL block.");
if (len) if (len)
PrintAndLogEx(WARNING, "NDEF NULL block size must be 0 instead of %d.", len); PrintAndLogEx(WARNING, "NDEF NULL block size must be 0, got %d bytes", len);
indx += len; indx += len;
break; break;
} }
case 0x03: { case 0x03: {
indx++; indx++;
uint16_t len = ndefTLVGetLength(&ndef[indx], &indx); uint16_t len = ndefTLVGetLength(&ndef[indx], &indx);
PrintAndLogEx(INFO, "-- NDEF message. len: %d", len); PrintAndLogEx(SUCCESS, "Found NDEF message (%d bytes)", len);
int res = NDEFRecordsDecodeAndPrint(&ndef[indx], len); int res = NDEFRecordsDecodeAndPrint(&ndef[indx], len);
if (res != PM3_SUCCESS) if (res != PM3_SUCCESS)
@@ -434,12 +458,12 @@ int NDEFDecodeAndPrint(uint8_t *ndef, size_t ndefLen, bool verbose) {
case 0xfd: { case 0xfd: {
indx++; indx++;
uint16_t len = ndefTLVGetLength(&ndef[indx], &indx); uint16_t len = ndefTLVGetLength(&ndef[indx], &indx);
PrintAndLogEx(INFO, "-- NDEF proprietary info. Skipped %d bytes.", len); PrintAndLogEx(SUCCESS, "-- NDEF proprietary info. Skipped %d bytes.", len);
indx += len; indx += len;
break; break;
} }
case 0xfe: { case 0xfe: {
PrintAndLogEx(INFO, "-- NDEF Terminator. Done."); PrintAndLogEx(SUCCESS, "-- NDEF Terminator. Done.");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
default: { default: {