X-Git-Url: https://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/a88c28271c9208b996ae86d3468a4fdbd77c791d..0c29544f640b8e8c03005b10229526a2d57e5954:/armsrc/mifarecmd.c?ds=sidebyside diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index 14d2b68a..6f57c113 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -14,12 +14,18 @@ //----------------------------------------------------------------------------- #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}; @@ -44,16 +50,16 @@ void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) struct Crypto1State *pcs; pcs = &mpcs; - // clear trace - clear_trace(); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + clear_trace(); + LED_A_ON(); LED_B_OFF(); 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; }; @@ -95,10 +101,12 @@ void MifareUC_Auth(uint8_t arg0, uint8_t *keybytes){ bool turnOffField = (arg0 == 1); LED_A_ON(); LED_B_OFF(); LED_C_OFF(); - clear_trace(); + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - if(!iso14443a_select_card(NULL, NULL, NULL)) { + clear_trace(); + + if(!iso14443a_select_card(NULL, NULL, NULL, true, 0)) { if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card"); OnError(0); return; @@ -129,10 +137,11 @@ void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) LEDsoff(); LED_A_ON(); - clear_trace(); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - int len = iso14443a_select_card(NULL, NULL, NULL); + clear_trace(); + + 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); @@ -199,17 +208,16 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) struct Crypto1State *pcs; pcs = &mpcs; - // clear trace - clear_trace(); - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + clear_trace(); + LED_A_ON(); LED_B_OFF(); 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"); } @@ -252,6 +260,10 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) // datain = KEY bytes void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain) { + LEDsoff(); + LED_A_ON(); + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + // free eventually allocated BigBuf memory BigBuf_free(); clear_trace(); @@ -269,11 +281,7 @@ void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain) return; } - LEDsoff(); - LED_A_ON(); - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - - 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); @@ -366,17 +374,16 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) struct Crypto1State *pcs; pcs = &mpcs; - // clear trace - clear_trace(); - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + clear_trace(); + LED_A_ON(); LED_B_OFF(); 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; }; @@ -430,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; @@ -472,10 +479,11 @@ void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) LEDsoff(); LED_A_ON(); - clear_trace(); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - if(!iso14443a_select_card(NULL, NULL, NULL)) { + clear_trace(); + + if(!iso14443a_select_card(NULL, NULL, NULL, true, 0)) { if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); OnError(0); return; @@ -530,10 +538,11 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain){ memcpy(pwd, datain, 16); LED_A_ON(); LED_B_OFF(); LED_C_OFF(); - clear_trace(); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - if(!iso14443a_select_card(NULL, NULL, NULL)) { + clear_trace(); + + if(!iso14443a_select_card(NULL, NULL, NULL, true, 0)) { if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); OnError(0); return; @@ -592,9 +601,138 @@ 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(); + } } @@ -632,18 +770,16 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat uint32_t auth1_time, auth2_time; static uint16_t delta_time; - // free eventually allocated BigBuf memory - BigBuf_free(); - // clear trace - clear_trace(); - set_tracing(false); - - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - LED_A_ON(); LED_C_OFF(); + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + // free eventually allocated BigBuf memory + BigBuf_free(); + if (calibrate) clear_trace(); + set_tracing(true); + // statistics on nonce distance int16_t isOK = 0; #define NESTED_MAX_TRIES 12 @@ -671,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; @@ -745,7 +881,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"); continue; }; @@ -769,7 +905,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat // 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; @@ -819,22 +955,23 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); - set_tracing(TRUE); } //----------------------------------------------------------------------------- // MIFARE check keys. key count up to 85. // //----------------------------------------------------------------------------- -void MifareChkKeys(uint8_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) { - // params - uint8_t blockNo = arg0; - uint8_t keyType = arg1; + 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]; @@ -847,38 +984,57 @@ void MifareChkKeys(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) int OLD_MF_DBGLEVEL = MF_DBGLEVEL; MF_DBGLEVEL = MF_DBG_NONE; - // clear trace - clear_trace(); - set_tracing(TRUE); - - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - LED_A_ON(); LED_B_OFF(); LED_C_OFF(); + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + + if (clearTrace) clear_trace(); + 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(); @@ -902,16 +1058,23 @@ 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. //----------------------------------------------------------------------------- + void MifareEMemClr(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){ + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); emlClearMem(); } void MifareEMemSet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){ + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); emlSetMem(datain, arg0, arg1); // data, block num, blocks count } void MifareEMemGet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){ + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); byte_t buf[USB_CMD_DATA_SIZE]; emlGetMem(buf, arg0, arg1); // data, block num, blocks count (max 4) @@ -938,19 +1101,17 @@ void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai byte_t dataoutbuf2[16]; uint8_t uid[10]; - // clear trace - clear_trace(); - set_tracing(false); - - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - LED_A_ON(); 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"); } @@ -1040,17 +1201,17 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai LED_A_ON(); LED_B_OFF(); LED_C_OFF(); + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); clear_trace(); - set_tracing(TRUE); - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + 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; }; @@ -1139,6 +1300,7 @@ void MifareCGetBlock(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 5 - need to set datain instead of issuing USB reply (called via ARM for StandAloneMode14a) uint8_t workFlags = arg0; uint8_t blockNo = arg2; @@ -1158,10 +1320,10 @@ void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai LED_A_ON(); LED_B_OFF(); LED_C_OFF(); - - clear_trace(); - set_tracing(TRUE); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + + clear_trace(); + set_tracing(true); } while (true) { @@ -1198,7 +1360,12 @@ void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai } 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)) { @@ -1236,7 +1403,7 @@ void MifareCIdent(){ cmd_send(CMD_ACK,isOK,0,0,0,0); } - // +// // DESFIRE // @@ -1246,10 +1413,10 @@ void Mifare_DES_Auth1(uint8_t arg0, uint8_t *datain){ uint8_t uid[10] = {0x00}; uint32_t cuid; - clear_trace(); 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);