hf 14a info - add MFC EV1 signature checks

This commit is contained in:
iceman1001 2021-02-19 13:39:35 +01:00
parent 848722f851
commit 9293a25e3e
7 changed files with 126 additions and 58 deletions

View file

@ -1658,7 +1658,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
} else {
// Double & triple sized UID, can be mapped to a manufacturer.
PrintAndLogEx(SUCCESS, "MANUFACTURER: " _YELLOW_("%s"), getTagInfo(card.uid[0]));
PrintAndLogEx(SUCCESS, "MANUFACTURER: " _YELLOW_("%s"), getTagInfo(card.uid[0]));
switch (card.uid[0]) {
case 0x02: // ST
@ -2101,6 +2101,14 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
if (do_nack_test)
detect_classic_nackbug(false);
}
uint8_t signature[32] = {0};
res = detect_mfc_ev1_signature(signature);
if (res == PM3_SUCCESS) {
mfc_ev1_print_signature(card.uid, card.uidlen, signature, sizeof(signature));
}
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf mf`") " commands");
}
if (isMifareUltralight)

View file

@ -27,6 +27,7 @@
#include "des.h" // des ecb
#include "crapto1/crapto1.h" // prng_successor
#include "cmdhf14a.h" // exchange APDU
#include "crypto/libpcrypto.h"
#define MFBLOCK_SIZE 16
@ -425,6 +426,46 @@ static int usage_hf14_gen3freeze(void) {
return PM3_SUCCESS;
}
int mfc_ev1_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signature, int signature_len) {
// ref: MIFARE Classic EV1 Originality Signature Validation
#define PUBLIC_MFCEV1_ECDA_KEYLEN 33
const ecdsa_publickey_t nxp_mfc_public_keys[] = {
{"NXP Mifare Classic MFC1C14_x", "044F6D3F294DEA5737F0F46FFEE88A356EED95695DD7E0C27A591E6F6F65962BAF"},
};
uint8_t i;
bool is_valid = false;
for (i = 0; i < ARRAYLEN(nxp_mfc_public_keys); i++) {
int dl = 0;
uint8_t key[PUBLIC_MFCEV1_ECDA_KEYLEN];
param_gethex_to_eol(nxp_mfc_public_keys[i].value, 0, key, PUBLIC_MFCEV1_ECDA_KEYLEN, &dl);
int res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP128R1, key, uid, uidlen, signature, signature_len, false);
is_valid = (res == 0);
if (is_valid)
break;
}
PrintAndLogEx(INFO, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature"));
if (is_valid == false || i == ARRAYLEN(nxp_mfc_public_keys)) {
PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp128r1");
PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, 32));
PrintAndLogEx(SUCCESS, " Signature verification: " _RED_("failed"));
return PM3_ESOFT;
}
PrintAndLogEx(INFO, " IC signature public key name: %s", nxp_mfc_public_keys[i].desc);
PrintAndLogEx(INFO, "IC signature public key value: %s", nxp_mfc_public_keys[i].value);
PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp128r1");
PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, 32));
PrintAndLogEx(SUCCESS, " Signature verification: " _GREEN_("successful"));
return PM3_SUCCESS;
}
static int GetHFMF14AUID(uint8_t *uid, int *uidlen) {
clearCommandBuffer();
SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT, 0, 0, NULL, 0);
@ -634,14 +675,14 @@ static int CmdHF14AMfWrBl(const char *Cmd) {
PrintAndLogEx(NORMAL, "Usage: hf mf wrbl <block number> <key A/B> <key (12 hex symbols)> <block data (32 hex symbols)>");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " hf mf wrbl 1 A FFFFFFFFFFFF 000102030405060708090A0B0C0D0E0F");
return 0;
return PM3_SUCCESS;
}
blockNo = param_get8(Cmd, 0);
cmdp = tolower(param_getchar(Cmd, 1));
if (cmdp == 0x00) {
PrintAndLogEx(NORMAL, "Key type must be A or B");
return 1;
return PM3_EINVARG;
}
if (cmdp != 'a')
@ -649,12 +690,12 @@ static int CmdHF14AMfWrBl(const char *Cmd) {
if (param_gethex(Cmd, 2, key, 12)) {
PrintAndLogEx(NORMAL, "Key must include 12 HEX symbols");
return 1;
return PM3_EINVARG;
}
if (param_gethex(Cmd, 3, bldata, 32)) {
PrintAndLogEx(NORMAL, "Block data must include 32 HEX symbols");
return 1;
return PM3_EINVARG;
}
PrintAndLogEx(NORMAL, "--block no %d, key %c - %s", blockNo, keyType ? 'B' : 'A', sprint_hex(key, 6));
@ -674,7 +715,7 @@ static int CmdHF14AMfWrBl(const char *Cmd) {
PrintAndLogEx(NORMAL, "Command execute timeout");
}
return 0;
return PM3_SUCCESS;
}
static int CmdHF14AMfRdBl(const char *Cmd) {
@ -706,34 +747,15 @@ static int CmdHF14AMfRdBl(const char *Cmd) {
}
PrintAndLogEx(NORMAL, "--block no %d, key %c - %s", blockNo, keyType ? 'B' : 'A', sprint_hex(key, 6));
mf_readblock_t payload;
payload.blockno = blockNo;
payload.keytype = keyType;
memcpy(payload.key, key, sizeof(payload.key));
clearCommandBuffer();
SendCommandNG(CMD_HF_MIFARE_READBL, (uint8_t *)&payload, sizeof(mf_readblock_t));
PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500)) {
uint8_t *data = resp.data.asBytes;
if (resp.status == PM3_SUCCESS) {
PrintAndLogEx(NORMAL, "data: %s", sprint_hex(data, 16));
} else {
PrintAndLogEx(FAILED, "failed reading block");
return PM3_ESOFT;
}
uint8_t data[16] = {0};
int res = mfReadBlock(blockNo, keyType, key, data);
if (res == PM3_SUCCESS) {
PrintAndLogEx(SUCCESS, "data: %s", sprint_hex(data, 16));
if ((data[6] || data[7] || data[8])) {
decode_print_st(blockNo, data);
}
} else {
PrintAndLogEx(WARNING, "Command execute timeout");
return PM3_ETIMEOUT;
}
return 0;
return PM3_SUCCESS;
}
static int CmdHF14AMfRdSc(const char *Cmd) {
@ -769,30 +791,26 @@ static int CmdHF14AMfRdSc(const char *Cmd) {
}
PrintAndLogEx(NORMAL, "--sector no %d, key %c - %s ", sectorNo, keyType ? 'B' : 'A', sprint_hex(key, 6));
clearCommandBuffer();
SendCommandMIX(CMD_HF_MIFARE_READSC, sectorNo, keyType, 0, key, 6);
PrintAndLogEx(NORMAL, "");
PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
uint8_t isOK = resp.oldarg[0] & 0xff;
uint8_t *data = resp.data.asBytes;
PrintAndLogEx(NORMAL, "isOk:%02x", isOK);
if (isOK) {
uint8_t blocks = NumBlocksPerSector(sectorNo);
uint8_t start = FirstBlockOfSector(sectorNo);
for (int i = 0; i < blocks; i++) {
PrintAndLogEx(NORMAL, "%3d | %s", start + i, sprint_hex(data + (i * 16), 16));
}
decode_print_st(start + blocks - 1, data + ((blocks - 1) * 16));
}
} else {
PrintAndLogEx(WARNING, "Command execute timeout");
uint8_t sc_size = mfNumBlocksPerSector(sectorNo) * 16;
uint8_t *data = calloc(sc_size, sizeof(uint8_t));
if (data == NULL) {
PrintAndLogEx(ERR, "failed to allocate memory");
return PM3_EMALLOC;
}
int res = mfReadSector(sectorNo, keyType, key, data);
if (res == PM3_SUCCESS) {
uint8_t blocks = NumBlocksPerSector(sectorNo);
uint8_t start = FirstBlockOfSector(sectorNo);
for (int i = 0; i < blocks; i++) {
PrintAndLogEx(NORMAL, "%3d | %s", start + i, sprint_hex(data + (i * 16), 16));
}
decode_print_st(start + blocks - 1, data + ((blocks - 1) * 16));
}
free(data);
return PM3_SUCCESS;
}

View file

@ -24,4 +24,6 @@ void readerAttack(sector_t *k_sector, uint8_t k_sectorsCount, nonces_t data, boo
void printKeyTable(uint8_t sectorscnt, sector_t *e_sector);
void printKeyTableEx(uint8_t sectorscnt, sector_t *e_sector, uint8_t start_sector);
void printKeyTable_fast(uint8_t sectorscnt, icesector_t *e_sector, uint64_t bar, uint64_t foo);
int mfc_ev1_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signature, int signature_len);
#endif

View file

@ -384,9 +384,8 @@ int ecdsa_signature_verify(mbedtls_ecp_group_id curveid, uint8_t *key_xy, uint8_
// take signature bytes, converts to ASN1 signature and tries to verify
int ecdsa_signature_r_s_verify(mbedtls_ecp_group_id curveid, uint8_t *key_xy, uint8_t *input, int length, uint8_t *r_s, size_t r_s_len, bool hash) {
int res;
uint8_t signature[MBEDTLS_ECDSA_MAX_LEN];
size_t signature_len;
uint8_t signature[MBEDTLS_ECDSA_MAX_LEN] = {0};
size_t signature_len = 0;
// convert r & s to ASN.1 signature
mbedtls_mpi r, s;
@ -395,7 +394,7 @@ int ecdsa_signature_r_s_verify(mbedtls_ecp_group_id curveid, uint8_t *key_xy, ui
mbedtls_mpi_read_binary(&r, r_s, r_s_len / 2);
mbedtls_mpi_read_binary(&s, r_s + r_s_len / 2, r_s_len / 2);
res = ecdsa_signature_to_asn1(&r, &s, signature, &signature_len);
int res = ecdsa_signature_to_asn1(&r, &s, signature, &signature_len);
if (res < 0) {
return res;
}

View file

@ -748,7 +748,6 @@ int mfReadSector(uint8_t sectorNo, uint8_t keyType, uint8_t *key, uint8_t *data)
clearCommandBuffer();
SendCommandMIX(CMD_HF_MIFARE_READSC, sectorNo, keyType, 0, key, 6);
PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
uint8_t isOK = resp.oldarg[0] & 0xff;
@ -760,10 +759,33 @@ int mfReadSector(uint8_t sectorNo, uint8_t keyType, uint8_t *key, uint8_t *data)
return PM3_EUNDEF;
}
} else {
PrintAndLogEx(ERR, "Command execute timeout");
PrintAndLogEx(DEBUG, "Command execute timeout");
return PM3_ETIMEOUT;
}
return PM3_SUCCESS;
}
int mfReadBlock(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t *data) {
mf_readblock_t payload = {
.blockno = blockNo,
.keytype = keyType
};
memcpy(payload.key, key, sizeof(payload.key));
clearCommandBuffer();
SendCommandNG(CMD_HF_MIFARE_READBL, (uint8_t *)&payload, sizeof(mf_readblock_t));
PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500)) {
memcpy(data, resp.data.asBytes, 16);
if (resp.status != PM3_SUCCESS) {
PrintAndLogEx(DEBUG, "failed reading block");
return PM3_ESOFT;
}
} else {
PrintAndLogEx(DEBUG, "Command execute timeout");
return PM3_ETIMEOUT;
}
return PM3_SUCCESS;
}
@ -1196,3 +1218,19 @@ int detect_mf_magic(bool is_mfc) {
}
return isGeneration;
}
int detect_mfc_ev1_signature(uint8_t *signature) {
if (signature == NULL) {
return PM3_EINVARG;
}
uint8_t sign[32] = {0};
uint8_t key[] = {0x4b, 0x79, 0x1b, 0xea, 0x7b, 0xcc};
int res = mfReadBlock(69, 1, key, sign);
if ( res == PM3_SUCCESS) {
res = mfReadBlock(70, 1, key, sign + 16);
if (res == PM3_SUCCESS) {
memcpy(signature, sign, sizeof(sign));
}
}
return res;
}

View file

@ -70,6 +70,7 @@ int mfCheckKeys_file(uint8_t *destfn, uint64_t *key);
int mfKeyBrute(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint64_t *resultkey);
int mfReadSector(uint8_t sectorNo, uint8_t keyType, uint8_t *key, uint8_t *data);
int mfReadBlock(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t *data);
int mfEmlGetMem(uint8_t *data, int blockNum, int blocksCount);
int mfEmlSetMem(uint8_t *data, int blockNum, int blocksCount);
@ -90,5 +91,7 @@ int detect_classic_prng(void);
int detect_classic_nackbug(bool verbose);
int detect_mf_magic(bool is_mfc);
int detect_classic_static_nonce(void);
int detect_mfc_ev1_signature(uint8_t *signature);
void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *data, int len, bool isEncrypted);
#endif