started hf mf hardnested

- acquire encrypted nonces
- save nonces to file
- modified iso14443a_select() to allow select without anticollision
This commit is contained in:
pwpiwi 2015-10-15 21:28:06 +02:00
commit 1da61a02fe
11 changed files with 429 additions and 90 deletions

View file

@ -427,7 +427,7 @@ void StandAloneMode14a()
SpinDelay(300); SpinDelay(300);
} }
} }
if (!iso14443a_select_card(uid, &hi14a_card[selected], &cuid)) if (!iso14443a_select_card(uid, &hi14a_card[selected], &cuid, true, 0))
continue; continue;
else else
{ {
@ -1121,6 +1121,9 @@ void UsbPacketReceived(uint8_t *packet, int len)
case CMD_MIFAREU_WRITEBL: case CMD_MIFAREU_WRITEBL:
MifareUWriteBlock(c->arg[0], c->arg[1], c->d.asBytes); MifareUWriteBlock(c->arg[0], c->arg[1], c->d.asBytes);
break; break;
case CMD_MIFARE_ACQUIRE_ENCRYPTED_NONCES:
MifareAcquireEncryptedNonces(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
break;
case CMD_MIFARE_NESTED: case CMD_MIFARE_NESTED:
MifareNested(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); MifareNested(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
break; break;

View file

@ -128,6 +128,7 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
//void MifareUWriteBlockCompat(uint8_t arg0,uint8_t *datain); //void MifareUWriteBlockCompat(uint8_t arg0,uint8_t *datain);
void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain); void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain);
void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint8_t *datain);
void MifareChkKeys(uint16_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain); void MifareChkKeys(uint16_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain);
void Mifare1ksim(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain); void Mifare1ksim(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain);
void MifareSetDbgLvl(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); void MifareSetDbgLvl(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);

View file

@ -526,7 +526,7 @@ int EPA_Setup()
// power up the field // power up the field
iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD); iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD);
// select the card // select the card
return_code = iso14443a_select_card(uid, &card_select_info, NULL); return_code = iso14443a_select_card(uid, &card_select_info, NULL, true, 0);
if (return_code == 1) { if (return_code == 1) {
// send the PPS request // send the PPS request
ReaderTransmit((uint8_t *)pps, sizeof(pps), NULL); ReaderTransmit((uint8_t *)pps, sizeof(pps), NULL);

View file

@ -1684,10 +1684,12 @@ int ReaderReceive(uint8_t *receivedAnswer, uint8_t *parity)
return Demod.len; return Demod.len;
} }
/* performs iso14443a anticollision procedure // performs iso14443a anticollision (optional) and card select procedure
* fills the uid pointer unless NULL // fills the uid and cuid pointer unless NULL
* fills resp_data unless NULL */ // fills the card info record unless NULL
int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, uint32_t *cuid_ptr) { // if anticollision is false, then the UID must be provided in uid_ptr[]
// and num_cascades must be set (1: 4 Byte UID, 2: 7 Byte UID, 3: 10 Byte UID)
int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades) {
uint8_t wupa[] = { 0x52 }; // 0x26 - REQA 0x52 - WAKE-UP uint8_t wupa[] = { 0x52 }; // 0x26 - REQA 0x52 - WAKE-UP
uint8_t sel_all[] = { 0x93,0x20 }; uint8_t sel_all[] = { 0x93,0x20 };
uint8_t sel_uid[] = { 0x93,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; uint8_t sel_uid[] = { 0x93,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
@ -1702,7 +1704,7 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u
int len; int len;
// Broadcast for a card, WUPA (0x52) will force response from all cards in the field // Broadcast for a card, WUPA (0x52) will force response from all cards in the field
ReaderTransmitBitsPar(wupa,7,0, NULL); ReaderTransmitBitsPar(wupa, 7, NULL, NULL);
// Receive the ATQA // Receive the ATQA
if(!ReaderReceive(resp, resp_par)) return 0; if(!ReaderReceive(resp, resp_par)) return 0;
@ -1713,10 +1715,12 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u
memset(p_hi14a_card->uid,0,10); memset(p_hi14a_card->uid,0,10);
} }
if (anticollision) {
// clear uid // clear uid
if (uid_ptr) { if (uid_ptr) {
memset(uid_ptr,0,10); memset(uid_ptr,0,10);
} }
}
// OK we will select at least at cascade 1, lets see if first byte of UID was 0x88 in // OK we will select at least at cascade 1, lets see if first byte of UID was 0x88 in
// which case we need to make a cascade 2 request and select - this is a long UID // which case we need to make a cascade 2 request and select - this is a long UID
@ -1725,6 +1729,7 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u
// SELECT_* (L1: 0x93, L2: 0x95, L3: 0x97) // SELECT_* (L1: 0x93, L2: 0x95, L3: 0x97)
sel_uid[0] = sel_all[0] = 0x93 + cascade_level * 2; sel_uid[0] = sel_all[0] = 0x93 + cascade_level * 2;
if (anticollision) {
// SELECT_ALL // SELECT_ALL
ReaderTransmit(sel_all, sizeof(sel_all), NULL); ReaderTransmit(sel_all, sizeof(sel_all), NULL);
if (!ReaderReceive(resp, resp_par)) return 0; if (!ReaderReceive(resp, resp_par)) return 0;
@ -1760,6 +1765,14 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u
} else { // no collision, use the response to SELECT_ALL as current uid } else { // no collision, use the response to SELECT_ALL as current uid
memcpy(uid_resp, resp, 4); memcpy(uid_resp, resp, 4);
} }
} else {
if (cascade_level < num_cascades - 1) {
uid_resp[0] = 0x88;
memcpy(uid_resp+1, uid_ptr+cascade_level*3, 3);
} else {
memcpy(uid_resp, uid_ptr+cascade_level*3, 4);
}
}
uid_resp_len = 4; uid_resp_len = 4;
// calculate crypto UID. Always use last 4 Bytes. // calculate crypto UID. Always use last 4 Bytes.
@ -1769,7 +1782,7 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u
// Construct SELECT UID command // Construct SELECT UID command
sel_uid[1] = 0x70; // transmitting a full UID (1 Byte cmd, 1 Byte NVB, 4 Byte UID, 1 Byte BCC, 2 Bytes CRC) sel_uid[1] = 0x70; // transmitting a full UID (1 Byte cmd, 1 Byte NVB, 4 Byte UID, 1 Byte BCC, 2 Bytes CRC)
memcpy(sel_uid+2, uid_resp, 4); // the UID memcpy(sel_uid+2, uid_resp, 4); // the UID received during anticollision, or the provided UID
sel_uid[6] = sel_uid[2] ^ sel_uid[3] ^ sel_uid[4] ^ sel_uid[5]; // calculate and add BCC sel_uid[6] = sel_uid[2] ^ sel_uid[3] ^ sel_uid[4] ^ sel_uid[5]; // calculate and add BCC
AppendCrc14443a(sel_uid, 7); // calculate and add CRC AppendCrc14443a(sel_uid, 7); // calculate and add CRC
ReaderTransmit(sel_uid, sizeof(sel_uid), NULL); ReaderTransmit(sel_uid, sizeof(sel_uid), NULL);
@ -1785,11 +1798,10 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u
uid_resp[0] = uid_resp[1]; uid_resp[0] = uid_resp[1];
uid_resp[1] = uid_resp[2]; uid_resp[1] = uid_resp[2];
uid_resp[2] = uid_resp[3]; uid_resp[2] = uid_resp[3];
uid_resp_len = 3; uid_resp_len = 3;
} }
if(uid_ptr) { if(uid_ptr && anticollision) {
memcpy(uid_ptr + (cascade_level*3), uid_resp, uid_resp_len); memcpy(uid_ptr + (cascade_level*3), uid_resp, uid_resp_len);
} }
@ -1910,7 +1922,7 @@ void ReaderIso14443a(UsbCommand *c)
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
if(!(param & ISO14A_NO_SELECT)) { if(!(param & ISO14A_NO_SELECT)) {
iso14a_card_select_t *card = (iso14a_card_select_t*)buf; iso14a_card_select_t *card = (iso14a_card_select_t*)buf;
arg0 = iso14443a_select_card(NULL,card,NULL); arg0 = iso14443a_select_card(NULL, card, NULL, true, 0);
cmd_send(CMD_ACK,arg0,card->uidlen,0,buf,sizeof(iso14a_card_select_t)); cmd_send(CMD_ACK,arg0,card->uidlen,0,buf,sizeof(iso14a_card_select_t));
} }
} }
@ -2084,7 +2096,7 @@ void ReaderMifare(bool first_try)
SpinDelay(100); SpinDelay(100);
} }
if(!iso14443a_select_card(uid, NULL, &cuid)) { if(!iso14443a_select_card(uid, NULL, &cuid, true, 0)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Mifare: Can't select card"); if (MF_DBGLEVEL >= 1) Dbprintf("Mifare: Can't select card");
continue; continue;
} }

View file

@ -83,7 +83,6 @@ extern int ReaderReceive(uint8_t *receivedAnswer, uint8_t *par);
extern void iso14443a_setup(uint8_t fpga_minor_mode); extern void iso14443a_setup(uint8_t fpga_minor_mode);
extern int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data); extern int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data);
extern int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *resp_data, uint32_t *cuid_ptr); extern int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *resp_data, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades);
extern void iso14a_set_trigger(bool enable); extern void iso14a_set_trigger(bool enable);
#endif /* __ISO14443A_H */ #endif /* __ISO14443A_H */

View file

@ -53,7 +53,7 @@ void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
LED_C_OFF(); LED_C_OFF();
while (true) { while (true) {
if(!iso14443a_select_card(uid, NULL, &cuid)) { if(!iso14443a_select_card(uid, NULL, &cuid, true, 0)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
break; break;
}; };
@ -100,7 +100,7 @@ void MifareUC_Auth(uint8_t arg0, uint8_t *keybytes){
clear_trace(); clear_trace();
if(!iso14443a_select_card(NULL, NULL, NULL)) { if(!iso14443a_select_card(NULL, NULL, NULL, true, 0)) {
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card"); if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card");
OnError(0); OnError(0);
return; return;
@ -135,7 +135,7 @@ void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain)
clear_trace(); clear_trace();
int len = iso14443a_select_card(NULL, NULL, NULL); int len = iso14443a_select_card(NULL, NULL, NULL, true, 0);
if(!len) { if(!len) {
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card (RC:%02X)",len); if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card (RC:%02X)",len);
OnError(1); OnError(1);
@ -211,7 +211,7 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
LED_C_OFF(); LED_C_OFF();
isOK = 1; isOK = 1;
if(!iso14443a_select_card(uid, NULL, &cuid)) { if(!iso14443a_select_card(uid, NULL, &cuid, true, 0)) {
isOK = 0; isOK = 0;
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
} }
@ -275,7 +275,7 @@ void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain)
return; return;
} }
int len = iso14443a_select_card(NULL, NULL, NULL); int len = iso14443a_select_card(NULL, NULL, NULL, true, 0);
if (!len) { if (!len) {
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card (RC:%d)",len); if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card (RC:%d)",len);
OnError(1); OnError(1);
@ -377,7 +377,7 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
LED_C_OFF(); LED_C_OFF();
while (true) { while (true) {
if(!iso14443a_select_card(uid, NULL, &cuid)) { if(!iso14443a_select_card(uid, NULL, &cuid, true, 0)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
break; break;
}; };
@ -431,7 +431,7 @@ void MifareUWriteBlockCompat(uint8_t arg0, uint8_t *datain)
clear_trace(); clear_trace();
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
if(!iso14443a_select_card(uid, NULL, NULL)) { if(!iso14443a_select_card(uid, NULL, NULL, true, 0)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
OnError(0); OnError(0);
return; return;
@ -477,7 +477,7 @@ void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain)
clear_trace(); clear_trace();
if(!iso14443a_select_card(NULL, NULL, NULL)) { if(!iso14443a_select_card(NULL, NULL, NULL, true, 0)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
OnError(0); OnError(0);
return; return;
@ -536,7 +536,7 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain){
clear_trace(); clear_trace();
if(!iso14443a_select_card(NULL, NULL, NULL)) { if(!iso14443a_select_card(NULL, NULL, NULL, true, 0)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
OnError(0); OnError(0);
return; return;
@ -601,6 +601,140 @@ int valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, uint8_t *parity) {
} }
//-----------------------------------------------------------------------------
// acquire encrypted nonces in order to perform the attack described in
// Carlo Meijer, Roel Verdult, "Ciphertext-only Cryptanalysis on Hardened
// Mifare Classic Cards" in Proceedings of the 22nd ACM SIGSAC Conference on
// Computer and Communications Security, 2015
//-----------------------------------------------------------------------------
void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint8_t *datain)
{
uint64_t ui64Key = 0;
uint8_t uid[10];
uint32_t cuid;
uint8_t cascade_levels = 0;
struct Crypto1State mpcs = {0, 0};
struct Crypto1State *pcs;
pcs = &mpcs;
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE];
int16_t isOK = 0;
uint8_t nt_enc1[4];
uint8_t par_enc[1];
uint8_t nt_par_enc = 0;
uint8_t buf[USB_CMD_DATA_SIZE];
uint32_t timeout;
uint8_t blockNo = arg0 & 0xff;
uint8_t keyType = (arg0 >> 8) & 0xff;
uint8_t targetBlockNo = arg1 & 0xff;
uint8_t targetKeyType = (arg1 >> 8) & 0xff;
ui64Key = bytes_to_num(datain, 6);
bool initialize = flags & 0x0001;
bool slow = flags & 0x0002;
#define AUTHENTICATION_TIMEOUT 848 // card times out 1ms after wrong authentication according to NXP documentation
#define PRE_AUTHENTICATION_LEADTIME 400 // some (non standard) cards need a pause after select before they are ready for first authentication
LED_A_ON();
LED_C_OFF();
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
if (initialize) {
clear_trace();
set_tracing(true);
}
LED_C_ON();
uint16_t num_nonces = 0;
bool have_uid = false;
for (uint16_t i = 0; i <= USB_CMD_DATA_SIZE - 4 - 4 - 1; ) {
// Test if the action was cancelled
if(BUTTON_PRESS()) {
isOK = -2;
break;
}
if (!have_uid) { // need a full select cycle to get the uid first
iso14a_card_select_t card_info;
if(!iso14443a_select_card(uid, &card_info, &cuid, true, 0)) {
if (MF_DBGLEVEL >= 1) Dbprintf("AcquireNonces: Can't select card (ALL)");
continue;
}
switch (card_info.uidlen) {
case 4 : cascade_levels = 1; break;
case 7 : cascade_levels = 2; break;
case 10: cascade_levels = 3; break;
default: break;
}
have_uid = true;
} else { // no need for anticollision. We can directly select the card
if(!iso14443a_select_card(uid, NULL, &cuid, false, cascade_levels)) {
if (MF_DBGLEVEL >= 1) Dbprintf("AcquireNonces: Can't select card (UID)");
continue;
}
}
if (slow) {
timeout = GetCountSspClk() + PRE_AUTHENTICATION_LEADTIME;
while(GetCountSspClk() < timeout);
}
uint32_t nt1;
if (mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, NULL)) {
if (MF_DBGLEVEL >= 1) Dbprintf("AcquireNonces: Auth1 error");
continue;
}
// nested authentication
uint16_t len = mifare_sendcmd_short(pcs, AUTH_NESTED, 0x60 + (targetKeyType & 0x01), targetBlockNo, receivedAnswer, par_enc, NULL);
if (len != 4) {
if (MF_DBGLEVEL >= 1) Dbprintf("AcquireNonces: Auth2 error len=%d", len);
continue;
}
// send a dummy byte as reader response in order to trigger the cards authentication timeout
uint8_t dummy_answer = 0;
ReaderTransmit(&dummy_answer, 1, NULL);
timeout = GetCountSspClk() + AUTHENTICATION_TIMEOUT;
num_nonces++;
if (num_nonces % 2) {
memcpy(nt_enc1, receivedAnswer, 4);
nt_par_enc = par_enc[0];
} else {
nt_par_enc |= par_enc[0];
memcpy(&buf[i], nt_enc1, 4);
i += 4;
memcpy(&buf[i], receivedAnswer, 4);
i += 4;
memcpy(&buf[i], &nt_par_enc, 1);
i += 1;
}
// wait for the card to become ready again
while(GetCountSspClk() < timeout);
}
LED_C_OFF();
crypto1_destroy(pcs);
LED_B_ON();
memcpy(&cuid, uid+(cascade_levels-1)*3, 4);
cmd_send(CMD_ACK, isOK, cuid, num_nonces, buf, sizeof(buf));
LED_B_OFF();
if (MF_DBGLEVEL >= 3) DbpString("AcquireEncryptedNonces finished");
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// MIFARE nested authentication. // MIFARE nested authentication.
// //
@ -672,7 +806,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat
continue; continue;
} }
if(!iso14443a_select_card(uid, NULL, &cuid)) { if(!iso14443a_select_card(uid, NULL, &cuid, true, 0)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Can't select card"); if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Can't select card");
rtr--; rtr--;
continue; continue;
@ -746,7 +880,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat
continue; continue;
} }
if(!iso14443a_select_card(uid, NULL, &cuid)) { if(!iso14443a_select_card(uid, NULL, &cuid, true, 0)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Can't select card"); if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Can't select card");
continue; continue;
}; };
@ -861,7 +995,7 @@ void MifareChkKeys(uint16_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
if (MF_DBGLEVEL >= 1) Dbprintf("ChkKeys: Halt error"); if (MF_DBGLEVEL >= 1) Dbprintf("ChkKeys: Halt error");
} }
if(!iso14443a_select_card(uid, NULL, &cuid)) { if(!iso14443a_select_card(uid, NULL, &cuid, true, 0)) {
if (OLD_MF_DBGLEVEL >= 1) Dbprintf("ChkKeys: Can't select card"); if (OLD_MF_DBGLEVEL >= 1) Dbprintf("ChkKeys: Can't select card");
break; break;
}; };
@ -954,7 +1088,7 @@ void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
bool isOK = true; bool isOK = true;
if(!iso14443a_select_card(uid, NULL, &cuid)) { if(!iso14443a_select_card(uid, NULL, &cuid, true, 0)) {
isOK = false; isOK = false;
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
} }
@ -1054,7 +1188,7 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
// get UID from chip // get UID from chip
if (workFlags & 0x01) { if (workFlags & 0x01) {
if(!iso14443a_select_card(uid, NULL, &cuid)) { if(!iso14443a_select_card(uid, NULL, &cuid, true, 0)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
break; break;
}; };
@ -1259,7 +1393,7 @@ void Mifare_DES_Auth1(uint8_t arg0, uint8_t *datain){
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
clear_trace(); clear_trace();
int len = iso14443a_select_card(uid, NULL, &cuid); int len = iso14443a_select_card(uid, NULL, &cuid, true, 0);
if(!len) { if(!len) {
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card"); if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card");
OnError(1); OnError(1);

View file

@ -784,6 +784,104 @@ int CmdHF14AMfNested(const char *Cmd)
return 0; return 0;
} }
int CmdHF14AMfNestedHard(const char *Cmd)
{
uint8_t blockNo = 0;
uint8_t keyType = 0;
uint8_t trgBlockNo = 0;
uint8_t trgKeyType = 0;
uint8_t key[6] = {0, 0, 0, 0, 0, 0};
char ctmp;
ctmp = param_getchar(Cmd, 0);
if (ctmp != 'R' && ctmp != 'r' && strlen(Cmd) < 20) {
PrintAndLog("Usage:");
PrintAndLog(" hf mf hardnested <block number> <key A|B> <key (12 hex symbols)>");
PrintAndLog(" <target block number> <target key A|B> [w] [s]");
PrintAndLog(" or hf mf hardnested r");
PrintAndLog(" ");
PrintAndLog("Options: ");
PrintAndLog(" w: Acquire nonces and write them to binary file nonces.bin");
PrintAndLog(" s: Slower acquisition (required by some non standard cards)");
PrintAndLog(" r: Read nonces.bin and start attack");
PrintAndLog(" ");
PrintAndLog(" sample1: hf mf hardnested 0 A FFFFFFFFFFFF 4 A");
PrintAndLog(" sample2: hf mf hardnested 0 A FFFFFFFFFFFF 4 A w");
PrintAndLog(" sample3: hf mf hardnested 0 A FFFFFFFFFFFF 4 A w s");
PrintAndLog(" sample4: hf mf hardnested r");
return 0;
}
bool nonce_file_read = false;
bool nonce_file_write = false;
bool slow = false;
if (ctmp == 'R' || ctmp == 'r') {
nonce_file_read = true;
} else {
blockNo = param_get8(Cmd, 0);
ctmp = param_getchar(Cmd, 1);
if (ctmp != 'a' && ctmp != 'A' && ctmp != 'b' && ctmp != 'B') {
PrintAndLog("Key type must be A or B");
return 1;
}
if (ctmp != 'A' && ctmp != 'a') {
keyType = 1;
}
if (param_gethex(Cmd, 2, key, 12)) {
PrintAndLog("Key must include 12 HEX symbols");
return 1;
}
trgBlockNo = param_get8(Cmd, 3);
ctmp = param_getchar(Cmd, 4);
if (ctmp != 'a' && ctmp != 'A' && ctmp != 'b' && ctmp != 'B') {
PrintAndLog("Target key type must be A or B");
return 1;
}
if (ctmp != 'A' && ctmp != 'a') {
trgKeyType = 1;
}
uint16_t i = 5;
while ((ctmp = param_getchar(Cmd, i))) {
if (ctmp == 's' || ctmp == 'S') {
slow = true;
} else if (ctmp == 'w' || ctmp == 'W') {
nonce_file_write = true;
} else {
PrintAndLog("Possible options are w and/or s");
return 1;
}
i++;
}
}
PrintAndLog("--target block no:%3d, target key type:%c, file action: %s, Slow: %s ",
trgBlockNo,
trgKeyType?'B':'A',
nonce_file_write?"write":nonce_file_read?"read":"none",
slow?"Yes":"No");
int16_t isOK = mfnestedhard(blockNo, keyType, key, trgBlockNo, trgKeyType, nonce_file_read, nonce_file_write, slow);
if (isOK) {
switch (isOK) {
case -1 : PrintAndLog("Error: No response from Proxmark.\n"); break;
case -2 : PrintAndLog("Button pressed. Aborted.\n"); break;
default : PrintAndLog("Unknown Error.\n");
}
return 2;
}
return 0;
}
int CmdHF14AMfChk(const char *Cmd) int CmdHF14AMfChk(const char *Cmd)
{ {
if (strlen(Cmd)<3) { if (strlen(Cmd)<3) {
@ -1964,6 +2062,7 @@ static command_t CommandTable[] =
{"chk", CmdHF14AMfChk, 0, "Test block keys"}, {"chk", CmdHF14AMfChk, 0, "Test block keys"},
{"mifare", CmdHF14AMifare, 0, "Read parity error messages."}, {"mifare", CmdHF14AMifare, 0, "Read parity error messages."},
{"nested", CmdHF14AMfNested, 0, "Test nested authentication"}, {"nested", CmdHF14AMfNested, 0, "Test nested authentication"},
{"hardnested", CmdHF14AMfNestedHard, 0, "Nested attack for hardened Mifare cards"},
{"sniff", CmdHF14AMfSniff, 0, "Sniff card-reader communication"}, {"sniff", CmdHF14AMfSniff, 0, "Sniff card-reader communication"},
{"sim", CmdHF14AMf1kSim, 0, "Simulate MIFARE card"}, {"sim", CmdHF14AMf1kSim, 0, "Simulate MIFARE card"},
{"eclr", CmdHF14AMfEClear, 0, "Clear simulator memory block"}, {"eclr", CmdHF14AMfEClear, 0, "Clear simulator memory block"},

View file

@ -119,6 +119,7 @@ local _commands = {
CMD_READER_MIFARE = 0x0611, CMD_READER_MIFARE = 0x0611,
CMD_MIFARE_NESTED = 0x0612, CMD_MIFARE_NESTED = 0x0612,
CMD_MIFARE_ACQUIRE_ENCRYPTED_NONCES = 0x0613,
CMD_MIFARE_READBL = 0x0620, CMD_MIFARE_READBL = 0x0620,
CMD_MIFAREU_READBL = 0x0720, CMD_MIFAREU_READBL = 0x0720,

View file

@ -193,6 +193,94 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t * key, uint8_t trgBlockNo
return 0; return 0;
} }
int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, bool nonce_file_read, bool nonce_file_write, bool slow)
{
UsbCommand resp;
FILE *fnonces = NULL;
uint32_t total_num_nonces = 0;
uint32_t flags = 0;
bool initialize = true;
clock_t time1;
//StateList_t statelists[2];
//struct Crypto1State *p1, *p2, *p3, *p4;
if (nonce_file_read) {
// don't acquire nonces, use pre-acquired data from file nonces.bin
PrintAndLog("Reading nonces not yet implemented.");
} else {
// acquire nonces.
time1 = clock();
do {
clearCommandBuffer();
flags |= initialize ? 0x0001 : 0;
flags |= slow ? 0x0002 : 0;
UsbCommand c = {CMD_MIFARE_ACQUIRE_ENCRYPTED_NONCES, {blockNo + keyType * 0x100, trgBlockNo + trgKeyType * 0x100, flags}};
memcpy(c.d.asBytes, key, 6);
SendCommand(&c);
initialize = false;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 3000)) {
return -1;
}
if (resp.arg[0]) {
return resp.arg[0]; // error during nested
}
uint32_t cuid = resp.arg[1];
uint16_t num_acquired_nonces = resp.arg[2];
//PrintAndLog("Received %d nonces", num_acquired_nonces);
if (nonce_file_write && fnonces == NULL) {
if ((fnonces = fopen("nonces.bin","wb")) == NULL) {
PrintAndLog("Could not create file nonces.bin");
return 1;
}
PrintAndLog("Writing acquired nonces to binary file nonces.bin...");
fwrite(&cuid, 1, sizeof(cuid), fnonces);
fwrite(&trgBlockNo, 1, sizeof(trgBlockNo), fnonces);
fwrite(&trgKeyType, 1, sizeof(trgKeyType), fnonces);
}
uint32_t nt_enc1, nt_enc2;
uint8_t par_enc;
uint8_t *bufp = resp.d.asBytes;
for (uint16_t i = 0; i < num_acquired_nonces/2; i++) {
memcpy(&nt_enc1, bufp, sizeof(nt_enc1));
bufp += sizeof(nt_enc1);
memcpy(&nt_enc2, bufp, sizeof(nt_enc2));
bufp += sizeof(nt_enc2);
memcpy(&par_enc, bufp, sizeof(par_enc));
bufp += sizeof(par_enc);
//printf("Encrypted nonce: %08x, encrypted_parity: %02x\n", nt_enc1, par_enc >> 4);
//printf("Encrypted nonce: %08x, encrypted_parity: %02x\n", nt_enc2, par_enc & 0x0f);
if (nonce_file_write) {
fwrite(&nt_enc1, 1, sizeof(nt_enc1), fnonces);
fwrite(&nt_enc2, 1, sizeof(nt_enc2), fnonces);
fwrite(&par_enc, 1, sizeof(par_enc), fnonces);
}
}
total_num_nonces += num_acquired_nonces;
} while (total_num_nonces < 5000);
if (nonce_file_write) {
fclose(fnonces);
}
PrintAndLog("Acquired a total of %d nonces at a rate of %d nonces/minute", total_num_nonces, total_num_nonces*60*CLOCKS_PER_SEC/(clock() - time1));
}
PrintAndLog("Attack not yet implemented");
return 0;
}
int mfCheckKeys (uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t keycnt, uint8_t * keyBlock, uint64_t * key){ int mfCheckKeys (uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t keycnt, uint8_t * keyBlock, uint64_t * key){
*key = 0; *key = 0;

View file

@ -50,6 +50,7 @@ typedef struct {
extern char logHexFileName[FILE_PATH_SIZE]; extern char logHexFileName[FILE_PATH_SIZE];
int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t * key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t * ResultKeys, bool calibrate); int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t * key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t * ResultKeys, bool calibrate);
int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t * key, uint8_t trgBlockNo, uint8_t trgKeyType, bool nonce_file_read, bool nonce_file_write, bool slow);
int mfCheckKeys (uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t keycnt, uint8_t * keyBlock, uint64_t * key); int mfCheckKeys (uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t keycnt, uint8_t * keyBlock, uint64_t * key);
int mfEmlGetMem(uint8_t *data, int blockNum, int blocksCount); int mfEmlGetMem(uint8_t *data, int blockNum, int blocksCount);

View file

@ -165,6 +165,7 @@ typedef struct{
#define CMD_READER_MIFARE 0x0611 #define CMD_READER_MIFARE 0x0611
#define CMD_MIFARE_NESTED 0x0612 #define CMD_MIFARE_NESTED 0x0612
#define CMD_MIFARE_ACQUIRE_ENCRYPTED_NONCES 0x0613
#define CMD_MIFARE_READBL 0x0620 #define CMD_MIFARE_READBL 0x0620
#define CMD_MIFAREU_READBL 0x0720 #define CMD_MIFAREU_READBL 0x0720