X-Git-Url: http://cvs.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/5330f5329f68fa6a95658ebd946d5eefc74e10c4..5191ad9e556e4209945ccce8122a96d87c1e92d9:/armsrc/mifarecmd.c?ds=sidebyside diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index fd6fde63..60a85c80 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -14,17 +14,23 @@ //----------------------------------------------------------------------------- #include "mifarecmd.h" + #include "apps.h" #include "util.h" +#include "parity.h" #include "crc.h" +#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 + + // the block number for the ISO14443-4 PCB -uint8_t pcb_blocknum = 0; +static uint8_t pcb_blocknum = 0; // Deselect card by sending a s-block. the crc is precalced for speed static uint8_t deselect_cmd[] = {0xc2,0xe0,0xb4}; //----------------------------------------------------------------------------- -// Select, Authenticate, Read a MIFARE tag. +// Select, Authenticate, Read a MIFARE tag. // read block //----------------------------------------------------------------------------- void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) @@ -34,7 +40,7 @@ void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) uint8_t keyType = arg1; uint64_t ui64Key = 0; ui64Key = bytes_to_num(datain, 6); - + // variables byte_t isOK = 0; byte_t dataoutbuf[16]; @@ -53,7 +59,7 @@ void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) LED_C_OFF(); 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"); break; }; @@ -62,7 +68,7 @@ void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) if (MF_DBGLEVEL >= 1) Dbprintf("Auth error"); break; }; - + if(mifare_classic_readblock(pcs, cuid, blockNo, dataoutbuf)) { if (MF_DBGLEVEL >= 1) Dbprintf("Read block error"); break; @@ -72,14 +78,14 @@ void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); break; }; - + isOK = 1; break; } - + // ----------------------------- crypto1 destroy crypto1_destroy(pcs); - + if (MF_DBGLEVEL >= 2) DbpString("READ BLOCK FINISHED"); LED_B_ON(); @@ -100,12 +106,12 @@ void MifareUC_Auth(uint8_t arg0, uint8_t *keybytes){ 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"); OnError(0); return; }; - + if(!mifare_ultra_auth(keybytes)){ if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Authentication failed"); OnError(1); @@ -135,7 +141,7 @@ void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) clear_trace(); - int len = iso14443a_select_card(NULL, NULL, NULL); + int len = iso14443a_select_card(NULL, NULL, NULL, true, 0); if(!len) { if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card (RC:%02X)",len); OnError(1); @@ -162,7 +168,7 @@ void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) OnError(1); return; } - } + } if( mifare_ultra_readblock(blockNo, dataout) ) { if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Read block error"); @@ -182,7 +188,7 @@ void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) } //----------------------------------------------------------------------------- -// Select, Authenticate, Read a MIFARE tag. +// Select, Authenticate, Read a MIFARE tag. // read sector (data = 4 x 16 bytes = 64 bytes, or 16 x 16 bytes = 256 bytes) //----------------------------------------------------------------------------- void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) @@ -192,7 +198,7 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) uint8_t keyType = arg1; uint64_t ui64Key = 0; ui64Key = bytes_to_num(datain, 6); - + // variables byte_t isOK = 0; byte_t dataoutbuf[16 * 16]; @@ -211,17 +217,17 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) LED_C_OFF(); isOK = 1; - if(!iso14443a_select_card(uid, NULL, &cuid)) { + if(!iso14443a_select_card(uid, NULL, &cuid, true, 0)) { isOK = 0; if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); } - + if(isOK && mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_FIRST)) { isOK = 0; if (MF_DBGLEVEL >= 1) Dbprintf("Auth error"); } - + for (uint8_t blockNo = 0; isOK && blockNo < NumBlocksPerSector(sectorNo); blockNo++) { if(mifare_classic_readblock(pcs, cuid, FirstBlockOfSector(sectorNo) + blockNo, dataoutbuf + 16 * blockNo)) { isOK = 0; @@ -229,14 +235,14 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) break; } } - + if(mifare_classic_halt(pcs, cuid)) { if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); } // ----------------------------- crypto1 destroy crypto1_destroy(pcs); - + if (MF_DBGLEVEL >= 2) DbpString("READ SECTOR FINISHED"); LED_B_ON(); @@ -275,7 +281,7 @@ void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain) return; } - int len = iso14443a_select_card(NULL, NULL, NULL); + int len = iso14443a_select_card(NULL, NULL, NULL, true, 0); if (!len) { if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card (RC:%d)",len); OnError(1); @@ -301,7 +307,7 @@ void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain) if (!mifare_ul_ev1_auth(pwd, pack)){ OnError(1); - return; + return; } } @@ -310,7 +316,7 @@ void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain) Dbprintf("Data exceeds buffer!!"); break; } - + len = mifare_ultra_readblock(blockNo + i, dataout + 4 * i); if (len) { @@ -346,7 +352,7 @@ void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain) } //----------------------------------------------------------------------------- -// Select, Authenticate, Write a MIFARE tag. +// Select, Authenticate, Write a MIFARE tag. // read block //----------------------------------------------------------------------------- void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) @@ -359,7 +365,7 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) ui64Key = bytes_to_num(datain, 6); memcpy(blockdata, datain + 10, 16); - + // variables byte_t isOK = 0; uint8_t uid[10]; @@ -377,7 +383,7 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) LED_C_OFF(); 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"); break; }; @@ -386,7 +392,7 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) if (MF_DBGLEVEL >= 1) Dbprintf("Auth error"); break; }; - + if(mifare_classic_writeblock(pcs, cuid, blockNo, blockdata)) { if (MF_DBGLEVEL >= 1) Dbprintf("Write block error"); break; @@ -396,14 +402,14 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); break; }; - + isOK = 1; break; } - + // ----------------------------- crypto1 destroy crypto1_destroy(pcs); - + if (MF_DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED"); LED_B_ON(); @@ -416,7 +422,7 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) LEDsoff(); } -/* // Command not needed but left for future testing +/* // Command not needed but left for future testing void MifareUWriteBlockCompat(uint8_t arg0, uint8_t *datain) { uint8_t blockNo = arg0; @@ -431,7 +437,7 @@ void MifareUWriteBlockCompat(uint8_t arg0, uint8_t *datain) clear_trace(); 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"); OnError(0); return; @@ -470,14 +476,14 @@ void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) byte_t blockdata[4] = {0x00}; memcpy(blockdata, datain,4); - + LEDsoff(); LED_A_ON(); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); 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"); OnError(0); return; @@ -493,7 +499,7 @@ void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) return; } } - + // UL-EV1 / NTAG authentication if (usePwd) { uint8_t pwd[4] = {0x00}; @@ -525,18 +531,18 @@ void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) } void MifareUSetPwd(uint8_t arg0, uint8_t *datain){ - + uint8_t pwd[16] = {0x00}; byte_t blockdata[4] = {0x00}; - + memcpy(pwd, datain, 16); - + LED_A_ON(); LED_B_OFF(); LED_C_OFF(); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); 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"); OnError(0); return; @@ -580,7 +586,7 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain){ if (MF_DBGLEVEL >= 1) Dbprintf("Write block error"); OnError(47); return; - }; + }; if(mifare_ultra_halt()) { if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); @@ -595,15 +601,144 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain){ // Return 1 if the nonce is invalid else return 0 int valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, uint8_t *parity) { - return ((oddparity((Nt >> 24) & 0xFF) == ((parity[0]) ^ oddparity((NtEnc >> 24) & 0xFF) ^ BIT(Ks1,16))) & \ - (oddparity((Nt >> 16) & 0xFF) == ((parity[1]) ^ oddparity((NtEnc >> 16) & 0xFF) ^ BIT(Ks1,8))) & \ - (oddparity((Nt >> 8) & 0xFF) == ((parity[2]) ^ oddparity((NtEnc >> 8) & 0xFF) ^ BIT(Ks1,0)))) ? 1 : 0; + return ((oddparity8((Nt >> 24) & 0xFF) == ((parity[0]) ^ oddparity8((NtEnc >> 24) & 0xFF) ^ BIT(Ks1,16))) & \ + (oddparity8((Nt >> 16) & 0xFF) == ((parity[1]) ^ oddparity8((NtEnc >> 16) & 0xFF) ^ BIT(Ks1,8))) & \ + (oddparity8((Nt >> 8) & 0xFF) == ((parity[2]) ^ oddparity8((NtEnc >> 8) & 0xFF) ^ BIT(Ks1,0)))) ? 1 : 0; +} + + +//----------------------------------------------------------------------------- +// 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 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; + bool field_off = flags & 0x0004; + + LED_A_ON(); + LED_C_OFF(); + + if (initialize) { + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + 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 - 9; ) { + + // Test if the action was cancelled + if(BUTTON_PRESS()) { + isOK = 2; + field_off = true; + 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, NULL, 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(buf+i, receivedAnswer, 4); + nt_par_enc = par_enc[0] & 0xf0; + } else { + nt_par_enc |= par_enc[0] >> 4; + memcpy(buf+i+4, receivedAnswer, 4); + memcpy(buf+i+8, &nt_par_enc, 1); + i += 9; + } + + // wait for the card to become ready again + while(GetCountSspClk() < timeout); + + } + + LED_C_OFF(); + + crypto1_destroy(pcs); + + LED_B_ON(); + cmd_send(CMD_ACK, isOK, cuid, num_nonces, buf, sizeof(buf)); + LED_B_OFF(); + + if (MF_DBGLEVEL >= 3) DbpString("AcquireEncryptedNonces finished"); + + if (field_off) { + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); + } } //----------------------------------------------------------------------------- -// MIFARE nested authentication. -// +// MIFARE nested authentication. +// //----------------------------------------------------------------------------- void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *datain) { @@ -615,7 +750,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat uint64_t ui64Key = 0; ui64Key = bytes_to_num(datain, 6); - + // variables uint16_t rtr, i, j, len; uint16_t davg; @@ -624,7 +759,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat uint32_t cuid, nt1, nt2, nttmp, nttest, ks1; uint8_t par[1]; uint32_t target_nt[2], target_ks[2]; - + uint8_t par_array[4]; uint16_t ncount = 0; struct Crypto1State mpcs = {0, 0}; @@ -644,7 +779,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat if (calibrate) clear_trace(); set_tracing(true); - + // statistics on nonce distance int16_t isOK = 0; #define NESTED_MAX_TRIES 12 @@ -656,7 +791,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat davg = dmax = 0; dmin = 2000; delta_time = 0; - + for (rtr = 0; rtr < 17; rtr++) { // Test if the action was cancelled @@ -672,7 +807,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat 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"); rtr--; continue; @@ -721,17 +856,17 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat } davg = (davg + (rtr - 1)/2) / (rtr - 1); - + if (MF_DBGLEVEL >= 3) Dbprintf("rtr=%d isOK=%d min=%d max=%d avg=%d, delta_time=%d", rtr, isOK, dmin, dmax, davg, delta_time); dmin = davg - 2; dmax = davg + 2; - + LED_B_OFF(); - + } - // ------------------------------------------------------------------------------------------------- - + // ------------------------------------------------------------------------------------------------- + LED_C_ON(); // get crypted nonces for target sector @@ -739,18 +874,18 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat target_nt[i] = 0; while(target_nt[i] == 0) { // continue until we have an unambiguous nonce - + // prepare next select. No need to power down the card. if(mifare_classic_halt(pcs, cuid)) { if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Halt error"); 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"); continue; }; - + auth1_time = 0; if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, &auth1_time)) { if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth1 error"); @@ -764,15 +899,15 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth2 error len=%d", len); continue; }; - - nt2 = bytes_to_num(receivedAnswer, 4); + + nt2 = bytes_to_num(receivedAnswer, 4); if (MF_DBGLEVEL >= 3) Dbprintf("Nonce#%d: Testing nt1=%08x nt2enc=%08x nt2par=%02x", i+1, nt1, nt2, par[0]); - + // Parity validity check for (j = 0; j < 4; j++) { - par_array[j] = (oddparity(receivedAnswer[j]) != ((par[0] >> (7-j)) & 0x01)); + par_array[j] = (oddparity8(receivedAnswer[j]) != ((par[0] >> (7-j)) & 0x01)); } - + ncount = 0; nttest = prng_successor(nt1, dmin - 1); for (j = dmin; j < dmax + 1; j++) { @@ -801,17 +936,17 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat } LED_C_OFF(); - + // ----------------------------- crypto1 destroy crypto1_destroy(pcs); - + byte_t buf[4 + 4 * 4]; memcpy(buf, &cuid, 4); memcpy(buf+4, &target_nt[0], 4); memcpy(buf+8, &target_ks[0], 4); memcpy(buf+12, &target_nt[1], 4); memcpy(buf+16, &target_ks[1], 4); - + LED_B_ON(); cmd_send(CMD_ACK, isOK, 0, targetBlockNo + (targetKeyType * 0x100), buf, sizeof(buf)); LED_B_OFF(); @@ -823,19 +958,20 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat } //----------------------------------------------------------------------------- -// MIFARE check keys. key count up to 85. -// +// MIFARE check keys. key count up to 85. +// //----------------------------------------------------------------------------- void MifareChkKeys(uint16_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) { - // params uint8_t blockNo = arg0 & 0xff; uint8_t keyType = (arg0 >> 8) & 0xff; bool clearTrace = arg1; uint8_t keyCount = arg2; uint64_t ui64Key = 0; - - // variables + + bool have_uid = false; + uint8_t cascade_levels = 0; + uint32_t timeout = 0; int i; byte_t isOK = 0; uint8_t uid[10]; @@ -843,41 +979,62 @@ void MifareChkKeys(uint16_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) struct Crypto1State mpcs = {0, 0}; struct Crypto1State *pcs; pcs = &mpcs; - + // clear debug level - int OLD_MF_DBGLEVEL = MF_DBGLEVEL; + int OLD_MF_DBGLEVEL = MF_DBGLEVEL; MF_DBGLEVEL = MF_DBG_NONE; - + LED_A_ON(); LED_B_OFF(); LED_C_OFF(); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); if (clearTrace) clear_trace(); - set_tracing(TRUE); + set_tracing(true); for (i = 0; i < keyCount; i++) { - if(mifare_classic_halt(pcs, cuid)) { - if (MF_DBGLEVEL >= 1) Dbprintf("ChkKeys: Halt error"); +// if(mifare_classic_halt(pcs, cuid)) { +// if (MF_DBGLEVEL >= 1) Dbprintf("ChkKeys: Halt error"); +// } + + // Iceman: use piwi's faster nonce collecting part in hardnested. + 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 (OLD_MF_DBGLEVEL >= 1) Dbprintf("ChkKeys: Can't select card"); + --i; // try same key once again + 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, NULL, false, cascade_levels)) { + if (OLD_MF_DBGLEVEL >= 1) Dbprintf("ChkKeys: Can't select card (UID)"); + --i; // try same key once again + continue; + } } - if(!iso14443a_select_card(uid, NULL, &cuid)) { - if (OLD_MF_DBGLEVEL >= 1) Dbprintf("ChkKeys: Can't select card"); - break; - }; - ui64Key = bytes_to_num(datain + i * 6, 6); if(mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) { + uint8_t dummy_answer = 0; + ReaderTransmit(&dummy_answer, 1, NULL); + timeout = GetCountSspClk() + AUTHENTICATION_TIMEOUT; + + // wait for the card to become ready again + while(GetCountSspClk() < timeout); continue; - }; - + } + isOK = 1; break; } - - // ----------------------------- crypto1 destroy - crypto1_destroy(pcs); - + LED_B_ON(); cmd_send(CMD_ACK,isOK,0,0,datain + i * 6,6); LED_B_OFF(); @@ -886,12 +1043,12 @@ void MifareChkKeys(uint16_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) LEDsoff(); // restore debug level - MF_DBGLEVEL = OLD_MF_DBGLEVEL; + MF_DBGLEVEL = OLD_MF_DBGLEVEL; } //----------------------------------------------------------------------------- // MIFARE commands set debug level -// +// //----------------------------------------------------------------------------- void MifareSetDbgLvl(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){ MF_DBGLEVEL = arg0; @@ -900,7 +1057,7 @@ void MifareSetDbgLvl(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai //----------------------------------------------------------------------------- // Work with emulator memory -// +// // Note: we call FpgaDownloadAndGo(FPGA_BITSTREAM_HF) here although FPGA is not // involved in dealing with emulator memory. But if it is called later, it might // destroy the Emulator Memory. @@ -928,7 +1085,7 @@ void MifareEMemGet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain) //----------------------------------------------------------------------------- // Load a card into the emulator memory -// +// //----------------------------------------------------------------------------- void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){ uint8_t numSectors = arg0; @@ -948,17 +1105,17 @@ void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai LED_B_OFF(); LED_C_OFF(); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - + clear_trace(); set_tracing(false); - + bool isOK = true; - if(!iso14443a_select_card(uid, NULL, &cuid)) { + if(!iso14443a_select_card(uid, NULL, &cuid, true, 0)) { isOK = false; if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); } - + for (uint8_t sectorNo = 0; isOK && sectorNo < numSectors; sectorNo++) { ui64Key = emlGetKey(sectorNo, keyType); if (sectorNo == 0){ @@ -974,7 +1131,7 @@ void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai break; } } - + for (uint8_t blockNo = 0; isOK && blockNo < NumBlocksPerSector(sectorNo); blockNo++) { if(isOK && mifare_classic_readblock(pcs, cuid, FirstBlockOfSector(sectorNo) + blockNo, dataoutbuf)) { isOK = false; @@ -1003,7 +1160,7 @@ void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); - + if (MF_DBGLEVEL >= 2) DbpString("EMUL FILL SECTORS FINISHED"); } @@ -1011,10 +1168,147 @@ void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai //----------------------------------------------------------------------------- // Work with "magic Chinese" card (email him: ouyangweidaxian@live.cn) -// +// //----------------------------------------------------------------------------- + +static bool isBlockTrailer(int blockN) { + if (blockN >= 0 && blockN < 128) { + return ((blockN & 0x03) == 0x03); + } + if (blockN >= 128 && blockN <= 256) { + return ((blockN & 0x0F) == 0x0F); + } + return FALSE; +} + +void MifareCWipe(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){ + // var + byte_t isOK = 0; + uint32_t numBlocks = arg0; + // cmdParams: + // bit 0 - wipe gen1a + // bit 1 - fill card with default data + // bit 2 - gen1a = 0, gen1b = 1 + uint8_t cmdParams = arg1; + bool needWipe = cmdParams & 0x01; + bool needFill = cmdParams & 0x02; + bool gen1b = cmdParams & 0x04; + + uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; + uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; + + uint8_t block0[16] = {0x01, 0x02, 0x03, 0x04, 0x04, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBE, 0xAF}; + uint8_t block1[16] = {0x00}; + uint8_t blockK[16] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x08, 0x77, 0x8F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + uint8_t d_block[18] = {0x00}; + + // card commands + uint8_t wupC1[] = { 0x40 }; + uint8_t wupC2[] = { 0x43 }; + uint8_t wipeC[] = { 0x41 }; + + // iso14443 setup + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + + // tracing + clear_trace(); + set_tracing(true); + + while (true){ + // wipe + if (needWipe){ + ReaderTransmitBitsPar(wupC1,7,0, NULL); + if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { + if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error"); + break; + }; + + ReaderTransmit(wipeC, sizeof(wipeC), NULL); + if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { + if (MF_DBGLEVEL >= 1) Dbprintf("wipeC error"); + break; + }; + + if(mifare_classic_halt(NULL, 0)) { + if (MF_DBGLEVEL > 2) Dbprintf("Halt error"); + }; + }; + + // put default data + if (needFill){ + // select commands + ReaderTransmitBitsPar(wupC1, 7, 0, NULL); + + // gen1b magic tag : do no issue wupC2 and don't expect 0x0a response after SELECT_UID (after getting UID from chip in 'hf mf csetuid' command) + if (!gen1b) { + + if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { + if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error"); + break; + }; + + ReaderTransmit(wupC2, sizeof(wupC2), NULL); + if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { + if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error"); + break; + }; + } + + // send blocks command + for (int blockNo = 0; blockNo < numBlocks; blockNo++) { + if ((mifare_sendcmd_short(NULL, 0, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 1) || (receivedAnswer[0] != 0x0a)) { + if (MF_DBGLEVEL >= 1) Dbprintf("write block send command error"); + break; + }; + + // check type of block and add crc + if (!isBlockTrailer(blockNo)){ + memcpy(d_block, block1, 16); + } else { + memcpy(d_block, blockK, 16); + } + if (blockNo == 0) { + memcpy(d_block, block0, 16); + } + AppendCrc14443a(d_block, 16); + + // send write command + ReaderTransmit(d_block, sizeof(d_block), NULL); + if ((ReaderReceive(receivedAnswer, receivedAnswerPar) != 1) || (receivedAnswer[0] != 0x0a)) { + if (MF_DBGLEVEL >= 1) Dbprintf("write block send data error"); + break; + }; + } + + // halt + // do no issue halt command for gen1b + if (!gen1b) { + if (mifare_classic_halt(NULL, 0)) { + if (MF_DBGLEVEL > 2) Dbprintf("Halt error"); + break; + } + } + } + break; + } + + // send USB response + LED_B_ON(); + cmd_send(CMD_ACK,isOK,0,0,NULL,0); + LED_B_OFF(); + + // reset fpga + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); + + return; +} + void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){ - + // params uint8_t needWipe = arg0; // bit 0 - need get UID @@ -1022,20 +1316,21 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai // bit 2 - need HALT after sequence // bit 3 - need init FPGA and field before sequence // bit 4 - need reset FPGA and LED + // bit 6 - gen1b backdoor type uint8_t workFlags = arg1; uint8_t blockNo = arg2; - + // card commands - uint8_t wupC1[] = { 0x40 }; - uint8_t wupC2[] = { 0x43 }; - uint8_t wipeC[] = { 0x41 }; - + uint8_t wupC1[] = { 0x40 }; + uint8_t wupC2[] = { 0x43 }; + uint8_t wipeC[] = { 0x41 }; + // variables byte_t isOK = 0; uint8_t uid[10] = {0x00}; uint8_t d_block[18] = {0x00}; uint32_t cuid; - + uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; @@ -1045,28 +1340,31 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai LED_B_OFF(); LED_C_OFF(); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - + clear_trace(); - set_tracing(TRUE); + set_tracing(true); } while (true) { // get UID from chip 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"); - break; - }; - - if(mifare_classic_halt(NULL, cuid)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); - break; - }; + // Continue, if we set wrong UID or wrong UID checksum or some ATQA or SAK we will can't select card. But we need to write block 0 to make card work. + //break; + }; + + if(mifare_classic_halt(NULL, cuid)) { + if (MF_DBGLEVEL > 2) Dbprintf("Halt error"); + // Continue, some magic tags misbehavies and send an answer to it. + // break; + }; }; - + // reset chip - if (needWipe){ + // Wipe command don't work with gen1b + if (needWipe && !(workFlags & 0x40)){ ReaderTransmitBitsPar(wupC1,7,0, NULL); if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error"); @@ -1079,52 +1377,62 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai break; }; - if(mifare_classic_halt(NULL, cuid)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); - break; + if(mifare_classic_halt(NULL, 0)) { + if (MF_DBGLEVEL > 2) Dbprintf("Halt error"); + // Continue, some magic tags misbehavies and send an answer to it. + // break; }; - }; + }; // write block if (workFlags & 0x02) { ReaderTransmitBitsPar(wupC1,7,0, NULL); - if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { - if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error"); - break; - }; - ReaderTransmit(wupC2, sizeof(wupC2), NULL); - if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { - if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error"); - break; - }; + // gen1b magic tag : do no issue wupC2 and don't expect 0x0a response after SELECT_UID (after getting UID from chip in 'hf mf csetuid' command) + if (!(workFlags & 0x40)) { + + if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { + if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error"); + break; + }; + + ReaderTransmit(wupC2, sizeof(wupC2), NULL); + if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { + if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error"); + break; + }; + } } if ((mifare_sendcmd_short(NULL, 0, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 1) || (receivedAnswer[0] != 0x0a)) { if (MF_DBGLEVEL >= 1) Dbprintf("write block send command error"); break; }; - + memcpy(d_block, datain, 16); AppendCrc14443a(d_block, 16); - + ReaderTransmit(d_block, sizeof(d_block), NULL); if ((ReaderReceive(receivedAnswer, receivedAnswerPar) != 1) || (receivedAnswer[0] != 0x0a)) { if (MF_DBGLEVEL >= 1) Dbprintf("write block send data error"); break; - }; - + }; + if (workFlags & 0x04) { - if (mifare_classic_halt(NULL, cuid)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); - break; - }; + // do no issue halt command for gen1b magic tag (#db# halt error. response len: 1) + if (!(workFlags & 0x40)) { + if (mifare_classic_halt(NULL, 0)) { + if (MF_DBGLEVEL > 2) Dbprintf("Halt error"); + // Continue, some magic tags misbehavies and send an answer to it. + // break; + } + } } - + isOK = 1; break; } - + LED_B_ON(); cmd_send(CMD_ACK,isOK,0,0,uid,4); LED_B_OFF(); @@ -1137,27 +1445,29 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){ - - // params + + // params // bit 1 - need wupC // bit 2 - need HALT after sequence // bit 3 - need init FPGA and field before sequence // bit 4 - need reset FPGA and LED + // bit 5 - need to set datain instead of issuing USB reply (called via ARM for StandAloneMode14a) + // bit 6 - gen1b backdoor type uint8_t workFlags = arg0; uint8_t blockNo = arg2; - + // card commands - uint8_t wupC1[] = { 0x40 }; - uint8_t wupC2[] = { 0x43 }; - + uint8_t wupC1[] = { 0x40 }; + uint8_t wupC2[] = { 0x43 }; + // variables byte_t isOK = 0; uint8_t data[18] = {0x00}; uint32_t cuid = 0; - + uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; - + if (workFlags & 0x08) { LED_A_ON(); LED_B_OFF(); @@ -1165,7 +1475,7 @@ void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); clear_trace(); - set_tracing(TRUE); + set_tracing(true); } while (true) { @@ -1174,14 +1484,16 @@ void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error"); break; - }; - + }; + // do no issue for gen1b magic tag + if (!(workFlags & 0x40)) { ReaderTransmit(wupC2, sizeof(wupC2), NULL); if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error"); break; }; } + } // read block if ((mifare_sendcmd_short(NULL, 0, 0x30, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 18)) { @@ -1189,20 +1501,29 @@ void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai break; }; memcpy(data, receivedAnswer, 18); - + if (workFlags & 0x04) { - if (mifare_classic_halt(NULL, cuid)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); - break; - }; + // do no issue halt command for gen1b magic tag (#db# halt error. response len: 1) + if (!(workFlags & 0x40)) { + if (mifare_classic_halt(NULL, cuid)) { + if (MF_DBGLEVEL > 1) Dbprintf("Halt error"); + // Continue, some magic tags misbehavies and send an answer to it. + // break; + } + } } - + isOK = 1; break; } - + LED_B_ON(); - cmd_send(CMD_ACK,isOK,0,0,data,18); + if (workFlags & 0x20) { + if (isOK) + memcpy(datain, data, 18); + } + else + cmd_send(CMD_ACK,isOK,0,0,data,18); LED_B_OFF(); if ((workFlags & 0x10) || (!isOK)) { @@ -1212,30 +1533,29 @@ void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai } void MifareCIdent(){ - + // card commands - uint8_t wupC1[] = { 0x40 }; - uint8_t wupC2[] = { 0x43 }; - + uint8_t wupC1[] = { 0x40 }; + uint8_t wupC2[] = { 0x43 }; + // variables - byte_t isOK = 1; - + byte_t isOK = 0; + uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; ReaderTransmitBitsPar(wupC1,7,0, NULL); - if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { - isOK = 0; - }; + if(ReaderReceive(receivedAnswer, receivedAnswerPar) && (receivedAnswer[0] == 0x0a)) { + isOK = 2; - ReaderTransmit(wupC2, sizeof(wupC2), NULL); - if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { - isOK = 0; + ReaderTransmit(wupC2, sizeof(wupC2), NULL); + if(ReaderReceive(receivedAnswer, receivedAnswerPar) && (receivedAnswer[0] == 0x0a)) { + isOK = 1; + }; }; - if (mifare_classic_halt(NULL, 0)) { - isOK = 0; - }; + // From iceman1001: removed the if, since some magic tags misbehavies and send an answer to it. + mifare_classic_halt(NULL, 0); cmd_send(CMD_ACK,isOK,0,0,0,0); } @@ -1249,11 +1569,11 @@ void Mifare_DES_Auth1(uint8_t arg0, uint8_t *datain){ byte_t dataout[11] = {0x00}; uint8_t uid[10] = {0x00}; uint32_t cuid; - + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); clear_trace(); - int len = iso14443a_select_card(uid, NULL, &cuid); + int len = iso14443a_select_card(uid, NULL, &cuid, true, 0); if(!len) { if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card"); OnError(1); @@ -1276,13 +1596,13 @@ void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain){ uint8_t key[16] = {0x00}; byte_t isOK = 0; byte_t dataout[12] = {0x00}; - + memcpy(key, datain, 16); - + isOK = mifare_desfire_des_auth2(cuid, key, dataout); - + if( isOK) { - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Authentication part2: Failed"); + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Authentication part2: Failed"); OnError(4); return; }