diff --git a/client/deps/amiitool/key_retail.bin b/client/resources/key_retail.bin similarity index 100% rename from client/deps/amiitool/key_retail.bin rename to client/resources/key_retail.bin diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index a2212005f..2b1631963 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -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) diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c index b8671c4b1..7b877658b 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -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 "); 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; } diff --git a/client/src/cmdhfmf.h b/client/src/cmdhfmf.h index 5325a7956..a4258bc67 100644 --- a/client/src/cmdhfmf.h +++ b/client/src/cmdhfmf.h @@ -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 diff --git a/client/src/crypto/libpcrypto.c b/client/src/crypto/libpcrypto.c index 5c5455bf6..723753d5f 100644 --- a/client/src/crypto/libpcrypto.c +++ b/client/src/crypto/libpcrypto.c @@ -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; } diff --git a/client/src/mifare/mifarehost.c b/client/src/mifare/mifarehost.c index 3df2e295c..c6e02013e 100644 --- a/client/src/mifare/mifarehost.c +++ b/client/src/mifare/mifarehost.c @@ -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; +} \ No newline at end of file diff --git a/client/src/mifare/mifarehost.h b/client/src/mifare/mifarehost.h index 7a3535257..c4c65737a 100644 --- a/client/src/mifare/mifarehost.h +++ b/client/src/mifare/mifarehost.h @@ -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