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)
This commit is contained in:
Philippe Teuwen 2024-10-14 15:32:21 +02:00
commit 85e463b222
3 changed files with 49 additions and 25 deletions

View file

@ -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_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 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 #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 + 256)
#define DMA_BUFFER_SIZE 512 #define DMA_BUFFER_SIZE 512

View file

@ -1045,13 +1045,19 @@ void MifareAcquireStaticEncryptedNonces(uint32_t flags, uint8_t *key) {
uint8_t uid[10] = {0x00}; uint8_t uid[10] = {0x00};
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00}; uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00};
uint8_t par_enc[1] = {0x00}; uint8_t par_enc[1] = {0x00};
// ((MIFARE_1K_MAXSECTOR + 1) * 2) * 9 < PM3_CMD_DATA_SIZE // ((MIFARE_1K_MAXSECTOR + 1) * 2) * 8 < PM3_CMD_DATA_SIZE
uint8_t buf[((MIFARE_1K_MAXSECTOR + 1) * 2) * 9] = {0x00}; // 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); uint64_t ui64Key = bytes_to_num(key, 6);
bool with_data = flags & 1; bool with_data = flags & 1;
uint32_t cuid = 0; uint32_t cuid = 0;
int16_t isOK = PM3_SUCCESS; int16_t isOK = PM3_SUCCESS;
uint16_t num_nonces = 0;
uint8_t cascade_levels = 0; uint8_t cascade_levels = 0;
bool have_uid = false; bool have_uid = false;
@ -1113,19 +1119,22 @@ void MifareAcquireStaticEncryptedNonces(uint32_t flags, uint8_t *key) {
isOK = PM3_ESOFT; isOK = PM3_ESOFT;
goto out; goto out;
}; };
if (with_data) { if ((with_data) && (keyType == 0)) {
if (blockNo < MIFARE_1K_MAXSECTOR * 4) { uint8_t data[16];
uint8_t data[16]; uint8_t blocks = 4;
for (uint16_t tb = blockNo; tb < blockNo + 4; tb++) { if (blockNo >= MIFARE_1K_MAXSECTOR * 4) {
memset(data, 0x00, sizeof(data)); // special RF08S advanced authentication blocks, let's dump in emulator just in case
int res = mifare_classic_readblock(pcs, tb, data); blocks = 8;
if (res == 1) { }
if (g_dbglevel >= DBG_ERROR) Dbprintf("AcquireStaticEncryptedNonces: Read error"); for (uint16_t tb = blockNo; tb < blockNo + blocks; tb++) {
isOK = PM3_ESOFT; memset(data, 0x00, sizeof(data));
goto out; int res = mifare_classic_readblock(pcs, tb, data);
} if (res == 1) {
emlSetMem_xt(data, tb, 1, 16); if (g_dbglevel >= DBG_ERROR) Dbprintf("AcquireStaticEncryptedNonces: Read error");
isOK = PM3_ESOFT;
goto out;
} }
emlSetMem_xt(data, tb, 1, 16);
} }
} }
// nested authentication // nested authentication
@ -1139,7 +1148,8 @@ void MifareAcquireStaticEncryptedNonces(uint32_t flags, uint8_t *key) {
crypto1_init(pcs, ui64Key); crypto1_init(pcs, ui64Key);
uint32_t nt = crypto1_word(pcs, nt_enc ^ cuid, 1) ^ nt_enc; uint32_t nt = crypto1_word(pcs, nt_enc ^ cuid, 1) ^ nt_enc;
// Dbprintf("Sec %2i key %i nT=%08x", sec, keyType + 4, nt); // 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 // send some crap to fail auth
uint8_t nack[] = {0x04}; uint8_t nack[] = {0x04};
ReaderTransmit(nack, sizeof(nack), NULL); ReaderTransmit(nack, sizeof(nack), NULL);
@ -1161,14 +1171,18 @@ void MifareAcquireStaticEncryptedNonces(uint32_t flags, uint8_t *key) {
isOK = PM3_ESOFT; isOK = PM3_ESOFT;
goto out; 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); nt_enc = bytes_to_num(receivedAnswer, 4);
uint8_t nt_par_err = ((((par_enc[0] >> 7) & 1) ^ oddparity8((nt_enc >> 24) & 0xFF)) << 3 | 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] >> 6) & 1) ^ oddparity8((nt_enc >> 16) & 0xFF)) << 2 |
(((par_enc[0] >> 5) & 1) ^ oddparity8((nt_enc >> 8) & 0xFF)) << 1 | (((par_enc[0] >> 5) & 1) ^ oddparity8((nt_enc >> 8) & 0xFF)) << 1 |
(((par_enc[0] >> 4) & 1) ^ oddparity8((nt_enc >> 0) & 0xFF))); (((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); // 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 // send some crap to fail auth
ReaderTransmit(nack, sizeof(nack), NULL); ReaderTransmit(nack, sizeof(nack), NULL);
} }
@ -1177,7 +1191,7 @@ out:
LED_C_OFF(); LED_C_OFF();
crypto1_deinit(pcs); crypto1_deinit(pcs);
LED_B_ON(); 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(); LED_B_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);

View file

@ -9924,16 +9924,22 @@ static int CmdHF14AMfISEN(const char *Cmd) {
uint8_t num_sectors = MIFARE_1K_MAXSECTOR + 1; uint8_t num_sectors = MIFARE_1K_MAXSECTOR + 1;
iso14a_fm11rf08s_nonces_with_data_t nonces_dump = {0}; iso14a_fm11rf08s_nonces_with_data_t nonces_dump = {0};
for (uint8_t sec = 0; sec < num_sectors; sec++) { for (uint8_t sec = 0; sec < num_sectors; sec++) {
memcpy(nonces_dump.nt[sec][0], resp.data.asBytes + ((sec * 2) * 9), 4); // reconstruct full nt
memcpy(nonces_dump.nt[sec][1], resp.data.asBytes + (((sec * 2) + 1) * 9), 4); 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++) { 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][0], resp.data.asBytes + ((sec * 2) * 8) + 4, 4);
memcpy(nonces_dump.nt_enc[sec][1], resp.data.asBytes + (((sec * 2) + 1) * 9) + 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++) { 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][0] = resp.data.asBytes[((sec * 2) * 8) + 2];
nonces_dump.par_err[sec][1] = resp.data.asBytes[(((sec * 2) + 1) * 9) + 8]; nonces_dump.par_err[sec][1] = resp.data.asBytes[(((sec * 2) + 1) * 8) + 2];
} }
if (collect_fm11rf08s_with_data) { if (collect_fm11rf08s_with_data) {
int bytes = MIFARE_1K_MAXBLOCK * MFBLOCK_SIZE; int bytes = MIFARE_1K_MAXBLOCK * MFBLOCK_SIZE;