diff --git a/armsrc/iclass.c b/armsrc/iclass.c index e85e6b1f2..8e8702bf2 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -1805,9 +1805,9 @@ static bool iclass_writeblock_sp(uint8_t blockno, uint8_t *data, uint8_t *mac, b uint8_t resp[10] = {0}; bool isOK = false; - if(short_delay){ + if (short_delay) { isOK = iclass_send_cmd_with_retries(write, write_len, resp, sizeof(resp), 10, 3, start_time, ICLASS_READER_TIMEOUT_UPDATE_FAST, eof_time, shallow_mod); - }else{ + } else { isOK = iclass_send_cmd_with_retries(write, write_len, resp, sizeof(resp), 10, 3, start_time, ICLASS_READER_TIMEOUT_UPDATE, eof_time, shallow_mod); } if (isOK == false) { @@ -2706,7 +2706,7 @@ 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] = ((uint8_t*)&hdr.conf)[0] + 1; //first block of AA2 + read_check_cc[1] = ((uint8_t *)&hdr.conf)[0] + 1; //first block of AA2 //Step1 Authenticate with AA1 using trace if (card_select) { @@ -2744,7 +2744,7 @@ void iClass_Recover(iclass_recover_req_t *msg) { } else { interrupted = true; } - if(msg->fast){ + if (msg->fast) { goto fast_restore; } goto out; @@ -2823,10 +2823,10 @@ void iClass_Recover(iclass_recover_req_t *msg) { memcpy(genkeyblock, zero_key, PICOPASS_BLOCK_SIZE); } - if(msg->fast){//if we're skipping restoring the original key to gain speed, xor the new index key with the previous index key and update the difference and track restore values differently - if(index > 0 && loops > 1){ - generate_single_key_block_inverted_opt(zero_key, index -1, fast_previous_key); - }else{ + if (msg->fast) { //if we're skipping restoring the original key to gain speed, xor the new index key with the previous index key and update the difference and track restore values differently + if (index > 0 && loops > 1) { + generate_single_key_block_inverted_opt(zero_key, index - 1, fast_previous_key); + } else { memcpy(fast_previous_key, zero_key, PICOPASS_BLOCK_SIZE); } for (int i = 0; i < PICOPASS_BLOCK_SIZE; i++) { @@ -2850,7 +2850,7 @@ void iClass_Recover(iclass_recover_req_t *msg) { if (iclass_writeblock_sp(blockno, genkeyblock, mac2, shallow_mod, &start_time, &eof_time, short_delay)) { status_message = 4; //wrote new key on the card - unverified } - if(!msg->fast){ //if we're going slow we check at every write that the write actually happened + if (!msg->fast) { //if we're going slow we check at every write that the write actually happened //Reset cypher state start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; iclass_send_as_reader(read_check_cc2, sizeof(read_check_cc2), &start_time, &eof_time, shallow_mod); @@ -2877,7 +2877,7 @@ void iClass_Recover(iclass_recover_req_t *msg) { written = true; } } - }else{ //if we're going fast we can skip the above checks as we're just xorring the key over and over + } else { //if we're going fast we can skip the above checks as we're just xorring the key over and over status_message = 5; written = true; } @@ -2900,11 +2900,11 @@ void iClass_Recover(iclass_recover_req_t *msg) { bool reverted = false; uint8_t revert_retries = 0; - if(msg->fast){ //if we're going fast only restore the original key at the end - if(recovered){ + if (msg->fast) { //if we're going fast only restore the original key at the end + if (recovered) { goto fast_restore; } - }else{ + } else { //if we're NOT going fast, regardless of bits being found, restore the original key and verify it while (!reverted) { //Regain privilege escalation with a readcheck @@ -3018,9 +3018,9 @@ fast_restore: Dbhexdump(8, fast_restore_key, false); Dbprintf(_RED_("Attempted to restore original key for %3d times and failed. Stopping. Card is likely unusable."), revert_retries); } - if(recovered){ + if (recovered) { goto restore; - }else{ + } else { goto out; } } @@ -3030,9 +3030,9 @@ restore: uint8_t partialkey[PICOPASS_BLOCK_SIZE] = {0}; for (int i = 0; i < PICOPASS_BLOCK_SIZE; i++) { - if(msg->fast){ + if (msg->fast) { partialkey[i] = fast_restore_key[i] ^ bits_found; - }else{ + } else { partialkey[i] = genkeyblock[i] ^ bits_found; } } diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index aeaf7f514..9ae1b2f86 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -4634,11 +4634,15 @@ typedef struct { // HF iClass legbrute - Brute-force worker thread static void *brute_thread(void *args_void) { + thread_args_t *args = (thread_args_t *)args_void; - uint8_t div_key[8], mac[4], verification_mac[4]; + uint8_t div_key[8]; + uint8_t mac[4]; + uint8_t verification_mac[4]; uint64_t index = args->index_start; while (!*(args->found)) { + generate_key_block_inverted(args->startingKey, index, div_key); doMAC(args->CCNR1, div_key, mac); @@ -4659,8 +4663,8 @@ static void *brute_thread(void *args_void) { if (index % 1000000 == 0 && !*(args->found)) { pthread_mutex_lock(args->log_lock); - if(args->thread_id == 0){ - PrintAndLogEx(INPLACE, "Tested "_YELLOW_("%" PRIu64 )" million keys, using "_YELLOW_("%d")" threads - Index: "_YELLOW_("%" PRIu64 )" - Last key on Thread[0]: %s", (index / 1000000) * args->thread_count, args->thread_count, index / 1000000, sprint_hex(div_key, 8)); + if (args->thread_id == 0) { + PrintAndLogEx(INPLACE, "Tested "_YELLOW_("%" PRIu64)" million keys, using "_YELLOW_("%d")" threads - Index: "_YELLOW_("%" PRIu64)" - Last key on Thread[0]: %s", (index / 1000000) * args->thread_count, args->thread_count, index / 1000000, sprint_hex(div_key, 8)); } pthread_mutex_unlock(args->log_lock); } @@ -4720,7 +4724,9 @@ static int CmdHFiClassLegBrute_MT(uint8_t epurse[8], uint8_t macs[8], uint8_t ma static int CmdHFiClassLegBrute(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf iclass legbrute", - "This command takes sniffed trace data and a partial raw key and bruteforces the remaining 40 bits of the raw key.", + "This command takes sniffed trace data and a partial raw key and bruteforces the remaining 40 bits of the raw key.\n" + "Complete 40 bit keyspace is 1'099'511'627'776 and command is lockdown to max 16 threads currently.\n" + "A possible worst case scenario on 16 threads estimates XXX days YYY hours MMM minutes.", "hf iclass legbrute --epurse feffffffffffffff --macs1 1306cad9b6c24466 --macs2 f0bf905e35f97923 --pk B4F12AADC5301225"); void *argtable[] = { diff --git a/doc/commands.json b/doc/commands.json index 455f1aa9d..ff01b983e 100644 --- a/doc/commands.json +++ b/doc/commands.json @@ -3493,7 +3493,7 @@ }, "hf iclass legbrute": { "command": "hf iclass legbrute", - "description": "This command take sniffed trace data and partial raw key and bruteforces the remaining 40 bits of the raw key.", + "description": "This command takes sniffed trace data and a partial raw key and bruteforces the remaining 40 bits of the raw key. Complete 40 bit keyspace is 1'099'511'627'776 and command is lockdown to max 16 threads currently. A possible worst case scenario on 16 threads estimates XXX days YYY hours MMM minutes.", "notes": [ "hf iclass legbrute --epurse feffffffffffffff --macs1 1306cad9b6c24466 --macs2 f0bf905e35f97923 --pk B4F12AADC5301225" ], @@ -3504,9 +3504,10 @@ "--macs1 MACs captured from the reader", "--macs2 MACs captured from the reader, different than the first set (with the same csn and epurse value)", "--pk Partial Key from legrec or starting key of keyblock from legbrute", - "--index Where to start from to retrieve the key, default 0 - value in millions e.g. 1 is 1 million" + "--index Where to start from to retrieve the key, default 0 - value in millions e.g. 1 is 1 million", + "--threads Number of threads to use, by default it uses the cpu's max threads (max 16)." ], - "usage": "hf iclass legbrute [-h] --epurse --macs1 --macs2 --pk [--index ]" + "usage": "hf iclass legbrute [-h] --epurse --macs1 --macs2 --pk [--index ] [--threads ]" }, "hf iclass legrec": { "command": "hf iclass legrec", @@ -3524,9 +3525,11 @@ "--debug Re-enables tracing for debugging. Limits cycles to 1.", "--notest Perform real writes on the card!", "--allnight Loops the loop for 10 times, recommended loop value of 5000.", + "--fast Increases the speed (4.6->7.4 key updates/second), higher risk to brick the card.", + "--sl Lower card comms delay times, further speeds increases, may cause more errors.", "--est Estimates the key updates based on the card's CSN assuming standard key." ], - "usage": "hf iclass legrec [-h] --macs [--index ] [--loop ] [--debug] [--notest] [--allnight] [--est]" + "usage": "hf iclass legrec [-h] --macs [--index ] [--loop ] [--debug] [--notest] [--allnight] [--fast] [--sl] [--est]" }, "hf iclass loclass": { "command": "hf iclass loclass", @@ -13372,6 +13375,6 @@ "metadata": { "commands_extracted": 768, "extracted_by": "PM3Help2JSON v1.00", - "extracted_on": "2025-06-04T16:02:17" + "extracted_on": "2025-06-06T11:25:04" } }