speedup hf mf chk

* revert queuing change
* instead allow arbitrary number of keys in MifareChkKeys()
* and move progress printing to MifareChkKeys()
This commit is contained in:
pwpiwi 2019-12-30 14:55:52 +01:00
parent 766c978bd0
commit ac2668f898
5 changed files with 99 additions and 178 deletions

View file

@ -1001,18 +1001,9 @@ void MifareChkKeys(uint16_t arg0, uint32_t arg1, uint8_t arg2, uint8_t *datain)
bool multisectorCheck = arg1 & 0x02;
bool init = arg1 & 0x04;
bool drop_field = arg1 & 0x08;
static bool reject_next = false;
uint32_t auth_timeout = arg1 >> 16;
uint8_t keyCount = arg2;
if (reject_next) {
reject_next = false;
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LED_D_OFF();
cmd_send(CMD_ACK, 0, -3, 0, NULL, 0);
return;
}
LED_A_ON();
if (init) {
@ -1033,24 +1024,18 @@ void MifareChkKeys(uint16_t arg0, uint32_t arg1, uint8_t arg2, uint8_t *datain)
TKeyIndex keyIndex = {{0}};
uint8_t sectorCnt = blockNo;
res = MifareMultisectorChk(datain, keyCount, sectorCnt, keyType, &auth_timeout, OLD_MF_DBGLEVEL, &keyIndex);
if (res >= 0)
if (res >= 0) {
cmd_send(CMD_ACK, 1, res, 0, keyIndex, 80);
else
} else {
cmd_send(CMD_ACK, 0, res, 0, NULL, 0);
if (res < 0 && usb_poll_validate_length()) // we want to exit but another set of keys has been queued!
reject_next = true;
}
} else {
res = MifareChkBlockKeys(datain, keyCount, blockNo, keyType, &auth_timeout, OLD_MF_DBGLEVEL);
if (res != 0 && usb_poll_validate_length()) // we want to exit but another set of keys has been queued!
reject_next = true;
if (res > 0)
if (res > 0) {
cmd_send(CMD_ACK, 1, res, 0, datain + (res - 1) * 6, 6);
else
} else {
cmd_send(CMD_ACK, 0, res, 0, NULL, 0);
}
}
if (drop_field || res != 0) {

View file

@ -867,8 +867,6 @@ int MifareChkBlockKeys(uint8_t *keys, uint8_t keyCount, uint8_t blockNo, uint8_t
int retryCount = 0;
for (uint8_t i = 0; i < keyCount; i++) {
// Allow button press / usb cmd to interrupt device
ui64Key = bytes_to_num(keys + i * 6, 6);
int res = MifareChkBlockKey(uid, &cuid, &cascade_levels, ui64Key, blockNo, keyType, auth_timeout, debugLevel);

View file

@ -675,7 +675,7 @@ int CmdHF14AMfNested(const char *Cmd) {
}
// check if we can authenticate to sector
res = mfCheckKeys(blockNo, keyType, timeout14a, true, true, true, false, 1, key, &key64);
res = mfCheckKeys(blockNo, keyType, timeout14a, true, 1, key, &key64);
if (res) {
PrintAndLog("Can't authenticate to block:%3d key type:%c key:%s", blockNo, keyType?'B':'A', sprint_hex(key, 6));
return 3;
@ -1270,29 +1270,23 @@ int CmdHF14AMfChk(const char *Cmd) {
} else {
int keyAB = keyType;
do {
for (uint32_t c = 0; c < keycnt; c += max_keys) {
res = mfCheckKeys(blockNo, keyAB & 0x01, timeout14a, true, keycnt, keyBlock, &key64);
clearTraceLog = false;
uint32_t size = keycnt-c > max_keys ? max_keys : keycnt-c;
bool init = (c == 0);
bool drop_field = (c + size == keycnt);
res = mfCheckKeys(blockNo, keyAB & 0x01, timeout14a, true, init, drop_field, false, size, &keyBlock[6 * c], &key64);
clearTraceLog = false;
if (res != 1) {
if (!res) {
// Use the common format below
// PrintAndLog("Found valid key:[%d:%c]%012" PRIx64, blockNo, (keyAB & 0x01)?'B':'A', key64);
foundAKey = true;
if (res != 1) {
if (!res) {
// Use the common format below
// PrintAndLog("Found valid key:[%d:%c]%012" PRIx64, blockNo, (keyAB & 0x01)?'B':'A', key64);
foundAKey = true;
// Store the Single Key for display list
// For a single block check, SectorsCnt = Sector that contains the block
e_sector[SectorsCnt-1].foundKey[(keyAB & 0x01)] = true; // flag key found
e_sector[SectorsCnt-1].Key[(keyAB & 0x01)] = key64; // Save key data
// Store the Single Key for display list
// For a single block check, SectorsCnt = Sector that contains the block
e_sector[SectorsCnt-1].foundKey[(keyAB & 0x01)] = true; // flag key found
e_sector[SectorsCnt-1].Key[(keyAB & 0x01)] = key64; // Save key data
}
} else {
PrintAndLog("Command execute timeout");
}
} else {
PrintAndLog("Command execute timeout");
}
} while(--keyAB > 0);
}

View file

@ -196,24 +196,15 @@ int mfDarkside(uint64_t *key) {
PrintAndLog("Found a possible key. Trying to authenticate...\n");
}
*key = -1;
uint8_t keyBlock[USB_CMD_DATA_SIZE];
int max_keys = USB_CMD_DATA_SIZE/6;
for (int i = 0; i < keycount; i += max_keys) {
int size = keycount - i > max_keys ? max_keys : keycount - i;
for (int j = 0; j < size; j++) {
if (par_list == 0) {
num_to_bytes(last_keylist[i*max_keys + j], 6, keyBlock+(j*6));
} else {
num_to_bytes(keylist[i*max_keys + j], 6, keyBlock+(j*6));
}
}
bool init = (i == 0);
bool drop_field = (i + size == keycount);
if (!mfCheckKeys(0, 0, 0, false, init, drop_field, false, size, keyBlock, key)) {
break;
}
uint8_t *keys_to_chk = malloc(keycount * 6);
for (int i = 0; i < keycount; i++) {
num_to_bytes(keylist[i], 6, keys_to_chk+i);
}
*key = -1;
mfCheckKeys(0, 0, 0, false, keycount, keys_to_chk, key);
free(keys_to_chk);
if (*key != -1) {
free(last_keylist);
@ -229,42 +220,64 @@ int mfDarkside(uint64_t *key) {
return 0;
}
int mfCheckKeys(uint8_t blockNo, uint8_t keyType, uint16_t timeout14a, bool clear_trace, bool init, bool drop_field, bool dont_wait, uint8_t keycnt, uint8_t * keyBlock, uint64_t * key) {
*key = -1;
bool multisectorCheck = false;
uint8_t flags = clear_trace | multisectorCheck << 1 | init << 2 | drop_field << 3;
int mfCheckKeys(uint8_t blockNo, uint8_t keyType, uint16_t timeout14a, bool clear_trace, uint32_t keycnt, uint8_t *keys, uint64_t *found_key) {
UsbCommand c = {CMD_MIFARE_CHKKEYS, {((blockNo & 0xff) | ((keyType & 0xff) << 8)), flags | timeout14a << 16, keycnt}};
memcpy(c.d.asBytes, keyBlock, 6 * keycnt);
SendCommand(&c);
bool display_progress = false;
uint64_t start_time = msclock();
uint64_t next_print_time = start_time + 5 * 1000;
if (dont_wait)
return 3;
return mfCheckKeysGetResponse(key);
}
int mfCheckKeysGetResponse(uint64_t *key) {
UsbCommand resp;
if (!WaitForResponseTimeout(CMD_ACK,&resp,3000))
return 1;
if ((resp.arg[0] & 0xff) != 0x01) {
if (((int)resp.arg[1]) < 0)
return (int)resp.arg[1];
return 2;
if (keycnt > 1000) {
PrintAndLog("We have %d keys to check. This will take some time!", keycnt);
PrintAndLog("Press button to abort.");
display_progress = true;
}
if (key)
*key = bytes_to_num(resp.d.asBytes, 6);
uint32_t max_keys = (keycnt > (USB_CMD_DATA_SIZE / 6)) ? (USB_CMD_DATA_SIZE / 6) : keycnt;
*found_key = -1;
bool multisectorCheck = false;
return 0;
for (int i = 0, ii = 0; i < keycnt; i += max_keys) {
if ((i + max_keys) >= keycnt) {
max_keys = keycnt - i;
}
bool init = (i == 0);
bool drop_field = (max_keys == keycnt);
uint8_t flags = clear_trace | multisectorCheck << 1 | init << 2 | drop_field << 3;
UsbCommand c = {CMD_MIFARE_CHKKEYS, {((blockNo & 0xff) | ((keyType & 0xff) << 8)), flags | timeout14a << 16, max_keys}};
memcpy(c.d.asBytes, keys + i * 6, max_keys * 6);
SendCommand(&c);
UsbCommand resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 3000))
return 1;
if ((resp.arg[0] & 0xff) != 0x01) {
if (((int)resp.arg[1]) < 0) { // error
return (int)resp.arg[1];
} else { // nothing found yet
if (display_progress && msclock() >= next_print_time) {
float brute_force_per_second = (float)(i - ii) / (float)(msclock() - start_time) * 1000.0;
ii = i;
start_time = msclock();
next_print_time = start_time + 10 * 1000;
PrintAndLog(" %8d keys left | %5.1f keys/sec | worst case %6.1f seconds remaining", keycnt - i, brute_force_per_second, (keycnt-i)/brute_force_per_second);
}
}
} else { // success
*found_key = bytes_to_num(resp.d.asBytes, 6);
return 0;
}
}
return 2; // nothing found
}
int mfCheckKeysSec(uint8_t sectorCnt, uint8_t keyType, uint16_t timeout14a, bool clear_trace, bool init, bool drop_field, uint8_t keycnt, uint8_t * keyBlock, sector_t * e_sector){
int mfCheckKeysSec(uint8_t sectorCnt, uint8_t keyType, uint16_t timeout14a, bool clear_trace, bool init, bool drop_field, uint8_t keycnt, uint8_t * keyBlock, sector_t * e_sector) {
uint8_t keyPtr = 0;
@ -317,7 +330,7 @@ typedef
uint32_t uid;
uint32_t blockNo;
uint32_t keyType;
uint32_t nt;
uint32_t nt_enc;
uint32_t ks1;
} StateList_t;
@ -329,12 +342,11 @@ void
__attribute__((force_align_arg_pointer))
#endif
#endif
*nested_worker_thread(void *arg)
{
*nested_worker_thread(void *arg) {
struct Crypto1State *p1;
StateList_t *statelist = arg;
statelist->head.slhead = lfsr_recovery32(statelist->ks1, statelist->nt ^ statelist->uid);
statelist->head.slhead = lfsr_recovery32(statelist->ks1, statelist->nt_enc ^ statelist->uid);
for (p1 = statelist->head.slhead; *(uint64_t *)p1 != 0; p1++);
statelist->len = p1 - statelist->head.slhead;
statelist->tail.sltail = --p1;
@ -345,7 +357,7 @@ __attribute__((force_align_arg_pointer))
int mfnested(uint8_t blockNo, uint8_t keyType, uint16_t timeout14a, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *resultKey, bool calibrate) {
uint32_t i, j, last_count;
uint32_t i;
uint32_t uid;
UsbCommand resp;
@ -359,11 +371,6 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint16_t timeout14a, uint8_t *key
int isOK = 1;
uint64_t next_print_time = 0;
uint64_t start_time;
float brute_force_time;
float brute_force_per_second;
// flush queue
(void)WaitForResponseTimeout(CMD_ACK,NULL,100);
@ -390,7 +397,7 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint16_t timeout14a, uint8_t *key
statelists[i].blockNo = resp.arg[2] & 0xff;
statelists[i].keyType = (resp.arg[2] >> 8) & 0xff;
statelists[i].uid = uid;
memcpy(&statelists[i].nt, (void *)(resp.d.asBytes + 4 + i * 8 + 0), 4);
memcpy(&statelists[i].nt_enc, (void *)(resp.d.asBytes + 4 + i * 8 + 0), 4);
memcpy(&statelists[i].ks1, (void *)(resp.d.asBytes + 4 + i * 8 + 4), 4);
}
@ -398,7 +405,7 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint16_t timeout14a, uint8_t *key
memcpy(&authentication_timeout, resp.d.asBytes + 20, 4);
PrintAndLog("Setting authentication timeout to %" PRIu32 "us", authentication_timeout * 1000 / 106);
if (statelists[0].nt == statelists[1].nt && statelists[0].ks1 == statelists[1].ks1)
if (statelists[0].nt_enc == statelists[1].nt_enc && statelists[0].ks1 == statelists[1].ks1)
num_unique_nonces = 1;
else
num_unique_nonces = 2;
@ -429,14 +436,14 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint16_t timeout14a, uint8_t *key
savestate = *p1;
while(Compare16Bits(p1, savep) == 0 && p1 <= statelists[0].tail.sltail) {
*p3 = *p1;
lfsr_rollback_word(p3, statelists[0].nt ^ statelists[0].uid, 0);
lfsr_rollback_word(p3, statelists[0].nt_enc ^ statelists[0].uid, 0);
p3++;
p1++;
}
savestate = *p2;
while(Compare16Bits(p2, savep) == 0 && p2 <= statelists[1].tail.sltail) {
*p4 = *p2;
lfsr_rollback_word(p4, statelists[1].nt ^ statelists[1].uid, 0);
lfsr_rollback_word(p4, statelists[1].nt_enc ^ statelists[1].uid, 0);
p4++;
p2++;
}
@ -454,7 +461,7 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint16_t timeout14a, uint8_t *key
statelists[1].tail.sltail=--p4;
for (i = 0; i < 2; i++) {
PrintAndLog("statelist %d: length:%d block:%02d keytype:%d nt:%08X ks1:%08X", i, statelists[i].len, statelists[i].blockNo, statelists[i].keyType, statelists[i].nt, statelists[i].ks1);
PrintAndLog("statelist %d: length:%d block:%02d keytype:%d nt_enc:%08X ks1:%08X", i, statelists[i].len, statelists[i].blockNo, statelists[i].keyType, statelists[i].nt_enc, statelists[i].ks1);
}
// the statelists now contain possible keys. The key we are searching for must be in the
@ -469,92 +476,30 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint16_t timeout14a, uint8_t *key
PrintAndLog("Nonce 1 and 2 are the same!");
}
if (statelists[0].len > 100) {
PrintAndLog("We have %d keys to check. This will take a very long time!", statelists[0].len);
PrintAndLog("Press button to abort.");
}
else if (statelists[0].len < 1) {
PrintAndLog("No candidate keys to check!");
}
else {
PrintAndLog("We have %d key(s) to check.", statelists[0].len);
}
uint32_t max_keys = (statelists[0].len > (USB_CMD_DATA_SIZE / 6)) ? (USB_CMD_DATA_SIZE / 6) : statelists[0].len;
keyBlock = calloc(max_keys, 6);
uint32_t num_keys = statelists[0].len;
keyBlock = calloc(num_keys, 6);
if (keyBlock == NULL) {
free(statelists[0].head.slhead);
free(statelists[1].head.slhead);
return -4;
}
memset(resultKey, 0, 6);
start_time = msclock();
next_print_time = start_time + 1 * 1000;
bool want_queue = (max_keys < statelists[0].len);
bool queued_next_set = false;
for (i = 0; i < num_keys; i++) {
crypto1_get_lfsr(statelists[0].head.slhead + i, &key64);
num_to_bytes(key64, 6, keyBlock + i*6);
}
// The list may still contain several key candidates. Test each of them with mfCheckKeys
for (i = 0; i < statelists[0].len; i += max_keys) {
if (next_print_time <= msclock()) {
brute_force_per_second = ((float)i) / (((float)(msclock() - start_time)) / 1000.0);
brute_force_time = ((float)(statelists[0].len - i)) / brute_force_per_second;
next_print_time = msclock() + 10 * 1000;
PrintAndLog(" %8d keys left | %5.1f keys/sec | worst case %6.1f seconds remaining", statelists[0].len - i, brute_force_per_second, brute_force_time);
}
isOK = mfCheckKeys(statelists[0].blockNo, statelists[0].keyType, authentication_timeout, true, num_keys, keyBlock, &key64);
if ((i+max_keys) >= statelists[0].len)
max_keys = statelists[0].len - i;
for (j = 0; j < max_keys; j++) {
crypto1_get_lfsr(statelists[0].head.slhead + i + j, &key64);
num_to_bytes(key64, 6, keyBlock+(j*6));
}
key64 = 0;
bool init = (i == 0);
bool drop_field = (i + max_keys == statelists[0].len);
bool dont_wait = want_queue && !queued_next_set;
isOK = mfCheckKeys(statelists[0].blockNo, statelists[0].keyType, authentication_timeout, true, init, drop_field, dont_wait, max_keys, keyBlock, &key64);
if (dont_wait && isOK == 3) {
queued_next_set = true;
continue;
}
if (isOK == 1) { // timeout
isOK = -1;
break;
}
else if (isOK < 0) { // -2 is button pressed
break;
}
else if (!isOK) {
num_to_bytes(key64, 6, resultKey);
break;
}
if (isOK == 0) { // success, key found
num_to_bytes(key64, 6, resultKey);
}
if (queued_next_set) {
i -= max_keys; // fix the count from the last trip through the for() loop
if (!isOK) {
mfCheckKeysGetResponse(NULL); // we already have what we want, just consume the queued response
}
else {
isOK = mfCheckKeysGetResponse(&key64);
if (isOK == 1) // timeout
isOK = -1;
else if (!isOK)
num_to_bytes(key64, 6, resultKey);
}
if (isOK == 1) { // timeout
isOK = -1;
}
if (isOK == 0 && statelists[0].len != 1)
PrintAndLog("Key found in %0.2f seconds after checking %d keys\n", ((float)(msclock() - start_time)) / 1000.0, i+max_keys);
free(statelists[0].head.slhead);
free(statelists[1].head.slhead);
free(keyBlock);

View file

@ -40,8 +40,7 @@ extern char logHexFileName[FILE_PATH_SIZE];
extern int mfDarkside(uint64_t *key);
extern int mfnested(uint8_t blockNo, uint8_t keyType, uint16_t timeout14a, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *ResultKeys, bool calibrate);
extern int mfCheckKeys(uint8_t blockNo, uint8_t keyType, uint16_t timeout14a, bool clear_trace, bool init, bool drop_field, bool dont_wait, uint8_t keycnt, uint8_t *keyBlock, uint64_t *key);
extern int mfCheckKeysGetResponse(uint64_t *key);
extern int mfCheckKeys(uint8_t blockNo, uint8_t keyType, uint16_t timeout14a, bool clear_trace, uint32_t keycnt, uint8_t *keyBlock, uint64_t *key);
extern int mfCheckKeysSec(uint8_t sectorCnt, uint8_t keyType, uint16_t timeout14a, bool clear_trace, bool init, bool drop_field, uint8_t keycnt, uint8_t * keyBlock, sector_t * e_sector);
extern int mfReadSector(uint8_t sectorNo, uint8_t keyType, uint8_t *key, uint8_t *data);