ulaes: add verify_cmac, display counters in mfu info, fix sig when schann in mfu info

This commit is contained in:
Philippe Teuwen
2026-02-09 12:44:50 +01:00
parent b7f3e4219e
commit 7c4758f40b
6 changed files with 94 additions and 57 deletions
+26
View File
@@ -23,6 +23,8 @@
#include "BigBuf.h"
#include "dbprint.h"
#include "mbedtls/aes.h"
#include "pm3_cmd.h"
#include "iso14443a.h"
static ulaes_key_t g_secure_session = {
.counter = 0,
@@ -173,3 +175,27 @@ void append_cmac(uint8_t *d, size_t n) {
increase_session_counter();
}
int verify_cmac(uint8_t *d, size_t n, bool verify_crc) {
// n = data size without cmac and without crc
uint8_t chk_d[n + ULAES_CMAC8_SIZE + 2];
memcpy(chk_d, d, n);
memset(chk_d + n, 0, sizeof(chk_d) - n);
append_cmac(chk_d, n);
if (memcmp(chk_d + n, d + n, ULAES_CMAC8_SIZE) != 0) {
if (g_dbglevel >= DBG_ERROR) {
Dbprintf("CMAC response error.");
}
return PM3_ECRC;
}
if (verify_crc) {
AddCrc14A(chk_d, n + ULAES_CMAC8_SIZE);
if (memcmp(chk_d + n + ULAES_CMAC8_SIZE, d + n + ULAES_CMAC8_SIZE, 2) != 0) {
if (g_dbglevel >= DBG_ERROR) {
Dbprintf("CRC response error.");
}
return PM3_ECRC;
}
}
return PM3_SUCCESS;
}
+3
View File
@@ -23,6 +23,8 @@
#include "common.h"
#define ULAES_CMAC8_SIZE 8
typedef struct {
bool use_schann;
uint8_t cmac_sk1[16];
@@ -41,5 +43,6 @@ bool get_session_channel(void);
void ulaes_cmac(const uint8_t *key, size_t key_len, const uint8_t *input, size_t ilen, uint8_t output[16]);
void ulaes_cmac8(uint8_t *cmac, uint8_t *mac);
void append_cmac(uint8_t *d, size_t n);
int verify_cmac(uint8_t *d, size_t n, bool verify_crc);
#endif
+1 -1
View File
@@ -868,7 +868,7 @@ void MifareUSetKey(mful_setkey_t *packet) {
if (iso14443a_select_card(NULL, NULL, NULL, true, 0, true) == 0) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Can't select card");
OnError(0);
OnErrorNG(CMD_HF_MIFAREU_SETKEY, PM3_ESOFT);
return;
};
+44 -39
View File
@@ -595,48 +595,54 @@ static int mifare_ultra_readblockEx(uint8_t blockNo, uint8_t *blockData) {
uint8_t receivedAnswer[MAX_FRAME_SIZE] = {0x00};
uint8_t receivedAnswerPar[MAX_PARITY_SIZE] = {0x00};
uint16_t len = 0;
uint8_t offset = 0;
if (get_session_channel()) {
offset = 8;
uint8_t cmd[2 + 8] = { ISO14443A_CMD_READBLOCK, blockNo };
uint8_t cmd[2 + ULAES_CMAC8_SIZE] = { ISO14443A_CMD_READBLOCK, blockNo };
append_cmac(cmd, 2);
len = mifare_sendcmd_schann(cmd, sizeof(cmd), receivedAnswer, sizeof(receivedAnswer), receivedAnswerPar, NULL);
if (len != 16 + ULAES_CMAC8_SIZE + 2) {
if (len == 1) {
if (g_dbglevel >= DBG_ERROR) {
Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
}
return PM3_ECARDEXCHANGE;
} else {
if (g_dbglevel >= DBG_ERROR) {
Dbprintf("Cmd Error: card timeout. len: %x", len);
}
return PM3_ETIMEOUT;
}
}
int ret = verify_cmac(receivedAnswer, 16, true);
if (ret != PM3_SUCCESS) {
return ret;
}
} else {
len = mifare_sendcmd_short(NULL, CRYPT_NONE, ISO14443A_CMD_READBLOCK, blockNo, receivedAnswer, sizeof(receivedAnswer), receivedAnswerPar, NULL);
}
if (len == 1) {
if (g_dbglevel >= DBG_ERROR) {
Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
if (len != 16 + 2) {
if (len == 1) {
if (g_dbglevel >= DBG_ERROR) {
Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
}
return PM3_ECARDEXCHANGE;
} else {
if (g_dbglevel >= DBG_ERROR) {
Dbprintf("Cmd Error: card timeout. len: %x", len);
}
return PM3_ETIMEOUT;
}
}
return PM3_ECARDEXCHANGE;
}
// Ev1 / Ul-C == 18 bytes response
// UL-Aes in secure messaging == 26
if (len != 18 + offset) {
if (g_dbglevel >= DBG_ERROR) {
Dbprintf("Cmd Error: card timeout. len: %x", len);
uint8_t bt[2] = {0x00, 0x00};
memcpy(bt, receivedAnswer + 16, 2);
AddCrc14A(receivedAnswer, 16);
if (bt[0] != receivedAnswer[16] || bt[1] != receivedAnswer[17]) {
if (g_dbglevel >= DBG_ERROR) {
Dbprintf("Cmd CRC response error.");
return PM3_ECRC;
}
}
return PM3_ETIMEOUT;
}
uint8_t bt[2] = {0x00, 0x00};
memcpy(bt, receivedAnswer + 16 + offset, 2);
AddCrc14A(receivedAnswer, 16 + offset);
if (bt[0] != receivedAnswer[16 + offset] || bt[1] != receivedAnswer[17 + offset]) {
if (g_dbglevel >= DBG_ERROR) {
Dbprintf("Cmd CRC response error.");
}
return PM3_ECRC;
}
// we are skipping verifying the cmac since we don't care.
// increase counter for the read response
increase_session_counter();
memcpy(blockData, receivedAnswer, 16);
return PM3_SUCCESS;
}
@@ -822,21 +828,20 @@ int mifare_ultra_writeblock(uint8_t blockNo, uint8_t *blockData) {
uint16_t len = 0;
if (get_session_channel()) {
uint8_t cmd[2 + 4 + 8] = { MIFARE_ULC_WRITE, blockNo };
uint8_t cmd[2 + 4 + ULAES_CMAC8_SIZE] = { MIFARE_ULC_WRITE, blockNo };
memcpy(cmd + 2, blockData, 4);
append_cmac(cmd, 2 + 4);
len = mifare_sendcmd_schann(cmd, sizeof(cmd), receivedAnswer, sizeof(receivedAnswer), receivedAnswerPar, NULL);
// we are skipping verifying the cmac, since we don't care.
// increase counter for the write response
increase_session_counter();
if (len != 10) {
if (len != ULAES_CMAC8_SIZE + 2) {
if (g_dbglevel >= DBG_INFO) {
Dbprintf("Cmd Send Error: " _RED_("%d"), len);
}
return PM3_EFAILED;
}
int ret = verify_cmac(receivedAnswer, 0, true);
if (ret != PM3_SUCCESS) {
return ret;
}
} else {
// command MIFARE_CLASSIC_WRITEBLOCK
+20 -15
View File
@@ -1459,27 +1459,31 @@ static int ulev1_print_configuration(uint64_t tagtype, uint8_t *data, uint8_t st
return PM3_SUCCESS;
}
static int ulev1_print_counters(void) {
static int ulev1_print_counters(uint64_t tagtype, bool use_schann) {
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Counters"));
uint8_t tear[1] = {0};
uint8_t counter[3] = {0, 0, 0};
int len = 0;
for (uint8_t i = 0; i < 3; ++i) {
ulev1_readTearing(i, tear, sizeof(tear));
len = ulev1_readCounter(i, counter, sizeof(counter), false);
len = ulev1_readCounter(i, counter, sizeof(counter), use_schann);
if (len == 3) {
PrintAndLogEx(INFO, " [%0d]: %s", i, sprint_hex(counter, 3));
PrintAndLogEx(SUCCESS, " - %02X tearing ( %s )"
, tear[0]
, (tear[0] == 0xBD) ? _GREEN_("ok") : _RED_("fail")
);
if ((tagtype & MFU_TT_UL_AES) != MFU_TT_UL_AES) {
ulev1_readTearing(i, tear, sizeof(tear));
PrintAndLogEx(SUCCESS, " - %02X tearing ( %s )"
, tear[0]
, (tear[0] == 0xBD) ? _GREEN_("ok") : _RED_("fail")
);
}
}
}
return len;
}
static int ulev1_print_signature(uint64_t tagtype, uint8_t *uid, uint8_t *signature, size_t signature_len) {
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature"));
int index = -1;
if (signature_len == 32) {
index = originality_check_verify(uid, 7, signature, signature_len, PK_MFUL);
@@ -2618,13 +2622,13 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
}
}
// do counters and signature first (don't neet auth)
// do counters and signature first (don't need auth)
// ul counters are different than ntag counters
if ((tagtype & (MFU_TT_UL_EV1_48 | MFU_TT_UL_EV1_128 | MFU_TT_UL_EV1 | MFU_TT_UL_AES))) {
if (ulev1_print_counters() != 3) {
if (ulev1_print_counters(tagtype, use_schann) != 3) {
// failed - re-select
if (ul_auth_select(&card, tagtype, has_auth_key, auth_key_ptr, pack, sizeof(pack), false) == PM3_ESOFT) {
if (ul_auth_select(&card, tagtype, has_auth_key, auth_key_ptr, pack, sizeof(pack), use_schann) == PM3_ESOFT) {
return PM3_ESOFT;
}
}
@@ -3631,7 +3635,7 @@ static int CmdHF14AMfUDump(const char *Cmd) {
if (has_auth_key) {
uint8_t dummy_pack[] = {0, 0};
ul_auth_select(&card, tagtype, has_auth_key, auth_key_ptr, dummy_pack, sizeof(dummy_pack), false);
ul_auth_select(&card, tagtype, has_auth_key, auth_key_ptr, dummy_pack, sizeof(dummy_pack), use_schann);
} else {
ul_select(&card);
}
@@ -3651,11 +3655,11 @@ static int CmdHF14AMfUDump(const char *Cmd) {
if (has_auth_key) {
uint8_t dummy_pack[] = {0, 0};
ul_auth_select(&card, tagtype, has_auth_key, auth_key_ptr, dummy_pack, sizeof(dummy_pack), false);
ul_auth_select(&card, tagtype, has_auth_key, auth_key_ptr, dummy_pack, sizeof(dummy_pack), use_schann);
} else {
ul_select(&card);
}
ulev1_readCounter(n, &get_counter_tearing[n][0], 3, false);
ulev1_readCounter(n, &get_counter_tearing[n][0], 3, use_schann);
if (has_auth_key) {
uint8_t dummy_pack[] = {0, 0};
@@ -3670,12 +3674,12 @@ static int CmdHF14AMfUDump(const char *Cmd) {
if (has_auth_key) {
uint8_t dummy_pack[] = {0, 0};
ul_auth_select(&card, tagtype, has_auth_key, auth_key_ptr, dummy_pack, sizeof(dummy_pack), false);
ul_auth_select(&card, tagtype, has_auth_key, auth_key_ptr, dummy_pack, sizeof(dummy_pack), use_schann);
} else {
ul_select(&card);
}
ulev1_readSignature(get_signature, sizeof(get_signature), false);
ulev1_readSignature(get_signature, sizeof(get_signature), use_schann);
DropField();
}
@@ -5023,6 +5027,7 @@ static int CmdHF14AMfUSetKey(const char *Cmd) {
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) {
-2
View File
@@ -195,8 +195,6 @@ int originality_check_verify_ex(uint8_t *data, uint8_t data_len, uint8_t *signat
int originality_check_print(uint8_t *signature, int signature_len, int index) {
PrintAndLogEx(NORMAL, "");
if ((index < 0) || (index >= ARRAYLEN(manufacturer_public_keys))) {
PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, 16));