hf mf mifare:

- gracefully exit on unsuccessful syncs instead of hard watchdog reset
This commit is contained in:
pwpiwi 2015-09-30 20:59:50 +02:00
parent 9dd0ac57ed
commit dfb387bf0f
3 changed files with 49 additions and 16 deletions

View file

@ -2016,6 +2016,7 @@ void ReaderMifare(bool first_try)
byte_t par_list[8] = {0x00}; byte_t par_list[8] = {0x00};
byte_t ks_list[8] = {0x00}; byte_t ks_list[8] = {0x00};
#define PRNG_SEQUENCE_LENGTH (1 << 16);
static uint32_t sync_time; static uint32_t sync_time;
static uint32_t sync_cycles; static uint32_t sync_cycles;
int catch_up_cycles = 0; int catch_up_cycles = 0;
@ -2026,7 +2027,7 @@ void ReaderMifare(bool first_try)
if (first_try) { if (first_try) {
mf_nr_ar3 = 0; mf_nr_ar3 = 0;
sync_time = GetCountSspClk() & 0xfffffff8; sync_time = GetCountSspClk() & 0xfffffff8;
sync_cycles = 65536; // theory: Mifare Classic's random generator repeats every 2^16 cycles (and so do the nonces). sync_cycles = PRNG_SEQUENCE_LENGTH; // theory: Mifare Classic's random generator repeats every 2^16 cycles (and so do the tag nonces).
nt_attacked = 0; nt_attacked = 0;
nt = 0; nt = 0;
par[0] = 0; par[0] = 0;
@ -2043,8 +2044,12 @@ void ReaderMifare(bool first_try)
LED_C_OFF(); LED_C_OFF();
#define DARKSIDE_MAX_TRIES 32 // number of tries to sync on PRNG cycle. Then give up. #define MAX_UNEXPECTED_RANDOM 4 // maximum number of unexpected (i.e. real) random numbers when trying to sync. Then give up.
uint16_t unsuccessfull_tries = 0; #define MAX_SYNC_TRIES 16
uint16_t unexpected_random = 0;
uint16_t sync_tries = 0;
int16_t debug_info_nr = -1;
uint32_t debug_info[MAX_SYNC_TRIES];
for(uint16_t i = 0; TRUE; i++) { for(uint16_t i = 0; TRUE; i++) {
@ -2062,17 +2067,21 @@ void ReaderMifare(bool first_try)
continue; continue;
} }
sync_time = (sync_time & 0xfffffff8) + sync_cycles + catch_up_cycles; if (debug_info_nr == -1) {
catch_up_cycles = 0; sync_time = (sync_time & 0xfffffff8) + sync_cycles + catch_up_cycles;
catch_up_cycles = 0;
// if we missed the sync time already, advance to the next nonce repeat // if we missed the sync time already, advance to the next nonce repeat
while(GetCountSspClk() > sync_time) { while(GetCountSspClk() > sync_time) {
sync_time = (sync_time & 0xfffffff8) + sync_cycles; sync_time = (sync_time & 0xfffffff8) + sync_cycles;
}
// Transmit MIFARE_CLASSIC_AUTH at synctime. Should result in returning the same tag nonce (== nt_attacked)
ReaderTransmit(mf_auth, sizeof(mf_auth), &sync_time);
} else {
ReaderTransmit(mf_auth, sizeof(mf_auth), NULL);
} }
// Transmit MIFARE_CLASSIC_AUTH at synctime. Should result in returning the same tag nonce (== nt_attacked)
ReaderTransmit(mf_auth, sizeof(mf_auth), &sync_time);
// Receive the (4 Byte) "random" nonce // Receive the (4 Byte) "random" nonce
if (!ReaderReceive(receivedAnswer, receivedAnswerPar)) { if (!ReaderReceive(receivedAnswer, receivedAnswerPar)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Mifare: Couldn't receive tag nonce"); if (MF_DBGLEVEL >= 1) Dbprintf("Mifare: Couldn't receive tag nonce");
@ -2089,19 +2098,32 @@ void ReaderMifare(bool first_try)
int nt_distance = dist_nt(previous_nt, nt); int nt_distance = dist_nt(previous_nt, nt);
if (nt_distance == 0) { if (nt_distance == 0) {
nt_attacked = nt; nt_attacked = nt;
} } else {
else {
if (nt_distance == -99999) { // invalid nonce received if (nt_distance == -99999) { // invalid nonce received
unsuccessfull_tries++; unexpected_random++;
if (!nt_attacked && unsuccessfull_tries > DARKSIDE_MAX_TRIES) { if (!nt_attacked && unexpected_random > MAX_UNEXPECTED_RANDOM) {
isOK = -3; // Card has an unpredictable PRNG. Give up isOK = -3; // Card has an unpredictable PRNG. Give up
break; break;
} else { } else {
continue; // continue trying... continue; // continue trying...
} }
} }
if (++sync_tries > MAX_SYNC_TRIES) {
if (sync_tries > 2 * MAX_SYNC_TRIES) {
isOK = -4; // Card's PRNG runs at an unexpected frequency or resets unexpectedly
break;
} else { // continue for a while, just to collect some debug info
debug_info[++debug_info_nr] = nt_distance;
continue;
}
}
sync_cycles = (sync_cycles - nt_distance); sync_cycles = (sync_cycles - nt_distance);
if (MF_DBGLEVEL >= 3) Dbprintf("calibrating in cycle %d. nt_distance=%d, Sync_cycles: %d\n", i, nt_distance, sync_cycles); if (sync_cycles <= 0) {
sync_cycles += PRNG_SEQUENCE_LENGTH;
}
if (MF_DBGLEVEL >= 3) {
Dbprintf("calibrating in cycle %d. nt_distance=%d, Sync_cycles: %d\n", i, nt_distance, sync_cycles);
}
continue; continue;
} }
} }
@ -2173,6 +2195,14 @@ void ReaderMifare(bool first_try)
mf_nr_ar[3] &= 0x1F; mf_nr_ar[3] &= 0x1F;
if (isOK == -4) {
if (MF_DBGLEVEL >= 3) {
for(uint16_t i = 0; i < MAX_SYNC_TRIES; i++) {
Dbprintf("collected debug info[%d] = %d\n", i, debug_info[i]);
}
}
}
byte_t buf[28]; byte_t buf[28];
memcpy(buf + 0, uid, 4); memcpy(buf + 0, uid, 4);
num_to_bytes(nt, 4, buf + 4); num_to_bytes(nt, 4, buf + 4);

View file

@ -58,6 +58,7 @@ start:
case -1 : PrintAndLog("Button pressed. Aborted.\n"); break; case -1 : PrintAndLog("Button pressed. Aborted.\n"); break;
case -2 : PrintAndLog("Card is not vulnerable to Darkside attack (doesn't send NACK on authentication requests).\n"); break; case -2 : PrintAndLog("Card is not vulnerable to Darkside attack (doesn't send NACK on authentication requests).\n"); break;
case -3 : PrintAndLog("Card is not vulnerable to Darkside attack (its random number generator is not predictable).\n"); break; case -3 : PrintAndLog("Card is not vulnerable to Darkside attack (its random number generator is not predictable).\n"); break;
case -4 : PrintAndLog("The card's random number generator is vulnerable but behaves somewhat weird (Mifare clone?). This needs to be fixed.\n"); break;
default: ; default: ;
} }
break; break;

View file

@ -112,6 +112,8 @@ function mfcrack_inner()
return nil, "Card is not vulnerable to Darkside attack (doesn't send NACK on authentication requests). You can try 'script run mfkeys' or 'hf mf chk' to test various known keys." return nil, "Card is not vulnerable to Darkside attack (doesn't send NACK on authentication requests). You can try 'script run mfkeys' or 'hf mf chk' to test various known keys."
elseif isOK == 0xFFFFFFFD then elseif isOK == 0xFFFFFFFD then
return nil, "Card is not vulnerable to Darkside attack (its random number generator is not predictable). You can try 'script run mfkeys' or 'hf mf chk' to test various known keys." return nil, "Card is not vulnerable to Darkside attack (its random number generator is not predictable). You can try 'script run mfkeys' or 'hf mf chk' to test various known keys."
elseif isOK == 0xFFFFFFFC then
return nil, "The card's random number generator is vulnerable but behaves somewhat weird (Mifare clone?). You can try 'script run mfkeys' or 'hf mf chk' to test various known keys."
elseif isOK ~= 1 then elseif isOK ~= 1 then
return nil, "Error occurred" return nil, "Error occurred"
end end