mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-19 21:03:48 -07:00
StaticNested fast decrypt(backdoor 2nt.).
This commit is contained in:
parent
1711338035
commit
de0549a269
2 changed files with 275 additions and 143 deletions
|
@ -1196,23 +1196,79 @@ void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8
|
||||||
set_tracing(false);
|
set_tracing(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MifareStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8_t targetKeyType, uint8_t *key) {
|
static void MifareFastStaticNestedImpl(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8_t targetKeyType, uint8_t* key, uint32_t* nt1, uint32_t* nt2, uint32_t* cuid, bool firstGet, int16_t* isOK) {
|
||||||
|
|
||||||
LEDsoff();
|
|
||||||
|
|
||||||
uint64_t ui64Key = 0;
|
uint64_t ui64Key = 0;
|
||||||
ui64Key = bytes_to_num(key, 6);
|
ui64Key = bytes_to_num(key, 6);
|
||||||
uint16_t len;
|
uint16_t len;
|
||||||
uint8_t uid[10] = {0x00};
|
uint8_t uid[10] = { 0x00 };
|
||||||
uint32_t cuid = 0, nt1, nt2;
|
uint8_t par[1] = { 0x00 };
|
||||||
uint32_t target_nt = 0, target_ks = 0;
|
uint8_t receivedAnswer[10] = { 0x00 };
|
||||||
uint8_t par[1] = {0x00};
|
|
||||||
uint8_t receivedAnswer[10] = {0x00};
|
|
||||||
|
|
||||||
struct Crypto1State mpcs = {0, 0};
|
struct Crypto1State mpcs = { 0, 0 };
|
||||||
struct Crypto1State *pcs;
|
struct Crypto1State* pcs;
|
||||||
pcs = &mpcs;
|
pcs = &mpcs;
|
||||||
|
|
||||||
|
*isOK = 0;
|
||||||
|
LED_C_ON();
|
||||||
|
|
||||||
|
for (uint8_t retry = 0; retry < 3 && (*isOK == 0); retry++) {
|
||||||
|
|
||||||
|
WDT_HIT();
|
||||||
|
|
||||||
|
// prepare next select. No need to power down the card.
|
||||||
|
if (mifare_classic_halt(pcs, *cuid)) {
|
||||||
|
if (g_dbglevel >= DBG_INFO) Dbprintf("Nested: Halt error");
|
||||||
|
retry--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!iso14443a_select_card(uid, NULL, cuid, true, 0, true)) {
|
||||||
|
if (g_dbglevel >= DBG_INFO) Dbprintf("Nested: Can't select card");
|
||||||
|
retry--;
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
// First authentication. Normal auth.
|
||||||
|
if (mifare_classic_authex(pcs, *cuid, blockNo, keyType, ui64Key, AUTH_FIRST, nt1, NULL)) {
|
||||||
|
if (g_dbglevel >= DBG_INFO) Dbprintf("Nested: Auth1 error");
|
||||||
|
retry--;
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
// not first get, we need auth again...
|
||||||
|
if (!firstGet) {
|
||||||
|
if (mifare_classic_authex(pcs, *cuid, blockNo, keyType, ui64Key, AUTH_NESTED, NULL, NULL)) {
|
||||||
|
if (g_dbglevel >= DBG_INFO) Dbprintf("Nested: Auth1 again error");
|
||||||
|
retry--;
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// second authentication. Nested auth
|
||||||
|
len = mifare_sendcmd_short(pcs, AUTH_NESTED, 0x60 + (targetKeyType & 0x01), targetBlockNo, receivedAnswer, par, NULL);
|
||||||
|
if (len != 4) {
|
||||||
|
if (g_dbglevel >= DBG_INFO) Dbprintf("Nested: Auth2 error len=%d", len);
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
*nt2 = bytes_to_num(receivedAnswer, 4);
|
||||||
|
*isOK = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
LED_C_OFF();
|
||||||
|
|
||||||
|
crypto1_deinit(pcs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MifareStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8_t targetKeyType, uint8_t* key) {
|
||||||
|
|
||||||
|
int16_t isOK;
|
||||||
|
uint32_t cuid;
|
||||||
|
uint32_t nt1_1, nt2_1;
|
||||||
|
uint32_t nt1_2, nt2_2;
|
||||||
|
|
||||||
|
LEDsoff();
|
||||||
LED_A_ON();
|
LED_A_ON();
|
||||||
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
|
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
|
||||||
|
|
||||||
|
@ -1222,76 +1278,43 @@ void MifareStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo,
|
||||||
clear_trace();
|
clear_trace();
|
||||||
set_tracing(true);
|
set_tracing(true);
|
||||||
|
|
||||||
int16_t isOK = 0;
|
MifareFastStaticNestedImpl(blockNo, keyType, targetBlockNo, targetKeyType, key, &nt1_1, &nt2_1, &cuid, true, &isOK);
|
||||||
LED_C_ON();
|
if (isOK) {
|
||||||
|
MifareFastStaticNestedImpl(blockNo, keyType, targetBlockNo, targetKeyType, key, &nt1_2, &nt2_2, &cuid, false, &isOK);
|
||||||
for (uint8_t retry = 0; retry < 3 && (isOK == 0); retry++) {
|
|
||||||
|
|
||||||
WDT_HIT();
|
|
||||||
|
|
||||||
// prepare next select. No need to power down the card.
|
|
||||||
if (mifare_classic_halt(pcs, cuid)) {
|
|
||||||
if (g_dbglevel >= DBG_INFO) Dbprintf("Nested: Halt error");
|
|
||||||
retry--;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
|
|
||||||
if (g_dbglevel >= DBG_INFO) Dbprintf("Nested: Can't select card");
|
|
||||||
retry--;
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
// First authentication. Normal auth.
|
|
||||||
if (mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, NULL)) {
|
|
||||||
if (g_dbglevel >= DBG_INFO) Dbprintf("Nested: Auth1 error");
|
|
||||||
retry--;
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
// second authentication. Nested auth
|
|
||||||
len = mifare_sendcmd_short(pcs, AUTH_NESTED, 0x60 + (targetKeyType & 0x01), targetBlockNo, receivedAnswer, par, NULL);
|
|
||||||
if (len != 4) {
|
|
||||||
if (g_dbglevel >= DBG_INFO) Dbprintf("Nested: Auth2 error len=%d", len);
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
nt2 = bytes_to_num(receivedAnswer, 4);
|
|
||||||
target_nt = prng_successor(nt1, 160);
|
|
||||||
target_ks = nt2 ^ target_nt;
|
|
||||||
isOK = 1;
|
|
||||||
|
|
||||||
if (g_dbglevel >= DBG_DEBUG) Dbprintf("Testing nt1=%08x nt2enc=%08x nt2par=%02x ks=%08x", nt1, nt2, par[0], target_ks);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LED_C_OFF();
|
|
||||||
|
|
||||||
crypto1_deinit(pcs);
|
|
||||||
|
|
||||||
struct p {
|
struct p {
|
||||||
int16_t isOK;
|
int16_t isOK;
|
||||||
uint8_t block;
|
uint8_t block;
|
||||||
uint8_t keytype;
|
uint8_t keytype;
|
||||||
uint8_t cuid[4];
|
uint8_t cuid[4];
|
||||||
uint8_t nt[4];
|
uint8_t nt1_1[4];
|
||||||
uint8_t ks[4];
|
uint8_t nt2_1[4];
|
||||||
|
// new nt
|
||||||
|
uint8_t nt1_2[4];
|
||||||
|
uint8_t nt2_2[4];
|
||||||
} PACKED payload;
|
} PACKED payload;
|
||||||
payload.isOK = isOK;
|
payload.isOK = isOK;
|
||||||
payload.block = targetBlockNo;
|
payload.block = targetBlockNo;
|
||||||
payload.keytype = targetKeyType;
|
payload.keytype = targetKeyType;
|
||||||
|
|
||||||
memcpy(payload.cuid, &cuid, 4);
|
memcpy(payload.cuid, &cuid, 4);
|
||||||
memcpy(payload.nt, &target_nt, 4);
|
|
||||||
memcpy(payload.ks, &target_ks, 4);
|
// copy nonces to response body.
|
||||||
|
memcpy(payload.nt1_1, &nt1_1, 4);
|
||||||
|
memcpy(payload.nt2_1, &nt2_1, 4);
|
||||||
|
memcpy(payload.nt1_2, &nt1_2, 4);
|
||||||
|
memcpy(payload.nt2_2, &nt2_2, 4);
|
||||||
|
|
||||||
LED_B_ON();
|
LED_B_ON();
|
||||||
reply_ng(CMD_HF_MIFARE_STATIC_NESTED, PM3_SUCCESS, (uint8_t *)&payload, sizeof(payload));
|
reply_ng(CMD_HF_MIFARE_STATIC_NESTED, PM3_SUCCESS, (uint8_t*)&payload, sizeof(payload));
|
||||||
LED_B_OFF();
|
LED_B_OFF();
|
||||||
|
|
||||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||||
LEDsoff();
|
LEDsoff();
|
||||||
set_tracing(false);
|
set_tracing(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// MIFARE check keys. key count up to 85.
|
// MIFARE check keys. key count up to 85.
|
||||||
//
|
//
|
||||||
|
|
|
@ -581,11 +581,11 @@ out:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *resultKey) {
|
int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t* key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t* resultKey) {
|
||||||
|
|
||||||
uint32_t uid;
|
uint32_t uid;
|
||||||
StateList_t statelists[1];
|
StateList_t statelists[2];
|
||||||
struct Crypto1State *p1, *p3;
|
struct Crypto1State* p1, * p2, * p3, * p4;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
uint8_t block;
|
uint8_t block;
|
||||||
|
@ -602,7 +602,7 @@ int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBl
|
||||||
|
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandNG(CMD_HF_MIFARE_STATIC_NESTED, (uint8_t *)&payload, sizeof(payload));
|
SendCommandNG(CMD_HF_MIFARE_STATIC_NESTED, (uint8_t*)&payload, sizeof(payload));
|
||||||
|
|
||||||
if (!WaitForResponseTimeout(CMD_HF_MIFARE_STATIC_NESTED, &resp, 2000))
|
if (!WaitForResponseTimeout(CMD_HF_MIFARE_STATIC_NESTED, &resp, 2000))
|
||||||
return PM3_ETIMEOUT;
|
return PM3_ETIMEOUT;
|
||||||
|
@ -615,51 +615,169 @@ int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBl
|
||||||
uint8_t block;
|
uint8_t block;
|
||||||
uint8_t keytype;
|
uint8_t keytype;
|
||||||
uint8_t cuid[4];
|
uint8_t cuid[4];
|
||||||
uint8_t nt[4];
|
uint8_t nt1_1[4];
|
||||||
uint8_t ks[4];
|
uint8_t nt2_1[4];
|
||||||
|
// new nt
|
||||||
|
uint8_t nt1_2[4];
|
||||||
|
uint8_t nt2_2[4];
|
||||||
} PACKED;
|
} PACKED;
|
||||||
struct p *package = (struct p *)resp.data.asBytes;
|
struct p* package = (struct p*)resp.data.asBytes;
|
||||||
|
|
||||||
// error during collecting static nested information
|
// error during collecting static nested information
|
||||||
if (package->isOK == 0) return PM3_EUNDEF;
|
if (package->isOK == 0) return PM3_EUNDEF;
|
||||||
|
|
||||||
|
uint32_t nt1_1, nt2_1;
|
||||||
|
uint32_t nt1_2, nt2_2;
|
||||||
|
uint32_t dist = 160;
|
||||||
|
|
||||||
memcpy(&uid, package->cuid, sizeof(package->cuid));
|
memcpy(&uid, package->cuid, sizeof(package->cuid));
|
||||||
|
memcpy(&nt1_1, package->nt1_1, 4);
|
||||||
|
memcpy(&nt2_1, package->nt2_1, 4);
|
||||||
|
memcpy(&nt1_2, package->nt1_2, 4);
|
||||||
|
memcpy(&nt2_2, package->nt2_2, 4);
|
||||||
|
|
||||||
statelists[0].blockNo = package->block;
|
// is fast decrypt supported?
|
||||||
statelists[0].keyType = package->keytype;
|
uint8_t level = 0;
|
||||||
statelists[0].uid = uid;
|
if (nt2_1 != nt2_2) {
|
||||||
|
level = 1;
|
||||||
memcpy(&statelists[0].nt_enc, package->nt, sizeof(package->nt));
|
// check level(staticnested)
|
||||||
memcpy(&statelists[0].ks1, package->ks, sizeof(package->ks));
|
if (nt1_1 == 0x01200145) {
|
||||||
|
level = 1;
|
||||||
// calc keys
|
}
|
||||||
pthread_t t;
|
if (nt1_1 == 0x009080A2) {
|
||||||
|
level = 2;
|
||||||
// create and run worker thread
|
if (trgKeyType == 1) {
|
||||||
pthread_create(&t, NULL, nested_worker_thread, &statelists[0]);
|
// if level is 2 and recover keyb, we must use 161 dist first.
|
||||||
|
dist = 161;
|
||||||
// wait for thread to terminate:
|
}
|
||||||
pthread_join(t, (void *)&statelists[0].head.slhead);
|
|
||||||
|
|
||||||
// the first 16 Bits of the cryptostate already contain part of our key.
|
|
||||||
p1 = p3 = statelists[0].head.slhead;
|
|
||||||
|
|
||||||
// create key candidates.
|
|
||||||
while (p1 <= statelists[0].tail.sltail) {
|
|
||||||
struct Crypto1State savestate;
|
|
||||||
savestate = *p1;
|
|
||||||
while (Compare16Bits(p1, &savestate) == 0 && p1 <= statelists[0].tail.sltail) {
|
|
||||||
*p3 = *p1;
|
|
||||||
lfsr_rollback_word(p3, statelists[0].nt_enc ^ statelists[0].uid, 0);
|
|
||||||
p3++;
|
|
||||||
p1++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
level = 0;
|
||||||
|
}
|
||||||
|
|
||||||
p3->odd = -1;
|
PrintAndLogEx(SUCCESS, "Auto detect staticnested level %d", level);
|
||||||
p3->even = -1;
|
|
||||||
statelists[0].len = p3 - statelists[0].head.slhead;
|
uint32_t ntp_1 = prng_successor(nt1_1, dist);
|
||||||
statelists[0].tail.sltail = --p3;
|
uint32_t ks1_1 = nt2_1 ^ ntp_1;
|
||||||
|
|
||||||
|
// normal static nested
|
||||||
|
if (level == 0) {
|
||||||
|
statelists[0].blockNo = package->block;
|
||||||
|
statelists[0].keyType = package->keytype;
|
||||||
|
statelists[0].uid = uid;
|
||||||
|
|
||||||
|
memcpy(&statelists[0].nt_enc, &ntp_1, sizeof(ntp_1));
|
||||||
|
memcpy(&statelists[0].ks1, &ks1_1, sizeof(ks1_1));
|
||||||
|
|
||||||
|
// calc keys
|
||||||
|
pthread_t t;
|
||||||
|
|
||||||
|
// create and run worker thread
|
||||||
|
pthread_create(&t, NULL, nested_worker_thread, &statelists[0]);
|
||||||
|
|
||||||
|
// wait for thread to terminate:
|
||||||
|
pthread_join(t, (void*)&statelists[0].head.slhead);
|
||||||
|
|
||||||
|
// the first 16 Bits of the cryptostate already contain part of our key.
|
||||||
|
p1 = p3 = statelists[0].head.slhead;
|
||||||
|
|
||||||
|
// create key candidates.
|
||||||
|
while (p1 <= statelists[0].tail.sltail) {
|
||||||
|
struct Crypto1State savestate;
|
||||||
|
savestate = *p1;
|
||||||
|
while (Compare16Bits(p1, &savestate) == 0 && p1 <= statelists[0].tail.sltail) {
|
||||||
|
*p3 = *p1;
|
||||||
|
lfsr_rollback_word(p3, statelists[0].nt_enc ^ statelists[0].uid, 0);
|
||||||
|
p3++;
|
||||||
|
p1++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p3->odd = -1;
|
||||||
|
p3->even = -1;
|
||||||
|
statelists[0].len = p3 - statelists[0].head.slhead;
|
||||||
|
statelists[0].tail.sltail = --p3;
|
||||||
|
}
|
||||||
|
else { // fast decrypt static nested
|
||||||
|
|
||||||
|
PrintAndLogEx(SUCCESS, "Fast staticnested decrypt running...");
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < 2; i++) {
|
||||||
|
statelists[i].blockNo = package->block;
|
||||||
|
statelists[i].keyType = package->keytype;
|
||||||
|
statelists[i].uid = uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
dist += 160;
|
||||||
|
|
||||||
|
uint32_t ntp_2 = prng_successor(nt1_2, dist);
|
||||||
|
uint32_t ks1_2 = nt2_2 ^ ntp_2;
|
||||||
|
|
||||||
|
memcpy(&statelists[0].nt_enc, &ntp_1, sizeof(ntp_1));
|
||||||
|
memcpy(&statelists[0].ks1, &ks1_1, sizeof(ks1_1));
|
||||||
|
|
||||||
|
memcpy(&statelists[1].nt_enc, &ntp_2, sizeof(ntp_2));
|
||||||
|
memcpy(&statelists[1].ks1, &ks1_2, sizeof(ks1_2));
|
||||||
|
|
||||||
|
// calc keys
|
||||||
|
pthread_t thread_id[2];
|
||||||
|
|
||||||
|
// create and run worker threads
|
||||||
|
for (uint8_t i = 0; i < 2; i++)
|
||||||
|
pthread_create(thread_id + i, NULL, nested_worker_thread, &statelists[i]);
|
||||||
|
|
||||||
|
// wait for threads to terminate:
|
||||||
|
for (uint8_t i = 0; i < 2; i++)
|
||||||
|
pthread_join(thread_id[i], (void*)&statelists[i].head.slhead);
|
||||||
|
|
||||||
|
// the first 16 Bits of the cryptostate already contain part of our key.
|
||||||
|
// Create the intersection of the two lists based on these 16 Bits and
|
||||||
|
// roll back the cryptostate
|
||||||
|
p1 = p3 = statelists[0].head.slhead;
|
||||||
|
p2 = p4 = statelists[1].head.slhead;
|
||||||
|
|
||||||
|
while (p1 <= statelists[0].tail.sltail && p2 <= statelists[1].tail.sltail) {
|
||||||
|
if (Compare16Bits(p1, p2) == 0) {
|
||||||
|
|
||||||
|
struct Crypto1State savestate;
|
||||||
|
savestate = *p1;
|
||||||
|
while (Compare16Bits(p1, &savestate) == 0 && p1 <= statelists[0].tail.sltail) {
|
||||||
|
*p3 = *p1;
|
||||||
|
lfsr_rollback_word(p3, statelists[0].nt_enc ^ statelists[0].uid, 0);
|
||||||
|
p3++;
|
||||||
|
p1++;
|
||||||
|
}
|
||||||
|
savestate = *p2;
|
||||||
|
while (Compare16Bits(p2, &savestate) == 0 && p2 <= statelists[1].tail.sltail) {
|
||||||
|
*p4 = *p2;
|
||||||
|
lfsr_rollback_word(p4, statelists[1].nt_enc ^ statelists[1].uid, 0);
|
||||||
|
p4++;
|
||||||
|
p2++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
while (Compare16Bits(p1, p2) == -1) p1++;
|
||||||
|
while (Compare16Bits(p1, p2) == 1) p2++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p3->odd = -1;
|
||||||
|
p3->even = -1;
|
||||||
|
p4->odd = -1;
|
||||||
|
p4->even = -1;
|
||||||
|
statelists[0].len = p3 - statelists[0].head.slhead;
|
||||||
|
statelists[1].len = p4 - statelists[1].head.slhead;
|
||||||
|
statelists[0].tail.sltail = --p3;
|
||||||
|
statelists[1].tail.sltail = --p4;
|
||||||
|
|
||||||
|
// the statelists now contain possible keys. The key we are searching for must be in the
|
||||||
|
// intersection of both lists
|
||||||
|
qsort(statelists[0].head.keyhead, statelists[0].len, sizeof(uint64_t), compare_uint64);
|
||||||
|
qsort(statelists[1].head.keyhead, statelists[1].len, sizeof(uint64_t), compare_uint64);
|
||||||
|
// Create the intersection
|
||||||
|
statelists[0].len = intersection(statelists[0].head.keyhead, statelists[1].head.keyhead);
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t keycnt = statelists[0].len;
|
uint32_t keycnt = statelists[0].len;
|
||||||
if (keycnt == 0) goto out;
|
if (keycnt == 0) goto out;
|
||||||
|
@ -667,43 +785,28 @@ int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBl
|
||||||
PrintAndLogEx(SUCCESS, "Found " _YELLOW_("%u") " key candidates", keycnt);
|
PrintAndLogEx(SUCCESS, "Found " _YELLOW_("%u") " key candidates", keycnt);
|
||||||
|
|
||||||
memset(resultKey, 0, 6);
|
memset(resultKey, 0, 6);
|
||||||
|
uint64_t key64 = -1;
|
||||||
|
|
||||||
// The list may still contain several key candidates. Test each of them with mfCheckKeys
|
// The list may still contain several key candidates. Test each of them with mfCheckKeys
|
||||||
uint32_t maxkeysinblock = IfPm3Flash() ? 1000 : KEYS_IN_BLOCK;
|
uint32_t maxkeysinblock = IfPm3Flash() ? 1000 : KEYS_IN_BLOCK;
|
||||||
uint32_t max_keys_chunk = keycnt > maxkeysinblock ? maxkeysinblock : keycnt;
|
uint32_t max_keys_chunk = keycnt > maxkeysinblock ? maxkeysinblock : keycnt;
|
||||||
|
|
||||||
uint8_t *mem = NULL;
|
uint8_t* mem = calloc((maxkeysinblock * 6) + 5, sizeof(uint8_t));
|
||||||
uint8_t *p_keyblock = NULL;
|
if (mem == NULL) {
|
||||||
|
free(statelists[0].head.slhead);
|
||||||
if (IfPm3Flash()) {
|
return PM3_EMALLOC;
|
||||||
|
|
||||||
// used for mfCheckKeys_file, which needs a header
|
|
||||||
mem = calloc((maxkeysinblock * 6) + 5, sizeof(uint8_t));
|
|
||||||
if (mem == NULL) {
|
|
||||||
free(statelists[0].head.slhead);
|
|
||||||
return PM3_EMALLOC;
|
|
||||||
}
|
|
||||||
|
|
||||||
mem[0] = statelists[0].keyType;
|
|
||||||
mem[1] = statelists[0].blockNo;
|
|
||||||
mem[2] = 1;
|
|
||||||
mem[3] = ((max_keys_chunk >> 8) & 0xFF);
|
|
||||||
mem[4] = (max_keys_chunk & 0xFF);
|
|
||||||
|
|
||||||
p_keyblock = mem + 5;
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// used for mfCheckKeys, which adds its own header.
|
|
||||||
mem = calloc((maxkeysinblock * 6), sizeof(uint8_t));
|
|
||||||
if (mem == NULL) {
|
|
||||||
free(statelists[0].head.slhead);
|
|
||||||
return PM3_EMALLOC;
|
|
||||||
}
|
|
||||||
p_keyblock = mem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mem[0] = statelists[0].keyType;
|
||||||
|
mem[1] = statelists[0].blockNo;
|
||||||
|
mem[2] = 1;
|
||||||
|
mem[3] = ((max_keys_chunk >> 8) & 0xFF);
|
||||||
|
mem[4] = (max_keys_chunk & 0xFF);
|
||||||
|
|
||||||
|
uint8_t* p_keyblock = mem + 5;
|
||||||
|
|
||||||
uint8_t destfn[32];
|
uint8_t destfn[32];
|
||||||
strncpy((char *)destfn, "static_nested_000.bin", sizeof(destfn) - 1);
|
strncpy((char*)destfn, "static_nested_000.bin", sizeof(destfn) - 1);
|
||||||
|
|
||||||
uint64_t start_time = msclock();
|
uint64_t start_time = msclock();
|
||||||
for (uint32_t i = 0; i < keycnt; i += max_keys_chunk) {
|
for (uint32_t i = 0; i < keycnt; i += max_keys_chunk) {
|
||||||
|
@ -717,8 +820,7 @@ int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBl
|
||||||
}
|
}
|
||||||
|
|
||||||
int res = 0;
|
int res = 0;
|
||||||
uint64_t key64 = 0;
|
key64 = 0;
|
||||||
|
|
||||||
uint32_t chunk = keycnt - i > max_keys_chunk ? max_keys_chunk : keycnt - i;
|
uint32_t chunk = keycnt - i > max_keys_chunk ? max_keys_chunk : keycnt - i;
|
||||||
|
|
||||||
// copy x keys to device.
|
// copy x keys to device.
|
||||||
|
@ -728,21 +830,22 @@ int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBl
|
||||||
}
|
}
|
||||||
|
|
||||||
// check a block of generated key candidates.
|
// check a block of generated key candidates.
|
||||||
if (IfPm3Flash()) {
|
if (IfPm3Flash() && keycnt > 10) {
|
||||||
|
|
||||||
mem[3] = ((chunk >> 8) & 0xFF);
|
mem[3] = ((chunk >> 8) & 0xFF);
|
||||||
mem[4] = (chunk & 0xFF);
|
mem[4] = (chunk & 0xFF);
|
||||||
|
|
||||||
// upload to flash.
|
// upload to flash.
|
||||||
res = flashmem_spiffs_load((char *)destfn, mem, 5 + (chunk * 6));
|
res = flashmem_spiffs_load((char*)destfn, mem, 5 + (chunk * 6));
|
||||||
if (res != PM3_SUCCESS) {
|
if (res != PM3_SUCCESS) {
|
||||||
PrintAndLogEx(WARNING, "\nSPIFFS upload failed");
|
PrintAndLogEx(WARNING, "\nSPIFFS upload failed");
|
||||||
free(mem);
|
free(mem);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
res = mfCheckKeys_file(destfn, &key64);
|
res = mfCheckKeys_file(destfn, &key64);
|
||||||
} else {
|
}
|
||||||
res = mfCheckKeys(statelists[0].blockNo, statelists[0].keyType, true, chunk, mem, &key64);
|
else {
|
||||||
|
res = mfCheckKeys(statelists[0].blockNo, statelists[0].keyType, false, chunk, p_keyblock, &key64);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res == PM3_SUCCESS) {
|
if (res == PM3_SUCCESS) {
|
||||||
|
@ -753,13 +856,14 @@ int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBl
|
||||||
num_to_bytes(key64, 6, resultKey);
|
num_to_bytes(key64, 6, resultKey);
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(SUCCESS, "target block: %3u key type: %c -- found valid key [ " _GREEN_("%s") " ]",
|
PrintAndLogEx(SUCCESS, "target block:%3u key type: %c -- found valid key [ " _GREEN_("%s") "]",
|
||||||
package->block,
|
package->block,
|
||||||
package->keytype ? 'B' : 'A',
|
package->keytype ? 'B' : 'A',
|
||||||
sprint_hex_inrow(resultKey, 6)
|
sprint_hex(resultKey, 6)
|
||||||
);
|
);
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
} else if (res == PM3_ETIMEOUT || res == PM3_EOPABORTED) {
|
}
|
||||||
|
else if (res == PM3_ETIMEOUT || res == PM3_EOPABORTED) {
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
free(mem);
|
free(mem);
|
||||||
return res;
|
return res;
|
||||||
|
@ -773,12 +877,17 @@ int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBl
|
||||||
free(mem);
|
free(mem);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
PrintAndLogEx(SUCCESS, "\ntarget block: %3u key type: %c",
|
PrintAndLogEx(SUCCESS, "\ntarget block:%3u key type: %c",
|
||||||
package->block,
|
package->block,
|
||||||
package->keytype ? 'B' : 'A'
|
package->keytype ? 'B' : 'A'
|
||||||
);
|
);
|
||||||
|
|
||||||
free(statelists[0].head.slhead);
|
free(statelists[0].head.slhead);
|
||||||
|
|
||||||
|
if (level != 0) {
|
||||||
|
free(statelists[1].head.slhead);
|
||||||
|
}
|
||||||
|
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue