mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-19 21:03:48 -07:00
add: hf mf personlize - Personalize the UID of a Mifare Classic EV1 card (@pwpiwi) see 0b4efbdef2
This commit is contained in:
parent
b5aad6759c
commit
074f6c374e
6 changed files with 171 additions and 6 deletions
|
@ -42,6 +42,7 @@
|
||||||
#include "Standalone/standalone.h"
|
#include "Standalone/standalone.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "ticks.h"
|
#include "ticks.h"
|
||||||
|
#include "commonutil.h"
|
||||||
|
|
||||||
#ifdef WITH_LCD
|
#ifdef WITH_LCD
|
||||||
#include "LCD.h"
|
#include "LCD.h"
|
||||||
|
@ -1247,6 +1248,17 @@ static void PacketReceived(PacketCommandNG *packet) {
|
||||||
// SniffMifare(packet->oldarg[0]);
|
// SniffMifare(packet->oldarg[0]);
|
||||||
// break;
|
// break;
|
||||||
// }
|
// }
|
||||||
|
case CMD_HF_MIFARE_PERSONALIZE_UID: {
|
||||||
|
struct p {
|
||||||
|
uint8_t keytype;
|
||||||
|
uint8_t pers_option;
|
||||||
|
uint8_t key[6];
|
||||||
|
} PACKED;
|
||||||
|
struct p *payload = (struct p *) packet->data.asBytes;
|
||||||
|
uint64_t authkey = bytes_to_num(payload->key, 6);
|
||||||
|
MifarePersonalizeUID(payload->keytype, payload->pers_option, authkey);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case CMD_HF_MIFARE_SETMOD: {
|
case CMD_HF_MIFARE_SETMOD: {
|
||||||
MifareSetMod(packet->data.asBytes);
|
MifareSetMod(packet->data.asBytes);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1805,6 +1805,63 @@ void MifareChkKeys_file(uint8_t *fn) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// MIFARE Personalize UID. Only for Mifare Classic EV1 7Byte UID
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
void MifarePersonalizeUID(uint8_t keyType, uint8_t perso_option, uint64_t key) {
|
||||||
|
|
||||||
|
uint16_t isOK = PM3_EUNDEF;
|
||||||
|
uint8_t uid[10];
|
||||||
|
uint32_t cuid;
|
||||||
|
struct Crypto1State mpcs = {0, 0};
|
||||||
|
struct Crypto1State *pcs;
|
||||||
|
pcs = &mpcs;
|
||||||
|
|
||||||
|
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
|
||||||
|
clear_trace();
|
||||||
|
set_tracing(true);
|
||||||
|
|
||||||
|
LED_A_ON();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
|
||||||
|
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t block_number = 0;
|
||||||
|
if (mifare_classic_auth(pcs, cuid, block_number, keyType, key, AUTH_FIRST)) {
|
||||||
|
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Auth error");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE];
|
||||||
|
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE];
|
||||||
|
int len = mifare_sendcmd_short(pcs, true, MIFARE_EV1_PERSONAL_UID, perso_option, receivedAnswer, receivedAnswerPar, NULL);
|
||||||
|
if (len != 1 || receivedAnswer[0] != CARD_ACK) {
|
||||||
|
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
|
||||||
|
break;;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mifare_classic_halt(pcs, cuid)) {
|
||||||
|
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Halt error");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
isOK = PM3_SUCCESS;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto1_deinit(pcs);
|
||||||
|
|
||||||
|
LED_B_ON();
|
||||||
|
reply_ng(CMD_HF_MIFARE_PERSONALIZE_UID, isOK, NULL, 0);
|
||||||
|
LED_B_OFF();
|
||||||
|
|
||||||
|
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||||
|
LEDsoff();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Work with emulator memory
|
// Work with emulator memory
|
||||||
//
|
//
|
||||||
|
@ -2276,23 +2333,23 @@ void MifareSetMod(uint8_t *datain) {
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
|
if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
|
||||||
if (DBGLEVEL >= 1) Dbprintf("Can't select card");
|
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mifare_classic_auth(pcs, cuid, 0, 0, ui64Key, AUTH_FIRST)) {
|
if (mifare_classic_auth(pcs, cuid, 0, 0, ui64Key, AUTH_FIRST)) {
|
||||||
if (DBGLEVEL >= 1) Dbprintf("Auth error");
|
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Auth error");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
int respLen;
|
int respLen;
|
||||||
if (((respLen = mifare_sendcmd_short(pcs, CRYPT_ALL, 0x43, mod, receivedAnswer, receivedAnswerPar, NULL)) != 1) || (receivedAnswer[0] != 0x0a)) {
|
if (((respLen = mifare_sendcmd_short(pcs, CRYPT_ALL, 0x43, mod, receivedAnswer, receivedAnswerPar, NULL)) != 1) || (receivedAnswer[0] != 0x0a)) {
|
||||||
if (DBGLEVEL >= 1) Dbprintf("SetMod error; response[0]: %hhX, len: %d", receivedAnswer[0], respLen);
|
if (DBGLEVEL >= DBG_ERROR) Dbprintf("SetMod error; response[0]: %hhX, len: %d", receivedAnswer[0], respLen);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mifare_classic_halt(pcs, cuid)) {
|
if (mifare_classic_halt(pcs, cuid)) {
|
||||||
if (DBGLEVEL >= 1) Dbprintf("Halt error");
|
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Halt error");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2304,7 +2361,6 @@ void MifareSetMod(uint8_t *datain) {
|
||||||
|
|
||||||
LED_B_ON();
|
LED_B_ON();
|
||||||
reply_ng(CMD_HF_MIFARE_SETMOD, isOK, NULL, 0);
|
reply_ng(CMD_HF_MIFARE_SETMOD, isOK, NULL, 0);
|
||||||
|
|
||||||
LED_B_OFF();
|
LED_B_OFF();
|
||||||
|
|
||||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||||
|
|
|
@ -45,6 +45,8 @@ void MifareCIdent(); // is "magic chinese" card?
|
||||||
void MifareHasStaticNonce(); // Has the tag a static nonce?
|
void MifareHasStaticNonce(); // Has the tag a static nonce?
|
||||||
|
|
||||||
void MifareSetMod(uint8_t *datain);
|
void MifareSetMod(uint8_t *datain);
|
||||||
|
void MifarePersonalizeUID(uint8_t keyType, uint8_t perso_option, uint64_t key);
|
||||||
|
|
||||||
void MifareUSetPwd(uint8_t arg0, uint8_t *datain);
|
void MifareUSetPwd(uint8_t arg0, uint8_t *datain);
|
||||||
void OnSuccessMagic();
|
void OnSuccessMagic();
|
||||||
void OnErrorMagic(uint8_t reason);
|
void OnErrorMagic(uint8_t reason);
|
||||||
|
|
|
@ -4798,6 +4798,95 @@ static int CmdHFMFNDEF(const char *Cmd) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int CmdHFMFPersonalize(const char *cmd) {
|
||||||
|
|
||||||
|
CLIParserInit("hf mf personalize",
|
||||||
|
"Personalize the UID of a Mifare Classic EV1 card. This is only possible if it is a 7Byte UID card and if it is not already personalized.",
|
||||||
|
"Usage:\n\thf mf personalize UIDF0 -> double size UID according to ISO/IEC14443-3\n"
|
||||||
|
"\thf mf personalize UIDF1 -> double size UID according to ISO/IEC14443-3, optional usage of selection process shortcut\n"
|
||||||
|
"\thf mf personalize UIDF2 -> single size random ID according to ISO/IEC14443-3\n"
|
||||||
|
"\thf mf personalize UIDF3 -> single size NUID according to ISO/IEC14443-3\n"
|
||||||
|
"\thf mf personalize -t B -k B0B1B2B3B4B5 UIDF3 -> use key B = 0xB0B1B2B3B4B5 instead of default key A\n");
|
||||||
|
|
||||||
|
void *argtable[] = {
|
||||||
|
arg_param_begin,
|
||||||
|
arg_str0("tT", "keytype", "<A|B>", "key type (A or B) to authenticate sector 0 (default: A)"),
|
||||||
|
arg_str0("kK", "key", "<key (hex 6 Bytes)>", "key to authenticate sector 0 (default: FFFFFFFFFFFF)"),
|
||||||
|
arg_str1(NULL, NULL, "<UIDF0|UIDF1|UIDF2|UIDF3>", "Personalization Option"),
|
||||||
|
arg_param_end
|
||||||
|
};
|
||||||
|
CLIExecWithReturn(cmd, argtable, true);
|
||||||
|
|
||||||
|
char keytypestr[2] = "a";
|
||||||
|
uint8_t keytype = 0x00;
|
||||||
|
int keytypestr_len;
|
||||||
|
int res = CLIParamStrToBuf(arg_get_str(1), (uint8_t*)keytypestr, 1, &keytypestr_len);
|
||||||
|
str_lower(keytypestr);
|
||||||
|
|
||||||
|
if (res || (keytypestr[0] != 'a' && keytypestr[0] != 'b')) {
|
||||||
|
PrintAndLogEx(ERR, "ERROR: not a valid key type. Key type must be A or B");
|
||||||
|
CLIParserFree();
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
if (keytypestr[0] == 'b') {
|
||||||
|
keytype = 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t key[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||||
|
int key_len;
|
||||||
|
res = CLIParamHexToBuf(arg_get_str(2), key, 6, &key_len);
|
||||||
|
if (res || (!res && key_len > 0 && key_len != 6)) {
|
||||||
|
PrintAndLogEx(ERR, "ERROR: not a valid key. Key must be 12 hex digits");
|
||||||
|
CLIParserFree();
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
char pers_optionstr[6];
|
||||||
|
int opt_len;
|
||||||
|
uint8_t pers_option;
|
||||||
|
res = CLIParamStrToBuf(arg_get_str(3), (uint8_t*)pers_optionstr, 5, &opt_len);
|
||||||
|
str_lower(pers_optionstr);
|
||||||
|
|
||||||
|
if (res || (!res && opt_len > 0 && opt_len != 5)
|
||||||
|
|| (strncmp(pers_optionstr, "uidf0", 5) && strncmp(pers_optionstr, "uidf1", 5) && strncmp(pers_optionstr, "uidf2", 5) && strncmp(pers_optionstr, "uidf3", 5))) {
|
||||||
|
PrintAndLogEx(ERR, "ERROR: invalid personalization option. Must be one of UIDF0, UIDF1, UIDF2, or UIDF3");
|
||||||
|
CLIParserFree();
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
if (!strncmp(pers_optionstr, "uidf0", 5)) {
|
||||||
|
pers_option = MIFARE_EV1_UIDF0;
|
||||||
|
} else if (!strncmp(pers_optionstr, "uidf1", 5)) {
|
||||||
|
pers_option = MIFARE_EV1_UIDF1;
|
||||||
|
} else if (!strncmp(pers_optionstr, "uidf2", 5)) {
|
||||||
|
pers_option = MIFARE_EV1_UIDF2;
|
||||||
|
} else {
|
||||||
|
pers_option = MIFARE_EV1_UIDF3;
|
||||||
|
}
|
||||||
|
|
||||||
|
CLIParserFree();
|
||||||
|
|
||||||
|
clearCommandBuffer();
|
||||||
|
|
||||||
|
struct {
|
||||||
|
uint8_t keytype;
|
||||||
|
uint8_t pers_option;
|
||||||
|
uint8_t key[6];
|
||||||
|
} PACKED payload;
|
||||||
|
payload.keytype = keytype;
|
||||||
|
payload.pers_option = pers_option;
|
||||||
|
|
||||||
|
memcpy(payload.key, key, 6);
|
||||||
|
|
||||||
|
SendCommandNG(CMD_HF_MIFARE_PERSONALIZE_UID, (uint8_t *)&payload, sizeof(payload));
|
||||||
|
|
||||||
|
PacketResponseNG resp;
|
||||||
|
if (!WaitForResponseTimeout(CMD_HF_MIFARE_PERSONALIZE_UID, &resp, 2500)) return PM3_ETIMEOUT;
|
||||||
|
|
||||||
|
PrintAndLogEx(SUCCESS, "Personalization %s", resp.status == PM3_SUCCESS ? "SUCCEEDED" : "FAILED");
|
||||||
|
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static int CmdHF14AMfList(const char *Cmd) {
|
static int CmdHF14AMfList(const char *Cmd) {
|
||||||
(void)Cmd; // Cmd is not used so far
|
(void)Cmd; // Cmd is not used so far
|
||||||
return CmdTraceList("mf");
|
return CmdTraceList("mf");
|
||||||
|
@ -4845,7 +4934,7 @@ static command_t CommandTable[] = {
|
||||||
{"-----------", CmdHelp, IfPm3Iso14443a, ""},
|
{"-----------", CmdHelp, IfPm3Iso14443a, ""},
|
||||||
{"mad", CmdHF14AMfMAD, IfPm3Iso14443a, "Checks and prints MAD"},
|
{"mad", CmdHF14AMfMAD, IfPm3Iso14443a, "Checks and prints MAD"},
|
||||||
{"ndef", CmdHFMFNDEF, IfPm3Iso14443a, "Prints NDEF records from card"},
|
{"ndef", CmdHFMFNDEF, IfPm3Iso14443a, "Prints NDEF records from card"},
|
||||||
|
{"personalize", CmdHFMFPersonalize, IfPm3Iso14443a, "Personalize UID (Mifare Classic EV1 only)"},
|
||||||
{"ice", CmdHF14AMfice, IfPm3Iso14443a, "collect MIFARE Classic nonces to file"},
|
{"ice", CmdHF14AMfice, IfPm3Iso14443a, "collect MIFARE Classic nonces to file"},
|
||||||
{NULL, NULL, NULL, NULL}
|
{NULL, NULL, NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
|
@ -505,6 +505,8 @@ typedef struct {
|
||||||
|
|
||||||
#define CMD_HF_MIFARE_SNIFF 0x0630
|
#define CMD_HF_MIFARE_SNIFF 0x0630
|
||||||
#define CMD_HF_MIFARE_MFKEY 0x0631
|
#define CMD_HF_MIFARE_MFKEY 0x0631
|
||||||
|
#define CMD_HF_MIFARE_PERSONALIZE_UID 0x0632
|
||||||
|
|
||||||
//ultralightC
|
//ultralightC
|
||||||
#define CMD_HF_MIFAREUC_AUTH 0x0724
|
#define CMD_HF_MIFAREUC_AUTH 0x0724
|
||||||
//0x0725 and 0x0726 no longer used
|
//0x0725 and 0x0726 no longer used
|
||||||
|
|
|
@ -163,6 +163,10 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
|
||||||
|
|
||||||
#define MIFARE_EV1_PERSONAL_UID 0x40
|
#define MIFARE_EV1_PERSONAL_UID 0x40
|
||||||
#define MIFARE_EV1_SETMODE 0x43
|
#define MIFARE_EV1_SETMODE 0x43
|
||||||
|
#define MIFARE_EV1_UIDF0 0x00
|
||||||
|
#define MIFARE_EV1_UIDF1 0x40
|
||||||
|
#define MIFARE_EV1_UIDF2 0x20
|
||||||
|
#define MIFARE_EV1_UIDF3 0x60
|
||||||
|
|
||||||
#define MIFARE_ULC_WRITE 0xA2
|
#define MIFARE_ULC_WRITE 0xA2
|
||||||
#define MIFARE_ULC_COMP_WRITE 0xA0
|
#define MIFARE_ULC_COMP_WRITE 0xA0
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue