Skip to content

Commit 176a93f

Browse files
authored
Merge pull request #2521 from Antiklesys/master
Updates to iclass legrec and legbrute
2 parents a0e8065 + a2a69b1 commit 176a93f

File tree

4 files changed

+148
-107
lines changed

4 files changed

+148
-107
lines changed

armsrc/util.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,7 @@ uint32_t get_flash_size(void) {
397397
}
398398

399399
// Combined function to convert an unsigned int to an array of hex values corresponding to the last three bits of k1
400-
void convertToHexArray(uint8_t num, uint8_t *partialkey) {
400+
void convertToHexArray(uint32_t num, uint8_t *partialkey) {
401401
char binaryStr[25]; // 24 bits for binary representation + 1 for null terminator
402402
binaryStr[24] = '\0'; // Null-terminate the string
403403

@@ -409,8 +409,8 @@ void convertToHexArray(uint8_t num, uint8_t *partialkey) {
409409

410410
// Split the binary string into groups of 3 and convert to hex
411411
for (int i = 0; i < 8 ; i++) {
412-
char group[4];
413-
strncpy(group, binaryStr + i * 3, 3);
412+
char group[4] = {'0', '0', '0', '\0'}; // Ensure group is initialized correctly
413+
memcpy(group, binaryStr + i * 3, 3); // Use memcpy to copy exactly 3 characters
414414
group[3] = '\0'; // Null-terminate the group string
415415
partialkey[i] = (uint8_t)strtoul(group, NULL, 2);
416416
}

armsrc/util.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ int hex2binarray(char *target, const char *source);
8888
int hex2binarray_n(char *target, const char *source, int sourcelen);
8989
int binarray2hex(const uint8_t *bs, int bs_len, uint8_t *hex);
9090

91-
void convertToHexArray(uint8_t num, uint8_t *partialkey);
91+
void convertToHexArray(uint32_t num, uint8_t *partialkey);
9292

9393
void LED(int led, int ms);
9494
void LEDsoff(void);

client/src/cmdhficlass.c

Lines changed: 139 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -3849,45 +3849,74 @@ void picopass_elite_nextKey(uint8_t *key) {
38493849
memcpy(key, key_state, 8);
38503850
}
38513851

3852-
static int CmdHFiClassRecover(uint8_t key[8]) {
3853-
3854-
uint32_t payload_size = sizeof(iclass_recover_req_t);
3855-
uint8_t aa2_standard_key[PICOPASS_BLOCK_SIZE] = {0};
3856-
memcpy(aa2_standard_key, iClass_Key_Table[1], PICOPASS_BLOCK_SIZE);
3857-
iclass_recover_req_t *payload = calloc(1, payload_size);
3858-
payload->req.use_raw = true;
3859-
payload->req.use_elite = false;
3860-
payload->req.use_credit_key = false;
3861-
payload->req.use_replay = true;
3862-
payload->req.send_reply = true;
3863-
payload->req.do_auth = true;
3864-
payload->req.shallow_mod = false;
3865-
payload->req2.use_raw = false;
3866-
payload->req2.use_elite = false;
3867-
payload->req2.use_credit_key = true;
3868-
payload->req2.use_replay = false;
3869-
payload->req2.send_reply = true;
3870-
payload->req2.do_auth = true;
3871-
payload->req2.shallow_mod = false;
3872-
memcpy(payload->req.key, key, 8);
3873-
memcpy(payload->req2.key, aa2_standard_key, 8);
3852+
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 allnight) {
3853+
3854+
int runs = 1;
3855+
int cycle = 1;
3856+
bool repeat = true;
3857+
if(allnight){
3858+
runs = 10;
3859+
}
3860+
3861+
while (repeat == true){
3862+
uint32_t payload_size = sizeof(iclass_recover_req_t);
3863+
uint8_t aa2_standard_key[PICOPASS_BLOCK_SIZE] = {0};
3864+
memcpy(aa2_standard_key, iClass_Key_Table[1], PICOPASS_BLOCK_SIZE);
3865+
iclass_recover_req_t *payload = calloc(1, payload_size);
3866+
payload->req.use_raw = true;
3867+
payload->req.use_elite = false;
3868+
payload->req.use_credit_key = false;
3869+
payload->req.use_replay = true;
3870+
payload->req.send_reply = true;
3871+
payload->req.do_auth = true;
3872+
payload->req.shallow_mod = false;
3873+
payload->req2.use_raw = false;
3874+
payload->req2.use_elite = false;
3875+
payload->req2.use_credit_key = true;
3876+
payload->req2.use_replay = false;
3877+
payload->req2.send_reply = true;
3878+
payload->req2.do_auth = true;
3879+
payload->req2.shallow_mod = false;
3880+
payload->index = index_start;
3881+
payload->loop = loop;
3882+
payload->debug = debug;
3883+
payload->test = test;
3884+
memcpy(payload->nfa, no_first_auth, PICOPASS_BLOCK_SIZE);
3885+
memcpy(payload->req.key, key, PICOPASS_BLOCK_SIZE);
3886+
memcpy(payload->req2.key, aa2_standard_key, PICOPASS_BLOCK_SIZE);
3887+
3888+
PrintAndLogEx(INFO, "Recover started...");
38743889

3875-
PrintAndLogEx(INFO, "Recover started...");
3876-
3877-
PacketResponseNG resp;
3878-
clearCommandBuffer();
3879-
SendCommandNG(CMD_HF_ICLASS_RECOVER, (uint8_t *)payload, payload_size);
3890+
PacketResponseNG resp;
3891+
clearCommandBuffer();
3892+
SendCommandNG(CMD_HF_ICLASS_RECOVER, (uint8_t *)payload, payload_size);
38803893

3881-
WaitForResponse(CMD_HF_ICLASS_RECOVER, &resp);
3894+
WaitForResponse(CMD_HF_ICLASS_RECOVER, &resp);
38823895

3883-
if (resp.status == PM3_SUCCESS) {
3884-
PrintAndLogEx(SUCCESS, "iCLASS Key Bits Recovery " _GREEN_("successful"));
3885-
} else {
3886-
PrintAndLogEx(WARNING, "iCLASS Key Bits Recovery " _RED_("failed"));
3896+
if (resp.status == PM3_SUCCESS) {
3897+
PrintAndLogEx(SUCCESS, "iCLASS Key Bits Recovery: " _GREEN_("completed!"));
3898+
repeat = false;
3899+
} else if (resp.status == PM3_ESOFT){
3900+
PrintAndLogEx(WARNING, "iCLASS Key Bits Recovery: " _RED_("failed/errors"));
3901+
repeat = false;
3902+
} else if (resp.status == PM3_EINVARG){
3903+
if(allnight){
3904+
if(runs <= cycle){
3905+
repeat = false;
3906+
}else{
3907+
index_start = index_start+loop;
3908+
cycle++;
3909+
}
3910+
}else{
3911+
repeat = false;
3912+
}
3913+
}
3914+
free(payload);
3915+
if(!repeat){
3916+
return resp.status;
3917+
}
38873918
}
3888-
3889-
free(payload);
3890-
return resp.status;
3919+
return PM3_SUCCESS;
38913920
}
38923921

38933922
void generate_key_block_inverted(const uint8_t *startingKey, uint64_t index, uint8_t *keyBlock) {
@@ -3912,84 +3941,60 @@ static int CmdHFiClassLegRecLookUp(const char *Cmd) {
39123941
CLIParserContext *ctx;
39133942
CLIParserInit(&ctx, "hf iclass legbrute",
39143943
"This command take sniffed trace data and partial raw key and bruteforces the remaining 40 bits of the raw key.",
3915-
"hf iclass legbrute --csn 8D7BD711FEFF12E0 --epurse feffffffffffffff --macs1 1306cad9b6c24466 --macs2 f0bf905e35f97923 --pk B4F12AADC5301225"
3944+
"hf iclass legbrute --epurse feffffffffffffff --macs1 1306cad9b6c24466 --macs2 f0bf905e35f97923 --pk B4F12AADC5301225"
39163945
);
39173946

39183947
void *argtable[] = {
39193948
arg_param_begin,
3920-
arg_str1(NULL, "csn", "<hex>", "Specify CSN as 8 hex bytes"),
39213949
arg_str1(NULL, "epurse", "<hex>", "Specify ePurse as 8 hex bytes"),
39223950
arg_str1(NULL, "macs1", "<hex>", "MACs captured from the reader"),
39233951
arg_str1(NULL, "macs2", "<hex>", "MACs captured from the reader, different than the first set (with the same csn and epurse value)"),
39243952
arg_str1(NULL, "pk", "<hex>", "Partial Key from legrec or starting key of keyblock from legbrute"),
3925-
arg_int0(NULL, "index", "<dec>", "Where to start from to retrieve the key, default 0"),
3953+
arg_int0(NULL, "index", "<dec>", "Where to start from to retrieve the key, default 0 - value in millions e.g. 1 is 1 million"),
39263954
arg_param_end
39273955
};
39283956
CLIExecWithReturn(ctx, Cmd, argtable, false);
39293957

3930-
int csn_len = 0;
3931-
uint8_t csn[8] = {0};
3932-
CLIGetHexWithReturn(ctx, 1, csn, &csn_len);
3933-
3934-
if (csn_len > 0) {
3935-
if (csn_len != 8) {
3936-
PrintAndLogEx(ERR, "CSN is incorrect length");
3937-
CLIParserFree(ctx);
3938-
return PM3_EINVARG;
3939-
}
3940-
}
3941-
39423958
int epurse_len = 0;
3943-
uint8_t epurse[8] = {0};
3944-
CLIGetHexWithReturn(ctx, 2, epurse, &epurse_len);
3945-
3946-
if (epurse_len > 0) {
3947-
if (epurse_len != 8) {
3948-
PrintAndLogEx(ERR, "ePurse is incorrect length");
3949-
CLIParserFree(ctx);
3950-
return PM3_EINVARG;
3951-
}
3952-
}
3959+
uint8_t epurse[PICOPASS_BLOCK_SIZE] = {0};
3960+
CLIGetHexWithReturn(ctx, 1, epurse, &epurse_len);
39533961

39543962
int macs_len = 0;
3955-
uint8_t macs[8] = {0};
3956-
CLIGetHexWithReturn(ctx, 3, macs, &macs_len);
3957-
3958-
if (macs_len > 0) {
3959-
if (macs_len != 8) {
3960-
PrintAndLogEx(ERR, "MAC1 is incorrect length");
3961-
CLIParserFree(ctx);
3962-
return PM3_EINVARG;
3963-
}
3964-
}
3963+
uint8_t macs[PICOPASS_BLOCK_SIZE] = {0};
3964+
CLIGetHexWithReturn(ctx, 2, macs, &macs_len);
39653965

39663966
int macs2_len = 0;
3967-
uint8_t macs2[8] = {0};
3968-
CLIGetHexWithReturn(ctx, 4, macs2, &macs2_len);
3969-
3970-
if (macs2_len > 0) {
3971-
if (macs2_len != 8) {
3972-
PrintAndLogEx(ERR, "MAC2 is incorrect length");
3973-
CLIParserFree(ctx);
3974-
return PM3_EINVARG;
3975-
}
3976-
}
3967+
uint8_t macs2[PICOPASS_BLOCK_SIZE] = {0};
3968+
CLIGetHexWithReturn(ctx, 3, macs2, &macs2_len);
39773969

39783970
int startingkey_len = 0;
3979-
uint8_t startingKey[8] = {0};
3980-
CLIGetHexWithReturn(ctx, 5, startingKey, &startingkey_len);
3981-
3982-
if (startingkey_len > 0) {
3983-
if (startingkey_len != 8) {
3984-
PrintAndLogEx(ERR, "Partial Key is incorrect length");
3985-
CLIParserFree(ctx);
3986-
return PM3_EINVARG;
3987-
}
3988-
}
3971+
uint8_t startingKey[PICOPASS_BLOCK_SIZE] = {0};
3972+
CLIGetHexWithReturn(ctx, 4, startingKey, &startingkey_len);
39893973

39903974
uint64_t index = arg_get_int_def(ctx, 6, 0); //has to be 64 as we're bruteforcing 40 bits
3975+
index = index * 1000000;
39913976

39923977
CLIParserFree(ctx);
3978+
3979+
if (epurse_len && epurse_len != PICOPASS_BLOCK_SIZE) {
3980+
PrintAndLogEx(ERR, "ePurse is incorrect length");
3981+
return PM3_EINVARG;
3982+
}
3983+
3984+
if (macs_len && macs_len != PICOPASS_BLOCK_SIZE) {
3985+
PrintAndLogEx(ERR, "MAC1 is incorrect length");
3986+
return PM3_EINVARG;
3987+
}
3988+
3989+
if (macs2_len && macs2_len != PICOPASS_BLOCK_SIZE) {
3990+
PrintAndLogEx(ERR, "MAC2 is incorrect length");
3991+
return PM3_EINVARG;
3992+
}
3993+
3994+
if (startingkey_len && startingkey_len != PICOPASS_BLOCK_SIZE) {
3995+
PrintAndLogEx(ERR, "Partial Key is incorrect length");
3996+
return PM3_EINVARG;
3997+
}
39933998
//Standalone Command End
39943999

39954000
uint8_t CCNR[12];
@@ -4005,7 +4010,6 @@ static int CmdHFiClassLegRecLookUp(const char *Cmd) {
40054010
memcpy(MAC_TAG, macs + 4, 4);
40064011
memcpy(MAC_TAG2, macs2 + 4, 4);
40074012

4008-
PrintAndLogEx(SUCCESS, " CSN: " _GREEN_("%s"), sprint_hex(csn, 8));
40094013
PrintAndLogEx(SUCCESS, " Epurse: %s", sprint_hex(epurse, 8));
40104014
PrintAndLogEx(SUCCESS, " MACS1: %s", sprint_hex(macs, 8));
40114015
PrintAndLogEx(SUCCESS, " MACS2: %s", sprint_hex(macs2, 8));
@@ -4072,34 +4076,66 @@ static int CmdHFiClassLegacyRecover(const char *Cmd) {
40724076

40734077
CLIParserContext *ctx;
40744078
CLIParserInit(&ctx, "hf iclass legrec",
4075-
"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!",
4076-
"hf iclass legrec --macs 0000000089cb984b"
4079+
"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!",
4080+
"hf iclass legrec --macs 0000000089cb984b\n"
4081+
"hf iclass legrec --macs 0000000089cb984b --index 0 --loop 100 --notest"
40774082
);
40784083

40794084
void *argtable[] = {
40804085
arg_param_begin,
4081-
arg_str1(NULL, "macs", "<hex>", "MACs"),
4086+
arg_str1(NULL, "macs", "<hex>", "AA1 Authentication MACs"),
4087+
arg_int0(NULL, "index", "<dec>", "Where to start from to retrieve the key, default 0"),
4088+
arg_int0(NULL, "loop", "<dec>", "The number of key retrieval cycles to perform, max 10000, default 100"),
4089+
arg_lit0(NULL, "debug", "Re-enables tracing for debugging. Limits cycles to 1."),
4090+
arg_lit0(NULL, "notest", "Perform real writes on the card!"),
4091+
arg_lit0(NULL, "allnight", "Loops the loop for 10 times, recommended loop value of 5000."),
40824092
arg_param_end
40834093
};
40844094
CLIExecWithReturn(ctx, Cmd, argtable, false);
40854095

40864096
int macs_len = 0;
4087-
uint8_t macs[8] = {0};
4097+
uint8_t macs[PICOPASS_BLOCK_SIZE] = {0};
40884098
CLIGetHexWithReturn(ctx, 1, macs, &macs_len);
4099+
uint32_t index = arg_get_int_def(ctx, 2, 0);
4100+
uint32_t loop = arg_get_int_def(ctx, 3, 100);
4101+
uint8_t no_first_auth[PICOPASS_BLOCK_SIZE] = {0};
4102+
bool debug = arg_get_lit(ctx, 4);
4103+
bool test = true;
4104+
bool no_test = arg_get_lit(ctx, 5);
4105+
bool allnight = arg_get_lit(ctx, 6);
40894106

4090-
if (macs_len > 0) {
4091-
if (macs_len != 8) {
4092-
PrintAndLogEx(ERR, "MAC is incorrect length");
4093-
CLIParserFree(ctx);
4094-
return PM3_EINVARG;
4095-
}
4107+
if(no_test){
4108+
test=false;
40964109
}
40974110

4111+
if(loop > 10000){
4112+
PrintAndLogEx(ERR, "Too many loops, arm prone to crashes. For safety specify a number lower than 10000");
4113+
CLIParserFree(ctx);
4114+
return PM3_EINVARG;
4115+
}else if (debug || test){
4116+
loop = 1;
4117+
}
4118+
4119+
uint8_t csn[PICOPASS_BLOCK_SIZE] = {0};
4120+
uint8_t new_div_key[PICOPASS_BLOCK_SIZE] = {0};
4121+
uint8_t CCNR[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
4122+
if (select_only(csn, CCNR, true, false) == false) {
4123+
DropField();
4124+
return PM3_ESOFT;
4125+
}
4126+
HFiClassCalcDivKey(csn, iClass_Key_Table[1], new_div_key, false);
4127+
memcpy(no_first_auth,new_div_key,PICOPASS_BLOCK_SIZE);
4128+
40984129
CLIParserFree(ctx);
40994130

4100-
CmdHFiClassRecover(macs);
4131+
if (macs_len && macs_len != PICOPASS_BLOCK_SIZE) {
4132+
PrintAndLogEx(ERR, "MAC is incorrect length");
4133+
return PM3_EINVARG;
4134+
}
4135+
4136+
iclass_recover(macs,index,loop,no_first_auth,debug,test,allnight);
41014137

4102-
PrintAndLogEx(WARNING, _YELLOW_("If the process completed, you can now run 'hf iclass legrecbrute' with the partial key found."));
4138+
PrintAndLogEx(WARNING, _YELLOW_("If the process completed successfully, you can now run 'hf iclass legbrute' with the partial key found."));
41034139

41044140
PrintAndLogEx(NORMAL, "");
41054141
return PM3_SUCCESS;

include/iclass_cmd.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,11 @@ typedef struct {
108108
typedef struct {
109109
iclass_auth_req_t req;
110110
iclass_auth_req_t req2;
111+
uint32_t index;
112+
uint32_t loop;
113+
uint8_t nfa[8];
114+
bool debug;
115+
bool test;
111116
} PACKED iclass_recover_req_t;
112117

113118
typedef struct iclass_premac {

0 commit comments

Comments
 (0)