- PM: used GetCountMifare in MifareNested() for improved timing accuracy and to deliver better quality nonces
- PM: MifareNested now delivers exactly two different nonces to avoid time consuming multiple lfsr_recovery32() on client side
- Client: replaced quicksort by bucketsort in crapto1.c which is faster
- Client: use multithreading (two parallel calls to lfsr_recovery32())
- Client: fixed a small bug in mfnested() (always showed trgkey=0)
- Client: introduced a mutex for PrintAndLog() to avoid interlaced printing
Minor rework of hf mf chk:
- Avoid time consuming off/on cycles. Send a "halt" instead.
// mifarecmd.h
void ReaderMifare(bool first_try);
+int32_t dist_nt(uint32_t nt1, uint32_t nt2);
void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *data);
void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain);
void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain);
}
// send the PPS request
- ReaderTransmit((uint8_t *)pps, sizeof(pps));
+ ReaderTransmit((uint8_t *)pps, sizeof(pps), NULL);
uint8_t pps_response[3];
return_code = ReaderReceive(pps_response);
if (return_code != 3 || pps_response[0] != 0xD0) {
LED_A_OFF();
}
+
+// prepare a delayed transfer. This simply shifts ToSend[] by a number
+// of bits specified in the delay parameter.
+void PrepareDelayedTransfer(uint16_t delay)
+{
+ uint8_t bitmask = 0;
+ uint8_t bits_to_shift = 0;
+ uint8_t bits_shifted = 0;
+
+ delay &= 0x07;
+ if (delay) {
+ for (uint16_t i = 0; i < delay; i++) {
+ bitmask |= (0x01 << i);
+ }
+ ToSend[++ToSendMax] = 0x00;
+ for (uint16_t i = 0; i < ToSendMax; i++) {
+ bits_to_shift = ToSend[i] & bitmask;
+ ToSend[i] = ToSend[i] >> delay;
+ ToSend[i] = ToSend[i] | (bits_shifted << (8 - delay));
+ bits_shifted = bits_to_shift;
+ }
+ }
+}
+
+
+
+
//-----------------------------------------------------------------------------
// Transmit the command (to the tag) that was placed in ToSend[].
+// Parameter timing:
+// if NULL: ignored
+// if == 0: return time of transfer
+// if != 0: delay transfer until time specified
//-----------------------------------------------------------------------------
-static void TransmitFor14443a(const uint8_t *cmd, int len, int *samples, int *wait)
+static void TransmitFor14443a(const uint8_t *cmd, int len, uint32_t *timing)
{
- int c;
+ int c;
- FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);
- if (wait)
- if(*wait < 10)
- *wait = 10;
- for(c = 0; c < *wait;) {
- if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
- AT91C_BASE_SSC->SSC_THR = 0x00; // For exact timing!
- c++;
- }
- if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
- volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR;
- (void)r;
- }
- WDT_HIT();
- }
+ if (timing) {
+ if(*timing == 0) { // Measure time
+ *timing = (GetCountMifare() + 8) & 0xfffffff8;
+ } else {
+ PrepareDelayedTransfer(*timing & 0x00000007); // Delay transfer (fine tuning - up to 7 MF clock ticks)
+ }
+ if(MF_DBGLEVEL >= 4 && GetCountMifare() >= (*timing & 0xfffffff8)) Dbprintf("TransmitFor14443a: Missed timing");
+ while(GetCountMifare() < (*timing & 0xfffffff8)); // Delay transfer (multiple of 8 MF clock ticks)
+ }
+
+ for(c = 0; c < 10;) { // standard delay for each transfer (allow tag to be ready after last transmission)
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
+ AT91C_BASE_SSC->SSC_THR = 0x00;
+ c++;
+ }
+ }
+
+ c = 0;
+ for(;;) {
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
+ AT91C_BASE_SSC->SSC_THR = cmd[c];
+ c++;
+ if(c >= len) {
+ break;
+ }
+ }
+ }
- c = 0;
- for(;;) {
- if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
- AT91C_BASE_SSC->SSC_THR = cmd[c];
- c++;
- if(c >= len) {
- break;
- }
- }
- if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
- volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR;
- (void)r;
- }
- WDT_HIT();
- }
- if (samples) *samples = (c + *wait) << 3;
}
//-----------------------------------------------------------------------------
for(;;) {
WDT_HIT();
- if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
- AT91C_BASE_SSC->SSC_THR = 0x00; // To make use of exact timing of next command from reader!!
- if (elapsed) (*elapsed)++;
- }
+ // if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
+ // AT91C_BASE_SSC->SSC_THR = 0x00; // To make use of exact timing of next command from reader!!
+ // if (elapsed) (*elapsed)++;
+ // }
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
if(c < iso14a_timeout) { c++; } else { return FALSE; }
b = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
}
}
-void ReaderTransmitBitsPar(uint8_t* frame, int bits, uint32_t par)
+void ReaderTransmitBitsPar(uint8_t* frame, int bits, uint32_t par, uint32_t *timing)
{
- int wait = 0;
- int samples = 0;
-
- // This is tied to other size changes
- // uint8_t* frame_addr = ((uint8_t*)BigBuf) + 2024;
+
CodeIso14443aBitsAsReaderPar(frame,bits,par);
// Select the card
- TransmitFor14443a(ToSend, ToSendMax, &samples, &wait);
+ TransmitFor14443a(ToSend, ToSendMax, timing);
if(trigger)
LED_A_ON();
if (tracing) LogTrace(frame,nbytes(bits),0,par,TRUE);
}
-void ReaderTransmitPar(uint8_t* frame, int len, uint32_t par)
+void ReaderTransmitPar(uint8_t* frame, int len, uint32_t par, uint32_t *timing)
{
- ReaderTransmitBitsPar(frame,len*8,par);
+ ReaderTransmitBitsPar(frame,len*8,par, timing);
}
-void ReaderTransmit(uint8_t* frame, int len)
+void ReaderTransmit(uint8_t* frame, int len, uint32_t *timing)
{
// Generate parity and redirect
- ReaderTransmitBitsPar(frame,len*8,GetParity(frame,len));
+ ReaderTransmitBitsPar(frame,len*8,GetParity(frame,len), timing);
}
int ReaderReceive(uint8_t* receivedAnswer)
int len;
// Broadcast for a card, WUPA (0x52) will force response from all cards in the field
- ReaderTransmitBitsPar(wupa,7,0);
+ ReaderTransmitBitsPar(wupa,7,0, NULL);
// Receive the ATQA
if(!ReaderReceive(resp)) return 0;
// Dbprintf("atqa: %02x %02x",resp[0],resp[1]);
sel_uid[0] = sel_all[0] = 0x93 + cascade_level * 2;
// SELECT_ALL
- ReaderTransmit(sel_all,sizeof(sel_all));
+ ReaderTransmit(sel_all,sizeof(sel_all), NULL);
if (!ReaderReceive(resp)) return 0;
// First backup the current uid
uid_resp_len = 4;
// Dbprintf("uid: %02x %02x %02x %02x",uid_resp[0],uid_resp[1],uid_resp[2],uid_resp[3]);
- // calculate crypto UID
- if(cuid_ptr) {
- *cuid_ptr = bytes_to_num(uid_resp, 4);
+ // calculate crypto UID. Always use last 4 Bytes.
+ if(cuid_ptr) {
+ *cuid_ptr = bytes_to_num(uid_resp, 4);
}
// Construct SELECT UID command
memcpy(sel_uid+2,resp,5);
AppendCrc14443a(sel_uid,7);
- ReaderTransmit(sel_uid,sizeof(sel_uid));
+ ReaderTransmit(sel_uid,sizeof(sel_uid), NULL);
// Receive the SAK
if (!ReaderReceive(resp)) return 0;
// Request for answer to select
AppendCrc14443a(rats, 2);
- ReaderTransmit(rats, sizeof(rats));
+ ReaderTransmit(rats, sizeof(rats), NULL);
if (!(len = ReaderReceive(resp))) return 0;
}
void iso14443a_setup() {
- // Set up the synchronous serial port
- FpgaSetupSsc();
+ // Set up the synchronous serial port
+ FpgaSetupSsc();
// Start from off (no field generated)
// Signal field is off with the appropriate LED
- LED_D_OFF();
- FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
- SpinDelay(50);
+// LED_D_OFF();
+// FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+ // SpinDelay(50);
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
// Signal field is on with the appropriate LED
LED_D_ON();
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);
- SpinDelay(50);
+ SpinDelay(7); // iso14443-3 specifies 5ms max.
iso14a_timeout = 2048; //default
}
memcpy(real_cmd+2, cmd, cmd_len);
AppendCrc14443a(real_cmd,cmd_len+2);
- ReaderTransmit(real_cmd, cmd_len+4);
+ ReaderTransmit(real_cmd, cmd_len+4, NULL);
size_t len = ReaderReceive(data);
uint8_t * data_bytes = (uint8_t *) data;
if (!len)
iso14a_command_t param = c->arg[0];
uint8_t * cmd = c->d.asBytes;
size_t len = c->arg[1];
- uint32_t arg0 = 0;
- byte_t buf[USB_CMD_DATA_SIZE];
+ uint32_t arg0 = 0;
+ byte_t buf[USB_CMD_DATA_SIZE];
- iso14a_clear_trace();
- iso14a_set_tracing(true);
+ iso14a_clear_trace();
+ iso14a_set_tracing(true);
if(param & ISO14A_REQUEST_TRIGGER) {
- iso14a_set_trigger(1);
- }
+ iso14a_set_trigger(1);
+ }
if(param & ISO14A_CONNECT) {
iso14443a_setup();
- arg0 = iso14443a_select_card(NULL,(iso14a_card_select_t*)buf,NULL);
+ arg0 = iso14443a_select_card(NULL, (iso14a_card_select_t*)buf, NULL);
cmd_send(CMD_ACK,arg0,0,0,buf,sizeof(iso14a_card_select_t));
-// UsbSendPacket((void *)ack, sizeof(UsbCommand));
}
if(param & ISO14A_SET_TIMEOUT) {
if(param & ISO14A_APDU) {
arg0 = iso14_apdu(cmd, len, buf);
cmd_send(CMD_ACK,arg0,0,0,buf,sizeof(buf));
-// UsbSendPacket((void *)ack, sizeof(UsbCommand));
}
if(param & ISO14A_RAW) {
AppendCrc14443a(cmd,len);
len += 2;
}
- ReaderTransmit(cmd,len);
+ ReaderTransmit(cmd,len, NULL);
arg0 = ReaderReceive(buf);
-// UsbSendPacket((void *)ack, sizeof(UsbCommand));
- cmd_send(CMD_ACK,arg0,0,0,buf,sizeof(buf));
+ cmd_send(CMD_ACK,arg0,0,0,buf,sizeof(buf));
}
if(param & ISO14A_REQUEST_TRIGGER) {
- iso14a_set_trigger(0);
- }
+ iso14a_set_trigger(0);
+ }
if(param & ISO14A_NO_DISCONNECT) {
return;
- }
+ }
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
}
-// prepare the Mifare AUTH transfer with an added necessary delay.
-void PrepareDelayedAuthTransfer(uint8_t* frame, int len, uint16_t delay)
-{
- CodeIso14443aBitsAsReaderPar(frame, len*8, GetParity(frame,len));
-
- uint8_t bitmask = 0;
- uint8_t bits_to_shift = 0;
- uint8_t bits_shifted = 0;
-
- if (delay) {
- for (uint16_t i = 0; i < delay; i++) {
- bitmask |= (0x01 << i);
- }
- ToSend[++ToSendMax] = 0x00;
- for (uint16_t i = 0; i < ToSendMax; i++) {
- bits_to_shift = ToSend[i] & bitmask;
- ToSend[i] = ToSend[i] >> delay;
- ToSend[i] = ToSend[i] | (bits_shifted << (8 - delay));
- bits_shifted = bits_to_shift;
- }
- }
-}
-
-
-
// Determine the distance between two nonces.
// Assume that the difference is small, but we don't know which is first.
// Therefore try in alternating directions.
StartCountMifare();
mf_nr_ar3 = 0;
iso14443a_setup();
- FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN); // resets some FPGA internal registers
while((GetCountMifare() & 0xffff0000) != 0x10000); // wait for counter to reset and "warm up"
- while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME); // wait for ssp_frame to be low
- while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME)); // sync on rising edge of ssp_frame
- sync_time = GetCountMifare();
+ sync_time = GetCountMifare() & 0xfffffff8;
sync_cycles = 65536; // theory: Mifare Classic's random generator repeats every 2^16 cycles (and so do the nonces).
nt_attacked = 0;
nt = 0;
LED_C_ON();
if(!iso14443a_select_card(uid, NULL, &cuid)) {
+ if (MF_DBGLEVEL >= 1) Dbprintf("Mifare: Can't select card");
continue;
}
//keep the card active
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);
- PrepareDelayedAuthTransfer(mf_auth, sizeof(mf_auth), (sync_cycles + catch_up_cycles) & 0x00000007);
+ // CodeIso14443aBitsAsReaderPar(mf_auth, sizeof(mf_auth)*8, GetParity(mf_auth, sizeof(mf_auth)*8));
- sync_time = sync_time + ((sync_cycles + catch_up_cycles) & 0xfffffff8);
+ 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
while(GetCountMifare() > sync_time) {
- sync_time = sync_time + (sync_cycles & 0xfffffff8);
+ sync_time = (sync_time & 0xfffffff8) + sync_cycles;
}
- // now sync. After syncing, the following Classic Auth will return the same tag nonce (mostly)
- while(GetCountMifare() < sync_time);
-
- // Transmit MIFARE_CLASSIC_AUTH
- int samples = 0;
- int wait = 0;
- TransmitFor14443a(ToSend, ToSendMax, &samples, &wait);
+ // 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
if (!ReaderReceive(receivedAnswer)) {
+ if (MF_DBGLEVEL >= 1) Dbprintf("Mifare: Couldn't receive tag nonce");
continue;
}
-
previous_nt = nt;
nt = bytes_to_num(receivedAnswer, 4);
// Transmit reader nonce with fake par
- ReaderTransmitPar(mf_nr_ar, sizeof(mf_nr_ar), par);
+ ReaderTransmitPar(mf_nr_ar, sizeof(mf_nr_ar), par, NULL);
if (first_try && previous_nt && !nt_attacked) { // we didn't calibrate our clock yet
int nt_distance = dist_nt(previous_nt, nt);
continue;
}
sync_cycles = (sync_cycles - nt_distance);
-// Dbprintf("calibrating in cycle %d. nt_distance=%d, Sync_cycles: %d\n", i, nt_distance, sync_cycles);
+ if (MF_DBGLEVEL >= 3) Dbprintf("calibrating in cycle %d. nt_distance=%d, Sync_cycles: %d\n", i, nt_distance, sync_cycles);
continue;
}
}
consecutive_resyncs = 0;
}
if (consecutive_resyncs < 3) {
- Dbprintf("Lost sync in cycle %d. nt_distance=%d. Consecutive Resyncs = %d. Trying one time catch up...\n", i, -catch_up_cycles, consecutive_resyncs);
+ if (MF_DBGLEVEL >= 3) 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 = sync_cycles + catch_up_cycles;
- 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);
+ if (MF_DBGLEVEL >= 3) 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);
}
continue;
}
// Receive answer. This will be a 4 Bit NACK when the 8 parity bits are OK after decoding
if (ReaderReceive(receivedAnswer))
{
- catch_up_cycles = 8; // the PRNG doesn't run during data transfers. 4 Bit = 8 cycles
+ catch_up_cycles = 8; // the PRNG is delayed by 8 cycles due to the NAC (4Bits = 0x05 encrypted) transfer
if (nt_diff == 0)
{
extern uint32_t GetParity(const uint8_t * pbtCmd, int iLen);
extern void AppendCrc14443a(uint8_t* data, int len);
-extern void ReaderTransmit(uint8_t* frame, int len);
-extern void ReaderTransmitBitsPar(uint8_t* frame, int bits, uint32_t par);
-extern void ReaderTransmitPar(uint8_t* frame, int len, uint32_t par);
+extern void ReaderTransmit(uint8_t* frame, int len, uint32_t *timing);
+extern void ReaderTransmitBitsPar(uint8_t* frame, int bits, uint32_t par, uint32_t *timing);
+extern void ReaderTransmitPar(uint8_t* frame, int len, uint32_t par, uint32_t *timing);
extern int ReaderReceive(uint8_t* receivedAnswer);
extern int ReaderReceivePar(uint8_t* receivedAnswer, uint32_t * parptr);
// UsbCommand ack = {CMD_ACK, {isOK, 0, 0}};\r
\r
LED_B_ON();\r
- cmd_send(CMD_ACK,isOK,0,0,0,0);\r
+ cmd_send(CMD_ACK,isOK,0,0,0,0);\r
// UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand));\r
LED_B_OFF();\r
\r
(oddparity((Nt >> 8) & 0xFF) == ((parity[2]) ^ oddparity((NtEnc >> 8) & 0xFF) ^ BIT(Ks1,0)))) ? 1 : 0;\r
}\r
\r
+\r
+\r
//-----------------------------------------------------------------------------\r
// MIFARE nested authentication. \r
// \r
//-----------------------------------------------------------------------------\r
-void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain)\r
+void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *datain)\r
{\r
// params\r
- uint8_t blockNo = arg0;\r
- uint8_t keyType = arg1;\r
- uint8_t targetBlockNo = arg2 & 0xff;\r
- uint8_t targetKeyType = (arg2 >> 8) & 0xff;\r
+ uint8_t blockNo = arg0 & 0xff;\r
+ uint8_t keyType = (arg0 >> 8) & 0xff;\r
+ uint8_t targetBlockNo = arg1 & 0xff;\r
+ uint8_t targetKeyType = (arg1 >> 8) & 0xff;\r
uint64_t ui64Key = 0;\r
\r
ui64Key = bytes_to_num(datain, 6);\r
\r
// variables\r
- int rtr, i, j, m, len;\r
- int davg, dmin, dmax;\r
+ uint16_t rtr, i, j, len;\r
+ uint16_t davg;\r
+ static uint16_t dmin, dmax;\r
uint8_t uid[10];\r
uint32_t cuid, nt1, nt2, nttmp, nttest, par, ks1;\r
+ uint32_t target_nt[2], target_ks[2];\r
+ \r
uint8_t par_array[4];\r
- nestedVector nvector[NES_MAX_INFO + 1][11];\r
- int nvectorcount[NES_MAX_INFO + 1];\r
- int ncount = 0;\r
+ uint16_t ncount = 0;\r
struct Crypto1State mpcs = {0, 0};\r
struct Crypto1State *pcs;\r
pcs = &mpcs;\r
uint8_t* receivedAnswer = mifare_get_bigbufptr();\r
\r
- //init\r
- for (i = 0; i < NES_MAX_INFO + 1; i++) nvectorcount[i] = 11; // 11 - empty block;\r
- \r
+ uint32_t auth1_time, auth2_time;\r
+ static uint16_t delta_time;\r
+\r
+ StartCountMifare();\r
+\r
// clear trace\r
iso14a_clear_trace();\r
- iso14a_set_tracing(false);\r
+ iso14a_set_tracing(false);\r
\r
iso14443a_setup();\r
\r
LED_A_ON();\r
- LED_B_ON();\r
LED_C_OFF();\r
\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
- SpinDelay(200);\r
- \r
- davg = dmax = 0;\r
- dmin = 2000;\r
\r
- // test nonce distance\r
- for (rtr = 0; rtr < 10; rtr++) {\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
- SpinDelay(100);\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);\r
+ while((GetCountMifare() & 0xffff0000) != 0x00010000); // wait for counter to reset and "warm up" \r
\r
- // Test if the action was cancelled\r
- if(BUTTON_PRESS()) {\r
- break;\r
- }\r
+ // statistics on nonce distance\r
+ if (calibrate) { // for first call only. Otherwise reuse previous calibration\r
+ LED_B_ON();\r
\r
- if(!iso14443a_select_card(uid, NULL, &cuid)) {\r
- if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");\r
- break;\r
- };\r
+ davg = dmax = 0;\r
+ dmin = 2000;\r
+ delta_time = 0;\r
\r
- if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1)) {\r
- if (MF_DBGLEVEL >= 1) Dbprintf("Auth1 error");\r
- break;\r
- };\r
+ for (rtr = 0; rtr < 17; rtr++) {\r
\r
- if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_NESTED, &nt2)) {\r
- if (MF_DBGLEVEL >= 1) Dbprintf("Auth2 error");\r
- break;\r
- };\r
- \r
- nttmp = prng_successor(nt1, 500);\r
- for (i = 501; i < 2000; i++) {\r
- nttmp = prng_successor(nttmp, 1);\r
- if (nttmp == nt2) break;\r
+ // prepare next select. No need to power down the card.\r
+ if(mifare_classic_halt(pcs, cuid)) {\r
+ if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Halt error");\r
+ rtr--;\r
+ continue;\r
+ }\r
+\r
+ if(!iso14443a_select_card(uid, NULL, &cuid)) {\r
+ if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Can't select card");\r
+ rtr--;\r
+ continue;\r
+ };\r
+\r
+ auth1_time = 0;\r
+ if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, &auth1_time)) {\r
+ if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth1 error");\r
+ rtr--;\r
+ continue;\r
+ };\r
+\r
+ if (delta_time) {\r
+ auth2_time = auth1_time + delta_time;\r
+ } else {\r
+ auth2_time = 0;\r
+ }\r
+ if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_NESTED, &nt2, &auth2_time)) {\r
+ if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth2 error");\r
+ rtr--;\r
+ continue;\r
+ };\r
+\r
+ nttmp = prng_successor(nt1, 500);\r
+ for (i = 501; i < 1200; i++) {\r
+ nttmp = prng_successor(nttmp, 1);\r
+ if (nttmp == nt2) break;\r
+ }\r
+\r
+ if (i != 1200) {\r
+ if (rtr != 0) {\r
+ davg += i;\r
+ dmin = MIN(dmin, i);\r
+ dmax = MAX(dmax, i);\r
+ }\r
+ else {\r
+ delta_time = auth2_time - auth1_time + 32; // allow some slack for proper timing\r
+ }\r
+ if (MF_DBGLEVEL >= 3) Dbprintf("Nested: calibrating... ntdist=%d", i);\r
+ }\r
}\r
\r
- if (i != 2000) {\r
- davg += i;\r
- if (dmin > i) dmin = i;\r
- if (dmax < i) dmax = i;\r
- if (MF_DBGLEVEL >= 4) Dbprintf("r=%d nt1=%08x nt2=%08x distance=%d", rtr, nt1, nt2, i);\r
- }\r
- }\r
- \r
- if (rtr == 0) return;\r
-\r
- davg = davg / rtr;\r
- if (MF_DBGLEVEL >= 3) Dbprintf("distance: min=%d max=%d avg=%d", dmin, dmax, davg);\r
+ if (rtr <= 1) return;\r
\r
- LED_B_OFF();\r
+ davg = (davg + (rtr - 1)/2) / (rtr - 1);\r
+ \r
+ if (MF_DBGLEVEL >= 3) Dbprintf("min=%d max=%d avg=%d, delta_time=%d", dmin, dmax, davg, delta_time);\r
\r
+ dmin = davg - 2;\r
+ dmax = davg + 2;\r
+ \r
+ LED_B_OFF();\r
+ \r
+ }\r
// ------------------------------------------------------------------------------------------------- \r
\r
LED_C_ON();\r
\r
// get crypted nonces for target sector\r
- for (rtr = 0; rtr < NS_RETRIES_GETNONCE; rtr++) {\r
- if (MF_DBGLEVEL >= 4) Dbprintf("------------------------------");\r
+ for(i=0; i < 2; i++) { // look for exactly two different nonces\r
\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
- SpinDelay(100);\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);\r
-\r
- // Test if the action was cancelled\r
- if(BUTTON_PRESS()) {\r
- break;\r
- }\r
-\r
- if(!iso14443a_select_card(uid, NULL, &cuid)) {\r
- if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");\r
- break;\r
- };\r
+ target_nt[i] = 0;\r
+ while(target_nt[i] == 0) { // continue until we have an unambiguous nonce\r
\r
- if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1)) {\r
- if (MF_DBGLEVEL >= 1) Dbprintf("Auth1 error");\r
- break;\r
- };\r
+ // prepare next select. No need to power down the card.\r
+ if(mifare_classic_halt(pcs, cuid)) {\r
+ if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Halt error");\r
+ continue;\r
+ }\r
\r
- // nested authentication\r
- len = mifare_sendcmd_shortex(pcs, AUTH_NESTED, 0x60 + (targetKeyType & 0x01), targetBlockNo, receivedAnswer, &par);\r
- if (len != 4) {\r
- if (MF_DBGLEVEL >= 1) Dbprintf("Auth2 error len=%d", len);\r
- break;\r
- };\r
- \r
- nt2 = bytes_to_num(receivedAnswer, 4); \r
- if (MF_DBGLEVEL >= 4) Dbprintf("r=%d nt1=%08x nt2enc=%08x nt2par=%08x", rtr, nt1, nt2, par);\r
- \r
- // Parity validity check\r
- for (i = 0; i < 4; i++) {\r
- par_array[i] = (oddparity(receivedAnswer[i]) != ((par & 0x08) >> 3));\r
- par = par << 1;\r
- }\r
+ if(!iso14443a_select_card(uid, NULL, &cuid)) {\r
+ if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Can't select card");\r
+ continue;\r
+ };\r
\r
- ncount = 0;\r
- nttest = prng_successor(nt1, dmin - NS_TOLERANCE);\r
- for (m = dmin - NS_TOLERANCE + 1; m < dmax + NS_TOLERANCE; m++) {\r
- nttest = prng_successor(nttest, 1);\r
- ks1 = nt2 ^ nttest;\r
-\r
- if (valid_nonce(nttest, nt2, ks1, par_array) && (ncount < 11)){\r
- \r
- nvector[NES_MAX_INFO][ncount].nt = nttest;\r
- nvector[NES_MAX_INFO][ncount].ks1 = ks1;\r
- ncount++;\r
- nvectorcount[NES_MAX_INFO] = ncount;\r
- if (MF_DBGLEVEL >= 4) Dbprintf("valid m=%d ks1=%08x nttest=%08x", m, ks1, nttest);\r
- }\r
+ auth1_time = 0;\r
+ if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, &auth1_time)) {\r
+ if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth1 error");\r
+ continue;\r
+ };\r
\r
- }\r
+ // nested authentication\r
+ auth2_time = auth1_time + delta_time;\r
+ len = mifare_sendcmd_shortex(pcs, AUTH_NESTED, 0x60 + (targetKeyType & 0x01), targetBlockNo, receivedAnswer, &par, &auth2_time);\r
+ if (len != 4) {\r
+ if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth2 error len=%d", len);\r
+ continue;\r
+ };\r
\r
- // select vector with length less than got\r
- if (nvectorcount[NES_MAX_INFO] != 0) {\r
- m = NES_MAX_INFO;\r
+ nt2 = bytes_to_num(receivedAnswer, 4); \r
+ if (MF_DBGLEVEL >= 3) Dbprintf("Nonce#%d: Testing nt1=%08x nt2enc=%08x nt2par=%02x", i+1, nt1, nt2, par);\r
\r
- for (i = 0; i < NES_MAX_INFO; i++)\r
- if (nvectorcount[i] > 10) {\r
- m = i;\r
- break;\r
- }\r
- \r
- if (m == NES_MAX_INFO)\r
- for (i = 0; i < NES_MAX_INFO; i++)\r
- if (nvectorcount[NES_MAX_INFO] < nvectorcount[i]) {\r
- m = i;\r
+ // Parity validity check\r
+ for (j = 0; j < 4; j++) {\r
+ par_array[j] = (oddparity(receivedAnswer[j]) != ((par & 0x08) >> 3));\r
+ par = par << 1;\r
+ }\r
+ \r
+ ncount = 0;\r
+ nttest = prng_successor(nt1, dmin - 1);\r
+ for (j = dmin; j < dmax + 1; j++) {\r
+ nttest = prng_successor(nttest, 1);\r
+ ks1 = nt2 ^ nttest;\r
+\r
+ if (valid_nonce(nttest, nt2, ks1, par_array)){\r
+ if (ncount > 0) { // we are only interested in disambiguous nonces, try again\r
+ if (MF_DBGLEVEL >= 3) Dbprintf("Nonce#%d: dismissed (ambigous), ntdist=%d", i+1, j);\r
+ target_nt[i] = 0;\r
+ break;\r
+ }\r
+ target_nt[i] = nttest;\r
+ target_ks[i] = ks1;\r
+ ncount++;\r
+ if (i == 1 && target_nt[1] == target_nt[0]) { // we need two different nonces\r
+ target_nt[i] = 0;\r
+ if (MF_DBGLEVEL >= 3) Dbprintf("Nonce#2: dismissed (= nonce#1), ntdist=%d", j);\r
break;\r
}\r
- \r
- if (m != NES_MAX_INFO) {\r
- for (i = 0; i < nvectorcount[m]; i++) {\r
- nvector[m][i] = nvector[NES_MAX_INFO][i];\r
+ if (MF_DBGLEVEL >= 3) Dbprintf("Nonce#%d: valid, ntdist=%d", i+1, j);\r
}\r
- nvectorcount[m] = nvectorcount[NES_MAX_INFO];\r
}\r
+ if (target_nt[i] == 0 && j == dmax+1 && MF_DBGLEVEL >= 3) Dbprintf("Nonce#%d: dismissed (all invalid)", i+1);\r
}\r
}\r
\r
memset(uid, 0x44, 4);\r
LogTrace(uid, 4, 0, 0, TRUE);\r
\r
-// UsbCommand ack = {CMD_ACK, {0, 0, 0}};\r
-\r
- for (i = 0; i < NES_MAX_INFO; i++) {\r
- if (nvectorcount[i] > 10) continue;\r
- \r
- for (j = 0; j < nvectorcount[i]; j += 5) {\r
- ncount = nvectorcount[i] - j;\r
- if (ncount > 5) ncount = 5; \r
-\r
-// ack.arg[0] = 0; // isEOF = 0\r
-// ack.arg[1] = ncount;\r
-// ack.arg[2] = targetBlockNo + (targetKeyType * 0x100);\r
-// memset(ack.d.asBytes, 0x00, sizeof(ack.d.asBytes));\r
- \r
- byte_t buf[48];\r
- memset(buf, 0x00, sizeof(buf));\r
- memcpy(buf, &cuid, 4);\r
- for (m = 0; m < ncount; m++) {\r
- memcpy(buf + 8 + m * 8 + 0, &nvector[i][m + j].nt, 4);\r
- memcpy(buf + 8 + m * 8 + 4, &nvector[i][m + j].ks1, 4);\r
- }\r
- \r
- LED_B_ON();\r
- cmd_send(CMD_ACK,0,ncount,targetBlockNo + (targetKeyType * 0x100),buf,48);\r
-// UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand));\r
- LED_B_OFF();\r
- }\r
- }\r
-\r
- // finalize list\r
-// ack.arg[0] = 1; // isEOF = 1\r
-// ack.arg[1] = 0;\r
-// ack.arg[2] = 0;\r
-// memset(ack.d.asBytes, 0x00, sizeof(ack.d.asBytes));\r
+ byte_t buf[4 + 4 * 4];\r
+ memcpy(buf, &cuid, 4);\r
+ memcpy(buf+4, &target_nt[0], 4);\r
+ memcpy(buf+8, &target_ks[0], 4);\r
+ memcpy(buf+12, &target_nt[1], 4);\r
+ memcpy(buf+16, &target_ks[1], 4);\r
\r
LED_B_ON();\r
-// UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand));\r
- cmd_send(CMD_ACK,1,0,0,0,0);\r
+ cmd_send(CMD_ACK, 0, 2, targetBlockNo + (targetKeyType * 0x100), buf, sizeof(buf));\r
LED_B_OFF();\r
\r
- if (MF_DBGLEVEL >= 4) DbpString("NESTED FINISHED");\r
+ if (MF_DBGLEVEL >= 3) DbpString("NESTED FINISHED");\r
\r
- // Thats it...\r
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
LEDsoff();\r
- \r
- iso14a_set_tracing(TRUE);\r
+ iso14a_set_tracing(TRUE);\r
}\r
\r
//-----------------------------------------------------------------------------\r
-// MIFARE check keys. key count up to 8. \r
+// MIFARE check keys. key count up to 85. \r
// \r
//-----------------------------------------------------------------------------\r
void MifareChkKeys(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)\r
\r
// clear trace\r
iso14a_clear_trace();\r
- iso14a_set_tracing(TRUE);\r
+ iso14a_set_tracing(TRUE);\r
\r
iso14443a_setup();\r
\r
LED_B_OFF();\r
LED_C_OFF();\r
\r
- SpinDelay(300);\r
+// SpinDelay(300);\r
for (i = 0; i < keyCount; i++) {\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
- SpinDelay(100);\r
- FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);\r
+// FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
+// SpinDelay(100);\r
+// FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);\r
+ // prepare next select by sending a HALT. There is no need to power down the card.\r
+ if(mifare_classic_halt(pcs, cuid)) {\r
+ if (MF_DBGLEVEL >= 1) Dbprintf("ChkKeys: Halt error");\r
+ }\r
\r
+ // SpinDelay(50);\r
+ \r
if(!iso14443a_select_card(uid, NULL, &cuid)) {\r
- if (OLD_MF_DBGLEVEL >= 1) Dbprintf("Can't select card");\r
+ if (OLD_MF_DBGLEVEL >= 1) Dbprintf("ChkKeys: Can't select card");\r
break;\r
};\r
\r
memset(uid, 0x44, 4);\r
LogTrace(uid, 4, 0, 0, TRUE);\r
\r
-// UsbCommand ack = {CMD_ACK, {isOK, 0, 0}};\r
-// if (isOK) memcpy(ack.d.asBytes, datain + i * 6, 6);\r
- \r
LED_B_ON();\r
cmd_send(CMD_ACK,isOK,0,0,datain + i * 6,6);\r
-// UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand));\r
LED_B_OFF();\r
\r
// Thats it...\r
\r
// reset chip\r
if (needWipe){\r
- ReaderTransmitBitsPar(wupC1,7,0);\r
+ ReaderTransmitBitsPar(wupC1,7,0, NULL);\r
if(!ReaderReceive(receivedAnswer) || (receivedAnswer[0] != 0x0a)) {\r
if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error");\r
break;\r
};\r
\r
- ReaderTransmit(wipeC, sizeof(wipeC));\r
+ ReaderTransmit(wipeC, sizeof(wipeC), NULL);\r
if(!ReaderReceive(receivedAnswer) || (receivedAnswer[0] != 0x0a)) {\r
if (MF_DBGLEVEL >= 1) Dbprintf("wipeC error");\r
break;\r
\r
// write block\r
if (workFlags & 0x02) {\r
- ReaderTransmitBitsPar(wupC1,7,0);\r
+ ReaderTransmitBitsPar(wupC1,7,0, NULL);\r
if(!ReaderReceive(receivedAnswer) || (receivedAnswer[0] != 0x0a)) {\r
if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error");\r
break;\r
};\r
\r
- ReaderTransmit(wupC2, sizeof(wupC2));\r
+ ReaderTransmit(wupC2, sizeof(wupC2), NULL);\r
if(!ReaderReceive(receivedAnswer) || (receivedAnswer[0] != 0x0a)) {\r
if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error");\r
break;\r
};\r
}\r
\r
- if ((mifare_sendcmd_short(NULL, 0, 0xA0, blockNo, receivedAnswer) != 1) || (receivedAnswer[0] != 0x0a)) {\r
+ if ((mifare_sendcmd_short(NULL, 0, 0xA0, blockNo, receivedAnswer, NULL) != 1) || (receivedAnswer[0] != 0x0a)) {\r
if (MF_DBGLEVEL >= 1) Dbprintf("write block send command error");\r
break;\r
};\r
memcpy(d_block, datain, 16);\r
AppendCrc14443a(d_block, 16);\r
\r
- ReaderTransmit(d_block, sizeof(d_block));\r
+ ReaderTransmit(d_block, sizeof(d_block), NULL);\r
if ((ReaderReceive(receivedAnswer) != 1) || (receivedAnswer[0] != 0x0a)) {\r
if (MF_DBGLEVEL >= 1) Dbprintf("write block send data error");\r
break;\r
\r
while (true) {\r
if (workFlags & 0x02) {\r
- ReaderTransmitBitsPar(wupC1,7,0);\r
+ ReaderTransmitBitsPar(wupC1,7,0, NULL);\r
if(!ReaderReceive(receivedAnswer) || (receivedAnswer[0] != 0x0a)) {\r
if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error");\r
break;\r
};\r
\r
- ReaderTransmit(wupC2, sizeof(wupC2));\r
+ ReaderTransmit(wupC2, sizeof(wupC2), NULL);\r
if(!ReaderReceive(receivedAnswer) || (receivedAnswer[0] != 0x0a)) {\r
if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error");\r
break;\r
}\r
\r
// read block\r
- if ((mifare_sendcmd_short(NULL, 0, 0x30, blockNo, receivedAnswer) != 18)) {\r
+ if ((mifare_sendcmd_short(NULL, 0, 0x30, blockNo, receivedAnswer, NULL) != 18)) {\r
if (MF_DBGLEVEL >= 1) Dbprintf("read block send command error");\r
break;\r
};\r
}\r
\r
// send commands\r
-int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t* answer)\r
+int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t* answer, uint32_t *timing)\r
{\r
- return mifare_sendcmd_shortex(pcs, crypted, cmd, data, answer, NULL);\r
+ return mifare_sendcmd_shortex(pcs, crypted, cmd, data, answer, NULL, timing);\r
}\r
\r
-int mifare_sendcmd_shortex(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t* answer, uint32_t * parptr)\r
+int mifare_sendcmd_shortex(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t* answer, uint32_t * parptr, uint32_t *timing)\r
{\r
uint8_t dcmd[4], ecmd[4];\r
uint32_t pos, par, res;\r
par = (par >> 1) | ( ((filter(pcs->odd) ^ oddparity(dcmd[pos])) & 0x01) * 0x08 );\r
} \r
\r
- ReaderTransmitPar(ecmd, sizeof(ecmd), par);\r
+ ReaderTransmitPar(ecmd, sizeof(ecmd), par, timing);\r
\r
} else {\r
- ReaderTransmit(dcmd, sizeof(dcmd));\r
+ ReaderTransmit(dcmd, sizeof(dcmd), timing);\r
}\r
\r
int len = ReaderReceivePar(answer, &par);\r
// mifare commands\r
int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint64_t isNested) \r
{\r
- return mifare_classic_authex(pcs, uid, blockNo, keyType, ui64Key, isNested, NULL);\r
+ return mifare_classic_authex(pcs, uid, blockNo, keyType, ui64Key, isNested, NULL, NULL);\r
}\r
\r
-int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint64_t isNested, uint32_t * ntptr) \r
+int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint64_t isNested, uint32_t * ntptr, uint32_t *timing) \r
{\r
// variables\r
int len; \r
uint8_t* receivedAnswer = mifare_get_bigbufptr();\r
\r
// Transmit MIFARE_CLASSIC_AUTH\r
- len = mifare_sendcmd_short(pcs, isNested, 0x60 + (keyType & 0x01), blockNo, receivedAnswer);\r
- if (MF_DBGLEVEL >= 4) Dbprintf("rand nonce len: %x", len); \r
+ len = mifare_sendcmd_short(pcs, isNested, 0x60 + (keyType & 0x01), blockNo, receivedAnswer, timing);\r
+ if (MF_DBGLEVEL >= 4) Dbprintf("rand nonce len: %x", len); \r
if (len != 4) return 1;\r
\r
ar[0] = 0x55;\r
} \r
\r
// Transmit reader nonce and reader answer\r
- ReaderTransmitPar(mf_nr_ar, sizeof(mf_nr_ar), par);\r
+ ReaderTransmitPar(mf_nr_ar, sizeof(mf_nr_ar), par, NULL);\r
\r
// Receive 4 bit answer\r
len = ReaderReceive(receivedAnswer);\r
uint8_t* receivedAnswer = mifare_get_bigbufptr();\r
\r
// command MIFARE_CLASSIC_READBLOCK\r
- len = mifare_sendcmd_short(pcs, 1, 0x30, blockNo, receivedAnswer);\r
+ len = mifare_sendcmd_short(pcs, 1, 0x30, blockNo, receivedAnswer, NULL);\r
if (len == 1) {\r
if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); \r
return 1;\r
uint8_t* receivedAnswer = mifare_get_bigbufptr();\r
\r
// command MIFARE_CLASSIC_WRITEBLOCK\r
- len = mifare_sendcmd_short(pcs, 1, 0xA0, blockNo, receivedAnswer);\r
+ len = mifare_sendcmd_short(pcs, 1, 0xA0, blockNo, receivedAnswer, NULL);\r
\r
if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK\r
if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); \r
par = (par >> 1) | ( ((filter(pcs->odd) ^ oddparity(d_block[pos])) & 0x01) * 0x20000 );\r
} \r
\r
- ReaderTransmitPar(d_block_enc, sizeof(d_block_enc), par);\r
+ ReaderTransmitPar(d_block_enc, sizeof(d_block_enc), par, NULL);\r
\r
// Receive the response\r
len = ReaderReceive(receivedAnswer); \r
// Mifare HALT\r
uint8_t* receivedAnswer = mifare_get_bigbufptr();\r
\r
- len = mifare_sendcmd_short(pcs, pcs == NULL ? 0:1, 0x50, 0x00, receivedAnswer);\r
+ len = mifare_sendcmd_short(pcs, pcs == NULL ? 0:1, 0x50, 0x00, receivedAnswer, NULL);\r
if (len != 0) {\r
if (MF_DBGLEVEL >= 1) Dbprintf("halt error. response len: %x", len); \r
return 1;\r
\r
extern int MF_DBGLEVEL;\r
\r
-//mifare nested\r
-#define MEM_CHUNK 10000\r
-#define TRY_KEYS 50\r
-#define NS_TOLERANCE 10 // [distance avg-value, distance avg+value]\r
-#define NS_RETRIES_GETNONCE 15\r
-#define NES_MAX_INFO 5\r
-\r
//mifare emulator states\r
#define MFEMUL_NOFIELD 0\r
#define MFEMUL_IDLE 1\r
\r
//functions\r
uint8_t* mifare_get_bigbufptr(void);\r
-int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t* answer);\r
-int mifare_sendcmd_shortex(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t* answer, uint32_t * parptr);\r
+int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t* answer, uint32_t *timing);\r
+int mifare_sendcmd_shortex(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t* answer, uint32_t * parptr, uint32_t *timing);\r
\r
int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, \\r
uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint64_t isNested);\r
int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, \\r
- uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint64_t isNested, uint32_t * ntptr);\r
+ uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint64_t isNested, uint32_t * ntptr, uint32_t *timing);\r
int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData); \r
int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData);\r
int mifare_classic_halt(struct Crypto1State *pcs, uint32_t uid); \r
#include "proxmark3.h"
#include "util.h"
#include "string.h"
+#include "apps.h"
size_t nbytes(size_t nbits) {
return (nbits/8)+((nbits%8)>0);
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN; // enable TC0
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN; // enable TC1
AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKEN; // enable TC2
+
+ // activate the ISO14443 part of the FPGA. We need the clock and frame signals.
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN);
+
+ // synchronize the counter with the ssp_frame signal.
+ while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME); // wait for ssp_frame to be low
+ while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME)); // sync on rising edge of ssp_frame (= start of transfer)
+
AT91C_BASE_TCB->TCB_BCR = 1; // assert Sync (set all timers to 0 on next active clock edge)
}
uint8_t blDiff = 0;\r
int SectorsCnt = 0;\r
uint8_t key[6] = {0, 0, 0, 0, 0, 0};\r
- uint8_t keyBlock[16 * 6];\r
+ uint8_t keyBlock[6*6];\r
uint64_t key64 = 0;\r
int transferToEml = 0;\r
\r
PrintAndLog("--target block no:%02x target key type:%02x ", trgBlockNo, trgKeyType);\r
\r
if (cmdp == 'o') {\r
- if (mfnested(blockNo, keyType, key, trgBlockNo, trgKeyType, keyBlock)) {\r
+ if (mfnested(blockNo, keyType, key, trgBlockNo, trgKeyType, keyBlock, true)) {\r
PrintAndLog("Nested error.");\r
return 2;\r
}\r
-\r
- for (i = 0; i < 16; i++) {\r
- PrintAndLog("count=%d key= %s", i, sprint_hex(keyBlock + i * 6, 6));\r
- }\r
- \r
- // test keys\r
- res = mfCheckKeys(trgBlockNo, trgKeyType, 8, keyBlock, &key64);\r
- if (res)\r
- res = mfCheckKeys(trgBlockNo, trgKeyType, 8, &keyBlock[6 * 8], &key64);\r
- if (!res) {\r
+ key64 = bytes_to_num(keyBlock, 6);\r
+ if (key64) {\r
PrintAndLog("Found valid key:%012"llx, key64);\r
\r
// transfer key to the emulator\r
}\r
}\r
else { // ------------------------------------ multiple sectors working\r
+ clock_t time1;\r
+ time1 = clock();\r
+\r
blDiff = blockNo % 4;\r
PrintAndLog("Block shift=%d", blDiff);\r
e_sector = calloc(SectorsCnt, sizeof(sector));\r
\r
//test current key 4 sectors\r
memcpy(keyBlock, key, 6);\r
- num_to_bytes(0xa0a1a2a3a4a5, 6, (uint8_t*)(keyBlock + 1 * 6));\r
- num_to_bytes(0xb0b1b2b3b4b5, 6, (uint8_t*)(keyBlock + 2 * 6));\r
- num_to_bytes(0xffffffffffff, 6, (uint8_t*)(keyBlock + 3 * 6));\r
- num_to_bytes(0x000000000000, 6, (uint8_t*)(keyBlock + 4 * 6));\r
+ num_to_bytes(0xffffffffffff, 6, (uint8_t*)(keyBlock + 1 * 6));\r
+ num_to_bytes(0x000000000000, 6, (uint8_t*)(keyBlock + 2 * 6));\r
+ num_to_bytes(0xa0a1a2a3a4a5, 6, (uint8_t*)(keyBlock + 3 * 6));\r
+ num_to_bytes(0xb0b1b2b3b4b5, 6, (uint8_t*)(keyBlock + 4 * 6));\r
num_to_bytes(0xaabbccddeeff, 6, (uint8_t*)(keyBlock + 5 * 6));\r
\r
PrintAndLog("Testing known keys. Sector count=%d", SectorsCnt);\r
e_sector[i].foundKey[j] = 1;\r
}\r
}\r
- } \r
+ }\r
+ \r
\r
// nested sectors\r
iterations = 0;\r
PrintAndLog("nested...");\r
+ bool calibrate = true;\r
for (i = 0; i < NESTED_SECTOR_RETRY; i++) {\r
- for (trgBlockNo = blDiff; trgBlockNo < SectorsCnt * 4; trgBlockNo = trgBlockNo + 4) \r
+ for (trgBlockNo = blDiff; trgBlockNo < SectorsCnt * 4; trgBlockNo = trgBlockNo + 4) {\r
for (trgKeyType = 0; trgKeyType < 2; trgKeyType++) { \r
if (e_sector[trgBlockNo / 4].foundKey[trgKeyType]) continue;\r
- if (mfnested(blockNo, keyType, key, trgBlockNo, trgKeyType, keyBlock)) continue;\r
+ PrintAndLog("-----------------------------------------------");\r
+ if(mfnested(blockNo, keyType, key, trgBlockNo, trgKeyType, keyBlock, calibrate)) {\r
+ PrintAndLog("Nested error.\n");\r
+ return 2;\r
+ }\r
+ else {\r
+ calibrate = false;\r
+ }\r
\r
iterations++;\r
- \r
- //try keys from nested\r
- res = mfCheckKeys(trgBlockNo, trgKeyType, 8, keyBlock, &key64);\r
- if (res)\r
- res = mfCheckKeys(trgBlockNo, trgKeyType, 8, &keyBlock[6 * 8], &key64);\r
- if (!res) {\r
+\r
+ key64 = bytes_to_num(keyBlock, 6);\r
+ if (key64) {\r
PrintAndLog("Found valid key:%012"llx, key64);\r
e_sector[trgBlockNo / 4].foundKey[trgKeyType] = 1;\r
e_sector[trgBlockNo / 4].Key[trgKeyType] = key64;\r
}\r
}\r
+ }\r
}\r
\r
- PrintAndLog("Iterations count: %d", iterations);\r
+ printf("Time in nested: %1.3f (%1.3f sec per key)\n\n", ((float)clock() - time1)/1000.0, ((float)clock() - time1)/iterations/1000.0);\r
+ \r
+ PrintAndLog("-----------------------------------------------\nIterations count: %d\n\n", iterations);\r
//print them\r
PrintAndLog("|---|----------------|---|----------------|---|");\r
PrintAndLog("|sec|key A |res|key B |res|");\r
while( !feof(f) ){\r
memset(buf, 0, sizeof(buf));\r
if (fgets(buf, sizeof(buf), f) == NULL) {\r
- PrintAndLog("File reading error.");\r
- return 2;\r
- }\r
+ PrintAndLog("File reading error.");\r
+ return 2;\r
+ }\r
\r
if (strlen(buf) < 12 || buf[11] == '\n')\r
continue;\r
\r
while (fgetc(f) != '\n' && !feof(f)) ; //goto next line\r
\r
- if( buf[0]=='#' ) continue; //The line start with # is remcommnet,skip\r
+ if( buf[0]=='#' ) continue; //The line start with # is comment, skip\r
\r
if (!isxdigit(buf[0])){\r
PrintAndLog("File content error. '%s' must include 12 HEX symbols",buf);\r
int b=blockNo;\r
for (int i=0; i<SectorsCnt; ++i) {\r
PrintAndLog("--SectorsCnt:%d block no:0x%02x key type:%C key count:%d ", i, b, t?'B':'A', keycnt);\r
- int size = keycnt>8?8:keycnt;\r
- for (int c = 0; c < keycnt; c+=size) {\r
- size=keycnt-c>8?8:keycnt-c; \r
- res = mfCheckKeys(b, t, size, keyBlock +6*c, &key64);\r
+ uint32_t max_keys = keycnt>USB_CMD_DATA_SIZE/6?USB_CMD_DATA_SIZE/6:keycnt;\r
+ for (uint32_t c = 0; c < keycnt; c+=max_keys) {\r
+ uint32_t size = keycnt-c>max_keys?max_keys:keycnt-c;\r
+ res = mfCheckKeys(b, t, size, &keyBlock[6*c], &key64);\r
if (res !=1) {\r
if (!res) {\r
PrintAndLog("Found valid key:[%012"llx"]",key64);\r
num_to_bytes(key64, 6, block + t*10);\r
mfEmlSetMem(block, get_trailer_block(b), 1);\r
}\r
- break;\r
- }\r
- else {\r
- printf("Not found yet, keycnt:%d\r", c+size);\r
- fflush(stdout);\r
}\r
} else {\r
PrintAndLog("Command execute timeout");\r
#include <stdio.h>\r
#include <stdlib.h> \r
#include <string.h>\r
+#include <pthread.h>\r
#include "mifarehost.h"\r
#include "proxmark3.h"\r
\r
// MIFARE\r
int compar_int(const void * a, const void * b) {\r
- return (*(uint64_t*)b - *(uint64_t*)a);\r
+ // didn't work: (the result is truncated to 32 bits)\r
+ //return (*(uint64_t*)b - *(uint64_t*)a);\r
+\r
+ // better:\r
+ if (*(uint64_t*)b == *(uint64_t*)a) return 0;\r
+ else if (*(uint64_t*)b > *(uint64_t*)a) return 1;\r
+ else return -1;\r
}\r
\r
-// Compare countKeys structure\r
-int compar_special_int(const void * a, const void * b) {\r
- return (((countKeys *)b)->count - ((countKeys *)a)->count);\r
+\r
+\r
+// Compare 16 Bits out of cryptostate\r
+int Compare16Bits(const void * a, const void * b) {\r
+ if ((*(uint64_t*)b & 0x00ff000000ff0000) == (*(uint64_t*)a & 0x00ff000000ff0000)) return 0;\r
+ else if ((*(uint64_t*)b & 0x00ff000000ff0000) > (*(uint64_t*)a & 0x00ff000000ff0000)) return 1;\r
+ else return -1;\r
}\r
\r
-countKeys * uniqsort(uint64_t * possibleKeys, uint32_t size) {\r
- int i, j = 0;\r
- int count = 0;\r
- countKeys *our_counts;\r
- \r
- qsort(possibleKeys, size, sizeof (uint64_t), compar_int);\r
- \r
- our_counts = calloc(size, sizeof(countKeys));\r
- if (our_counts == NULL) {\r
- PrintAndLog("Memory allocation error for our_counts");\r
- return NULL;\r
- }\r
+\r
+typedef \r
+ struct {\r
+ union {\r
+ struct Crypto1State *slhead;\r
+ uint64_t *keyhead;\r
+ };\r
+ union {\r
+ struct Crypto1State *sltail;\r
+ uint64_t *keytail;\r
+ };\r
+ uint32_t len;\r
+ uint32_t uid;\r
+ uint32_t blockNo;\r
+ uint32_t keyType;\r
+ uint32_t nt;\r
+ uint32_t ks1;\r
+ } StateList_t;\r
+\r
+\r
+// wrapper function for multi-threaded lfsr_recovery32\r
+void* nested_worker_thread(void *arg)\r
+{\r
+ struct Crypto1State *p1;\r
+ StateList_t *statelist = arg;\r
+\r
+ statelist->slhead = lfsr_recovery32(statelist->ks1, statelist->nt ^ statelist->uid);\r
+ for (p1 = statelist->slhead; *(uint64_t *)p1 != 0; p1++);\r
+ statelist->len = p1 - statelist->slhead;\r
+ statelist->sltail = --p1;\r
+ qsort(statelist->slhead, statelist->len, sizeof(uint64_t), Compare16Bits);\r
\r
- for (i = 0; i < size; i++) {\r
- if (possibleKeys[i+1] == possibleKeys[i]) { \r
- count++;\r
- } else {\r
- our_counts[j].key = possibleKeys[i];\r
- our_counts[j].count = count;\r
- j++;\r
- count=0;\r
- }\r
- }\r
- qsort(our_counts, j, sizeof(countKeys), compar_special_int);\r
- return (our_counts);\r
+ return statelist->slhead;\r
}\r
\r
-int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t * key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t * resultKeys) \r
+\r
+\r
+\r
+int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t * key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t * resultKey, bool calibrate) \r
{\r
- int i, m, len;\r
- uint8_t isEOF;\r
+ uint16_t i, len;\r
uint32_t uid;\r
- fnVector * vector = NULL;\r
- countKeys *ck;\r
- int lenVector = 0;\r
UsbCommand resp;\r
- \r
- memset(resultKeys, 0x00, 16 * 6);\r
\r
+ \r
+ StateList_t statelists[2];\r
+ struct Crypto1State *p1, *p2, *p3, *p4;\r
+ \r
// flush queue\r
WaitForResponseTimeout(CMD_ACK,NULL,100);\r
\r
- UsbCommand c = {CMD_MIFARE_NESTED, {blockNo, keyType, trgBlockNo + trgKeyType * 0x100}};\r
+ UsbCommand c = {CMD_MIFARE_NESTED, {blockNo + keyType * 0x100, trgBlockNo + trgKeyType * 0x100, calibrate}};\r
memcpy(c.d.asBytes, key, 6);\r
- SendCommand(&c);\r
-\r
- PrintAndLog("\n");\r
-\r
- // wait cycle\r
- while (true) {\r
- printf(".");\r
- if (ukbhit()) {\r
- getchar();\r
- printf("\naborted via keyboard!\n");\r
- break;\r
- }\r
-\r
- if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {\r
- isEOF = resp.arg[0] & 0xff;\r
+ SendCommand(&c);\r
\r
- if (isEOF) break;\r
- \r
- len = resp.arg[1] & 0xff;\r
- if (len == 0) continue;\r
- \r
+ if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {\r
+ len = resp.arg[1];\r
+ if (len == 2) { \r
memcpy(&uid, resp.d.asBytes, 4);\r
- PrintAndLog("uid:%08x len=%d trgbl=%d trgkey=%x", uid, len, resp.arg[2] & 0xff, (resp.arg[2] >> 8) & 0xff);\r
- vector = (fnVector *) realloc((void *)vector, (lenVector + len) * sizeof(fnVector) + 200);\r
- if (vector == NULL) {\r
- PrintAndLog("Memory allocation error for fnVector. len: %d bytes: %d", lenVector + len, (lenVector + len) * sizeof(fnVector)); \r
- break;\r
- }\r
+ PrintAndLog("uid:%08x len=%d trgbl=%d trgkey=%x", uid, len, (uint16_t)resp.arg[2] & 0xff, (uint16_t)resp.arg[2] >> 8);\r
\r
- for (i = 0; i < len; i++) {\r
- vector[lenVector + i].blockNo = resp.arg[2] & 0xff;\r
- vector[lenVector + i].keyType = (resp.arg[2] >> 8) & 0xff;\r
- vector[lenVector + i].uid = uid;\r
+ for (i = 0; i < 2; i++) {\r
+ statelists[i].blockNo = resp.arg[2] & 0xff;\r
+ statelists[i].keyType = (resp.arg[2] >> 8) & 0xff;\r
+ statelists[i].uid = uid;\r
\r
- memcpy(&vector[lenVector + i].nt, (void *)(resp.d.asBytes + 8 + i * 8 + 0), 4);\r
- memcpy(&vector[lenVector + i].ks1, (void *)(resp.d.asBytes + 8 + i * 8 + 4), 4);\r
+ memcpy(&statelists[i].nt, (void *)(resp.d.asBytes + 4 + i * 8 + 0), 4);\r
+ memcpy(&statelists[i].ks1, (void *)(resp.d.asBytes + 4 + i * 8 + 4), 4);\r
}\r
-\r
- lenVector += len;\r
+ }\r
+ else {\r
+ PrintAndLog("Got 0 keys from proxmark."); \r
+ return 1;\r
}\r
}\r
\r
- if (!lenVector) {\r
- PrintAndLog("Got 0 keys from proxmark."); \r
- return 1;\r
- }\r
- printf("------------------------------------------------------------------\n");\r
- \r
// calc keys\r
- struct Crypto1State* revstate = NULL;\r
- struct Crypto1State* revstate_start = NULL;\r
- uint64_t lfsr;\r
- int kcount = 0;\r
- pKeys *pk;\r
- \r
- if ((pk = (void *) malloc(sizeof(pKeys))) == NULL) return 1;\r
- memset(pk, 0x00, sizeof(pKeys));\r
\r
- for (m = 0; m < lenVector; m++) {\r
- // And finally recover the first 32 bits of the key\r
- revstate = lfsr_recovery32(vector[m].ks1, vector[m].nt ^ vector[m].uid);\r
- if (revstate_start == NULL) revstate_start = revstate;\r
+ pthread_t thread_id[2];\r
+ \r
+ // create and run worker threads\r
+ for (i = 0; i < 2; i++) {\r
+ pthread_create(thread_id + i, NULL, nested_worker_thread, &statelists[i]);\r
+ }\r
\r
- while ((revstate->odd != 0x0) || (revstate->even != 0x0)) {\r
- lfsr_rollback_word(revstate, vector[m].nt ^ vector[m].uid, 0);\r
- crypto1_get_lfsr(revstate, &lfsr);\r
+ // wait for threads to terminate:\r
+ for (i = 0; i < 2; i++) {\r
+ pthread_join(thread_id[i], (void*)&statelists[i].slhead);\r
+ }\r
+\r
\r
- // Allocate a new space for keys\r
- if (((kcount % MEM_CHUNK) == 0) || (kcount >= pk->size)) {\r
- pk->size += MEM_CHUNK;\r
-//fprintf(stdout, "New chunk by %d, sizeof %d\n", kcount, pk->size * sizeof(uint64_t));\r
- pk->possibleKeys = (uint64_t *) realloc((void *)pk->possibleKeys, pk->size * sizeof(uint64_t));\r
- if (pk->possibleKeys == NULL) {\r
- PrintAndLog("Memory allocation error for pk->possibleKeys"); \r
- return 1;\r
- }\r
+ // the first 16 Bits of the cryptostate already contain part of our key.\r
+ // Create the intersection of the two lists based on these 16 Bits and\r
+ // roll back the cryptostate\r
+ p1 = p3 = statelists[0].slhead; \r
+ p2 = p4 = statelists[1].slhead;\r
+ while (p1 <= statelists[0].sltail && p2 <= statelists[1].sltail) {\r
+ if (Compare16Bits(p1, p2) == 0) {\r
+ struct Crypto1State savestate, *savep = &savestate;\r
+ savestate = *p1;\r
+ while(Compare16Bits(p1, savep) == 0 && p1 <= statelists[0].sltail) {\r
+ *p3 = *p1;\r
+ lfsr_rollback_word(p3, statelists[0].nt ^ statelists[0].uid, 0);\r
+ p3++;\r
+ p1++;\r
+ }\r
+ savestate = *p2;\r
+ while(Compare16Bits(p2, savep) == 0 && p2 <= statelists[1].sltail) {\r
+ *p4 = *p2;\r
+ lfsr_rollback_word(p4, statelists[1].nt ^ statelists[1].uid, 0);\r
+ p4++;\r
+ p2++;\r
}\r
- pk->possibleKeys[kcount] = lfsr;\r
- kcount++;\r
- revstate++;\r
}\r
- free(revstate_start);\r
- revstate_start = NULL;\r
-\r
+ else {\r
+ while (Compare16Bits(p1, p2) == -1) p1++;\r
+ while (Compare16Bits(p1, p2) == 1) p2++;\r
+ }\r
}\r
- \r
- // Truncate\r
- if (kcount != 0) {\r
- pk->size = --kcount;\r
- if ((pk->possibleKeys = (uint64_t *) realloc((void *)pk->possibleKeys, pk->size * sizeof(uint64_t))) == NULL) {\r
- PrintAndLog("Memory allocation error for pk->possibleKeys"); \r
- return 1;\r
- } \r
+ p3->even = 0; p3->odd = 0;\r
+ p4->even = 0; p4->odd = 0;\r
+ statelists[0].len = p3 - statelists[0].slhead;\r
+ statelists[1].len = p4 - statelists[1].slhead;\r
+ statelists[0].sltail=--p3;\r
+ statelists[1].sltail=--p4;\r
+\r
+ // the statelists now contain possible keys. The key we are searching for must be in the\r
+ // intersection of both lists. Create the intersection:\r
+ qsort(statelists[0].keyhead, statelists[0].len, sizeof(uint64_t), compar_int);\r
+ qsort(statelists[1].keyhead, statelists[1].len, sizeof(uint64_t), compar_int);\r
+\r
+ uint64_t *p5, *p6, *p7;\r
+ p5 = p7 = statelists[0].keyhead; \r
+ p6 = statelists[1].keyhead;\r
+ while (p5 <= statelists[0].keytail && p6 <= statelists[1].keytail) {\r
+ if (compar_int(p5, p6) == 0) {\r
+ *p7++ = *p5++;\r
+ p6++;\r
+ }\r
+ else {\r
+ while (compar_int(p5, p6) == -1) p5++;\r
+ while (compar_int(p5, p6) == 1) p6++;\r
+ }\r
}\r
-\r
- PrintAndLog("Total keys count:%d", kcount);\r
- ck = uniqsort(pk->possibleKeys, pk->size);\r
-\r
- // fill key array\r
- for (i = 0; i < 16 ; i++) {\r
- num_to_bytes(ck[i].key, 6, (uint8_t*)(resultKeys + i * 6));\r
+ statelists[0].len = p7 - statelists[0].keyhead;\r
+ statelists[0].keytail=--p7;\r
+\r
+ memset(resultKey, 0, 6);\r
+ // The list may still contain several key candidates. Test each of them with mfCheckKeys\r
+ for (i = 0; i < statelists[0].len; i++) {\r
+ uint8_t keyBlock[6];\r
+ uint64_t key64;\r
+ crypto1_get_lfsr(statelists[0].slhead + i, &key64);\r
+ num_to_bytes(key64, 6, keyBlock);\r
+ key64 = 0;\r
+ if (!mfCheckKeys(statelists[0].blockNo, statelists[0].keyType, 1, keyBlock, &key64)) {\r
+ num_to_bytes(key64, 6, resultKey);\r
+ break;\r
+ }\r
}\r
-\r
- // finalize\r
- free(pk->possibleKeys);\r
- free(pk);\r
- free(ck);\r
- free(vector);\r
-\r
+ \r
+ free(statelists[0].slhead);\r
+ free(statelists[1].slhead);\r
+ \r
return 0;\r
}\r
\r
int mfCheckKeys (uint8_t blockNo, uint8_t keyType, uint8_t keycnt, uint8_t * keyBlock, uint64_t * key){\r
+\r
*key = 0;\r
\r
- UsbCommand c = {CMD_MIFARE_CHKKEYS, {blockNo, keyType, keycnt}};\r
+ UsbCommand c = {CMD_MIFARE_CHKKEYS, {blockNo, keyType, keycnt}};\r
memcpy(c.d.asBytes, keyBlock, 6 * keycnt);\r
- SendCommand(&c);\r
+ SendCommand(&c);\r
\r
UsbCommand resp;\r
if (!WaitForResponseTimeout(CMD_ACK,&resp,3000)) return 1;\r
\r
#define TRACE_ERROR 0xFF\r
\r
-typedef struct fnVector { uint8_t blockNo, keyType; uint32_t uid, nt, ks1; } fnVector;\r
-\r
typedef struct {\r
uint64_t Key[2];\r
int foundKey[2];\r
} sector;\r
\r
-typedef struct {\r
- uint64_t *possibleKeys;\r
- uint32_t size;\r
-} pKeys;\r
-\r
-typedef struct {\r
- uint64_t key;\r
- int count;\r
-} countKeys;\r
-\r
extern char logHexFileName[200];\r
\r
-int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t * key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t * ResultKeys);\r
+int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t * key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t * ResultKeys, bool calibrate);\r
int mfCheckKeys (uint8_t blockNo, uint8_t keyType, uint8_t keycnt, uint8_t * keyBlock, uint64_t * key);\r
\r
int mfEmlGetMem(uint8_t *data, int blockNum, int blocksCount);\r
#define filter(x) (filterlut[(x) & 0xfffff])\r
#endif\r
\r
+\r
+\r
+typedef struct bucket {\r
+ uint32_t *head;\r
+ uint32_t *bp;\r
+} bucket_t;\r
+\r
+typedef bucket_t bucket_array_t[2][0x100];\r
+\r
+typedef struct bucket_info {\r
+ struct {\r
+ uint32_t *head, *tail;\r
+ } bucket_info[2][0x100];\r
+ uint32_t numbuckets;\r
+ } bucket_info_t;\r
+ \r
+\r
+static void bucket_sort_intersect(uint32_t* const estart, uint32_t* const estop,\r
+ uint32_t* const ostart, uint32_t* const ostop,\r
+ bucket_info_t *bucket_info, bucket_array_t bucket)\r
+{\r
+ uint32_t *p1, *p2;\r
+ uint32_t *start[2];\r
+ uint32_t *stop[2];\r
+ \r
+ start[0] = estart;\r
+ stop[0] = estop;\r
+ start[1] = ostart;\r
+ stop[1] = ostop;\r
+ \r
+ // init buckets to be empty\r
+ for (uint32_t i = 0; i < 2; i++) {\r
+ for (uint32_t j = 0x00; j <= 0xff; j++) {\r
+ bucket[i][j].bp = bucket[i][j].head;\r
+ }\r
+ }\r
+ \r
+ // sort the lists into the buckets based on the MSB (contribution bits)\r
+ for (uint32_t i = 0; i < 2; i++) { \r
+ for (p1 = start[i]; p1 <= stop[i]; p1++) {\r
+ uint32_t bucket_index = (*p1 & 0xff000000) >> 24;\r
+ *(bucket[i][bucket_index].bp++) = *p1;\r
+ }\r
+ }\r
+\r
+ \r
+ // write back intersecting buckets as sorted list.\r
+ // fill in bucket_info with head and tail of the bucket contents in the list and number of non-empty buckets.\r
+ uint32_t nonempty_bucket;\r
+ for (uint32_t i = 0; i < 2; i++) {\r
+ p1 = start[i];\r
+ nonempty_bucket = 0;\r
+ for (uint32_t j = 0x00; j <= 0xff; j++) {\r
+ if (bucket[0][j].bp != bucket[0][j].head && bucket[1][j].bp != bucket[1][j].head) { // non-empty intersecting buckets only\r
+ bucket_info->bucket_info[i][nonempty_bucket].head = p1;\r
+ for (p2 = bucket[i][j].head; p2 < bucket[i][j].bp; *p1++ = *p2++);\r
+ bucket_info->bucket_info[i][nonempty_bucket].tail = p1 - 1;\r
+ nonempty_bucket++;\r
+ }\r
+ }\r
+ bucket_info->numbuckets = nonempty_bucket;\r
+ }\r
+}\r
+\r
+\r
static void quicksort(uint32_t* const start, uint32_t* const stop)\r
{\r
uint32_t *it = start + 1, *rit = stop;\r
quicksort(start, rit - 1);\r
quicksort(rit + 1, stop);\r
}\r
+\r
+\r
/** binsearch\r
* Binary search for the first occurence of *stop's MSB in sorted [start,stop]\r
*/\r
extend_table(uint32_t *tbl, uint32_t **end, int bit, int m1, int m2, uint32_t in)\r
{\r
in <<= 24;\r
- for(*tbl <<= 1; tbl <= *end; *++tbl <<= 1)\r
- if(filter(*tbl) ^ filter(*tbl | 1)) {\r
- *tbl |= filter(*tbl) ^ bit;\r
- update_contribution(tbl, m1, m2);\r
- *tbl ^= in;\r
- } else if(filter(*tbl) == bit) {\r
- *++*end = tbl[1];\r
- tbl[1] = tbl[0] | 1;\r
- update_contribution(tbl, m1, m2);\r
- *tbl++ ^= in;\r
- update_contribution(tbl, m1, m2);\r
- *tbl ^= in;\r
- } else\r
- *tbl-- = *(*end)--;\r
+\r
+ for(uint32_t *p = tbl; p <= *end; p++) {\r
+ *p <<= 1;\r
+ if(filter(*p) != filter(*p | 1)) { // replace\r
+ *p |= filter(*p) ^ bit;\r
+ update_contribution(p, m1, m2);\r
+ *p ^= in;\r
+ } else if(filter(*p) == bit) { // insert\r
+ *++*end = p[1];\r
+ p[1] = p[0] | 1;\r
+ update_contribution(p, m1, m2);\r
+ *p++ ^= in;\r
+ update_contribution(p, m1, m2);\r
+ *p ^= in;\r
+ } else { // drop\r
+ *p-- = *(*end)--;\r
+ } \r
+ }\r
+ \r
}\r
+\r
+\r
/** extend_table_simple\r
* using a bit of the keystream extend the table of possible lfsr states\r
*/\r
static inline void\r
extend_table_simple(uint32_t *tbl, uint32_t **end, int bit)\r
{\r
- for(*tbl <<= 1; tbl <= *end; *++tbl <<= 1)\r
- if(filter(*tbl) ^ filter(*tbl | 1)) {\r
+ for(*tbl <<= 1; tbl <= *end; *++tbl <<= 1) \r
+ if(filter(*tbl) ^ filter(*tbl | 1)) { // replace\r
*tbl |= filter(*tbl) ^ bit;\r
- } else if(filter(*tbl) == bit) {\r
+ } else if(filter(*tbl) == bit) { // insert\r
*++*end = *++tbl;\r
*tbl = tbl[-1] | 1;\r
- } else\r
+ } else // drop\r
*tbl-- = *(*end)--;\r
}\r
+\r
+\r
/** recover\r
* recursively narrow down the search space, 4 bits of keystream at a time\r
*/\r
static struct Crypto1State*\r
recover(uint32_t *o_head, uint32_t *o_tail, uint32_t oks,\r
uint32_t *e_head, uint32_t *e_tail, uint32_t eks, int rem,\r
- struct Crypto1State *sl, uint32_t in)\r
+ struct Crypto1State *sl, uint32_t in, bucket_array_t bucket)\r
{\r
- uint32_t *o, *e, i;\r
+ uint32_t *o, *e;\r
+ bucket_info_t bucket_info;\r
\r
if(rem == -1) {\r
for(e = e_head; e <= e_tail; ++e) {\r
for(o = o_head; o <= o_tail; ++o, ++sl) {\r
sl->even = *o;\r
sl->odd = *e ^ parity(*o & LF_POLY_ODD);\r
- sl[1].odd = sl[1].even = 0;\r
}\r
}\r
+ sl->odd = sl->even = 0;\r
return sl;\r
}\r
\r
- for(i = 0; i < 4 && rem--; i++) {\r
+ for(uint32_t i = 0; i < 4 && rem--; i++) {\r
extend_table(o_head, &o_tail, (oks >>= 1) & 1,\r
LF_POLY_EVEN << 1 | 1, LF_POLY_ODD << 1, 0);\r
if(o_head > o_tail)\r
return sl;\r
}\r
\r
- quicksort(o_head, o_tail);\r
- quicksort(e_head, e_tail);\r
-\r
- while(o_tail >= o_head && e_tail >= e_head)\r
- if(((*o_tail ^ *e_tail) >> 24) == 0) {\r
- o_tail = binsearch(o_head, o = o_tail);\r
- e_tail = binsearch(e_head, e = e_tail);\r
- sl = recover(o_tail--, o, oks,\r
- e_tail--, e, eks, rem, sl, in);\r
- }\r
- else if(*o_tail > *e_tail)\r
- o_tail = binsearch(o_head, o_tail) - 1;\r
- else\r
- e_tail = binsearch(e_head, e_tail) - 1;\r
-\r
+ bucket_sort_intersect(e_head, e_tail, o_head, o_tail, &bucket_info, bucket);\r
+ \r
+ for (int i = bucket_info.numbuckets - 1; i >= 0; i--) {\r
+ sl = recover(bucket_info.bucket_info[1][i].head, bucket_info.bucket_info[1][i].tail, oks,\r
+ bucket_info.bucket_info[0][i].head, bucket_info.bucket_info[0][i].tail, eks,\r
+ rem, sl, in, bucket);\r
+ }\r
+ \r
return sl;\r
}\r
/** lfsr_recovery\r
uint32_t *even_head = 0, *even_tail = 0, eks = 0;\r
int i;\r
\r
+ // split the keystream into an odd and even part\r
for(i = 31; i >= 0; i -= 2)\r
oks = oks << 1 | BEBIT(ks2, i);\r
for(i = 30; i >= 0; i -= 2)\r
odd_head = odd_tail = malloc(sizeof(uint32_t) << 21);\r
even_head = even_tail = malloc(sizeof(uint32_t) << 21);\r
statelist = malloc(sizeof(struct Crypto1State) << 18);\r
- if(!odd_tail-- || !even_tail-- || !statelist)\r
+ if(!odd_tail-- || !even_tail-- || !statelist) {\r
goto out;\r
-\r
+ }\r
statelist->odd = statelist->even = 0;\r
\r
+ // allocate memory for out of place bucket_sort\r
+ bucket_array_t bucket;\r
+ for (uint32_t i = 0; i < 2; i++)\r
+ for (uint32_t j = 0; j <= 0xff; j++) {\r
+ bucket[i][j].head = malloc(sizeof(uint32_t)<<14);\r
+ if (!bucket[i][j].head) {\r
+ goto out;\r
+ }\r
+ }\r
+\r
+ \r
+ // initialize statelists: add all possible states which would result into the rightmost 2 bits of the keystream\r
for(i = 1 << 20; i >= 0; --i) {\r
if(filter(i) == (oks & 1))\r
*++odd_tail = i;\r
*++even_tail = i;\r
}\r
\r
+ // extend the statelists. Look at the next 8 Bits of the keystream (4 Bit each odd and even):\r
for(i = 0; i < 4; i++) {\r
extend_table_simple(odd_head, &odd_tail, (oks >>= 1) & 1);\r
extend_table_simple(even_head, &even_tail, (eks >>= 1) & 1);\r
}\r
\r
- in = (in >> 16 & 0xff) | (in << 16) | (in & 0xff00);\r
+ // the statelists now contain all states which could have generated the last 10 Bits of the keystream.\r
+ // 22 bits to go to recover 32 bits in total. From now on, we need to take the "in"\r
+ // parameter into account.\r
+\r
+ in = (in >> 16 & 0xff) | (in << 16) | (in & 0xff00); // Byte swapping\r
+\r
recover(odd_head, odd_tail, oks,\r
- even_head, even_tail, eks, 11, statelist, in << 1);\r
+ even_head, even_tail, eks, 11, statelist, in << 1, bucket);\r
+\r
\r
out:\r
free(odd_head);\r
free(even_head);\r
+ for (uint32_t i = 0; i < 2; i++)\r
+ for (uint32_t j = 0; j <= 0xff; j++)\r
+ free(bucket[i][j].head);\r
+ \r
return statelist;\r
}\r
\r
#include "ui.h"
#include "sleep.h"
+// a global mutex to prevent interlaced printing from different threads
+pthread_mutex_t print_lock;
+
static serial_port sp;
static UsbCommand txcmd;
volatile static bool txcmd_pending = false;
+
void SendCommand(UsbCommand *c) {
#if 0
printf("Sending %d bytes\n", sizeof(UsbCommand));
}
int main(int argc, char* argv[]) {
- srand(time(0));
+ srand(time(0));
- if (argc < 2) {
- printf("syntax: %s <port>\n\n",argv[0]);
- printf("\tLinux example:'%s /dev/ttyACM0'\n\n", argv[0]);
- return 1;
- }
+ if (argc < 2) {
+ printf("syntax: %s <port>\n\n",argv[0]);
+ printf("\tLinux example:'%s /dev/ttyACM0'\n\n", argv[0]);
+ return 1;
+ }
- // Make sure to initialize
- struct main_loop_arg marg = {
- .usb_present = 0,
- .script_cmds_file = NULL
- };
- pthread_t main_loop_t;
+ // Make sure to initialize
+ struct main_loop_arg marg = {
+ .usb_present = 0,
+ .script_cmds_file = NULL
+ };
+ pthread_t main_loop_t;
/*
usb_init();
}
*/
- sp = uart_open(argv[1]);
- if (sp == INVALID_SERIAL_PORT) {
- printf("ERROR: invalid serial port\n");
- marg.usb_present = 0;
- offline = 1;
- } else if (sp == CLAIMED_SERIAL_PORT) {
- printf("ERROR: serial port is claimed by another process\n");
- marg.usb_present = 0;
- offline = 1;
- } else {
- marg.usb_present = 1;
- offline = 0;
- }
+ sp = uart_open(argv[1]);
+ if (sp == INVALID_SERIAL_PORT) {
+ printf("ERROR: invalid serial port\n");
+ marg.usb_present = 0;
+ offline = 1;
+ } else if (sp == CLAIMED_SERIAL_PORT) {
+ printf("ERROR: serial port is claimed by another process\n");
+ marg.usb_present = 0;
+ offline = 1;
+ } else {
+ marg.usb_present = 1;
+ offline = 0;
+ }
- // If the user passed the filename of the 'script' to execute, get it
- if (argc > 2 && argv[2]) {
- marg.script_cmds_file = argv[2];
- }
+ // If the user passed the filename of the 'script' to execute, get it
+ if (argc > 2 && argv[2]) {
+ marg.script_cmds_file = argv[2];
+ }
- pthread_create(&main_loop_t, NULL, &main_loop, &marg);
- InitGraphics(argc, argv);
+ // create a mutex to avoid interlacing print commands from our different threads
+ pthread_mutex_init(&print_lock, NULL);
- MainGraphics();
+ pthread_create(&main_loop_t, NULL, &main_loop, &marg);
+ InitGraphics(argc, argv);
- pthread_join(main_loop_t, NULL);
+ MainGraphics();
+
+ pthread_join(main_loop_t, NULL);
// if (marg.usb_present == 1) {
// CloseProxmark();
// }
- // Clean up the port
- uart_close(sp);
+ // Clean up the port
+ uart_close(sp);
+
+ // clean up mutex
+ pthread_mutex_destroy(&print_lock);
return 0;
}
#include <stdio.h>
#include <time.h>
#include <readline/readline.h>
+#include <pthread.h>
#include "ui.h"
int PlotGridX, PlotGridY, PlotGridXdefault= 64, PlotGridYdefault= 64;
int offline;
+extern pthread_mutex_t print_lock;
+
static char *logfilename = "proxmark3.log";
void PrintAndLog(char *fmt, ...)
{
char *saved_line;
int saved_point;
- va_list argptr, argptr2;
- static FILE *logfile = NULL;
- static int logging=1;
+ va_list argptr, argptr2;
+ static FILE *logfile = NULL;
+ static int logging=1;
- if (logging && !logfile) {
- logfile=fopen(logfilename, "a");
- if (!logfile) {
- fprintf(stderr, "Can't open logfile, logging disabled!\n");
- logging=0;
- }
- }
+ // lock this section to avoid interlacing prints from different threats
+ pthread_mutex_lock(&print_lock);
+
+ if (logging && !logfile) {
+ logfile=fopen(logfilename, "a");
+ if (!logfile) {
+ fprintf(stderr, "Can't open logfile, logging disabled!\n");
+ logging=0;
+ }
+ }
int need_hack = (rl_readline_state & RL_STATE_READCMD) > 0;
rl_redisplay();
}
- va_start(argptr, fmt);
- va_copy(argptr2, argptr);
- vprintf(fmt, argptr);
- printf(" "); // cleaning prompt
- va_end(argptr);
- printf("\n");
+ va_start(argptr, fmt);
+ va_copy(argptr2, argptr);
+ vprintf(fmt, argptr);
+ printf(" "); // cleaning prompt
+ va_end(argptr);
+ printf("\n");
if (need_hack) {
rl_restore_prompt();
free(saved_line);
}
- if (logging && logfile) {
- vfprintf(logfile, fmt, argptr2);
- fprintf(logfile,"\n");
- fflush(logfile);
- }
- va_end(argptr2);
+ if (logging && logfile) {
+ vfprintf(logfile, fmt, argptr2);
+ fprintf(logfile,"\n");
+ fflush(logfile);
+ }
+ va_end(argptr2);
+
+ //release lock
+ pthread_mutex_unlock(&print_lock);
}
+
void SetLogFilename(char *fn)
{
logfilename = fn;