From 85e463b2224f0826bc6fce08eaf4a6c18f9d74f4 Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Mon, 14 Oct 2024 15:32:21 +0200 Subject: [PATCH] hf mf isen --collect_fm11rf08s_with_data optimizations: * do not read data blocks twice * store data in the emulator memory, to be prepared for standalone modes and to not allocate large buffer on stack * 9->8 bytes to store each key data in emulator memory (half_nt + nt_par_err + flag + nt_enc) --- armsrc/BigBuf.h | 4 ++++ armsrc/mifarecmd.c | 52 ++++++++++++++++++++++++++++---------------- client/src/cmdhfmf.c | 18 ++++++++++----- 3 files changed, 49 insertions(+), 25 deletions(-) diff --git a/armsrc/BigBuf.h b/armsrc/BigBuf.h index f73af3818..2e905a45c 100644 --- a/armsrc/BigBuf.h +++ b/armsrc/BigBuf.h @@ -26,6 +26,10 @@ #define MAX_MIFARE_FRAME_SIZE 18 // biggest Mifare frame is answer to a read (one block = 16 Bytes) + 2 Bytes CRC #define MAX_MIFARE_PARITY_SIZE 3 // need 18 parity bits for the 18 Byte above. 3 Bytes are enough to store these #define CARD_MEMORY_SIZE 4096 +// For now we're storing FM11RF08S nonces in the upper 1k of CARD_MEMORY_SIZE +// but we might have to allocate extra space if one day we've to support sth like a FM11RF32S +#define CARD_MEMORY_RF08S_OFFSET 1024 + //#define DMA_BUFFER_SIZE (512 + 256) #define DMA_BUFFER_SIZE 512 diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index 1f59f45ca..be6c63e6d 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -1045,13 +1045,19 @@ void MifareAcquireStaticEncryptedNonces(uint32_t flags, uint8_t *key) { uint8_t uid[10] = {0x00}; uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00}; uint8_t par_enc[1] = {0x00}; - // ((MIFARE_1K_MAXSECTOR + 1) * 2) * 9 < PM3_CMD_DATA_SIZE - uint8_t buf[((MIFARE_1K_MAXSECTOR + 1) * 2) * 9] = {0x00}; + // ((MIFARE_1K_MAXSECTOR + 1) * 2) * 8 < PM3_CMD_DATA_SIZE + // we're storing nonces in emulator memory at CARD_MEMORY_RF08S_OFFSET + // one sector data in one 16-byte block with for each keytype: + // uint16_t nt_first_half (as we can reconstruct the other half) + // uint8_t nt_par_err + // uint8_t flag: if 0xAA and key=000000000000 it means we don't know the key yet + // uint32_t nt_enc + // buf: working buffer to prepare those "blocks" + uint8_t buf[MIFARE_BLOCK_SIZE] = {0x00}; uint64_t ui64Key = bytes_to_num(key, 6); bool with_data = flags & 1; uint32_t cuid = 0; int16_t isOK = PM3_SUCCESS; - uint16_t num_nonces = 0; uint8_t cascade_levels = 0; bool have_uid = false; @@ -1113,19 +1119,22 @@ void MifareAcquireStaticEncryptedNonces(uint32_t flags, uint8_t *key) { isOK = PM3_ESOFT; goto out; }; - if (with_data) { - if (blockNo < MIFARE_1K_MAXSECTOR * 4) { - uint8_t data[16]; - for (uint16_t tb = blockNo; tb < blockNo + 4; tb++) { - memset(data, 0x00, sizeof(data)); - int res = mifare_classic_readblock(pcs, tb, data); - if (res == 1) { - if (g_dbglevel >= DBG_ERROR) Dbprintf("AcquireStaticEncryptedNonces: Read error"); - isOK = PM3_ESOFT; - goto out; - } - emlSetMem_xt(data, tb, 1, 16); + if ((with_data) && (keyType == 0)) { + uint8_t data[16]; + uint8_t blocks = 4; + if (blockNo >= MIFARE_1K_MAXSECTOR * 4) { + // special RF08S advanced authentication blocks, let's dump in emulator just in case + blocks = 8; + } + for (uint16_t tb = blockNo; tb < blockNo + blocks; tb++) { + memset(data, 0x00, sizeof(data)); + int res = mifare_classic_readblock(pcs, tb, data); + if (res == 1) { + if (g_dbglevel >= DBG_ERROR) Dbprintf("AcquireStaticEncryptedNonces: Read error"); + isOK = PM3_ESOFT; + goto out; } + emlSetMem_xt(data, tb, 1, 16); } } // nested authentication @@ -1139,7 +1148,8 @@ void MifareAcquireStaticEncryptedNonces(uint32_t flags, uint8_t *key) { crypto1_init(pcs, ui64Key); uint32_t nt = crypto1_word(pcs, nt_enc ^ cuid, 1) ^ nt_enc; // Dbprintf("Sec %2i key %i nT=%08x", sec, keyType + 4, nt); - num_to_bytes(nt, 4, buf + (((sec * 2) + keyType) * 9)); + // store nt (first half) + num_to_bytes(nt >> 16, 2, buf + (keyType * 8)); // send some crap to fail auth uint8_t nack[] = {0x04}; ReaderTransmit(nack, sizeof(nack), NULL); @@ -1161,14 +1171,18 @@ void MifareAcquireStaticEncryptedNonces(uint32_t flags, uint8_t *key) { isOK = PM3_ESOFT; goto out; } - memcpy(buf + (((sec * 2) + keyType) * 9) + 4, receivedAnswer, 4); + // store nt_enc + memcpy(buf + (keyType * 8) + 4, receivedAnswer, 4); nt_enc = bytes_to_num(receivedAnswer, 4); uint8_t nt_par_err = ((((par_enc[0] >> 7) & 1) ^ oddparity8((nt_enc >> 24) & 0xFF)) << 3 | (((par_enc[0] >> 6) & 1) ^ oddparity8((nt_enc >> 16) & 0xFF)) << 2 | (((par_enc[0] >> 5) & 1) ^ oddparity8((nt_enc >> 8) & 0xFF)) << 1 | (((par_enc[0] >> 4) & 1) ^ oddparity8((nt_enc >> 0) & 0xFF))); // Dbprintf("Sec %2i key %i {nT}=%02x%02x%02x%02x perr=%x", sec, keyType, receivedAnswer[0], receivedAnswer[1], receivedAnswer[2], receivedAnswer[3], nt_par_err); - buf[(((sec * 2) + keyType) * 9) + 8] = nt_par_err; + // store nt_par_err + buf[(keyType * 8) + 2] = nt_par_err; + buf[(keyType * 8) + 3] = 0xAA; // flag to tell we don't know the key yet + emlSetMem_xt(buf, (CARD_MEMORY_RF08S_OFFSET / MIFARE_BLOCK_SIZE) + sec, 1, MIFARE_BLOCK_SIZE); // send some crap to fail auth ReaderTransmit(nack, sizeof(nack), NULL); } @@ -1177,7 +1191,7 @@ out: LED_C_OFF(); crypto1_deinit(pcs); LED_B_ON(); - reply_old(CMD_ACK, isOK, cuid, num_nonces, buf, sizeof(buf)); + reply_old(CMD_ACK, isOK, cuid, 0, BigBuf_get_EM_addr() + CARD_MEMORY_RF08S_OFFSET, MIFARE_BLOCK_SIZE * (MIFARE_1K_MAXSECTOR + 1)); LED_B_OFF(); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c index 32705409a..be3e3fa23 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -9924,16 +9924,22 @@ static int CmdHF14AMfISEN(const char *Cmd) { uint8_t num_sectors = MIFARE_1K_MAXSECTOR + 1; iso14a_fm11rf08s_nonces_with_data_t nonces_dump = {0}; for (uint8_t sec = 0; sec < num_sectors; sec++) { - memcpy(nonces_dump.nt[sec][0], resp.data.asBytes + ((sec * 2) * 9), 4); - memcpy(nonces_dump.nt[sec][1], resp.data.asBytes + (((sec * 2) + 1) * 9), 4); + // reconstruct full nt + uint32_t nt; + nt = bytes_to_num(resp.data.asBytes + ((sec * 2) * 8), 2); + nt = nt << 16 | prng_successor(nt, 16); + num_to_bytes(nt, 4, nonces_dump.nt[sec][0]); + nt = bytes_to_num(resp.data.asBytes + (((sec * 2) + 1) * 8), 2); + nt = nt << 16 | prng_successor(nt, 16); + num_to_bytes(nt, 4, nonces_dump.nt[sec][1]); } for (uint8_t sec = 0; sec < num_sectors; sec++) { - memcpy(nonces_dump.nt_enc[sec][0], resp.data.asBytes + ((sec * 2) * 9) + 4, 4); - memcpy(nonces_dump.nt_enc[sec][1], resp.data.asBytes + (((sec * 2) + 1) * 9) + 4, 4); + memcpy(nonces_dump.nt_enc[sec][0], resp.data.asBytes + ((sec * 2) * 8) + 4, 4); + memcpy(nonces_dump.nt_enc[sec][1], resp.data.asBytes + (((sec * 2) + 1) * 8) + 4, 4); } for (uint8_t sec = 0; sec < num_sectors; sec++) { - nonces_dump.par_err[sec][0] = resp.data.asBytes[((sec * 2) * 9) + 8]; - nonces_dump.par_err[sec][1] = resp.data.asBytes[(((sec * 2) + 1) * 9) + 8]; + nonces_dump.par_err[sec][0] = resp.data.asBytes[((sec * 2) * 8) + 2]; + nonces_dump.par_err[sec][1] = resp.data.asBytes[(((sec * 2) + 1) * 8) + 2]; } if (collect_fm11rf08s_with_data) { int bytes = MIFARE_1K_MAXBLOCK * MFBLOCK_SIZE;