mirror of
https://github.com/Proxmark/proxmark3.git
synced 2025-07-16 02:03:00 -07:00
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:
parent
766c978bd0
commit
ac2668f898
5 changed files with 99 additions and 178 deletions
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue