Merge pull request #3111 from Antiklesys/master

Added --credit option for hf iclass legrec
This commit is contained in:
Iceman
2026-03-06 08:56:21 +01:00
committed by GitHub
4 changed files with 44 additions and 21 deletions
+1
View File
@@ -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]
- Added --credit option for `hf iclass legrec` command to perform a credit key recovery. This is experimental and unfinished as it only partially works.(@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)
+15 -4
View File
@@ -2746,6 +2746,9 @@ 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. */
@@ -2788,7 +2791,7 @@ void iClass_Recover(iclass_recover_req_t *msg) {
}
//Step0 Card Select Routine
eof_time = 0; //reset eof time
res = select_iclass_tag(&hdr, false, &eof_time, shallow_mod);
res = select_iclass_tag(&hdr, msg->credit_recovery, &eof_time, shallow_mod);
if (res) {
status_message = 1; //card select successful
card_select = true;
@@ -2796,14 +2799,16 @@ 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 macs successful
status_message = 2; //authentication with AA1(AA2 if credit recovery) macs successful
card_auth = true;
}
}
@@ -2852,7 +2857,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, false, &eof_time, shallow_mod);
res = select_iclass_tag(&hdr, msg->credit_recovery, &eof_time, shallow_mod);
if (res) {
status_message = 1; // card select successful
card_select = true;
@@ -2923,6 +2928,9 @@ 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);
@@ -3072,6 +3080,9 @@ 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;
+27 -16
View File
@@ -4610,7 +4610,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) {
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) {
int runs = 1;
int cycle = 1;
@@ -4631,22 +4631,15 @@ static int iclass_recover(uint8_t key[8], uint32_t index_start, uint32_t loop, u
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;
payload->index = index_start;
payload->loop = loop;
payload->debug = debug;
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);
memcpy(payload->req2.key, aa2_standard_key, PICOPASS_BLOCK_SIZE);
PrintAndLogEx(INFO, "Recover started...");
@@ -4925,7 +4918,7 @@ static void generate_single_key_block_inverted_opt(const uint8_t *startingKey, u
}
static int CmdHFiClassLegacyRecSim(void) {
static int CmdHFiClassLegacyRecSim(bool credit) {
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, _YELLOW_("This simulation assumes the card is standard keyed."));
@@ -4940,7 +4933,11 @@ static int CmdHFiClassLegacyRecSim(void) {
}
uint8_t new_div_key[8] = {0};
HFiClassCalcDivKey(csn, iClass_Key_Table[0], new_div_key, false);
if (credit == true){
HFiClassCalcDivKey(csn, iClass_Key_Table[1], new_div_key, false);
}else{
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};
@@ -5016,7 +5013,8 @@ static int CmdHFiClassLegacyRecover(const char *Cmd) {
arg_lit0(NULL, "allnight", "Loops the loop for 10 times, recommended loop value of 5000"),
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"),
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);
@@ -5034,9 +5032,10 @@ 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();
CmdHFiClassLegacyRecSim(credit);
return PM3_SUCCESS;
}
@@ -5048,9 +5047,14 @@ static int CmdHFiClassLegacyRecover(const char *Cmd) {
PrintAndLogEx(ERR, "Too many loops, arm prone to crashes. For safety specify a number lower than 10000");
CLIParserFree(ctx);
return PM3_EINVARG;
} else if (debug || test) {
} else if (test) {
loop = 1;
fast = false;
}else if (debug) {
if (loop > 10){
loop = 10;
}
fast = false;
}
uint8_t csn[PICOPASS_BLOCK_SIZE] = {0};
@@ -5060,7 +5064,14 @@ static int CmdHFiClassLegacyRecover(const char *Cmd) {
DropField();
return PM3_ESOFT;
}
diversifyKey(csn, iClass_Key_Table[1], new_div_key);
if(credit == true){
diversifyKey(csn, iClass_Key_Table[0], new_div_key);
fast = false;
}else{
diversifyKey(csn, iClass_Key_Table[1], new_div_key);
}
memcpy(no_first_auth, new_div_key, PICOPASS_BLOCK_SIZE);
CLIParserFree(ctx);
@@ -5074,7 +5085,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);
iclass_recover(macs, index, loop, no_first_auth, debug, test, fast, short_delay, allnight, credit);
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(WARNING, _YELLOW_("If the process completed successfully"));
PrintAndLogEx(HINT, "Hint: run `" _YELLOW_("hf iclass legbrute -h") "` with the partial key found");
+1 -1
View File
@@ -120,7 +120,6 @@ typedef struct {
typedef struct {
iclass_auth_req_t req;
iclass_auth_req_t req2;
uint32_t index;
uint32_t loop;
uint8_t nfa[8];
@@ -128,6 +127,7 @@ typedef struct {
bool test;
bool fast;
bool short_delay;
bool credit_recovery;
} PACKED iclass_recover_req_t;
typedef struct iclass_premac {