hf mf cauth/aesauth/cchk/aeschk: make fast READ0 optional

This commit is contained in:
Philippe Teuwen
2026-02-24 16:46:00 +01:00
parent a73f945c49
commit b8a5e7b656
4 changed files with 57 additions and 33 deletions
+13 -6
View File
@@ -287,14 +287,21 @@ static int MifareUFastRead0(void) {
// 1 = failed auth
// 0 = correct
static uint8_t chkKey3Pass(uint8_t keyno, uint8_t *keybytes, uint32_t *auths, bool use_schann, bool check_answer) {
static uint8_t chkKey3Pass(uint8_t keyno, uint8_t *keybytes, uint32_t *auths, bool use_schann, bool check_answer, bool use_fastread0) {
uint8_t i = 0, res = 2;
bool selected = false;
while (i < 5) {
if (MifareUFastRead0() == 0) {
++i;
continue;
if (use_fastread0) {
if (MifareUFastRead0() == 0) {
++i;
continue;
}
} else {
if (iso14443a_select_card(NULL, NULL, NULL, true, 0, true) == 0) {
++i;
continue;
}
}
selected = true;
if (g_dbglevel >= DBG_EXTENDED) Dbhexdump(MIFAREU3P_KEY_SIZE, keybytes, false);
@@ -334,7 +341,7 @@ void MifareU3PassAuth(mful_3passauth_t *packet) {
for (uint16_t r = 0; r < 1 + packet->retries; r++) {
WDT_HIT();
if (chkKey3Pass(packet->keyno, packet->key, &auths, packet->use_schann, packet->check_answer) == 0) {
if (chkKey3Pass(packet->keyno, packet->key, &auths, packet->use_schann, packet->check_answer, packet->use_fastread0) == 0) {
res = PM3_SUCCESS;
goto out;
}
@@ -416,7 +423,7 @@ void MifareU3PassChkKeys(mful_3passchk_t *packet) {
memcpy(fullkeybytes + (packet->segment * keysize), packet->data + (i * keysize), keysize);
}
}
if (chkKey3Pass(packet->key_index, fullkeybytes, &auths, false, packet->check_answer) == 0) {
if (chkKey3Pass(packet->key_index, fullkeybytes, &auths, false, packet->check_answer, packet->use_fastread0) == 0) {
foundkeys++;
memcpy(rpayload.key, fullkeybytes, MIFAREU3P_KEY_SIZE);
res = PM3_SUCCESS;
+26 -16
View File
@@ -521,13 +521,14 @@ Default AES key is 00-00h. Both the data and UID one.
Data key is 00, UID is 01. Authenticity is 02h
Auth is 1A[Key ID][CRC] - AF[RndB] - AF[RndA][RndB'] - 00[RndA']
*/
static int ul3pass_authentication(const uint8_t *key, uint8_t keyno, bool switch_off_field, int retries, uint32_t *auths, uint32_t *ms, bool schann, bool check_answer) {
static int ul3pass_authentication(const uint8_t *key, uint8_t keyno, bool switch_off_field, int retries, uint32_t *auths, uint32_t *ms, bool schann, bool check_answer, bool use_fastread0) {
// keyno < 3: ULAES
// keyno = 3: ULC
mful_3passauth_t payload = {
.turn_off_field = switch_off_field,
.check_answer = check_answer,
.use_schann = schann,
.use_fastread0 = use_fastread0,
.keyno = keyno,
.retries = retries,
};
@@ -613,7 +614,7 @@ int trace_mfuc_try_default_3des_keys(uint8_t **correct_key, int state, uint8_t (
}
// param override, means we override hw debug levels.
static int try_default_3des_keys(bool override, uint8_t **correct_key) {
static int try_default_3des_keys(bool override, uint8_t **correct_key, bool use_fastread0) {
uint8_t dbg_curr = DBG_NONE;
if (override) {
@@ -633,7 +634,7 @@ static int try_default_3des_keys(bool override, uint8_t **correct_key) {
for (uint8_t i = 0; i < ARRAYLEN(default_3des_keys); ++i) {
uint8_t *key = default_3des_keys[i];
if (ul3pass_authentication(key, MIFAREULC_KEY_INDEX, true, 0, NULL, NULL, false, true) == PM3_SUCCESS) {
if (ul3pass_authentication(key, MIFAREULC_KEY_INDEX, true, 0, NULL, NULL, false, true, use_fastread0) == PM3_SUCCESS) {
*correct_key = key;
res = PM3_SUCCESS;
break;
@@ -647,7 +648,7 @@ static int try_default_3des_keys(bool override, uint8_t **correct_key) {
}
// param override, means we override hw debug levels.
static int try_default_aes_keys(bool override, bool use_schann) {
static int try_default_aes_keys(bool override, bool use_schann, bool use_fastread0) {
uint8_t dbg_curr = DBG_NONE;
if (override) {
@@ -670,7 +671,7 @@ static int try_default_aes_keys(bool override, bool use_schann) {
for (uint8_t keyno = 0; keyno < 3; keyno++) {
if (ul3pass_authentication(key, keyno, true, 0, NULL, NULL, use_schann, true) == PM3_SUCCESS) {
if (ul3pass_authentication(key, keyno, true, 0, NULL, NULL, use_schann, true, use_fastread0) == PM3_SUCCESS) {
char keystr[20] = {0};
switch (keyno) {
@@ -707,16 +708,16 @@ static int ul_auth_select(iso14a_card_select_t *card, uint64_t tagtype, bool has
if (ul_select(card) == false) {
return PM3_ESOFT;
}
bool use_fastread0 = false;
if (hasAuthKey && (tagtype & MFU_TT_UL_C)) {
//will select card automatically and close connection on error
if (ul3pass_authentication(authkey, MIFAREULC_KEY_INDEX, false, 0, NULL, NULL, false, true) != PM3_SUCCESS) {
if (ul3pass_authentication(authkey, MIFAREULC_KEY_INDEX, false, 0, NULL, NULL, false, true, use_fastread0) != PM3_SUCCESS) {
PrintAndLogEx(WARNING, "Authentication Failed UL-C");
return PM3_ESOFT;
}
} else if (hasAuthKey && (tagtype & MFU_TT_UL_AES)) {
//will select card automatically and close connection on error
if (ul3pass_authentication(authkey, 0, false, 0, NULL, NULL, use_schann, true) != PM3_SUCCESS) {
if (ul3pass_authentication(authkey, 0, false, 0, NULL, NULL, use_schann, true, use_fastread0) != PM3_SUCCESS) {
PrintAndLogEx(WARNING, "Authentication Failed UL-AES");
return PM3_ESOFT;
}
@@ -2608,7 +2609,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
}
// also try to diversify default keys.. look into CmdHF14AMfGenDiverseKeys
if (try_default_3des_keys(override, &key) == PM3_SUCCESS) {
if (try_default_3des_keys(override, &key, false) == PM3_SUCCESS) {
PrintAndLogEx(SUCCESS, "Found default 3des key: ");
uint8_t keySwap[16];
memcpy(keySwap, SwapEndian64(key, 16, 8), 16);
@@ -2773,7 +2774,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
if (ak_len != 16) {
// also try to diversify default keys.. look into CmdHF14AMfGenDiverseKeys
if (try_default_aes_keys(override, use_schann) != PM3_SUCCESS) {
if (try_default_aes_keys(override, use_schann, false) != PM3_SUCCESS) {
PrintAndLogEx(INFO, "n/a");
}
DropField();
@@ -4324,7 +4325,7 @@ static int mfu_3pass_load_keys(uint8_t **pkeyBlock, uint32_t *pkeycnt, const cha
static int mfu_3pass_check_keys(uint8_t key_index, uint8_t firstChunk, uint8_t lastChunk,
uint32_t nkeys, int segment, uint8_t *ref_key, bool xor_ref_key, uint8_t *keyBlock,
bool verbose, bool quiet, uint32_t *auths, uint32_t *ms, bool check_answer) {
bool verbose, bool quiet, uint32_t *auths, uint32_t *ms, bool check_answer, bool use_fastread0) {
// send keychunk
clearCommandBuffer();
@@ -4335,6 +4336,7 @@ static int mfu_3pass_check_keys(uint8_t key_index, uint8_t firstChunk, uint8_t l
.xor_ref_key = xor_ref_key,
.segment = segment != -1 ? segment : 4,
.check_answer = check_answer,
.use_fastread0 = use_fastread0,
.nkeys = nkeys
};
struct rp {
@@ -4427,6 +4429,7 @@ static int CmdHF14AMfUCAuth(const char *Cmd) {
arg_lit0("k", NULL, "Keep field on (only if a key is provided)"),
arg_int0("r", "retries", "<n>", "Number of retries with provided key (def: 0)"),
arg_lit0("n", "nocheck", "Skip checking tag answer correctness (only if a key is provided)"),
arg_lit0("0", "read0", "Use fast READ0 (skip anticol)"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
@@ -4439,6 +4442,7 @@ static int CmdHF14AMfUCAuth(const char *Cmd) {
bool keep_field_on = arg_get_lit(ctx, 3);
int retries = arg_get_int_def(ctx, 4, 0);
bool check_answer = !arg_get_lit(ctx, 5);
bool use_fastread0 = arg_get_lit(ctx, 6);
CLIParserFree(ctx);
if (ak_len != 16 && ak_len != 0) {
@@ -4471,11 +4475,11 @@ static int CmdHF14AMfUCAuth(const char *Cmd) {
if (ak_len == 0) {
PrintAndLogEx(INFO, "Called with no key, checking default keys...");
isok = try_default_3des_keys(false, &auth_key_ptr);
isok = try_default_3des_keys(false, &auth_key_ptr, use_fastread0);
} else {
// try user-supplied
isok = ul3pass_authentication(auth_key_ptr, MIFAREULC_KEY_INDEX, !keep_field_on, retries, &auths, &ms, false, check_answer);
isok = ul3pass_authentication(auth_key_ptr, MIFAREULC_KEY_INDEX, !keep_field_on, retries, &auths, &ms, false, check_answer, use_fastread0);
}
if (isok == PM3_SUCCESS) {
@@ -4505,6 +4509,7 @@ static int CmdHF14AMfUCAuthChk(const char *Cmd) {
arg_str0("k", "key", "<hex>", "Starting key, 16 hex bytes (def: zero key), for segment check"),
arg_lit0("x", "xor", "XOR starting key with segment candidates (def: override)"),
arg_lit0("n", "nocheck", "Skip checking tag answer correctness"),
arg_lit0("0", "read0", "Use fast READ0 (skip anticol)"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
@@ -4519,6 +4524,7 @@ static int CmdHF14AMfUCAuthChk(const char *Cmd) {
CLIGetHexWithReturn(ctx, 4, ref_key, &ref_keylen);
bool xor_ref_key = arg_get_lit(ctx, 5);
bool check_answer = !arg_get_lit(ctx, 6);
bool use_fastread0 = arg_get_lit(ctx, 7);
CLIParserFree(ctx);
if (fnlen == 0) {
@@ -4582,7 +4588,7 @@ static int CmdHF14AMfUCAuthChk(const char *Cmd) {
if (nkeys == keycnt - i) {
lastChunk = true;
}
int res = mfu_3pass_check_keys(MIFAREULC_KEY_INDEX, firstChunk, lastChunk, nkeys, segment, ref_key, xor_ref_key, keyBlock + (i * keysize), false, true, &auths, &ms, check_answer);
int res = mfu_3pass_check_keys(MIFAREULC_KEY_INDEX, firstChunk, lastChunk, nkeys, segment, ref_key, xor_ref_key, keyBlock + (i * keysize), false, true, &auths, &ms, check_answer, use_fastread0);
if (firstChunk)
firstChunk = false;
@@ -4632,6 +4638,7 @@ static int CmdHF14AMfUAESAuth(const char *Cmd) {
arg_lit0(NULL, "schann", "use secure channel. Must have key"),
arg_int0("r", "retries", "<n>", "Number of retries (def: 0)"),
arg_lit0("n", "nocheck", "Skip checking tag answer correctness"),
arg_lit0("0", "read0", "Use fast READ0 (skip anticol)"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
@@ -4646,6 +4653,7 @@ static int CmdHF14AMfUAESAuth(const char *Cmd) {
bool use_schann = arg_get_lit(ctx, 5);
int retries = arg_get_int_def(ctx, 6, 0);
bool check_answer = !arg_get_lit(ctx, 7);
bool use_fastread0 = arg_get_lit(ctx, 8);
CLIParserFree(ctx);
if (ak_len == 0) {
@@ -4674,7 +4682,7 @@ static int CmdHF14AMfUAESAuth(const char *Cmd) {
uint32_t auths = 0;
uint32_t ms = 0;
int result = ul3pass_authentication(auth_key_ptr, key_index, !keep_field_on, retries, &auths, &ms, use_schann, check_answer);
int result = ul3pass_authentication(auth_key_ptr, key_index, !keep_field_on, retries, &auths, &ms, use_schann, check_answer, use_fastread0);
if (result == PM3_SUCCESS) {
PrintAndLogEx(SUCCESS, "Authentication with " _YELLOW_("%s") " " _GREEN_("%s") " ( " _GREEN_("ok")" )"
, key_type[key_index]
@@ -4709,6 +4717,7 @@ static int CmdHF14AMfUAESAuthChk(const char *Cmd) {
arg_str0("k", "key", "<hex>", "Starting key, 16 hex bytes (def: zero key), for segment check"),
arg_lit0("x", "xor", "XOR starting key with segment candidates (def: override)"),
arg_lit0("n", "nocheck", "Skip checking tag answer correctness"),
arg_lit0("0", "read0", "Use fast READ0 (skip anticol)"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
@@ -4724,6 +4733,7 @@ static int CmdHF14AMfUAESAuthChk(const char *Cmd) {
CLIGetHexWithReturn(ctx, 5, ref_key, &ref_keylen);
bool xor_ref_key = arg_get_lit(ctx, 6);
bool check_answer = !arg_get_lit(ctx, 7);
bool use_fastread0 = arg_get_lit(ctx, 8);
CLIParserFree(ctx);
if (fnlen == 0) {
@@ -4791,7 +4801,7 @@ static int CmdHF14AMfUAESAuthChk(const char *Cmd) {
lastChunk = true;
}
int res = mfu_3pass_check_keys(key_index, firstChunk, lastChunk, nkeys, segment, ref_key, xor_ref_key, keyBlock + (i * keysize), false, true, &auths, &ms, check_answer);
int res = mfu_3pass_check_keys(key_index, firstChunk, lastChunk, nkeys, segment, ref_key, xor_ref_key, keyBlock + (i * keysize), false, true, &auths, &ms, check_answer, use_fastread0);
if (firstChunk)
firstChunk = false;
+13 -9
View File
@@ -7185,9 +7185,10 @@
"-k Keep field on (only if a key is provided)",
"--schann use secure channel. Must have key",
"-r, --retries <n> Number of retries (def: 0)",
"-n, --nocheck Skip checking tag answer correctness"
"-n, --nocheck Skip checking tag answer correctness",
"-0, --read0 Use fast READ0 (skip anticol)"
],
"usage": "hf mfu aesauth [-hlkn] [--key <hex>] [-i <0..2>] [--schann] [-r <n>]"
"usage": "hf mfu aesauth [-hlkn0] [--key <hex>] [-i <0..2>] [--schann] [-r <n>]"
},
"hf mfu aeschk": {
"command": "hf mfu aeschk",
@@ -7204,9 +7205,10 @@
"-r, --retries <0..255> Number of retries (def: 0)",
"-k, --key <hex> Starting key, 16 hex bytes (def: zero key), for segment check",
"-x, --xor XOR starting key with segment candidates (def: override)",
"-n, --nocheck Skip checking tag answer correctness"
"-n, --nocheck Skip checking tag answer correctness",
"-0, --read0 Use fast READ0 (skip anticol)"
],
"usage": "hf mfu aeschk [-hxn] [-f <fn>] [-i <0..2>] [-s <0..3>] [-r <0..255>] [-k <hex>]"
"usage": "hf mfu aeschk [-hxn0] [-f <fn>] [-i <0..2>] [-s <0..3>] [-r <0..255>] [-k <hex>]"
},
"hf mfu amiibo": {
"command": "hf mfu amiibo",
@@ -7240,9 +7242,10 @@
"-l Swap entered key's endianness",
"-k Keep field on (only if a key is provided)",
"-r, --retries <n> Number of retries with provided key (def: 0)",
"-n, --nocheck Skip checking tag answer correctness (only if a key is provided)"
"-n, --nocheck Skip checking tag answer correctness (only if a key is provided)",
"-0, --read0 Use fast READ0 (skip anticol)"
],
"usage": "hf mfu cauth [-hlkn] [--key <hex>] [-r <n>]"
"usage": "hf mfu cauth [-hlkn0] [--key <hex>] [-r <n>]"
},
"hf mfu cchk": {
"command": "hf mfu cchk",
@@ -7258,9 +7261,10 @@
"-r, --retries <0..255> Number of retries (def: 0)",
"-k, --key <hex> Starting key, 16 hex bytes (def: zero key), for segment check",
"-x, --xor XOR starting key with segment candidates (def: override)",
"-n, --nocheck Skip checking tag answer correctness"
"-n, --nocheck Skip checking tag answer correctness",
"-0, --read0 Use fast READ0 (skip anticol)"
],
"usage": "hf mfu cchk [-hxn] [-f <fn>] [-s <0..3>] [-r <0..255>] [-k <hex>]"
"usage": "hf mfu cchk [-hxn0] [-f <fn>] [-s <0..3>] [-r <0..255>] [-k <hex>]"
},
"hf mfu dump": {
"command": "hf mfu dump",
@@ -13813,6 +13817,6 @@
"metadata": {
"commands_extracted": 791,
"extracted_by": "PM3Help2JSON v1.00",
"extracted_on": "2026-02-21T11:42:25"
"extracted_on": "2026-02-24T15:41:26"
}
}
+5 -2
View File
@@ -379,7 +379,8 @@ typedef struct {
uint8_t check_answer : 1;
uint8_t keyno : 2;
uint8_t use_schann : 1;
uint8_t reserved : 3;
uint8_t use_fastread0 : 1;
uint8_t reserved : 2;
uint16_t retries;
uint8_t key[16];
} PACKED mful_3passauth_t;
@@ -395,7 +396,9 @@ typedef struct {
uint8_t xor_ref_key : 1;
uint8_t segment : 3;
uint8_t check_answer : 1;
uint8_t nkeys : 7;
uint8_t use_fastread0 : 1;
// max nkeys: (PM3_CMD_DATA_SIZE - MIFAREU3P_CHKKEY_HEADER) / MIFAREU3P_KEY_SIZE < 32
uint8_t nkeys : 6;
uint8_t ref_key[MIFAREU3P_KEY_SIZE];
uint8_t data[PM3_CMD_DATA_SIZE - MIFAREU3P_CHKKEY_HEADER];
} PACKED mful_3passchk_t;