mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 22:03:42 -07:00
added support to verify UL AES signatures. This tag supports of randomizing UID and mixing with AES keys, making a generic signature algo a bit harder. But for the non mixed signature check it should work. Also added Ul AES version for it to be correct identified.
This commit is contained in:
parent
463356469a
commit
7adadde5f5
2 changed files with 62 additions and 24 deletions
|
@ -51,6 +51,7 @@
|
|||
#define MAX_MY_D_MOVE 0x25
|
||||
#define MAX_MY_D_MOVE_LEAN 0x0F
|
||||
#define MAX_UL_NANO_40 0x0A
|
||||
#define MAX_UL_AES 0x37
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
|
@ -86,7 +87,8 @@ static uint64_t UL_TYPES_ARRAY[] = {
|
|||
MFU_TT_NTAG_213_TT, MFU_TT_NTAG_213_C,
|
||||
MFU_TT_MAGIC_1A, MFU_TT_MAGIC_1B,
|
||||
MFU_TT_MAGIC_NTAG, MFU_TT_NTAG_210u,
|
||||
MFU_TT_UL_MAGIC, MFU_TT_UL_C_MAGIC
|
||||
MFU_TT_UL_MAGIC, MFU_TT_UL_C_MAGIC,
|
||||
MFU_TT_UL_AES
|
||||
};
|
||||
|
||||
static uint8_t UL_MEMORY_ARRAY[ARRAYLEN(UL_TYPES_ARRAY)] = {
|
||||
|
@ -107,7 +109,7 @@ static uint8_t UL_MEMORY_ARRAY[ARRAYLEN(UL_TYPES_ARRAY)] = {
|
|||
// MAGIC_1A, MAGIC_1B, MAGIC_NTAG,
|
||||
MAX_UL_BLOCKS, MAX_UL_BLOCKS, MAX_NTAG_216,
|
||||
// NTAG_210u, UL_MAGIC, UL_C_MAGIC
|
||||
MAX_NTAG_210, MAX_UL_BLOCKS, MAX_ULC_BLOCKS
|
||||
MAX_NTAG_210, MAX_UL_BLOCKS, MAX_ULC_BLOCKS, MAX_UL_AES
|
||||
};
|
||||
|
||||
//------------------------------------
|
||||
|
@ -428,7 +430,6 @@ static int ulev1_readTearing(uint8_t counter, uint8_t *response, uint16_t respon
|
|||
}
|
||||
|
||||
static int ulev1_readSignature(uint8_t *response, uint16_t responseLength) {
|
||||
|
||||
uint8_t cmd[] = {MIFARE_ULEV1_READSIG, 0x00};
|
||||
int len = ul_send_cmd_raw(cmd, sizeof(cmd), response, responseLength);
|
||||
return len;
|
||||
|
@ -1023,6 +1024,7 @@ static int ulev1_print_counters(void) {
|
|||
static int ulev1_print_signature(uint64_t tagtype, uint8_t *uid, uint8_t *signature, size_t signature_len) {
|
||||
|
||||
#define PUBLIC_ECDA_KEYLEN 33
|
||||
#define PUBLIC_ECDA_192_KEYLEN 49
|
||||
// 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
|
||||
|
@ -1036,6 +1038,11 @@ static int ulev1_print_signature(uint64_t tagtype, uint8_t *uid, uint8_t *signat
|
|||
{"MIKRON Public key", "04f971eda742a4a80d32dcf6a814a707cc3dc396d35902f72929fdcd698b3468f2"},
|
||||
};
|
||||
|
||||
// https://www.nxp.com/docs/en/application-note/AN13452.pdf
|
||||
const ecdsa_publickey_t nxp_mfu_192_public_keys[] = {
|
||||
{"NXP Ultralight AES", "0453BF8C49B7BD9FE3207A91513B9C1D238ECAB07186B772104AB535F7D3AE63CF7C7F3DD0D169DA3E99E43C6399621A86"},
|
||||
};
|
||||
|
||||
/*
|
||||
uint8_t nxp_mfu_public_keys[6][PUBLIC_ECDA_KEYLEN] = {
|
||||
// UL, NTAG21x and NDEF
|
||||
|
@ -1084,6 +1091,7 @@ static int ulev1_print_signature(uint64_t tagtype, uint8_t *uid, uint8_t *signat
|
|||
*/
|
||||
uint8_t i;
|
||||
bool is_valid = false;
|
||||
if (signature_len == 32) {
|
||||
for (i = 0; i < ARRAYLEN(nxp_mfu_public_keys); i++) {
|
||||
|
||||
int dl = 0;
|
||||
|
@ -1096,22 +1104,47 @@ static int ulev1_print_signature(uint64_t tagtype, uint8_t *uid, uint8_t *signat
|
|||
if (is_valid)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool is_192_valid = false;
|
||||
if (signature_len == 48) {
|
||||
for (i = 0; i < ARRAYLEN(nxp_mfu_192_public_keys); i++) {
|
||||
int dl = 0;
|
||||
uint8_t key[PUBLIC_ECDA_192_KEYLEN] = {0};
|
||||
param_gethex_to_eol(nxp_mfu_192_public_keys[i].value, 0, key, PUBLIC_ECDA_192_KEYLEN, &dl);
|
||||
|
||||
int res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP192R1, key, uid, 7, signature, signature_len, false);
|
||||
|
||||
is_192_valid = (res == 0);
|
||||
if (is_192_valid)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature"));
|
||||
if (is_valid == false || i == ARRAYLEN(nxp_mfu_public_keys)) {
|
||||
PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp128r1");
|
||||
if (is_192_valid ) {
|
||||
PrintAndLogEx(INFO, " IC signature public key name: " _GREEN_("%s"), nxp_mfu_192_public_keys[i].desc);
|
||||
PrintAndLogEx(INFO, "IC signature public key value: %s", nxp_mfu_192_public_keys[i].value);
|
||||
PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp192r1");
|
||||
PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, signature_len));
|
||||
PrintAndLogEx(SUCCESS, " Signature verification ( " _RED_("fail") " )");
|
||||
return PM3_ESOFT;
|
||||
PrintAndLogEx(SUCCESS, " Signature verification ( " _GREEN_("successful") " )");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
if (is_valid) {
|
||||
PrintAndLogEx(INFO, " IC signature public key name: " _GREEN_("%s"), nxp_mfu_public_keys[i].desc);
|
||||
PrintAndLogEx(INFO, "IC signature public key value: %s", nxp_mfu_public_keys[i].value);
|
||||
PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp128r1");
|
||||
PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, signature_len));
|
||||
PrintAndLogEx(SUCCESS, " Signature verification ( " _GREEN_("successful") " )");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, " Elliptic curve parameters: %s", (signature_len == 48) ? "NID_secp192r1" : "NID_secp128r1" );
|
||||
PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, signature_len));
|
||||
PrintAndLogEx(SUCCESS, " Signature verification ( " _RED_("fail") " )");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
static int ulev1_print_version(uint8_t *data) {
|
||||
|
@ -1641,13 +1674,14 @@ uint32_t GetHF14AMfU_Type(void) {
|
|||
else if (memcmp(version, "\x00\x04\x03\x02\x01\x00\x0B", 7) == 0) { tagtype = MFU_TT_UL_EV1_48; break; }
|
||||
else if (memcmp(version, "\x00\x04\x03\x01\x01\x00\x0E", 7) == 0) { tagtype = MFU_TT_UL_EV1_128; break; }
|
||||
else if (memcmp(version, "\x00\x04\x03\x02\x01\x00\x0E", 7) == 0) { tagtype = MFU_TT_UL_EV1_128; break; }
|
||||
else if (memcmp(version, "\x00\x04\x03\x01\x04\x00\x0F\x03", 8) == 0) { tagtype = MFU_TT_UL_AES; break; }
|
||||
else if (memcmp(version, "\x00\x34\x21\x01\x01\x00\x0E", 7) == 0) { tagtype = MFU_TT_UL_EV1_128; break; } // Mikron JSC Russia EV1 41 pages tag
|
||||
else if (memcmp(version, "\x00\x04\x04\x01\x01\x00\x0B", 7) == 0) { tagtype = MFU_TT_NTAG_210; break; }
|
||||
else if (memcmp(version, "\x00\x04\x04\x01\x02\x00\x0B", 7) == 0) { tagtype = MFU_TT_NTAG_210u; break; }
|
||||
else if (memcmp(version, "\x00\x04\x04\x02\x02\x00\x0B", 7) == 0) { tagtype = MFU_TT_NTAG_210u; break; }
|
||||
else if (memcmp(version, "\x00\x04\x04\x01\x01\x00\x0E", 7) == 0) { tagtype = MFU_TT_NTAG_212; break; }
|
||||
else if (memcmp(version, "\x00\x04\x04\x02\x01\x00\x0F", 7) == 0) { tagtype = MFU_TT_NTAG_213; break; }
|
||||
else if (memcmp(version, "\x00\x53\x04\x02\x01\x00\x0F", 7) == 0) { tagtype = MFU_TT_NTAG_213; break; } //Shanghai Feiju Microelectronics Co. Ltd. China (Xiaomi Air Purifier filter)
|
||||
else if (memcmp(version, "\x00\x53\x04\x02\x01\x00\x0F", 7) == 0) { tagtype = MFU_TT_NTAG_213; break; } // Shanghai Feiju Microelectronics Co. Ltd. China (Xiaomi Air Purifier filter)
|
||||
else if (memcmp(version, "\x00\x04\x04\x02\x01\x01\x0F", 7) == 0) { tagtype = MFU_TT_NTAG_213_C; break; }
|
||||
else if (memcmp(version, "\x00\x04\x04\x02\x01\x00\x11", 7) == 0) { tagtype = MFU_TT_NTAG_215; break; }
|
||||
else if (memcmp(version, "\x00\x04\x04\x02\x01\x00\x13", 7) == 0) { tagtype = MFU_TT_NTAG_216; break; }
|
||||
|
@ -1894,8 +1928,9 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
|
|||
if ((tagtype & (MFU_TT_UL_EV1_48 | MFU_TT_UL_EV1_128 | MFU_TT_UL_EV1 | MFU_TT_UL_NANO_40 |
|
||||
MFU_TT_NTAG_210u | MFU_TT_NTAG_213 | MFU_TT_NTAG_213_F | MFU_TT_NTAG_213_C |
|
||||
MFU_TT_NTAG_213_TT | MFU_TT_NTAG_215 | MFU_TT_NTAG_216 | MFU_TT_NTAG_216_F |
|
||||
MFU_TT_NTAG_I2C_1K | MFU_TT_NTAG_I2C_2K | MFU_TT_NTAG_I2C_1K_PLUS | MFU_TT_NTAG_I2C_2K_PLUS))) {
|
||||
uint8_t ulev1_signature[32] = {0x00};
|
||||
MFU_TT_NTAG_I2C_1K | MFU_TT_NTAG_I2C_2K | MFU_TT_NTAG_I2C_1K_PLUS | MFU_TT_NTAG_I2C_2K_PLUS |
|
||||
MFU_TT_UL_AES))) {
|
||||
uint8_t ulev1_signature[49] = {0x00};
|
||||
status = ulev1_readSignature(ulev1_signature, sizeof(ulev1_signature));
|
||||
if (status == -1) {
|
||||
PrintAndLogEx(ERR, "Error: tag didn't answer to READ SIGNATURE");
|
||||
|
@ -1903,7 +1938,9 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
|
|||
return PM3_ESOFT;
|
||||
}
|
||||
if (status == 32) {
|
||||
ulev1_print_signature(tagtype, card.uid, ulev1_signature, sizeof(ulev1_signature));
|
||||
ulev1_print_signature(tagtype, card.uid, ulev1_signature, 32);
|
||||
} else if (status == 48) {
|
||||
ulev1_print_signature(tagtype, card.uid, ulev1_signature, 48);
|
||||
} else {
|
||||
// re-select
|
||||
if (ul_auth_select(&card, tagtype, has_auth_key, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) {
|
||||
|
|
|
@ -88,6 +88,7 @@ uint32_t ul_ev1_otpgenA(uint8_t *uid);
|
|||
#define MFU_TT_MAGIC_1B (0x20000000ULL | MFU_TT_MAGIC)
|
||||
#define MFU_TT_MAGIC_NTAG (0x40000000ULL | MFU_TT_MAGIC)
|
||||
#define MFU_TT_NTAG_210u 0x80000000ULL
|
||||
#define MFU_TT_UL_AES 0x100000000ULL
|
||||
#define MFU_TT_UL_MAGIC (MFU_TT_UL | MFU_TT_MAGIC)
|
||||
#define MFU_TT_UL_C_MAGIC (MFU_TT_UL_C | MFU_TT_MAGIC)
|
||||
// Don't forget to fill UL_TYPES_ARRAY and UL_MEMORY_ARRAY if new types are added
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue