mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2024-12-28 19:31:19 +08:00
chg: 'hf mf nack' - only test all 256 parities for one nonce when synced.
0 nack = has not bug. 1 nack == has bug x nacks == most likely a clone card which answers nack to all requests.
This commit is contained in:
parent
53d8668e00
commit
6e5038f224
2 changed files with 43 additions and 71 deletions
|
@ -2549,55 +2549,47 @@ void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype ) {
|
|||
* Mifare Classic NACK-bug detection
|
||||
*/
|
||||
void DetectNACKbug() {
|
||||
|
||||
#define PRNG_SEQUENCE_LENGTH (1 << 16)
|
||||
#define MAX_UNEXPECTED_RANDOM 4 // maximum number of unexpected (i.e. real) random numbers when trying to sync, then give up.
|
||||
#define MAX_SYNC_TRIES 32
|
||||
|
||||
uint8_t mf_auth[] = {0x60, 0, 0, 0};
|
||||
uint8_t mf_nr_ar[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
|
||||
uint8_t mf_auth[] = {0x60, 0x00, 0xF5, 0x7B};
|
||||
uint8_t mf_nr_ar[] = {0,0,0,0,0,0,0,0};
|
||||
uint8_t uid[10] = {0,0,0,0,0,0,0,0,0,0};
|
||||
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00};
|
||||
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = {0x00};
|
||||
uint8_t par[1] = {0}; // maximum 8 Bytes to be sent here, 1 byte parity is therefore enough
|
||||
uint32_t nt = 0;
|
||||
uint32_t previous_nt = 0;
|
||||
uint32_t cuid = 0;
|
||||
int32_t isOK = 0;
|
||||
|
||||
int32_t catch_up_cycles = 0;
|
||||
int32_t last_catch_up = 0;
|
||||
int32_t nt_distance = 0;
|
||||
|
||||
|
||||
uint32_t nt = 0, previous_nt = 0, nt_attacked = 0, cuid = 0;
|
||||
int32_t isOK = 0, catch_up_cycles = 0, last_catch_up = 0;
|
||||
uint8_t cascade_levels = 0, num_nacks = 0;
|
||||
uint16_t elapsed_prng_sequences = 1;
|
||||
uint16_t consecutive_resyncs = 0;
|
||||
uint16_t unexpected_random = 0;
|
||||
uint16_t sync_tries = 0;
|
||||
uint32_t nt_attacked = 0;
|
||||
uint32_t sync_time = 0;
|
||||
uint32_t sync_cycles = 0;
|
||||
uint8_t cascade_levels = 0;
|
||||
|
||||
bool have_uid = false;
|
||||
|
||||
uint8_t num_nacks = 0;
|
||||
// Mifare Classic's random generator repeats every 2^16 cycles (and so do the nonces).
|
||||
uint32_t sync_cycles = PRNG_SEQUENCE_LENGTH;
|
||||
|
||||
#define PRNG_SEQUENCE_LENGTH (1 << 16)
|
||||
#define MAX_UNEXPECTED_RANDOM 4 // maximum number of unexpected (i.e. real) random numbers when trying to sync, then give up.
|
||||
#define MAX_SYNC_TRIES 32
|
||||
#define MAX_PRNG_TRIES 20 // when we gone through 10 prng sequences without managing to sync, then give up.
|
||||
|
||||
AppendCrc14443a(mf_auth, 2);
|
||||
// create our reader nonce randomly
|
||||
uint32_t nonce = prng_successor( GetCountSspClk() & 0xfffffff8 , 32);
|
||||
num_to_bytes(nonce, 4, mf_nr_ar);
|
||||
|
||||
BigBuf_free(); BigBuf_Clear_ext(false);
|
||||
clear_trace();
|
||||
set_tracing(true);
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD);
|
||||
|
||||
sync_time = GetCountSspClk() & 0xfffffff8;
|
||||
sync_cycles = PRNG_SEQUENCE_LENGTH; // Mifare Classic's random generator repeats every 2^16 cycles (and so do the nonces).
|
||||
sync_time = GetCountSspClk() & 0xfffffff8;
|
||||
|
||||
if (MF_DBGLEVEL >= 4) Dbprintf("Mifare::Sync %u", sync_time);
|
||||
if (MF_DBGLEVEL >= 4) Dbprintf("Mifare::Sync %u", sync_time);
|
||||
|
||||
LED_C_ON();
|
||||
uint16_t i;
|
||||
for (i = 0; num_nacks < 3; ++i) {
|
||||
for (i = 0; true; ++i) {
|
||||
|
||||
WDT_HIT();
|
||||
|
||||
|
@ -2653,16 +2645,11 @@ void DetectNACKbug() {
|
|||
// Transmit reader nonce with fake par
|
||||
ReaderTransmitPar(mf_nr_ar, sizeof(mf_nr_ar), par, NULL);
|
||||
|
||||
if ( elapsed_prng_sequences > MAX_PRNG_TRIES) {
|
||||
isOK = -4; // Card's PRNG runs at an unexpected frequency or resets unexpectedly
|
||||
break;
|
||||
}
|
||||
|
||||
// we didn't calibrate our clock yet,
|
||||
// iceman: has to be calibrated every time.
|
||||
if (previous_nt && !nt_attacked) {
|
||||
|
||||
nt_distance = dist_nt(previous_nt, nt);
|
||||
int nt_distance = dist_nt(previous_nt, nt);
|
||||
|
||||
// if no distance between, then we are in sync.
|
||||
if (nt_distance == 0) {
|
||||
|
@ -2675,7 +2662,9 @@ void DetectNACKbug() {
|
|||
isOK = -3;
|
||||
break;
|
||||
} else {
|
||||
if (sync_cycles <= 0) sync_cycles += PRNG_SEQUENCE_LENGTH;
|
||||
if (sync_cycles <= 0) {
|
||||
sync_cycles += PRNG_SEQUENCE_LENGTH;
|
||||
}
|
||||
LED_B_OFF();
|
||||
continue; // continue trying...
|
||||
}
|
||||
|
@ -2707,7 +2696,7 @@ void DetectNACKbug() {
|
|||
|
||||
if ( (nt != nt_attacked) && nt_attacked) {
|
||||
// we somehow lost sync. Try to catch up again...
|
||||
catch_up_cycles = ABS(dist_nt(nt_attacked, nt));
|
||||
catch_up_cycles = -dist_nt(nt_attacked, nt);
|
||||
|
||||
if (catch_up_cycles == 99999) {
|
||||
// invalid nonce received. Don't resync on that one.
|
||||
|
@ -2725,14 +2714,16 @@ void DetectNACKbug() {
|
|||
}
|
||||
|
||||
if (consecutive_resyncs < 3) {
|
||||
if (MF_DBGLEVEL >= 4)
|
||||
if (MF_DBGLEVEL >= 4) {
|
||||
Dbprintf("Lost sync in cycle %d. nt_distance=%d. Consecutive Resyncs = %d. Trying one time catch up...\n", i, catch_up_cycles, consecutive_resyncs);
|
||||
}
|
||||
} else {
|
||||
sync_cycles += catch_up_cycles;
|
||||
|
||||
if (MF_DBGLEVEL >= 4)
|
||||
if (MF_DBGLEVEL >= 4) {
|
||||
Dbprintf("Lost sync in cycle %d for the fourth time consecutively (nt_distance = %d). Adjusting sync_cycles to %d.\n", i, catch_up_cycles, sync_cycles);
|
||||
|
||||
Dbprintf("nt [%08x] attacted [%08x]", nt, nt_attacked );
|
||||
}
|
||||
last_catch_up = 0;
|
||||
catch_up_cycles = 0;
|
||||
consecutive_resyncs = 0;
|
||||
|
@ -2744,37 +2735,24 @@ void DetectNACKbug() {
|
|||
if (ReaderReceive(receivedAnswer, receivedAnswerPar)) {
|
||||
catch_up_cycles = 8; // the PRNG is delayed by 8 cycles due to the NAC (4Bits = 0x05 encrypted) transfer
|
||||
num_nacks++;
|
||||
|
||||
par[0] = 0;
|
||||
//new nonce
|
||||
mf_nr_ar[0]++;
|
||||
mf_nr_ar[1]++;
|
||||
mf_nr_ar[2]++;
|
||||
mf_nr_ar[3]++;
|
||||
|
||||
} else {
|
||||
// No NACK.
|
||||
par[0]++;
|
||||
// tried all 256 possible parities without success.
|
||||
if (par[0] == 0x00) {
|
||||
//
|
||||
if ( num_nacks < 3 ) {
|
||||
//new nonce
|
||||
mf_nr_ar[0]++;
|
||||
mf_nr_ar[1]++;
|
||||
mf_nr_ar[2]++;
|
||||
mf_nr_ar[3]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we are testing all 256 possibilities.
|
||||
par[0]++;
|
||||
|
||||
// tried all 256 possible parities without success.
|
||||
if (par[0] == 0) {
|
||||
if ( num_nacks > 1 )
|
||||
isOK = -2;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// reset the resyncs since we got a complete transaction on right time.
|
||||
consecutive_resyncs = 0;
|
||||
} // end for loop
|
||||
|
||||
if (num_nacks == 3)
|
||||
isOK = 1;
|
||||
|
||||
// num_nacks = number of nacks recieved. should be only 1. if not its a clone card which always sends NACK (parity == 0) ?
|
||||
// i = number of authentications sent. Not always 256, since we are trying to sync but close to it.
|
||||
cmd_send(CMD_ACK, isOK, num_nacks, i, 0, 0 );
|
||||
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
|
|
|
@ -2871,22 +2871,16 @@ int CmdHf14AMfNack(const char *Cmd) {
|
|||
uint32_t nacks = resp.arg[1];
|
||||
uint32_t auths = resp.arg[2];
|
||||
|
||||
PrintAndLog("Three different nonces used, expecting three nacks");
|
||||
PrintAndLog("Num of sent auth requestes : %u", auths);
|
||||
PrintAndLog("Num of received NACK : %u", nacks);
|
||||
switch( ok ) {
|
||||
case -1 : PrintAndLog("Button pressed. Aborted."); return 1;
|
||||
case -2 : PrintAndLog("Card answers NACK, (most likely a clone)"); return 1;
|
||||
case -3 : PrintAndLog("Card random number generator is not predictable)."); return 1;
|
||||
case -4 : PrintAndLog("Card random number generator seems to be based on the wellknown");
|
||||
PrintAndLog("generating polynomial with 16 effective bits only, but shows unexpected behaviour."); return 1;
|
||||
case 1 : PrintAndLog("Card has NACK bug."); return 1;
|
||||
case 0 : {
|
||||
if ( nacks > 0 )
|
||||
PrintAndLog("Card may have NACK bug. inconclusive result");
|
||||
else
|
||||
PrintAndLog("Card has not NACK bug.");
|
||||
return 1;
|
||||
}
|
||||
case 0 : PrintAndLog("Card has not NACK bug."); return 1;
|
||||
default : PrintAndLog(" errorcode from device [%i]", ok); return 1;
|
||||
}
|
||||
break;
|
||||
|
|
Loading…
Reference in a new issue