hf mfu setkey: supports ulc/ulaes auth and ulaes schann

This commit is contained in:
Philippe Teuwen
2026-02-09 01:08:23 +01:00
parent a2ba91043f
commit 9f70011fee
6 changed files with 139 additions and 64 deletions
+1 -1
View File
@@ -1877,7 +1877,7 @@ static void PacketReceived(PacketCommandNG *packet) {
break;
}
case CMD_HF_MIFAREU_SETKEY: {
MifareUSetKey(packet->oldarg[0], packet->data.asBytes);
MifareUSetKey((mful_setkey_t *)packet->data.asBytes);
break;
}
case CMD_HF_MIFARE_READSC: {
+1 -1
View File
@@ -3441,7 +3441,7 @@ int iso14443a_fast_select_card(const uint8_t *uid_ptr, uint8_t num_cascades) {
}
void iso14443a_setup(uint8_t fpga_minor_mode) {
set_session_channel(false);
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
// Set up the synchronous serial port
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_ISO14443A);
+30 -21
View File
@@ -856,15 +856,7 @@ void MifareUWriteBlockCompat(mful_writeblock_t *packet) {
set_tracing(false);
}
void MifareUSetKey(uint8_t arg0, uint8_t *datain) {
uint8_t key[16] = {0x00};
if (arg0 < 1 || arg0 > 3) {
OnError(0);
return;
}
memcpy(key, datain, 16);
void MifareUSetKey(mful_setkey_t *packet) {
LED_A_ON();
LED_B_OFF();
@@ -880,34 +872,51 @@ void MifareUSetKey(uint8_t arg0, uint8_t *datain) {
return;
};
bool useCKey = (packet->keytype == 1); // UL_C
bool useAESKey = (packet->keytype == 3); // UL_AES
uint8_t start_block = 4; // just to be safe
switch (arg0) {
case 1: // UL-C
start_block = 44;
break;
case 2: // UL-AES DataProtKey
if (useCKey) { // UL-C
start_block = 44;
} else if (useAESKey) { // UL-AES
if (packet->key_index == 0) { // UL-AES DataProtKey
start_block = 48;
break;
case 3: // UL-AES UIDRetrKey
} else if (packet->key_index == 1) { // UL-AES UIDRetrKey
start_block = 52;
break;
}
}
// UL-C authentication
if (useCKey && packet->has_auth_key) {
if (mifare_ultra_3des_auth(packet->auth_key, true) == 0) {
OnErrorNG(CMD_HF_MIFAREU_SETKEY, PM3_ESOFT);
return;
}
}
// UL-AES authentication
if (useAESKey && packet->has_auth_key) {
if (mifare_ultra_aes_auth(0, packet->auth_key, packet->use_schann, true) == 0) {
OnErrorNG(CMD_HF_MIFAREU_SETKEY, PM3_ESOFT);
return;
}
}
for (int i = 0; i < 4; i++) {
if (mifare_ultra_writeblock(start_block + i, key + (i * 4)) != PM3_SUCCESS) {
if (mifare_ultra_writeblock(start_block + i, packet->key + (i * 4)) != PM3_SUCCESS) {
if (g_dbglevel >= DBG_INFO) Dbprintf("Write block error");
OnError(start_block + i);
OnErrorNG(CMD_HF_MIFAREU_SETKEY, PM3_ESOFT);
return;
};
}
if (mifare_ultra_halt()) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Halt error");
OnError(0);
OnErrorNG(CMD_HF_MIFAREU_SETKEY, PM3_ESOFT);
return;
};
reply_mix(CMD_ACK, 1, 0, 0, 0, 0);
reply_ng(CMD_HF_MIFAREU_SETKEY, PM3_SUCCESS, NULL, 0);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
set_tracing(false);
+1 -1
View File
@@ -67,7 +67,7 @@ void MifareG4WriteBlk(uint8_t blockno, uint8_t *pwd, uint8_t *data, uint8_t work
void MifareSetMod(uint8_t *datain);
void MifarePersonalizeUID(uint8_t keyType, uint8_t perso_option, uint64_t key);
void MifareUSetKey(uint8_t arg0, uint8_t *datain);
void MifareUSetKey(mful_setkey_t *packet);
void OnSuccessMagic(void);
void OnErrorMagic(uint8_t reason);
+97 -40
View File
@@ -4927,6 +4927,8 @@ static int CmdHF14AMfUSetKey(const char *Cmd) {
arg_str0("k", "key", "<hex>", "New key (16 hex bytes)"),
arg_int0("i", "idx", "<0..1>", "New key index (def: 0), only for UL-AES"),
arg_lit0("l", NULL, "Swap entered keys' endianness"),
arg_str0(NULL, "usekey", "<hex>", "Current UL-C 3DES or UL-AES DataProt key (16 hex bytes)"),
arg_lit0(NULL, "schann", "use secure channel. Must have usekey"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
@@ -4937,6 +4939,11 @@ static int CmdHF14AMfUSetKey(const char *Cmd) {
CLIGetHexWithReturn(ctx, 1, authenticationkey, &ak_len);
int key_index = arg_get_int_def(ctx, 2, 0);
bool swap_endian = arg_get_lit(ctx, 3);
int use_ak_len = 0;
uint8_t use_authenticationkey[16] = {0x00};
uint8_t *use_auth_key_ptr = use_authenticationkey;
CLIGetHexWithReturn(ctx, 4, use_authenticationkey, &use_ak_len);
bool use_schann = arg_get_lit(ctx, 5);
CLIParserFree(ctx);
if (ak_len != 16) {
@@ -4948,6 +4955,19 @@ static int CmdHF14AMfUSetKey(const char *Cmd) {
return PM3_EINVARG;
}
bool has_auth_key = false;
if (use_ak_len == 16) {
has_auth_key = true;
} else if (use_ak_len != 0) {
PrintAndLogEx(WARNING, "usekey must be 16 hex bytes\n");
return PM3_EINVARG;
}
if (use_schann && has_auth_key == false) {
PrintAndLogEx(WARNING, "Secure channel must be called with usekey");
return PM3_EINVARG;
}
uint64_t tagtype = GetHF14AMfU_Type();
if (tagtype == MFU_TT_UL_ERROR) {
return PM3_ESOFT;
@@ -4968,25 +4988,49 @@ static int CmdHF14AMfUSetKey(const char *Cmd) {
}
}
clearCommandBuffer();
if ((tagtype & MFU_TT_UL_C) == MFU_TT_UL_C) {
SendCommandMIX(CMD_HF_MIFAREU_SETKEY, 1, 0, 0, auth_key_ptr, sizeof(authenticationkey));
} else if ((tagtype & MFU_TT_UL_AES) == MFU_TT_UL_AES) {
SendCommandMIX(CMD_HF_MIFAREU_SETKEY, key_index + 2, 0, 0, auth_key_ptr, sizeof(authenticationkey));
// Swap endianness of usekey
if (swap_endian) {
if (use_ak_len == 16) {
if (((tagtype & MFU_TT_UL_C) == MFU_TT_UL_C)) {
use_auth_key_ptr = SwapEndian64(use_authenticationkey, use_ak_len, 8);
} else if (((tagtype & MFU_TT_UL_AES) == MFU_TT_UL_AES)) {
use_auth_key_ptr = SwapEndian64(use_authenticationkey, use_ak_len, 16);
}
}
}
PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
if ((resp.oldarg[0] & 0xff) == 1) {
PrintAndLogEx(INFO, "New key... " _GREEN_("%s"), sprint_hex_inrow(authenticationkey, sizeof(authenticationkey)));
} else {
PrintAndLogEx(WARNING, "Failed writing at block %u", (uint8_t)(resp.oldarg[1] & 0xFF));
return PM3_ESOFT;
if (has_auth_key) {
if (((tagtype & MFU_TT_UL_C) == MFU_TT_UL_C)) {
PrintAndLogEx(INFO, "Using 3des... " _GREEN_("%s"), sprint_hex_inrow(use_authenticationkey, use_ak_len));
} else if (((tagtype & MFU_TT_UL_AES) == MFU_TT_UL_AES)) {
PrintAndLogEx(INFO, "Using aes... " _GREEN_("%s"), sprint_hex_inrow(use_authenticationkey, use_ak_len));
}
} else {
PrintAndLogEx(WARNING, "command execution time out");
}
mful_setkey_t packet = {
.has_auth_key = has_auth_key,
.use_schann = use_schann,
.key_index = key_index,
.keytype = ((tagtype & MFU_TT_UL_C) == MFU_TT_UL_C) ? 1 : 3, // 1=ULC 3=ULAES
};
if (has_auth_key) {
memcpy(packet.auth_key, use_auth_key_ptr, 16);
}
memcpy(packet.key, auth_key_ptr, 16);
clearCommandBuffer();
PacketResponseNG resp;
SendCommandNG(CMD_HF_MIFAREU_SETKEY, (uint8_t *)&packet, sizeof(packet));
if (WaitForResponseTimeout(CMD_HF_MIFAREU_SETKEY, &resp, 1500) == false) {
return PM3_ETIMEOUT;
}
if (resp.status == PM3_SUCCESS) {
PrintAndLogEx(INFO, "New key... " _GREEN_("%s"), sprint_hex_inrow(authenticationkey, sizeof(authenticationkey)));
} else {
PrintAndLogEx(WARNING, "Failed writing key");
return PM3_ESOFT;
}
return PM3_SUCCESS;
}
@@ -6770,6 +6814,13 @@ static int CmdHF14AMfuWipe(const char *Cmd) {
PrintAndLogEx(INFO, "-----+-----------------------------");
mful_setkey_t packet = {
.has_auth_key = false,
.use_schann = false,
.key_index = 0,
};
PacketResponseNG resp;
ulc:
// UL-C - set 3-DES key
@@ -6780,21 +6831,21 @@ ulc:
0x21, 0x4E, 0x41, 0x43, 0x55, 0x4F, 0x59, 0x46
};
uint8_t *def_key_ptr = SwapEndian64(defaultkey, 16, 8);
packet.keytype = 1; // UL-C
memcpy(packet.key, def_key_ptr, 16);
clearCommandBuffer();
SendCommandMIX(CMD_HF_MIFAREU_SETKEY, 1, 0, 0, def_key_ptr, sizeof(defaultkey));
PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
if ((resp.oldarg[0] & 0xff) == 1) {
PrintAndLogEx(INFO, "Ultralight C new key... " _GREEN_("%s"), sprint_hex_inrow(defaultkey, sizeof(defaultkey)));
} else {
PrintAndLogEx(WARNING, "Failed writing at block %u", (uint8_t)(resp.oldarg[1] & 0xFF));
return PM3_ESOFT;
}
} else {
SendCommandNG(CMD_HF_MIFAREU_SETKEY, (uint8_t *)&packet, sizeof(packet));
if (WaitForResponseTimeout(CMD_HF_MIFAREU_SETKEY, &resp, 1500) == false) {
PrintAndLogEx(WARNING, "command execution time out");
return PM3_ETIMEOUT;
}
if (resp.status == PM3_SUCCESS) {
PrintAndLogEx(INFO, "Ultralight C new key... " _GREEN_("%s"), sprint_hex_inrow(defaultkey, sizeof(defaultkey)));
} else {
PrintAndLogEx(WARNING, "Failed writing key");
return PM3_ESOFT;
}
}
ulaes:
@@ -6803,30 +6854,36 @@ ulaes:
// Set AES keys
uint8_t defaultkey[16] = { 0 };
uint8_t *def_key_ptr = SwapEndian64(defaultkey, 16, 16);
packet.keytype = 3; // UL-AES
packet.key_index = 0;
memcpy(packet.key, def_key_ptr, 16);
clearCommandBuffer();
SendCommandMIX(CMD_HF_MIFAREU_SETKEY, 2, 0, 0, def_key_ptr, sizeof(defaultkey));
PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
if ((resp.oldarg[0] & 0xff) != 1) {
PrintAndLogEx(WARNING, "Failed writing at block %u", (uint8_t)(resp.oldarg[1] & 0xFF));
}
} else {
SendCommandNG(CMD_HF_MIFAREU_SETKEY, (uint8_t *)&packet, sizeof(packet));
if (WaitForResponseTimeout(CMD_HF_MIFAREU_SETKEY, &resp, 1500) == false) {
PrintAndLogEx(WARNING, "command execution time out");
return PM3_ETIMEOUT;
}
clearCommandBuffer();
SendCommandMIX(CMD_HF_MIFAREU_SETKEY, 3, 0, 0, def_key_ptr, sizeof(defaultkey));
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
if ((resp.oldarg[0] & 0xff) == 1) {
PrintAndLogEx(INFO, "Ultralight AES new key... " _GREEN_("%s"), sprint_hex_inrow(defaultkey, sizeof(defaultkey)));
} else {
PrintAndLogEx(WARNING, "Failed writing at block %u", (uint8_t)(resp.oldarg[1] & 0xFF));
return PM3_ESOFT;
}
if (resp.status == PM3_SUCCESS) {
PrintAndLogEx(INFO, "Ultralight AES new DataProtKey... " _GREEN_("%s"), sprint_hex_inrow(defaultkey, sizeof(defaultkey)));
} else {
PrintAndLogEx(WARNING, "Failed writing key");
return PM3_ESOFT;
}
packet.key_index = 1;
clearCommandBuffer();
SendCommandNG(CMD_HF_MIFAREU_SETKEY, (uint8_t *)&packet, sizeof(packet));
if (WaitForResponseTimeout(CMD_HF_MIFAREU_SETKEY, &resp, 1500) == false) {
PrintAndLogEx(WARNING, "command execution time out");
return PM3_ETIMEOUT;
}
if (resp.status == PM3_SUCCESS) {
PrintAndLogEx(INFO, "Ultralight AES new UIDRetrKey... " _GREEN_("%s"), sprint_hex_inrow(defaultkey, sizeof(defaultkey)));
} else {
PrintAndLogEx(WARNING, "Failed writing key");
return PM3_ESOFT;
}
}
+9
View File
@@ -414,6 +414,15 @@ typedef struct {
uint8_t data[16];
} PACKED mful_writeblock_t;
typedef struct {
bool has_auth_key;
bool use_schann;
uint8_t auth_key[16];
uint8_t keytype;
uint8_t key_index;
uint8_t key[16];
} PACKED mful_setkey_t;
typedef struct {
uint8_t status;
uint8_t CSN[8];