From 51c44843c9f30c8a20fada5589fd6239039b3240 Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Sat, 4 Apr 2026 01:07:47 +0800 Subject: [PATCH 1/2] Removed --credit from hf iclass legrec Option wasn't working and caused unnecessary complexity in the workflow. --- CHANGELOG.md | 1 - armsrc/iclass.c | 18 +++--------------- client/src/cmdhficlass.c | 24 ++++++------------------ include/iclass_cmd.h | 1 - 4 files changed, 9 insertions(+), 35 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dae36c4cb..a55172404 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,7 +31,6 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Added DESFire AID values related to LEAF (@kormax) - Added `dict`, `ascii`, `mad` presets for `hf mfdes bruteaid` (@kormax) - Added tag loss detection & recovery into `hf mfdes bruteaid` (@kormax) -- Added `--credit` option to `hf iclass legrec` for credit key recovery. Note: this option alone is experimental and only partially functional; the standard key recovery works normally.(@antiklesys) - Added hardening for all host binaries. Exact level of hardening depends on the OS (@doegox) - Added `hf aliro read` command (@kormax) - Added `hf aliro info` command (@kormax) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index e8c2d7295..0e62d9caa 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -2813,9 +2813,6 @@ void iClass_Recover(iclass_recover_req_t *msg) { uint32_t start_time = 0; uint8_t read_check_cc[] = { 0x10 | ICLASS_CMD_READCHECK, 0x18 }; //block 24 with credit key uint8_t read_check_cc2[] = { 0x80 | ICLASS_CMD_READCHECK, 0x02 }; //block 2 -> to check Kd macs - if (msg->credit_recovery == true) { - read_check_cc[0] = 0x80 | ICLASS_CMD_READCHECK; //still block 24 but with debit key - } /* iclass_mac_table is a series of weak macs, those weak macs correspond to the different combinations of the last 3 bits of each key byte. */ @@ -2858,7 +2855,7 @@ void iClass_Recover(iclass_recover_req_t *msg) { } //Step0 Card Select Routine eof_time = 0; //reset eof time - res = select_iclass_tag(&hdr, msg->credit_recovery, &eof_time, shallow_mod); + res = select_iclass_tag(&hdr, false, &eof_time, shallow_mod); if (res) { status_message = 1; //card select successful card_select = true; @@ -2866,16 +2863,13 @@ void iClass_Recover(iclass_recover_req_t *msg) { //Step 0A - The read_check_cc block has to be in AA2, set it by checking the card configuration read_check_cc[1] = hdr.conf.app_limit + 1; //first block of AA2 - if (msg->credit_recovery == true) { - read_check_cc[1] = hdr.conf.app_limit - 1; //last block of AA1 - } //Step1 Authenticate with AA1 using trace if (card_select) { memcpy(original_mac, msg->req.key, 8); start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; res = authenticate_iclass_tag(&msg->req, &hdr, &start_time, &eof_time, mac1); if (res) { - status_message = 2; //authentication with AA1(AA2 if credit recovery) macs successful + status_message = 2; //authentication with AA1 macs successful card_auth = true; } } @@ -2924,7 +2918,7 @@ void iClass_Recover(iclass_recover_req_t *msg) { set_tracing(false); // disable tracing to prevent crashes - set to true for debugging // Step0 Card Select Routine eof_time = 0; // reset eof time - res = select_iclass_tag(&hdr, msg->credit_recovery, &eof_time, shallow_mod); + res = select_iclass_tag(&hdr, false, &eof_time, shallow_mod); if (res) { status_message = 1; // card select successful card_select = true; @@ -2995,9 +2989,6 @@ void iClass_Recover(iclass_recover_req_t *msg) { uint8_t wb[9] = {0}; uint8_t blockno = 3; - if (msg->credit_recovery == true) { - blockno = 4; - } wb[0] = blockno; memcpy(wb + 1, genkeyblock, 8); doMAC_N(wb, sizeof(wb), div_key2, mac2); @@ -3147,9 +3138,6 @@ fast_restore: uint8_t mac2[4] = {0}; uint8_t wb[9] = {0}; uint8_t blockno = 3; - if (msg->credit_recovery == true) { - blockno = 4; - } wb[0] = blockno; bool reverted = false; uint8_t revert_retries = 0; diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 247103e24..272351499 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -5957,7 +5957,7 @@ void picopass_elite_nextKey(uint8_t *key) { memcpy(key, key_state, PICOPASS_BLOCK_SIZE); } -static int iclass_recover(uint8_t key[8], uint32_t index_start, uint32_t loop, uint8_t no_first_auth[8], bool debug, bool test, bool fast, bool short_delay, bool allnight, bool credit) { +static int iclass_recover(uint8_t key[8], uint32_t index_start, uint32_t loop, uint8_t no_first_auth[8], bool debug, bool test, bool fast, bool short_delay, bool allnight) { int runs = 1; int cycle = 1; @@ -5989,7 +5989,6 @@ static int iclass_recover(uint8_t key[8], uint32_t index_start, uint32_t loop, u payload->test = test; payload->fast = fast; payload->short_delay = short_delay; - payload->credit_recovery = credit; memcpy(payload->nfa, no_first_auth, PICOPASS_BLOCK_SIZE); memcpy(payload->req.key, key, PICOPASS_BLOCK_SIZE); @@ -6396,7 +6395,7 @@ static void generate_single_key_block_inverted_opt(const uint8_t *startingKey, u } -static int CmdHFiClassLegacyRecSim(bool credit) { +static int CmdHFiClassLegacyRecSim(void) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, _YELLOW_("This simulation assumes the card is standard keyed.")); @@ -6411,11 +6410,7 @@ static int CmdHFiClassLegacyRecSim(bool credit) { } uint8_t new_div_key[8] = {0}; - if (credit == true) { - HFiClassCalcDivKey(csn, iClass_Key_Table[1], new_div_key, false); - } else { - HFiClassCalcDivKey(csn, iClass_Key_Table[0], new_div_key, false); - } + HFiClassCalcDivKey(csn, iClass_Key_Table[0], new_div_key, false); uint8_t key[PICOPASS_BLOCK_SIZE] = {0}; uint8_t original_key[PICOPASS_BLOCK_SIZE] = {0}; @@ -6492,7 +6487,6 @@ static int CmdHFiClassLegacyRecover(const char *Cmd) { arg_lit0(NULL, "fast", "Increases the speed (4.6->7.4 key updates/second), higher risk to brick the card"), arg_lit0(NULL, "sl", "Lower card comms delay times, further speeds increases, may cause more errors"), arg_lit0(NULL, "est", "Estimates the key updates based on the card's CSN assuming standard key, can be used with --credit option"), - arg_lit0(NULL, "credit", "EXPERIMENTAL : Recover the credit key using KD 0"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -6510,10 +6504,9 @@ static int CmdHFiClassLegacyRecover(const char *Cmd) { bool fast = arg_get_lit(ctx, 7); bool short_delay = arg_get_lit(ctx, 8); bool sim = arg_get_lit(ctx, 9); - bool credit = arg_get_lit(ctx, 10); if (sim) { - CmdHFiClassLegacyRecSim(credit); + CmdHFiClassLegacyRecSim(); return PM3_SUCCESS; } @@ -6549,12 +6542,7 @@ static int CmdHFiClassLegacyRecover(const char *Cmd) { return PM3_ESOFT; } - if (credit == true) { - diversifyKey(csn, iClass_Key_Table[0], new_div_key); - fast = false; - } else { - diversifyKey(csn, iClass_Key_Table[1], new_div_key); - } + diversifyKey(csn, iClass_Key_Table[1], new_div_key); memcpy(no_first_auth, new_div_key, PICOPASS_BLOCK_SIZE); @@ -6569,7 +6557,7 @@ static int CmdHFiClassLegacyRecover(const char *Cmd) { PrintAndLogEx(INFO, "---------------------------------------"); PrintAndLogEx(INFO, "Press " _GREEN_("pm3 button") " to abort"); PrintAndLogEx(INFO, "--------------- " _CYAN_("start") " -----------------\n"); - iclass_recover(macs, index, loop, no_first_auth, debug, test, fast, short_delay, allnight, credit); + iclass_recover(macs, index, loop, no_first_auth, debug, test, fast, short_delay, allnight); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(WARNING, _YELLOW_("If the process completed successfully")); PrintAndLogEx(HINT, "Hint: run `" _YELLOW_("hf iclass legbrute -h") "` with the partial key found"); diff --git a/include/iclass_cmd.h b/include/iclass_cmd.h index cdda920f5..9c265cd99 100644 --- a/include/iclass_cmd.h +++ b/include/iclass_cmd.h @@ -128,7 +128,6 @@ typedef struct { bool test; bool fast; bool short_delay; - bool credit_recovery; } PACKED iclass_recover_req_t; typedef struct iclass_premac { From 2bdbd5a73c9b5bce9fa03d929b0b79ff92b1f1dd Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Sat, 4 Apr 2026 02:01:29 +0800 Subject: [PATCH 2/2] Stability update Benchmarked multiple cards. This is a stable value with the least performance loss. --- armsrc/iclass.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/armsrc/iclass.h b/armsrc/iclass.h index 2d2bf8c42..7933e32cb 100644 --- a/armsrc/iclass.h +++ b/armsrc/iclass.h @@ -34,7 +34,7 @@ // times in samples @ 212kHz when acting as reader #define ICLASS_READER_TIMEOUT_ACTALL 330 // 1558us, nominal 330us + 7slots*160us = 1450us #define ICLASS_READER_TIMEOUT_UPDATE 3390 // 16000us, nominal 4-15ms -#define ICLASS_READER_TIMEOUT_UPDATE_FAST 1500 // A copy of ICLASS_READER_TIMEOUT_UPDATE with reduced timeout values +#define ICLASS_READER_TIMEOUT_UPDATE_FAST 1600 // A copy of ICLASS_READER_TIMEOUT_UPDATE with reduced timeout values #define ICLASS_READER_TIMEOUT_OTHERS 80 // 380us, nominal 330us // The length of a received command will in most cases be no more than 18 bytes.