mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 05:43:48 -07:00
Merge pull request #1072 from tcprst/iclass_cliparser
hf iclass chk, managekeys, calcnewkey, lookup, sim - now use cliparser
This commit is contained in:
commit
4f55b349df
4 changed files with 335 additions and 384 deletions
|
@ -51,103 +51,6 @@ static uint8_t iClass_Key_Table[ICLASS_KEYS_MAX][8] = {
|
||||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
|
||||||
};
|
};
|
||||||
|
|
||||||
static int usage_hf_iclass_sim(void) {
|
|
||||||
PrintAndLogEx(NORMAL, "Simulate a iCLASS legacy/standard tag\n");
|
|
||||||
PrintAndLogEx(NORMAL, "Usage: hf iCLASS sim [h] <option> [CSN]\n");
|
|
||||||
PrintAndLogEx(NORMAL, "Options");
|
|
||||||
PrintAndLogEx(NORMAL, " h : Show this help");
|
|
||||||
PrintAndLogEx(NORMAL, " 0 <CSN> : simulate the given CSN");
|
|
||||||
PrintAndLogEx(NORMAL, " 1 : simulate default CSN");
|
|
||||||
PrintAndLogEx(NORMAL, " 2 : Reader-attack, gather reader responses to extract elite key");
|
|
||||||
PrintAndLogEx(NORMAL, " 3 : Full simulation using emulator memory (see 'hf iclass eload')");
|
|
||||||
PrintAndLogEx(NORMAL, " 4 : Reader-attack, adapted for KeyRoll mode, gather reader responses to extract elite key");
|
|
||||||
PrintAndLogEx(NORMAL, "Examples:");
|
|
||||||
PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass sim 0 031FEC8AF7FF12E0"));
|
|
||||||
PrintAndLogEx(NORMAL, " -- execute loclass attack online part");
|
|
||||||
PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass sim 2"));
|
|
||||||
PrintAndLogEx(NORMAL, " -- simulate full iCLASS 2k tag");
|
|
||||||
PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass eload -f hf-iclass-AA162D30F8FF12F1-dump.bin"));
|
|
||||||
PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass sim 3"));
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
|
||||||
return PM3_SUCCESS;
|
|
||||||
}
|
|
||||||
static int usage_hf_iclass_calc_newkey(void) {
|
|
||||||
PrintAndLogEx(NORMAL, "Calculate new key for updating\n");
|
|
||||||
PrintAndLogEx(NORMAL, "Usage: hf iclass calc_newkey o <old key> n <new key> s [csn] e\n");
|
|
||||||
PrintAndLogEx(NORMAL, "Options:");
|
|
||||||
PrintAndLogEx(NORMAL, " h : Show this help");
|
|
||||||
PrintAndLogEx(NORMAL, " o <old key> : *specify a key as 16 hex symbols or a key number as 1 symbol");
|
|
||||||
PrintAndLogEx(NORMAL, " n <new key> : *specify a key as 16 hex symbols or a key number as 1 symbol");
|
|
||||||
PrintAndLogEx(NORMAL, " s <csn> : specify a card Serial number to diversify the key (if omitted will attempt to read a csn)");
|
|
||||||
PrintAndLogEx(NORMAL, " e : specify new key as elite calc");
|
|
||||||
PrintAndLogEx(NORMAL, " ee : specify old and new key as elite calc");
|
|
||||||
PrintAndLogEx(NORMAL, "Examples:");
|
|
||||||
PrintAndLogEx(NORMAL, " -- e key to e key given csn");
|
|
||||||
PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass calcnewkey o 1122334455667788 n 2233445566778899 s deadbeafdeadbeaf ee"));
|
|
||||||
PrintAndLogEx(NORMAL, " -- std key to e key read csn");
|
|
||||||
PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass calcnewkey o 1122334455667788 n 2233445566778899 e"));
|
|
||||||
PrintAndLogEx(NORMAL, " -- std to std read csn");
|
|
||||||
PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass calcnewkey o 1122334455667788 n 2233445566778899"));
|
|
||||||
PrintAndLogEx(NORMAL, "\nNOTE: * = required");
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
|
||||||
return PM3_SUCCESS;
|
|
||||||
}
|
|
||||||
static int usage_hf_iclass_managekeys(void) {
|
|
||||||
PrintAndLogEx(NORMAL, "Manage iCLASS Keys in client memory:\n");
|
|
||||||
PrintAndLogEx(NORMAL, "Usage: hf iclass managekeys n [keynbr] k [key] f [filename] s l p\n");
|
|
||||||
PrintAndLogEx(NORMAL, "Options:");
|
|
||||||
PrintAndLogEx(NORMAL, " h : Show this help");
|
|
||||||
PrintAndLogEx(NORMAL, " n <keynbr> : specify the keyNbr to set in memory");
|
|
||||||
PrintAndLogEx(NORMAL, " k <key> : set a key in memory");
|
|
||||||
PrintAndLogEx(NORMAL, " f <filename> : specify a filename to use with load or save operations");
|
|
||||||
PrintAndLogEx(NORMAL, " s : save keys in memory to file specified by filename");
|
|
||||||
PrintAndLogEx(NORMAL, " l : load keys to memory from file specified by filename");
|
|
||||||
PrintAndLogEx(NORMAL, " p : print keys loaded into memory\n");
|
|
||||||
PrintAndLogEx(NORMAL, "Examples:");
|
|
||||||
PrintAndLogEx(NORMAL, " -- set key");
|
|
||||||
PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass managekeys n 0 k 1122334455667788"));
|
|
||||||
PrintAndLogEx(NORMAL, " -- save key file");
|
|
||||||
PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass managekeys f mykeys.bin s"));
|
|
||||||
PrintAndLogEx(NORMAL, " -- load key file");
|
|
||||||
PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass managekeys f mykeys.bin l"));
|
|
||||||
PrintAndLogEx(NORMAL, " -- print keys");
|
|
||||||
PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass managekeys p"));
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
|
||||||
return PM3_SUCCESS;
|
|
||||||
}
|
|
||||||
static int usage_hf_iclass_chk(void) {
|
|
||||||
PrintAndLogEx(NORMAL, "Checkkeys loads a dictionary text file with 8byte hex keys to test authenticating against a iClass tag\n");
|
|
||||||
PrintAndLogEx(NORMAL, "Usage: hf iclass chk [h|e|r] [f (*.dic)]\n");
|
|
||||||
PrintAndLogEx(NORMAL, "Options:");
|
|
||||||
PrintAndLogEx(NORMAL, " h Show this help");
|
|
||||||
PrintAndLogEx(NORMAL, " f <filename> Dictionary file with default iclass keys");
|
|
||||||
PrintAndLogEx(NORMAL, " r raw");
|
|
||||||
PrintAndLogEx(NORMAL, " e elite");
|
|
||||||
PrintAndLogEx(NORMAL, " c credit key (if not use, default is debit)");
|
|
||||||
PrintAndLogEx(NORMAL, "Examples:");
|
|
||||||
PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass chk f dictionaries/iclass_default_keys.dic"));
|
|
||||||
PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass chk f dictionaries/iclass_default_keys.dic e"));
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
|
||||||
return PM3_SUCCESS;
|
|
||||||
}
|
|
||||||
static int usage_hf_iclass_lookup(void) {
|
|
||||||
PrintAndLogEx(NORMAL, "Lookup keys takes some sniffed trace data and tries to verify what key was used against a dictionary file\n");
|
|
||||||
PrintAndLogEx(NORMAL, "Usage: hf iclass lookup [h|e|r] [f (*.dic)] [u <csn>] [p <epurse>] [m <macs>]\n");
|
|
||||||
PrintAndLogEx(NORMAL, "Options:");
|
|
||||||
PrintAndLogEx(NORMAL, " h Show this help");
|
|
||||||
PrintAndLogEx(NORMAL, " f <filename> Dictionary file with default iclass keys");
|
|
||||||
PrintAndLogEx(NORMAL, " u CSN");
|
|
||||||
PrintAndLogEx(NORMAL, " p EPURSE");
|
|
||||||
PrintAndLogEx(NORMAL, " m macs");
|
|
||||||
PrintAndLogEx(NORMAL, " r raw");
|
|
||||||
PrintAndLogEx(NORMAL, " e elite");
|
|
||||||
PrintAndLogEx(NORMAL, "Examples:");
|
|
||||||
PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass lookup u 9655a400f8ff12e0 p f0ffffffffffffff m 0000000089cb984b f dictionaries/iclass_default_keys.dic"));
|
|
||||||
PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass lookup u 9655a400f8ff12e0 p f0ffffffffffffff m 0000000089cb984b f dictionaries/iclass_default_keys.dic e"));
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
|
||||||
return PM3_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cmp_uint32(const void *a, const void *b) {
|
static int cmp_uint32(const void *a, const void *b) {
|
||||||
|
|
||||||
const iclass_prekey_t *x = (const iclass_prekey_t *)a;
|
const iclass_prekey_t *x = (const iclass_prekey_t *)a;
|
||||||
|
@ -455,24 +358,48 @@ static int CmdHFiClassSniff(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int CmdHFiClassSim(const char *Cmd) {
|
static int CmdHFiClassSim(const char *Cmd) {
|
||||||
|
CLIParserContext *ctx;
|
||||||
|
CLIParserInit(&ctx, "hf iclass sim",
|
||||||
|
"Simulate a iCLASS legacy/standard tag",
|
||||||
|
"hf iclass sim -t 0 --csn 031FEC8AF7FF12E0 -> simulate with specficied CSN\n"
|
||||||
|
"hf iclass sim -t 1 -> simulate with default CSN\n"
|
||||||
|
"hf iclass sim -t 2 -> execute loclass attack online part\n"
|
||||||
|
"hf iclass eload -f hf-iclass-AA162D30F8FF12F1-dump.bin -> simulate full iCLASS 2k tag\n"
|
||||||
|
"hf iclass sim -t 3 -> simulate full iCLASS 2k tag\n"
|
||||||
|
"hf iclass sim -t 4 -> Reader-attack, adapted for KeyRoll mode, gather reader responses to extract elite key");
|
||||||
|
|
||||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
void *argtable[] = {
|
||||||
if (strlen(Cmd) < 1 || cmdp == 'h') return usage_hf_iclass_sim();
|
arg_param_begin,
|
||||||
|
arg_int1("t", "type", NULL, "Simulation type to use"),
|
||||||
|
arg_str0(NULL, "csn", "<hex>", "Specify CSN as 8 bytes (16 hex symbols) to use with sim type 0"),
|
||||||
|
arg_param_end
|
||||||
|
};
|
||||||
|
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||||
|
|
||||||
uint8_t CSN[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
int sim_type = arg_get_int(ctx, 1);
|
||||||
uint8_t sim_type = param_get8ex(Cmd, 0, 0, 10);
|
|
||||||
|
|
||||||
if (sim_type == 0) {
|
int csn_len = 0;
|
||||||
if (param_gethex(Cmd, 1, CSN, 16)) {
|
uint8_t csn[8] = {0};
|
||||||
PrintAndLogEx(ERR, "A CSN should consist of 16 HEX symbols");
|
CLIGetHexWithReturn(ctx, 2, csn, &csn_len);
|
||||||
return usage_hf_iclass_sim();
|
|
||||||
|
if (sim_type == 0 && csn_len > 0) {
|
||||||
|
if (csn_len != 8) {
|
||||||
|
PrintAndLogEx(ERR, "CSN is incorrect length");
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
PrintAndLogEx(INFO, " simtype: %02x CSN: %s", sim_type, sprint_hex(CSN, 8));
|
PrintAndLogEx(INFO, " simtype: %02x CSN: %s", sim_type, sprint_hex(csn, 8));
|
||||||
|
} else if (sim_type == 0 && csn_len == 0) {
|
||||||
|
PrintAndLogEx(ERR, "Simtype 0 requires CSN argument (--csn)");
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
if (sim_type > 4) {
|
if (sim_type > 4) {
|
||||||
PrintAndLogEx(ERR, "Undefined simtype %d", sim_type);
|
PrintAndLogEx(ERR, "Undefined simtype %d", sim_type);
|
||||||
return usage_hf_iclass_sim();
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
// remember to change the define NUM_CSNS to match.
|
// remember to change the define NUM_CSNS to match.
|
||||||
|
@ -626,10 +553,10 @@ static int CmdHFiClassSim(const char *Cmd) {
|
||||||
case ICLASS_SIM_MODE_FULL:
|
case ICLASS_SIM_MODE_FULL:
|
||||||
default: {
|
default: {
|
||||||
PrintAndLogEx(INFO, "Starting iCLASS simulation");
|
PrintAndLogEx(INFO, "Starting iCLASS simulation");
|
||||||
PrintAndLogEx(INFO, "press " _YELLOW_("`enter`") " to cancel");
|
PrintAndLogEx(INFO, "press " _YELLOW_("`button`") " to cancel");
|
||||||
uint8_t numberOfCSNs = 0;
|
uint8_t numberOfCSNs = 0;
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandMIX(CMD_HF_ICLASS_SIMULATE, sim_type, numberOfCSNs, 1, CSN, 8);
|
SendCommandMIX(CMD_HF_ICLASS_SIMULATE, sim_type, numberOfCSNs, 1, csn, 8);
|
||||||
|
|
||||||
if (sim_type == ICLASS_SIM_MODE_FULL)
|
if (sim_type == ICLASS_SIM_MODE_FULL)
|
||||||
PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass esave -h") "` to save the emulator memory to file");
|
PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass esave -h") "` to save the emulator memory to file");
|
||||||
|
@ -1359,7 +1286,7 @@ static int CmdHFiClassDump(const char *Cmd) {
|
||||||
if (credit_key_len > 0) {
|
if (credit_key_len > 0) {
|
||||||
auth = true;
|
auth = true;
|
||||||
have_credit_key = true;
|
have_credit_key = true;
|
||||||
if (key_len != 8) {
|
if (credit_key_len != 8) {
|
||||||
PrintAndLogEx(ERR, "Credit key is incorrect length");
|
PrintAndLogEx(ERR, "Credit key is incorrect length");
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
|
@ -2377,89 +2304,127 @@ static void HFiClassCalcNewKey(uint8_t *CSN, uint8_t *OLDKEY, uint8_t *NEWKEY, u
|
||||||
}
|
}
|
||||||
|
|
||||||
static int CmdHFiClassCalcNewKey(const char *Cmd) {
|
static int CmdHFiClassCalcNewKey(const char *Cmd) {
|
||||||
uint8_t OLDKEY[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
CLIParserContext *ctx;
|
||||||
uint8_t NEWKEY[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
CLIParserInit(&ctx, "hf iclass calcnewkey",
|
||||||
uint8_t xor_div_key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
"Calculate new keys for updating (blocks 3 & 4)",
|
||||||
uint8_t CSN[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
"hf iclass calcnewkey --old 1122334455667788 --new 2233445566778899 --csn deadbeafdeadbeaf --elite2 -> e key to e key given csn\n"
|
||||||
uint8_t keyNbr = 0;
|
"hf iclass calcnewkey --old 1122334455667788 --new 2233445566778899 --elite -> std key to e key read csn\n"
|
||||||
uint8_t dataLen = 0;
|
"hf iclass calcnewkey --old 1122334455667788 --new 2233445566778899 -> std to std read csn");
|
||||||
char tempStr[50] = {0};
|
|
||||||
bool givenCSN = false;
|
|
||||||
bool old_elite = false;
|
|
||||||
bool elite = false;
|
|
||||||
bool errors = false;
|
|
||||||
uint8_t cmdp = 0;
|
|
||||||
|
|
||||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
void *argtable[] = {
|
||||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
arg_param_begin,
|
||||||
case 'h':
|
arg_str0(NULL, "old", "<hex>", "Specify key as 8 bytes (16 hex symbols)"),
|
||||||
return usage_hf_iclass_calc_newkey();
|
arg_int0(NULL, "oki", "<dec>", "Old key index to select key from memory 'hf iclass managekeys'"),
|
||||||
case 'e':
|
arg_str0(NULL, "new", "<hex>", "Specify key as 8 bytes (16 hex symbols)"),
|
||||||
dataLen = param_getstr(Cmd, cmdp, tempStr, sizeof(tempStr));
|
arg_int0(NULL, "nki", "<dec>", "New key index to select key from memory 'hf iclass managekeys'"),
|
||||||
if (dataLen == 2)
|
arg_str0(NULL, "csn", "<hex>", "Specify a Card Serial Number (CSN) to diversify the key (if omitted will attempt to read a CSN)"),
|
||||||
old_elite = true;
|
arg_lit0(NULL, "elite", "Elite computations applied to new key"),
|
||||||
elite = true;
|
arg_lit0(NULL, "elite2", "Elite computations applied to both old and new key"),
|
||||||
cmdp++;
|
arg_param_end
|
||||||
break;
|
};
|
||||||
case 'n':
|
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||||
dataLen = param_getstr(Cmd, cmdp + 1, tempStr, sizeof(tempStr));
|
|
||||||
if (dataLen == 16) {
|
int old_key_len = 0;
|
||||||
errors = param_gethex(tempStr, 0, NEWKEY, dataLen);
|
uint8_t old_key[8] = {0};
|
||||||
} else if (dataLen == 1) {
|
CLIGetHexWithReturn(ctx, 1, old_key, &old_key_len);
|
||||||
keyNbr = param_get8(Cmd, cmdp + 1);
|
|
||||||
if (keyNbr < ICLASS_KEYS_MAX) {
|
int old_key_nr = arg_get_int_def(ctx, 2, -1);
|
||||||
memcpy(NEWKEY, iClass_Key_Table[keyNbr], 8);
|
|
||||||
|
if (old_key_len > 0 && old_key_nr >= 0) {
|
||||||
|
PrintAndLogEx(ERR, "Please specify old key or index, not both");
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (old_key_len > 0) {
|
||||||
|
if (old_key_len != 8) {
|
||||||
|
PrintAndLogEx(ERR, "Old key is incorrect length");
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
} else if (old_key_nr >= 0) {
|
||||||
|
if (old_key_nr < ICLASS_KEYS_MAX) {
|
||||||
|
memcpy(old_key, iClass_Key_Table[old_key_nr], 8);
|
||||||
|
PrintAndLogEx(SUCCESS, "Using old key[%d] " _GREEN_("%s"), old_key_nr, sprint_hex(iClass_Key_Table[old_key_nr], 8));
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(WARNING, "\nERROR: NewKey Nbr is invalid\n");
|
PrintAndLogEx(ERR, "Key number is invalid");
|
||||||
errors = true;
|
CLIParserFree(ctx);
|
||||||
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(WARNING, "\nERROR: NewKey is incorrect length\n");
|
PrintAndLogEx(ERR, "Please specify an old key or old key index");
|
||||||
errors = true;
|
CLIParserFree(ctx);
|
||||||
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
cmdp += 2;
|
|
||||||
break;
|
int new_key_len = 0;
|
||||||
case 'o':
|
uint8_t new_key[8] = {0};
|
||||||
dataLen = param_getstr(Cmd, cmdp + 1, tempStr, sizeof(tempStr));
|
CLIGetHexWithReturn(ctx, 3, new_key, &new_key_len);
|
||||||
if (dataLen == 16) {
|
|
||||||
errors = param_gethex(tempStr, 0, OLDKEY, dataLen);
|
int new_key_nr = arg_get_int_def(ctx, 4, -1);
|
||||||
} else if (dataLen == 1) {
|
|
||||||
keyNbr = param_get8(Cmd, cmdp + 1);
|
if (new_key_len > 0 && new_key_nr >= 0) {
|
||||||
if (keyNbr < ICLASS_KEYS_MAX) {
|
PrintAndLogEx(ERR, "Please specify new key or index, not both");
|
||||||
memcpy(OLDKEY, iClass_Key_Table[keyNbr], 8);
|
CLIParserFree(ctx);
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_key_len > 0) {
|
||||||
|
if (new_key_len != 8) {
|
||||||
|
PrintAndLogEx(ERR, "New key is incorrect length");
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
} else if (new_key_nr >= 0) {
|
||||||
|
if (new_key_nr < ICLASS_KEYS_MAX) {
|
||||||
|
memcpy(new_key, iClass_Key_Table[new_key_nr], 8);
|
||||||
|
PrintAndLogEx(SUCCESS, "Using new key[%d] " _GREEN_("%s"), new_key_nr, sprint_hex(iClass_Key_Table[new_key_nr], 8));
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(WARNING, "\nERROR: Credit KeyNbr is invalid\n");
|
PrintAndLogEx(ERR, "Key number is invalid");
|
||||||
errors = true;
|
CLIParserFree(ctx);
|
||||||
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(WARNING, "\nERROR: Credit Key is incorrect length\n");
|
PrintAndLogEx(ERR, "Please specify an new key or old key index");
|
||||||
errors = true;
|
CLIParserFree(ctx);
|
||||||
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
cmdp += 2;
|
|
||||||
break;
|
int csn_len = 0;
|
||||||
case 's':
|
uint8_t csn[8] = {0};
|
||||||
|
CLIGetHexWithReturn(ctx, 5, csn, &csn_len);
|
||||||
|
bool givenCSN = false;
|
||||||
|
|
||||||
|
if (csn_len > 0) {
|
||||||
givenCSN = true;
|
givenCSN = true;
|
||||||
if (param_gethex(Cmd, cmdp + 1, CSN, 16))
|
if (csn_len != 8) {
|
||||||
return usage_hf_iclass_calc_newkey();
|
PrintAndLogEx(ERR, "CSN is incorrect length");
|
||||||
cmdp += 2;
|
CLIParserFree(ctx);
|
||||||
break;
|
return PM3_EINVARG;
|
||||||
default:
|
|
||||||
PrintAndLogEx(WARNING, "unknown parameter '%c'\n", param_getchar(Cmd, cmdp));
|
|
||||||
errors = true;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (errors || cmdp < 4) return usage_hf_iclass_calc_newkey();
|
|
||||||
|
bool elite = arg_get_lit(ctx, 6);
|
||||||
|
bool old_elite = false;
|
||||||
|
|
||||||
|
if (arg_get_lit(ctx, 7)) {
|
||||||
|
elite = true;
|
||||||
|
old_elite = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
|
uint8_t xor_div_key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
|
||||||
if (givenCSN == false) {
|
if (givenCSN == false) {
|
||||||
uint8_t CCNR[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
uint8_t CCNR[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
if (select_only(CSN, CCNR, true) == false) {
|
if (select_only(csn, CCNR, true) == false) {
|
||||||
DropField();
|
DropField();
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HFiClassCalcNewKey(CSN, OLDKEY, NEWKEY, xor_div_key, elite, old_elite, true);
|
HFiClassCalcNewKey(csn, old_key, new_key, xor_div_key, elite, old_elite, true);
|
||||||
|
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -2520,83 +2485,88 @@ static int printKeys(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int CmdHFiClassManageKeys(const char *Cmd) {
|
static int CmdHFiClassManageKeys(const char *Cmd) {
|
||||||
uint8_t keyNbr = 0;
|
CLIParserContext *ctx;
|
||||||
uint8_t dataLen = 0;
|
CLIParserInit(&ctx, "hf iclass managekeys",
|
||||||
uint8_t KEY[8] = {0};
|
"Manage iCLASS Keys in client memory",
|
||||||
char filename[FILE_PATH_SIZE];
|
"hf iclass managekeys --ki 0 -k 1122334455667788 -> set key\n"
|
||||||
uint8_t fileNameLen = 0;
|
"hf iclass managekeys -f mykeys.bin --save -> save key file\n"
|
||||||
bool errors = false;
|
"hf iclass managekeys -f mykeys.bin --load -> load key file\n"
|
||||||
uint8_t operation = 0;
|
"hf iclass managekeys -p -> print keys");
|
||||||
char tempStr[20];
|
|
||||||
uint8_t cmdp = 0;
|
|
||||||
|
|
||||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
void *argtable[] = {
|
||||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
arg_param_begin,
|
||||||
case 'h':
|
arg_str0("f", "file", "<filename>", "Specify a filename to use with load or save operations"),
|
||||||
return usage_hf_iclass_managekeys();
|
arg_str0("k", "key", "<hex>", "Access key as 16 hex symbols"),
|
||||||
case 'f':
|
arg_int0(NULL, "ki", "<dec>", "Specify key index to set key in memory"),
|
||||||
fileNameLen = param_getstr(Cmd, cmdp + 1, filename, sizeof(filename));
|
arg_lit0(NULL, "save", "Save keys in memory to file specified by filename"),
|
||||||
if (fileNameLen < 1) {
|
arg_lit0(NULL, "load", "Load keys to memory from file specified by filename"),
|
||||||
PrintAndLogEx(ERR, "No filename found");
|
arg_lit0("p", "print", "Print keys loaded into memory"),
|
||||||
errors = true;
|
arg_param_end
|
||||||
|
};
|
||||||
|
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||||
|
|
||||||
|
int fnlen = 0;
|
||||||
|
char filename[FILE_PATH_SIZE] = {0};
|
||||||
|
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||||
|
|
||||||
|
int key_len = 0;
|
||||||
|
uint8_t key[8] = {0};
|
||||||
|
CLIGetHexWithReturn(ctx, 2, key, &key_len);
|
||||||
|
uint8_t operation = 0;
|
||||||
|
|
||||||
|
if (key_len > 0) {
|
||||||
|
operation += 3;
|
||||||
|
if (key_len != 8) {
|
||||||
|
PrintAndLogEx(ERR, "Key is incorrect length");
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
cmdp += 2;
|
|
||||||
break;
|
|
||||||
case 'n':
|
|
||||||
keyNbr = param_get8(Cmd, cmdp + 1);
|
|
||||||
if (keyNbr >= ICLASS_KEYS_MAX) {
|
|
||||||
PrintAndLogEx(ERR, "Invalid block number, MAX is " _YELLOW_("%d"), ICLASS_KEYS_MAX);
|
|
||||||
errors = true;
|
|
||||||
}
|
}
|
||||||
cmdp += 2;
|
|
||||||
break;
|
int key_nr = arg_get_int_def(ctx, 3, -1);
|
||||||
case 'k':
|
|
||||||
operation += 3; //set key
|
if (key_nr >= 0) {
|
||||||
dataLen = param_getstr(Cmd, cmdp + 1, tempStr, sizeof(tempStr));
|
if (key_nr < ICLASS_KEYS_MAX) {
|
||||||
if (dataLen == 16) { //ul-c or ev1/ntag key length
|
PrintAndLogEx(SUCCESS, "Setting key[%d] " _GREEN_("%s"), key_nr);
|
||||||
errors = param_gethex(tempStr, 0, KEY, dataLen);
|
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(WARNING, "\nERROR: Key is incorrect length\n");
|
PrintAndLogEx(ERR, "Key number is invalid");
|
||||||
errors = true;
|
CLIParserFree(ctx);
|
||||||
}
|
return PM3_EINVARG;
|
||||||
cmdp += 2;
|
|
||||||
break;
|
|
||||||
case 'p':
|
|
||||||
operation += 4; //print keys in memory
|
|
||||||
cmdp++;
|
|
||||||
break;
|
|
||||||
case 'l':
|
|
||||||
operation += 5; //load keys from file
|
|
||||||
cmdp++;
|
|
||||||
break;
|
|
||||||
case 's':
|
|
||||||
operation += 6; //save keys to file
|
|
||||||
cmdp++;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
PrintAndLogEx(WARNING, "unknown parameter '%c'\n", param_getchar(Cmd, cmdp));
|
|
||||||
errors = true;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (errors) return usage_hf_iclass_managekeys();
|
|
||||||
|
if (arg_get_lit(ctx, 4)) { //save
|
||||||
|
operation += 6;
|
||||||
|
}
|
||||||
|
if (arg_get_lit(ctx, 5)) { //load
|
||||||
|
operation += 5;
|
||||||
|
}
|
||||||
|
if (arg_get_lit(ctx, 6)) { //print
|
||||||
|
operation += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
if (operation == 0) {
|
if (operation == 0) {
|
||||||
PrintAndLogEx(WARNING, "no operation specified (load, save, or print)\n");
|
PrintAndLogEx(ERR, "No operation specified (load, save, or print)\n");
|
||||||
return usage_hf_iclass_managekeys();
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
if (operation > 6) {
|
if (operation > 6) {
|
||||||
PrintAndLogEx(WARNING, "Too many operations specified\n");
|
PrintAndLogEx(ERR, "Too many operations specified\n");
|
||||||
return usage_hf_iclass_managekeys();
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
if (operation > 4 && fileNameLen == 0) {
|
if (operation > 4 && fnlen == 0) {
|
||||||
PrintAndLogEx(WARNING, "You must enter a filename when loading or saving\n");
|
PrintAndLogEx(ERR, "You must enter a filename when loading or saving\n");
|
||||||
return usage_hf_iclass_managekeys();
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
if (key_len > 0 && key_nr == -1) {
|
||||||
|
PrintAndLogEx(ERR, "Please specify key index when specifying key");
|
||||||
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (operation) {
|
switch (operation) {
|
||||||
case 3:
|
case 3:
|
||||||
memcpy(iClass_Key_Table[keyNbr], KEY, 8);
|
memcpy(iClass_Key_Table[key_nr], key, 8);
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
case 4:
|
case 4:
|
||||||
return printKeys();
|
return printKeys();
|
||||||
|
@ -2628,7 +2598,7 @@ static void add_key(uint8_t *key) {
|
||||||
if (i == ICLASS_KEYS_MAX) {
|
if (i == ICLASS_KEYS_MAX) {
|
||||||
PrintAndLogEx(INFO, "Couldn't find an empty keyslot");
|
PrintAndLogEx(INFO, "Couldn't find an empty keyslot");
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(HINT, "Try " _YELLOW_("`hf iclass managekeys p`") " to view keys");
|
PrintAndLogEx(HINT, "Try " _YELLOW_("`hf iclass managekeys -p`") " to view keys");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2730,60 +2700,41 @@ static int iclass_chk_keys(uint8_t *keyBlock, uint32_t keycount) {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int CmdHFiClassCheckKeys(const char *Cmd) {
|
static int CmdHFiClassCheckKeys(const char *Cmd) {
|
||||||
|
CLIParserContext *ctx;
|
||||||
|
CLIParserInit(&ctx, "hf iclass chk",
|
||||||
|
"Checkkeys loads a dictionary text file with 8byte hex keys to test authenticating against a iClass tag",
|
||||||
|
"hf iclass chk -f dictionaries/iclass_default_keys.dic\n"
|
||||||
|
"hf iclass chk -f dictionaries/iclass_default_keys.dic --elite");
|
||||||
|
|
||||||
// empty string
|
void *argtable[] = {
|
||||||
if (strlen(Cmd) == 0) return usage_hf_iclass_chk();
|
arg_param_begin,
|
||||||
|
arg_str1("f", "file", "<filename>", "Dictionary file with default iclass keys"),
|
||||||
|
arg_lit0(NULL, "credit", "key is assumed to be the credit key"),
|
||||||
|
arg_lit0(NULL, "elite", "elite computations applied to key"),
|
||||||
|
arg_lit0(NULL, "raw", "no computations applied to key (raw)"),
|
||||||
|
arg_param_end
|
||||||
|
};
|
||||||
|
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||||
|
|
||||||
|
int fnlen = 0;
|
||||||
|
char filename[FILE_PATH_SIZE] = {0};
|
||||||
|
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||||
|
|
||||||
|
bool use_credit_key = arg_get_lit(ctx, 2);
|
||||||
|
bool use_elite = arg_get_lit(ctx, 3);
|
||||||
|
bool use_raw = arg_get_lit(ctx, 4);
|
||||||
|
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
uint8_t CSN[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
uint8_t CSN[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
uint8_t CCNR[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
uint8_t CCNR[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
|
||||||
// elite key, raw key, standard key
|
|
||||||
bool use_elite = false;
|
|
||||||
bool use_raw = false;
|
|
||||||
bool use_credit_key = false;
|
|
||||||
bool found_key = false;
|
bool found_key = false;
|
||||||
//bool found_credit = false;
|
//bool found_credit = false;
|
||||||
bool got_csn = false;
|
bool got_csn = false;
|
||||||
bool errors = false;
|
|
||||||
uint8_t cmdp = 0x00;
|
|
||||||
|
|
||||||
char filename[FILE_PATH_SIZE] = {0};
|
|
||||||
uint8_t fileNameLen = 0;
|
|
||||||
|
|
||||||
uint64_t t1 = msclock();
|
uint64_t t1 = msclock();
|
||||||
|
|
||||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
|
||||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
|
||||||
case 'h':
|
|
||||||
return usage_hf_iclass_chk();
|
|
||||||
case 'f':
|
|
||||||
fileNameLen = param_getstr(Cmd, cmdp + 1, filename, sizeof(filename));
|
|
||||||
if (fileNameLen < 1) {
|
|
||||||
PrintAndLogEx(WARNING, _RED_("no filename found after f"));
|
|
||||||
errors = true;
|
|
||||||
}
|
|
||||||
cmdp += 2;
|
|
||||||
break;
|
|
||||||
case 'e':
|
|
||||||
use_elite = true;
|
|
||||||
cmdp++;
|
|
||||||
break;
|
|
||||||
case 'c':
|
|
||||||
use_credit_key = true;
|
|
||||||
cmdp++;
|
|
||||||
break;
|
|
||||||
case 'r':
|
|
||||||
use_raw = true;
|
|
||||||
cmdp++;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
PrintAndLogEx(WARNING, "unknown parameter '%c'\n", param_getchar(Cmd, cmdp));
|
|
||||||
errors = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (errors) return usage_hf_iclass_chk();
|
|
||||||
|
|
||||||
uint8_t *keyBlock = NULL;
|
uint8_t *keyBlock = NULL;
|
||||||
uint32_t keycount = 0;
|
uint32_t keycount = 0;
|
||||||
|
|
||||||
|
@ -2935,89 +2886,84 @@ out:
|
||||||
// this method tries to identify in which configuration mode a iCLASS / iCLASS SE reader is in.
|
// this method tries to identify in which configuration mode a iCLASS / iCLASS SE reader is in.
|
||||||
// Standard or Elite / HighSecurity mode. It uses a default key dictionary list in order to work.
|
// Standard or Elite / HighSecurity mode. It uses a default key dictionary list in order to work.
|
||||||
static int CmdHFiClassLookUp(const char *Cmd) {
|
static int CmdHFiClassLookUp(const char *Cmd) {
|
||||||
|
CLIParserContext *ctx;
|
||||||
|
CLIParserInit(&ctx, "hf iclass lookup",
|
||||||
|
"Lookup keys takes some sniffed trace data and tries to verify what key was used against a dictionary file",
|
||||||
|
"hf iclass lookup --csn 9655a400f8ff12e0 --epurse f0ffffffffffffff --macs 0000000089cb984b -f dictionaries/iclass_default_keys.dic\n"
|
||||||
|
"hf iclass lookup --csn 9655a400f8ff12e0 --epurse f0ffffffffffffff --macs 0000000089cb984b -f dictionaries/iclass_default_keys.dic --elite");
|
||||||
|
|
||||||
|
void *argtable[] = {
|
||||||
|
arg_param_begin,
|
||||||
|
arg_str1("f", "file", "<filename>", "Dictionary file with default iclass keys"),
|
||||||
|
arg_str1(NULL, "csn", "<hex>", "Specify CSN as 8 bytes (16 hex symbols)"),
|
||||||
|
arg_str1(NULL, "epurse", "<hex>", "Specify ePurse as 8 bytes (16 hex symbols)"),
|
||||||
|
arg_str1(NULL, "macs", "<hex>", "MACs"),
|
||||||
|
arg_lit0(NULL, "raw", "no computations applied to key (raw)"),
|
||||||
|
arg_lit0(NULL, "elite", "Elite computations applied to key"),
|
||||||
|
arg_param_end
|
||||||
|
};
|
||||||
|
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||||
|
|
||||||
|
int fnlen = 0;
|
||||||
|
char filename[FILE_PATH_SIZE] = {0};
|
||||||
|
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||||
|
|
||||||
|
int csn_len = 0;
|
||||||
|
uint8_t csn[8] = {0};
|
||||||
|
CLIGetHexWithReturn(ctx, 2, 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, 3, 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, 4, macs, &macs_len);
|
||||||
|
|
||||||
|
if (macs_len > 0) {
|
||||||
|
if (macs_len != 8) {
|
||||||
|
PrintAndLogEx(ERR, "MAC is incorrect length");
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool use_elite = arg_get_lit(ctx, 5);
|
||||||
|
bool use_raw = arg_get_lit(ctx, 6);
|
||||||
|
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
uint8_t CSN[8];
|
|
||||||
uint8_t EPURSE[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
||||||
uint8_t MACS[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
||||||
uint8_t CCNR[12];
|
uint8_t CCNR[12];
|
||||||
uint8_t MAC_TAG[4] = { 0, 0, 0, 0 };
|
uint8_t MAC_TAG[4] = { 0, 0, 0, 0 };
|
||||||
|
|
||||||
// elite key, raw key, standard key
|
|
||||||
bool use_elite = false;
|
|
||||||
bool use_raw = false;
|
|
||||||
bool errors = false;
|
|
||||||
uint8_t cmdp = 0x00;
|
|
||||||
|
|
||||||
char filename[FILE_PATH_SIZE] = {0};
|
|
||||||
|
|
||||||
iclass_prekey_t *prekey = NULL;
|
iclass_prekey_t *prekey = NULL;
|
||||||
int len = 0;
|
|
||||||
// if empty string
|
|
||||||
if (strlen(Cmd) == 0) errors = true;
|
|
||||||
// time
|
// time
|
||||||
uint64_t t1 = msclock();
|
uint64_t t1 = msclock();
|
||||||
|
|
||||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
|
||||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
|
||||||
case 'h':
|
|
||||||
return usage_hf_iclass_lookup();
|
|
||||||
case 'f':
|
|
||||||
if (param_getstr(Cmd, cmdp + 1, filename, sizeof(filename)) < 1) {
|
|
||||||
PrintAndLogEx(WARNING, "No filename found after f");
|
|
||||||
errors = true;
|
|
||||||
}
|
|
||||||
cmdp += 2;
|
|
||||||
break;
|
|
||||||
case 'u':
|
|
||||||
param_gethex_ex(Cmd, cmdp + 1, CSN, &len);
|
|
||||||
if (len >> 1 != sizeof(CSN)) {
|
|
||||||
PrintAndLogEx(WARNING, "Wrong CSN length, expected %zu got [%d]", sizeof(CSN), len >> 1);
|
|
||||||
errors = true;
|
|
||||||
}
|
|
||||||
cmdp += 2;
|
|
||||||
break;
|
|
||||||
case 'm':
|
|
||||||
param_gethex_ex(Cmd, cmdp + 1, MACS, &len);
|
|
||||||
if (len >> 1 != sizeof(MACS)) {
|
|
||||||
PrintAndLogEx(WARNING, "Wrong MACS length, expected %zu got [%d] ", sizeof(MACS), len >> 1);
|
|
||||||
errors = true;
|
|
||||||
} else {
|
|
||||||
memcpy(MAC_TAG, MACS + 4, 4);
|
|
||||||
}
|
|
||||||
cmdp += 2;
|
|
||||||
break;
|
|
||||||
case 'p':
|
|
||||||
param_gethex_ex(Cmd, cmdp + 1, EPURSE, &len);
|
|
||||||
if (len >> 1 != sizeof(EPURSE)) {
|
|
||||||
PrintAndLogEx(WARNING, "Wrong EPURSE length, expected %zu got [%d] ", sizeof(EPURSE), len >> 1);
|
|
||||||
errors = true;
|
|
||||||
}
|
|
||||||
cmdp += 2;
|
|
||||||
break;
|
|
||||||
case 'e':
|
|
||||||
use_elite = true;
|
|
||||||
cmdp++;
|
|
||||||
break;
|
|
||||||
case 'r':
|
|
||||||
use_raw = true;
|
|
||||||
cmdp++;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
PrintAndLogEx(WARNING, "unknown parameter '%c'\n", param_getchar(Cmd, cmdp));
|
|
||||||
errors = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (errors) return usage_hf_iclass_lookup();
|
|
||||||
|
|
||||||
// stupid copy.. CCNR is a combo of epurse and reader nonce
|
// stupid copy.. CCNR is a combo of epurse and reader nonce
|
||||||
memcpy(CCNR, EPURSE, 8);
|
memcpy(CCNR, epurse, 8);
|
||||||
memcpy(CCNR + 8, MACS, 4);
|
memcpy(CCNR + 8, macs, 4);
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, " CSN: " _GREEN_("%s"), sprint_hex(CSN, sizeof(CSN)));
|
PrintAndLogEx(SUCCESS, " CSN: " _GREEN_("%s"), sprint_hex(csn, sizeof(csn)));
|
||||||
PrintAndLogEx(SUCCESS, " Epurse: %s", sprint_hex(EPURSE, sizeof(EPURSE)));
|
PrintAndLogEx(SUCCESS, " Epurse: %s", sprint_hex(epurse, sizeof(epurse)));
|
||||||
PrintAndLogEx(SUCCESS, " MACS: %s", sprint_hex(MACS, sizeof(MACS)));
|
PrintAndLogEx(SUCCESS, " MACS: %s", sprint_hex(macs, sizeof(macs)));
|
||||||
PrintAndLogEx(SUCCESS, " CCNR: " _GREEN_("%s"), sprint_hex(CCNR, sizeof(CCNR)));
|
PrintAndLogEx(SUCCESS, " CCNR: " _GREEN_("%s"), sprint_hex(CCNR, sizeof(CCNR)));
|
||||||
PrintAndLogEx(SUCCESS, "TAG MAC: %s", sprint_hex(MAC_TAG, sizeof(MAC_TAG)));
|
PrintAndLogEx(SUCCESS, "TAG MAC: %s", sprint_hex(MAC_TAG, sizeof(MAC_TAG)));
|
||||||
|
|
||||||
|
@ -3039,7 +2985,7 @@ static int CmdHFiClassLookUp(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, "Generating diversified keys...");
|
PrintAndLogEx(SUCCESS, "Generating diversified keys...");
|
||||||
GenerateMacKeyFrom(CSN, CCNR, use_raw, use_elite, keyBlock, keycount, prekey);
|
GenerateMacKeyFrom(csn, CCNR, use_raw, use_elite, keyBlock, keycount, prekey);
|
||||||
|
|
||||||
if (use_elite)
|
if (use_elite)
|
||||||
PrintAndLogEx(SUCCESS, "Using " _YELLOW_("elite algo"));
|
PrintAndLogEx(SUCCESS, "Using " _YELLOW_("elite algo"));
|
||||||
|
|
|
@ -515,7 +515,7 @@ int bruteforceDump(uint8_t dump[], size_t dumpsize, uint16_t keytable[]) {
|
||||||
PrintAndLogEx(SUCCESS, "time: %" PRIu64 " seconds", t1 / 1000);
|
PrintAndLogEx(SUCCESS, "time: %" PRIu64 " seconds", t1 / 1000);
|
||||||
|
|
||||||
if (res != PM3_SUCCESS) {
|
if (res != PM3_SUCCESS) {
|
||||||
PrintAndLogEx(ERR, "loclass exiting. Try run " _YELLOW_("`hf iclass sim 2`") " again and collect new data");
|
PrintAndLogEx(ERR, "loclass exiting. Try run " _YELLOW_("`hf iclass sim -t 2`") " again and collect new data");
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -109,19 +109,20 @@ Print keystore
|
||||||
```
|
```
|
||||||
Options
|
Options
|
||||||
---
|
---
|
||||||
p : print keys loaded into memory
|
-p, --print Print keys loaded into memory
|
||||||
|
|
||||||
pm3 --> hf iclass managekeys p
|
|
||||||
|
pm3 --> hf iclass managekeys -p
|
||||||
```
|
```
|
||||||
|
|
||||||
Add key to keystore [0-7]
|
Add key to keystore [0-7]
|
||||||
```
|
```
|
||||||
Options
|
Options
|
||||||
---
|
---
|
||||||
n <keynbr> : specify the keyNbr to set in memory
|
-f, --file <filename> Specify a filename to use with load or save operations
|
||||||
k <key> : set a key in memory
|
--ki <dec> Specify key index to set key in memory
|
||||||
|
|
||||||
pm3 --> hf iclass managekeys n 3 k AFA785A7DAB33378
|
pm3 --> hf iclass managekeys --ki 3 -k AFA785A7DAB33378
|
||||||
```
|
```
|
||||||
|
|
||||||
Encrypt iCLASS Block
|
Encrypt iCLASS Block
|
||||||
|
@ -167,20 +168,23 @@ Simulate iCLASS
|
||||||
```
|
```
|
||||||
Options
|
Options
|
||||||
---
|
---
|
||||||
0 <CSN> simulate the given CSN
|
-t, --type <int> Simulation type to use
|
||||||
|
--csn <hex> Specify CSN as 8 bytes (16 hex symbols) to use with sim type 0
|
||||||
|
Types:
|
||||||
|
0 simulate the given CSN
|
||||||
1 simulate default CSN
|
1 simulate default CSN
|
||||||
2 Runs online part of LOCLASS attack
|
2 Runs online part of LOCLASS attack
|
||||||
3 Full simulation using emulator memory (see 'hf iclass eload')
|
3 Full simulation using emulator memory (see 'hf iclass eload')
|
||||||
4 Runs online part of LOCLASS attack against reader in keyroll mode
|
4 Runs online part of LOCLASS attack against reader in keyroll mode
|
||||||
|
|
||||||
pm3 --> hf iclass sim 3
|
pm3 --> hf iclass sim -t 3
|
||||||
```
|
```
|
||||||
|
|
||||||
Simulate iCLASS Sequence
|
Simulate iCLASS Sequence
|
||||||
```
|
```
|
||||||
pm3 --> hf iclass dump --ki 0
|
pm3 --> hf iclass dump --ki 0
|
||||||
pm3 --> hf iclass eload -f hf-iclass-db883702f8ff12e0.bin
|
pm3 --> hf iclass eload -f hf-iclass-db883702f8ff12e0.bin
|
||||||
pm3 --> hf iclass sim 3
|
pm3 --> hf iclass sim -t 3
|
||||||
```
|
```
|
||||||
|
|
||||||
Extract custom iCLASS key (loclass attack)
|
Extract custom iCLASS key (loclass attack)
|
||||||
|
@ -189,11 +193,11 @@ Options
|
||||||
---
|
---
|
||||||
f <filename> : specify a filename to clone from
|
f <filename> : specify a filename to clone from
|
||||||
k <key> : Access Key as 16 hex symbols or 1 hex to select key from memory
|
k <key> : Access Key as 16 hex symbols or 1 hex to select key from memory
|
||||||
e : If 'e' is specified, elite computations applied to key
|
--elite : Elite computations applied to key
|
||||||
|
|
||||||
pm3 --> hf iclass sim 2
|
pm3 --> hf iclass sim -t 2
|
||||||
pm3 --> hf iclass loclass -f iclass_mac_attack.bin
|
pm3 --> hf iclass loclass -f iclass_mac_attack.bin
|
||||||
pm3 --> hf iclass managekeys n 7 k <Kcus>
|
pm3 --> hf iclass managekeys --ki 7 -k <Kcus>
|
||||||
pm3 --> hf iclass dump --ki 7 --elite
|
pm3 --> hf iclass dump --ki 7 --elite
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -201,13 +205,14 @@ Verify custom iCLASS key
|
||||||
```
|
```
|
||||||
Options
|
Options
|
||||||
---
|
---
|
||||||
f <filename> : Dictionary file with default iCLASS keys
|
-f, --file <filename> Dictionary file with default iclass keys
|
||||||
u : CSN
|
--csn <hex> Specify CSN as 8 bytes (16 hex symbols)
|
||||||
p : EPURSE
|
--epurse <hex> Specify ePurse as 8 bytes (16 hex symbols)
|
||||||
m : macs
|
--macs <hex> MACs
|
||||||
e : elite
|
--raw no computations applied to key (raw)
|
||||||
|
--elite Elite computations applied to key
|
||||||
|
|
||||||
pm3 --> hf iclass lookup u 010a0ffff7ff12e0 p feffffffffffffff m 66348979153c41b9 f iclass_default_keys e
|
pm3 --> hf iclass lookup --csn 010a0ffff7ff12e0 --epurse feffffffffffffff --macs 66348979153c41b9 -f iclass_default_keys --elite
|
||||||
```
|
```
|
||||||
|
|
||||||
## MIFARE
|
## MIFARE
|
||||||
|
|
|
@ -4,7 +4,7 @@ This document is primarily intended for understanding `hf iclass loclass` and fi
|
||||||
|
|
||||||
LOCLASS aim is to recover the used masterkey for that specific reader configured in Elite mode / High Security mode.
|
LOCLASS aim is to recover the used masterkey for that specific reader configured in Elite mode / High Security mode.
|
||||||
|
|
||||||
LOCLASS, is a two part attack. First is the online part where you gather needed information from the reader by presenting a carefully selected CSN and save the responses to file. For the first part you run `hf iclass sim 2` and take notice of the saved filename.
|
LOCLASS, is a two part attack. First is the online part where you gather needed information from the reader by presenting a carefully selected CSN and save the responses to file. For the first part you run `hf iclass sim -t 2` and take notice of the saved filename.
|
||||||
|
|
||||||
The second part is offline, where the information gathered from the first step is used in a series of DES operations to figure out the used
|
The second part is offline, where the information gathered from the first step is used in a series of DES operations to figure out the used
|
||||||
masterkey.
|
masterkey.
|
||||||
|
@ -21,6 +21,6 @@ run `hf iclass loclass --test`.
|
||||||
This test mode uses two files.
|
This test mode uses two files.
|
||||||
|
|
||||||
- `iclass_dump.bin`
|
- `iclass_dump.bin`
|
||||||
this is a sample file from `hf iclass sim 2`, with complete keytable recovery, using 128 carefully selected CSN and the file contains the MAC results from reader.
|
this is a sample file from `hf iclass sim -t 2`, with complete keytable recovery, using 128 carefully selected CSN and the file contains the MAC results from reader.
|
||||||
- `iclass_key.bin`
|
- `iclass_key.bin`
|
||||||
this is file shall contain the legacy masterkey, AA1 key. loclass uses it to verify that permutation / reversing / generation of key is correct.
|
this is file shall contain the legacy masterkey, AA1 key. loclass uses it to verify that permutation / reversing / generation of key is correct.
|
Loading…
Add table
Add a link
Reference in a new issue