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
parent d3a434b966
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_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

View file

@ -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);

View file

@ -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;