Merge pull request #2697 from piotrva/move-keys-library-to-spiffs

Move keys library to spiffs
This commit is contained in:
Iceman 2024-12-28 19:21:35 +01:00 committed by GitHub
commit 2c72db9b54
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 173 additions and 243 deletions

View file

@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file.
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
## [unreleased][unreleased] ## [unreleased][unreleased]
- Changed flash-stored key dictionaries (Mifare, iClass, T55XX) and T55XX configurations to SPIFFS files (@piotrva)
- Changed `lf em 410x sim` to use default gap value of 0 and extended help (@piotrva) - Changed `lf em 410x sim` to use default gap value of 0 and extended help (@piotrva)
- Changed `hf 14a info` - now identifies MIAFRE Duox (@iceman1001) - Changed `hf 14a info` - now identifies MIAFRE Duox (@iceman1001)
- Added `hf iclass trbl` to perform tear-off attacks on iClass (@antiklesys) - Added `hf iclass trbl` to perform tear-off attacks on iClass (@antiklesys)

View file

@ -440,7 +440,41 @@ static void SendStatus(uint32_t wait) {
ModInfo(); ModInfo();
#ifdef WITH_FLASH #ifdef WITH_FLASH
Flashmem_print_info(); DbpString(_CYAN_("Flash memory dictionary loaded"));
uint32_t num = 0;
if (exists_in_spiffs(MF_KEYS_FILE)) {
num = size_in_spiffs(MF_KEYS_FILE) / MF_KEY_LENGTH;
} else {
num = 0;
}
if (num > 0) {
Dbprintf(" Mifare.................. "_YELLOW_("%u")" keys (spiffs: "_GREEN_("%s")")", num, MF_KEYS_FILE);
} else {
Dbprintf(" Mifare.................. "_RED_("%u")" keys (spiffs: "_RED_("%s")")", num, MF_KEYS_FILE);
}
if (exists_in_spiffs(T55XX_KEYS_FILE)) {
num = size_in_spiffs(T55XX_KEYS_FILE) / T55XX_KEY_LENGTH;
} else {
num = 0;
}
if (num > 0) {
Dbprintf(" T55xx................... "_YELLOW_("%u")" keys (spiffs: "_GREEN_("%s")")", num, T55XX_KEYS_FILE);
} else {
Dbprintf(" T55xx................... "_RED_("%u")" keys (spiffs: "_RED_("%s")")", num, T55XX_KEYS_FILE);
}
if (exists_in_spiffs(ICLASS_KEYS_FILE)) {
num = size_in_spiffs(ICLASS_KEYS_FILE) / ICLASS_KEY_LENGTH;
} else {
num = 0;
}
if (num > 0) {
Dbprintf(" iClass.................. "_YELLOW_("%u")" keys (spiffs: "_GREEN_("%s")")", num, ICLASS_KEYS_FILE);
} else {
Dbprintf(" iClass.................. "_RED_("%u")" keys (spiffs: "_RED_("%s")")", num, ICLASS_KEYS_FILE);
}
#endif #endif
DbpString(""); DbpString("");
reply_ng(CMD_STATUS, PM3_SUCCESS, NULL, 0); reply_ng(CMD_STATUS, PM3_SUCCESS, NULL, 0);
@ -2748,34 +2782,7 @@ static void PacketReceived(PacketCommandNG *packet) {
break; break;
} }
if (payload->startidx == DEFAULT_T55XX_KEYS_OFFSET_P(spi_flash_pages64k)) { if (payload->startidx == FLASH_MEM_SIGNATURE_OFFSET_P(spi_flash_pages64k)) {
Flash_CheckBusy(BUSY_TIMEOUT);
Flash_WriteEnable();
Flash_Erase4k(spi_flash_pages64k - 1, 0xC);
} else if (payload->startidx == DEFAULT_MF_KEYS_OFFSET_P(spi_flash_pages64k)) {
Flash_CheckBusy(BUSY_TIMEOUT);
Flash_WriteEnable();
Flash_Erase4k(spi_flash_pages64k - 1, 0x5);
Flash_CheckBusy(BUSY_TIMEOUT);
Flash_WriteEnable();
Flash_Erase4k(spi_flash_pages64k - 1, 0x6);
Flash_CheckBusy(BUSY_TIMEOUT);
Flash_WriteEnable();
Flash_Erase4k(spi_flash_pages64k - 1, 0x7);
Flash_CheckBusy(BUSY_TIMEOUT);
Flash_WriteEnable();
Flash_Erase4k(spi_flash_pages64k - 1, 0x8);
Flash_CheckBusy(BUSY_TIMEOUT);
Flash_WriteEnable();
Flash_Erase4k(spi_flash_pages64k - 1, 0x9);
Flash_CheckBusy(BUSY_TIMEOUT);
Flash_WriteEnable();
Flash_Erase4k(spi_flash_pages64k - 1, 0xA);
} else if (payload->startidx == DEFAULT_ICLASS_KEYS_OFFSET_P(spi_flash_pages64k)) {
Flash_CheckBusy(BUSY_TIMEOUT);
Flash_WriteEnable();
Flash_Erase4k(spi_flash_pages64k - 1, 0xB);
} else if (payload->startidx == FLASH_MEM_SIGNATURE_OFFSET_P(spi_flash_pages64k)) {
Flash_CheckBusy(BUSY_TIMEOUT); Flash_CheckBusy(BUSY_TIMEOUT);
Flash_WriteEnable(); Flash_WriteEnable();
Flash_Erase4k(spi_flash_pages64k - 1, 0xF); Flash_Erase4k(spi_flash_pages64k - 1, 0xF);

View file

@ -37,7 +37,8 @@
#include "protocols.h" #include "protocols.h"
#include "pmflash.h" #include "pmflash.h"
#include "flashmem.h" // persistence on flash #include "flashmem.h" // persistence on flash
#include "appmain.h" // print stack #include "spiffs.h" // spiffs
#include "appmain.h" // print stack
/* /*
Notes about EM4xxx timings. Notes about EM4xxx timings.
@ -324,31 +325,7 @@ void setT55xxConfig(uint8_t arg0, const t55xx_configurations_t *c) {
return; return;
} }
if (!FlashInit()) { if (SPIFFS_OK == rdv40_spiffs_write(T55XX_CONFIG_FILE, (uint8_t*)&T55xx_Timing, T55XX_CONFIG_LEN, RDV40_SPIFFS_SAFETY_SAFE)) {
BigBuf_free();
return;
}
uint8_t *buf = BigBuf_malloc(T55XX_CONFIG_LEN);
Flash_CheckBusy(BUSY_TIMEOUT);
uint16_t res = Flash_ReadDataCont(T55XX_CONFIG_OFFSET, buf, T55XX_CONFIG_LEN);
if (res == 0) {
FlashStop();
BigBuf_free();
return;
}
memcpy(buf, &T55xx_Timing, T55XX_CONFIG_LEN);
// delete old configuration
Flash_CheckBusy(BUSY_TIMEOUT);
Flash_WriteEnable();
Flash_Erase4k(3, 0xD);
// write new
res = Flash_Write(T55XX_CONFIG_OFFSET, buf, T55XX_CONFIG_LEN);
if (res == T55XX_CONFIG_LEN && g_dbglevel > 1) {
DbpString("T55XX Config save " _GREEN_("success")); DbpString("T55XX Config save " _GREEN_("success"));
} }
@ -363,15 +340,23 @@ t55xx_configurations_t *getT55xxConfig(void) {
void loadT55xxConfig(void) { void loadT55xxConfig(void) {
#ifdef WITH_FLASH #ifdef WITH_FLASH
if (!FlashInit()) { uint8_t *buf = BigBuf_malloc(T55XX_CONFIG_LEN);
uint32_t size = 0;
if (exists_in_spiffs(T55XX_CONFIG_FILE)) {
size = size_in_spiffs(T55XX_CONFIG_FILE);
}
if (size == 0) {
Dbprintf("Spiffs file: %s does not exists or empty.", T55XX_CONFIG_FILE);
BigBuf_free();
return; return;
} }
uint8_t *buf = BigBuf_malloc(T55XX_CONFIG_LEN); if (SPIFFS_OK != rdv40_spiffs_read(T55XX_CONFIG_FILE, buf, T55XX_CONFIG_LEN, RDV40_SPIFFS_SAFETY_SAFE)) {
Dbprintf("Spiffs file: %s cannot be read.", T55XX_CONFIG_FILE);
Flash_CheckBusy(BUSY_TIMEOUT); BigBuf_free();
uint16_t isok = Flash_ReadDataCont(T55XX_CONFIG_OFFSET, buf, T55XX_CONFIG_LEN); return;
FlashStop(); }
// verify read mem is actual data. // verify read mem is actual data.
uint8_t cntA = T55XX_CONFIG_LEN, cntB = T55XX_CONFIG_LEN; uint8_t cntA = T55XX_CONFIG_LEN, cntB = T55XX_CONFIG_LEN;
@ -380,6 +365,7 @@ void loadT55xxConfig(void) {
if (buf[i] == 0x00) cntB--; if (buf[i] == 0x00) cntB--;
} }
if (!cntA || !cntB) { if (!cntA || !cntB) {
Dbprintf("Spiffs file: %s does not malformed or empty.", T55XX_CONFIG_FILE);
BigBuf_free(); BigBuf_free();
return; return;
} }
@ -387,7 +373,7 @@ void loadT55xxConfig(void) {
if (buf[0] != 0xFF) // if not set for clear if (buf[0] != 0xFF) // if not set for clear
memcpy((uint8_t *)&T55xx_Timing, buf, T55XX_CONFIG_LEN); memcpy((uint8_t *)&T55xx_Timing, buf, T55XX_CONFIG_LEN);
if (isok == T55XX_CONFIG_LEN) { if (size == T55XX_CONFIG_LEN) {
if (g_dbglevel > 1) DbpString("T55XX Config load success"); if (g_dbglevel > 1) DbpString("T55XX Config load success");
} }
@ -2146,29 +2132,34 @@ void T55xx_ChkPwds(uint8_t flags, bool ledcontrol) {
#ifdef WITH_FLASH #ifdef WITH_FLASH
BigBuf_Clear_EM(); BigBuf_Clear_EM();
uint16_t isok = 0; uint32_t size = 0;
uint8_t counter[2] = {0x00, 0x00};
isok = Flash_ReadData(DEFAULT_T55XX_KEYS_OFFSET_P(spi_flash_pages64k), counter, sizeof(counter));
if (isok != sizeof(counter))
goto OUT;
pwd_count = (uint16_t)(counter[1] << 8 | counter[0]); if (exists_in_spiffs(T55XX_KEYS_FILE)) {
size = size_in_spiffs(T55XX_KEYS_FILE);
}
if (size == 0) {
Dbprintf("Spiffs file: %s does not exists or empty.", T55XX_KEYS_FILE);
goto OUT;
}
pwd_count = size / T55XX_KEY_LENGTH;
if (pwd_count == 0) if (pwd_count == 0)
goto OUT; goto OUT;
// since flash can report way too many pwds, we need to limit it. // since flash can report way too many pwds, we need to limit it.
// bigbuff EM size is determined by CARD_MEMORY_SIZE // bigbuff EM size is determined by CARD_MEMORY_SIZE
// a password is 4bytes. // a password is 4bytes.
uint16_t pwd_size_available = MIN(CARD_MEMORY_SIZE, pwd_count * 4); uint16_t pwd_size_available = MIN(CARD_MEMORY_SIZE, pwd_count * T55XX_KEY_LENGTH);
// adjust available pwd_count // adjust available pwd_count
pwd_count = pwd_size_available / 4; pwd_count = pwd_size_available / T55XX_KEY_LENGTH;
isok = Flash_ReadData(DEFAULT_T55XX_KEYS_OFFSET_P(spi_flash_pages64k) + 2, pwds, pwd_size_available); if (SPIFFS_OK == rdv40_spiffs_read_as_filetype(T55XX_KEYS_FILE, pwds, pwd_size_available, RDV40_SPIFFS_SAFETY_SAFE)) {
if (isok != pwd_size_available) if (g_dbglevel >= DBG_ERROR) Dbprintf("Loaded %u passwords from spiffs file: %s", pwd_count, T55XX_KEYS_FILE);
} else {
Dbprintf("Spiffs file: %s cannot be read.", T55XX_KEYS_FILE);
goto OUT; goto OUT;
}
Dbprintf("Password dictionary count " _YELLOW_("%d"), pwd_count);
#endif #endif

View file

@ -1900,31 +1900,36 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da
#ifdef WITH_FLASH #ifdef WITH_FLASH
if (use_flashmem) { if (use_flashmem) {
BigBuf_free(); BigBuf_free();
uint16_t isok = 0; uint32_t size = 0;
uint8_t size[2] = {0x00, 0x00}; if (exists_in_spiffs(MF_KEYS_FILE)) {
isok = Flash_ReadData(DEFAULT_MF_KEYS_OFFSET_P(spi_flash_pages64k), size, 2); size = size_in_spiffs(MF_KEYS_FILE);
if (isok != 2) }
if (size == 0) {
Dbprintf("Spiffs file: %s does not exists or empty.", MF_KEYS_FILE);
goto OUT; goto OUT;
}
keyCount = size[1] << 8 | size[0]; keyCount = size / MF_KEY_LENGTH;
if (keyCount == 0) if (keyCount == 0)
goto OUT; goto OUT;
// limit size of available for keys in bigbuff // limit size of available for keys in bigbuff
// a key is 6bytes // a key is 6bytes
uint16_t key_mem_available = MIN(BigBuf_get_size(), keyCount * 6); uint16_t key_mem_available = MIN(BigBuf_get_size(), keyCount * MF_KEY_LENGTH);
keyCount = key_mem_available / 6; keyCount = key_mem_available / MF_KEY_LENGTH;
datain = BigBuf_malloc(key_mem_available); datain = BigBuf_malloc(key_mem_available);
if (datain == NULL) if (datain == NULL)
goto OUT; goto OUT;
isok = Flash_ReadData(DEFAULT_MF_KEYS_OFFSET_P(spi_flash_pages64k) + 2, datain, key_mem_available); if (SPIFFS_OK == rdv40_spiffs_read_as_filetype(MF_KEYS_FILE, datain, keyCount * MF_KEY_LENGTH, RDV40_SPIFFS_SAFETY_SAFE)) {
if (isok != key_mem_available) if (g_dbglevel >= DBG_ERROR) Dbprintf("Loaded %u keys from spiffs file: %s", keyCount, MF_KEYS_FILE);
} else {
Dbprintf("Spiffs file: %s cannot be read.", MF_KEYS_FILE);
goto OUT; goto OUT;
}
} }
#endif #endif

View file

@ -17,6 +17,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include "cmdflashmem.h" #include "cmdflashmem.h"
#include <ctype.h> #include <ctype.h>
#include <string.h>
#include "cmdparser.h" // command_t #include "cmdparser.h" // command_t
#include "cliparser.h" #include "cliparser.h"
#include "pmflash.h" // rdv40validation_t #include "pmflash.h" // rdv40validation_t
@ -192,7 +193,7 @@ static int CmdFlashMemLoad(const char *Cmd) {
CLIParserInit(&ctx, "mem load", CLIParserInit(&ctx, "mem load",
"Loads binary file into flash memory on device\n" "Loads binary file into flash memory on device\n"
"Warning: mem area to be written must have been wiped first\n" "Warning: mem area to be written must have been wiped first\n"
"( this is already taken care when loading dictionaries )", "( dictionaries are serviced as files in spiffs so no wipe is needed )",
"mem load -f myfile -> upload file myfile values at default offset 0\n" "mem load -f myfile -> upload file myfile values at default offset 0\n"
"mem load -f myfile -o 1024 -> upload file myfile values at offset 1024\n" "mem load -f myfile -o 1024 -> upload file myfile values at offset 1024\n"
"mem load -f mfc_default_keys -m -> upload MFC keys\n" "mem load -f mfc_default_keys -m -> upload MFC keys\n"
@ -217,6 +218,7 @@ static int CmdFlashMemLoad(const char *Cmd) {
bool is_t55xx = arg_get_lit(ctx, 4); bool is_t55xx = arg_get_lit(ctx, 4);
int fnlen = 0; int fnlen = 0;
char filename[FILE_PATH_SIZE] = {0}; char filename[FILE_PATH_SIZE] = {0};
char spiffsDest[32] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 5), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); CLIParamStrToBuf(arg_get_str(ctx, 5), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
CLIParserFree(ctx); CLIParserFree(ctx);
@ -246,57 +248,46 @@ static int CmdFlashMemLoad(const char *Cmd) {
switch (d) { switch (d) {
case DICTIONARY_MIFARE: case DICTIONARY_MIFARE:
offset = DEFAULT_MF_KEYS_OFFSET_P(spi_flash_pages); keylen = MF_KEY_LENGTH;
keylen = 6; res = loadFileDICTIONARY(filename, data, &datalen, keylen, &keycount);
res = loadFileDICTIONARY(filename, data + 2, &datalen, keylen, &keycount);
if (res || !keycount) { if (res || !keycount) {
free(data); free(data);
return PM3_EFILE; return PM3_EFILE;
} }
// limited space on flash mem if (datalen > FLASH_MEM_MAX_SIZE_P(spi_flash_pages)) {
if (keycount > DEFAULT_MF_KEYS_MAX) { PrintAndLogEx(ERR, "error, filesize is larger than available memory");
keycount = DEFAULT_MF_KEYS_MAX; free(data);
datalen = keycount * keylen; return PM3_EOVFLOW;
} }
strcpy(spiffsDest, MF_KEYS_FILE);
data[0] = (keycount >> 0) & 0xFF;
data[1] = (keycount >> 8) & 0xFF;
datalen += 2;
break; break;
case DICTIONARY_T55XX: case DICTIONARY_T55XX:
offset = DEFAULT_T55XX_KEYS_OFFSET_P(spi_flash_pages); keylen = T55XX_KEY_LENGTH;
keylen = 4; res = loadFileDICTIONARY(filename, data, &datalen, keylen, &keycount);
res = loadFileDICTIONARY(filename, data + 2, &datalen, keylen, &keycount);
if (res || !keycount) { if (res || !keycount) {
free(data); free(data);
return PM3_EFILE; return PM3_EFILE;
} }
// limited space on flash mem if (datalen > FLASH_MEM_MAX_SIZE_P(spi_flash_pages)) {
if (keycount > DEFAULT_T55XX_KEYS_MAX) { PrintAndLogEx(ERR, "error, filesize is larger than available memory");
keycount = DEFAULT_T55XX_KEYS_MAX; free(data);
datalen = keycount * keylen; return PM3_EOVFLOW;
} }
strcpy(spiffsDest, T55XX_KEYS_FILE);
data[0] = (keycount >> 0) & 0xFF;
data[1] = (keycount >> 8) & 0xFF;
datalen += 2;
break; break;
case DICTIONARY_ICLASS: case DICTIONARY_ICLASS:
offset = DEFAULT_ICLASS_KEYS_OFFSET_P(spi_flash_pages); keylen = ICLASS_KEY_LENGTH;
res = loadFileDICTIONARY(filename, data + 2, &datalen, keylen, &keycount); res = loadFileDICTIONARY(filename, data, &datalen, keylen, &keycount);
if (res || !keycount) { if (res || !keycount) {
free(data); free(data);
return PM3_EFILE; return PM3_EFILE;
} }
// limited space on flash mem if (datalen > FLASH_MEM_MAX_SIZE_P(spi_flash_pages)) {
if (keycount > DEFAULT_ICLASS_KEYS_MAX) { PrintAndLogEx(ERR, "error, filesize is larger than available memory");
keycount = DEFAULT_ICLASS_KEYS_MAX; free(data);
datalen = keycount * keylen; return PM3_EOVFLOW;
} }
strcpy(spiffsDest, ICLASS_KEYS_FILE);
data[0] = (keycount >> 0) & 0xFF;
data[1] = (keycount >> 8) & 0xFF;
datalen += 2;
break; break;
case DICTIONARY_NONE: case DICTIONARY_NONE:
res = loadFile_safe(filename, ".bin", (void **)&data, &datalen); res = loadFile_safe(filename, ".bin", (void **)&data, &datalen);
@ -326,44 +317,57 @@ static int CmdFlashMemLoad(const char *Cmd) {
uint32_t bytes_sent = 0; uint32_t bytes_sent = 0;
uint32_t bytes_remaining = datalen; uint32_t bytes_remaining = datalen;
// we will treat dictionary files as spiffs files, so we need to handle this here
// fast push mode if (d != DICTIONARY_NONE) {
g_conn.block_after_ACK = true; res = flashmem_spiffs_load(spiffsDest, data, datalen);
if (res != PM3_SUCCESS) {
while (bytes_remaining > 0) { PrintAndLogEx(FAILED, "Failed writing passwrods to file %s", spiffsDest);
uint32_t bytes_in_packet = MIN(FLASH_MEM_BLOCK_SIZE, bytes_remaining);
clearCommandBuffer();
flashmem_old_write_t payload = {
.startidx = offset + bytes_sent,
.len = bytes_in_packet,
};
memcpy(payload.data, data + bytes_sent, bytes_in_packet);
SendCommandNG(CMD_FLASHMEM_WRITE, (uint8_t *)&payload, sizeof(payload));
bytes_remaining -= bytes_in_packet;
bytes_sent += bytes_in_packet;
PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_FLASHMEM_WRITE, &resp, 2000) == false) {
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
g_conn.block_after_ACK = false;
free(data); free(data);
return PM3_ETIMEOUT; return res;
}
PrintAndLogEx(SUCCESS, "Wrote "_GREEN_("%u")" passwords to file "_GREEN_("%s"), keycount, spiffsDest);
SendCommandNG(CMD_SPIFFS_UNMOUNT, NULL, 0);
SendCommandNG(CMD_SPIFFS_MOUNT, NULL, 0);
} else {
// fast push mode
g_conn.block_after_ACK = true;
while (bytes_remaining > 0) {
uint32_t bytes_in_packet = MIN(FLASH_MEM_BLOCK_SIZE, bytes_remaining);
clearCommandBuffer();
flashmem_old_write_t payload = {
.startidx = offset + bytes_sent,
.len = bytes_in_packet,
};
memcpy(payload.data, data + bytes_sent, bytes_in_packet);
SendCommandNG(CMD_FLASHMEM_WRITE, (uint8_t *)&payload, sizeof(payload));
bytes_remaining -= bytes_in_packet;
bytes_sent += bytes_in_packet;
PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_FLASHMEM_WRITE, &resp, 2000) == false) {
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
g_conn.block_after_ACK = false;
free(data);
return PM3_ETIMEOUT;
}
if (resp.status != PM3_SUCCESS) {
g_conn.block_after_ACK = false;
PrintAndLogEx(FAILED, "Flash write fail [offset %u]", bytes_sent);
free(data);
return PM3_EFLASH;
}
} }
if (resp.status != PM3_SUCCESS) { g_conn.block_after_ACK = false;
g_conn.block_after_ACK = false; PrintAndLogEx(SUCCESS, "Wrote "_GREEN_("%zu")" bytes to offset "_GREEN_("%u"), datalen, offset);
PrintAndLogEx(FAILED, "Flash write fail [offset %u]", bytes_sent);
free(data);
return PM3_EFLASH;
}
} }
g_conn.block_after_ACK = false;
free(data); free(data);
PrintAndLogEx(SUCCESS, "Wrote "_GREEN_("%zu")" bytes to offset "_GREEN_("%u"), datalen, offset);
return PM3_SUCCESS; return PM3_SUCCESS;
} }

View file

@ -273,7 +273,9 @@ int mf_check_keys_fast_ex(uint8_t sectorsCnt, uint8_t firstChunk, uint8_t lastCh
// max timeout for one chunk of 85keys, 60*3sec = 180seconds // max timeout for one chunk of 85keys, 60*3sec = 180seconds
// s70 with 40*2 keys to check, 80*85 = 6800 auth. // s70 with 40*2 keys to check, 80*85 = 6800 auth.
// takes about 97s, still some margin before abort // takes about 97s, still some margin before abort
if (timeout > 180) { // timeout = 180 => ~360s @ Mifare Classic 1k @ ~2300 keys in dict
// ~2300 keys @ Mifare Classic 1k => ~620s
if (timeout > 60*12) {
PrintAndLogEx(WARNING, "\nNo response from Proxmark3. Aborting..."); PrintAndLogEx(WARNING, "\nNo response from Proxmark3. Aborting...");
return PM3_ETIMEOUT; return PM3_ETIMEOUT;
} }

View file

@ -383,43 +383,6 @@ void Flashmem_print_status(void) {
FlashStop(); FlashStop();
} }
void Flashmem_print_info(void) {
if (!FlashInit()) return;
DbpString(_CYAN_("Flash memory dictionary loaded"));
// load dictionary offsets.
uint8_t keysum[2];
uint16_t num;
Flash_CheckBusy(BUSY_TIMEOUT);
uint16_t isok = Flash_ReadDataCont(DEFAULT_MF_KEYS_OFFSET_P(spi_flash_pages64k), keysum, 2);
if (isok == 2) {
num = ((keysum[1] << 8) | keysum[0]);
if (num != 0xFFFF && num != 0x0)
Dbprintf(" Mifare.................. "_YELLOW_("%u")" / "_GREEN_("%u")" keys", num, DEFAULT_MF_KEYS_MAX);
}
Flash_CheckBusy(BUSY_TIMEOUT);
isok = Flash_ReadDataCont(DEFAULT_T55XX_KEYS_OFFSET_P(spi_flash_pages64k), keysum, 2);
if (isok == 2) {
num = ((keysum[1] << 8) | keysum[0]);
if (num != 0xFFFF && num != 0x0)
Dbprintf(" T55x7................... "_YELLOW_("%u")" / "_GREEN_("%u")" keys", num, DEFAULT_T55XX_KEYS_MAX);
}
Flash_CheckBusy(BUSY_TIMEOUT);
isok = Flash_ReadDataCont(DEFAULT_ICLASS_KEYS_OFFSET_P(spi_flash_pages64k), keysum, 2);
if (isok == 2) {
num = ((keysum[1] << 8) | keysum[0]);
if (num != 0xFFFF && num != 0x0)
Dbprintf(" iClass.................. "_YELLOW_("%u")" / "_GREEN_("%u")" keys", num, DEFAULT_ICLASS_KEYS_MAX);
}
FlashStop();
}
bool FlashDetect(void) { bool FlashDetect(void) {
flash_device_type_t flash_data = {0}; flash_device_type_t flash_data = {0};
bool ret = false; bool ret = false;

View file

@ -134,7 +134,6 @@ uint16_t Flash_Write(uint32_t address, uint8_t *in, uint16_t len);
uint16_t Flash_WriteData(uint32_t address, uint8_t *in, uint16_t len); uint16_t Flash_WriteData(uint32_t address, uint8_t *in, uint16_t len);
uint16_t Flash_WriteDataCont(uint32_t address, uint8_t *in, uint16_t len); uint16_t Flash_WriteDataCont(uint32_t address, uint8_t *in, uint16_t len);
void Flashmem_print_status(void); void Flashmem_print_status(void);
void Flashmem_print_info(void);
typedef struct { typedef struct {
uint8_t manufacturer_id; uint8_t manufacturer_id;

View file

@ -37,20 +37,20 @@ Therefore a flash address can be interpreted as such:
Page 0: Page 0:
* available for user data * available for user data
* to dump it: `mem dump -f page0_dump -o 0 -l 65536` * to dump it: `mem dump -f page0_dump -o 0 -l 65536`
* to erase it: `mem wipe p 0` * to erase it: `mem wipe -p 0`
Page 1: Page 1:
* available for user data * available for user data
* to dump it: `mem dump -f page1_dump -o 65536 -l 65536` * to dump it: `mem dump -f page1_dump -o 65536 -l 65536`
* to erase it: `mem wipe p 1` * to erase it: `mem wipe -p 1`
Page 2: Page 2:
* available for user data * available for user data
* to dump it: `mem dump -f page2_dump -o 131072 -l 65536` * to dump it: `mem dump -f page2_dump -o 131072 -l 65536`
* to erase it: `mem wipe p 2` * to erase it: `mem wipe -p 2`
Page 3: Page 3:
* used by Proxmark3 RDV4 specific functions: flash signature and keys dictionaries, see below for details * used by Proxmark3 RDV4 specific functions: flash signature, see below for details
* to dump it: `mem dump -f page3_dump -o 196608 -l 65536` * to dump it: `mem dump -f page3_dump -o 196608 -l 65536`
* to erase it: * to erase it:
* **Beware** it will erase your flash signature so better to back it up first as you won't be able to regenerate it by yourself! * **Beware** it will erase your flash signature so better to back it up first as you won't be able to regenerate it by yourself!
@ -62,22 +62,6 @@ Page 3:
Page3 is used as follows by the Proxmark3 RDV4 firmware: Page3 is used as follows by the Proxmark3 RDV4 firmware:
* **MF_KEYS**
* offset: page 3 sector 5 (0x5) @ 3*0x10000+5*0x1000=0x35000
* length: 6 sectors
* **ICLASS_KEYS**
* offset: page 3 sector 11 (0xB) @ 3*0x10000+11*0x1000=0x3B000
* length: 1 sector
* **T55XX_KEYS**
* offset: page 3 sector 12 (0xC) @ 3*0x10000+12*0x1000=0x3C000
* length: 1 sector
* **T55XX_CONFIG**
* offset: page 3 sector 13 (0xD) @ 3*0x10000+13*0x1000=0x3D000
* length: 1 sector (actually only a few bytes are used to store `t55xx_config` structure)
* **RSA SIGNATURE**, see below for details * **RSA SIGNATURE**, see below for details
* offset: page 3 sector 15 (0xF) offset 0xF7F @ 3*0x10000+15*0x1000+0xF7F=0x3FF7F (decimal 262015) * offset: page 3 sector 15 (0xF) offset 0xF7F @ 3*0x10000+15*0x1000+0xF7F=0x3FF7F (decimal 262015)
* length: 128 bytes * length: 128 bytes

View file

@ -26,9 +26,6 @@
// //
// 0x3F000 - 1 4kb sector = signature // 0x3F000 - 1 4kb sector = signature
// 0x3E000 - 1 4kb sector = settings // 0x3E000 - 1 4kb sector = settings
// 0x3D000 - 1 4kb sector = default T55XX keys dictionary
// 0x3B000 - 1 4kb sector = default ICLASS keys dictionary
// 0x35000 - 6 4kb sectors = default MFC keys dictionary
// //
#ifndef FLASH_MEM_BLOCK_SIZE #ifndef FLASH_MEM_BLOCK_SIZE
# define FLASH_MEM_BLOCK_SIZE 256 # define FLASH_MEM_BLOCK_SIZE 256
@ -68,42 +65,19 @@
# define T55XX_CONFIG_LEN sizeof( t55xx_configurations_t ) # define T55XX_CONFIG_LEN sizeof( t55xx_configurations_t )
#endif #endif
#ifndef T55XX_CONFIG_OFFSET #define T55XX_CONFIG_FILE "cfg_t55xx.bin"
# define T55XX_CONFIG_OFFSET (FLASH_MEM_MAX_4K_SECTOR - 0x2000)
#endif
#ifndef T55XX_CONFIG_OFFSET_P
# define T55XX_CONFIG_OFFSET_P(p64k) (FLASH_MEM_MAX_4K_SECTOR_P(p64k) - 0x2000)
#endif
// Reserved space for T55XX PWD = 4 kb // T55XX PWD stored in spiffs
#ifndef DEFAULT_T55XX_KEYS_OFFSET #define T55XX_KEYS_FILE "dict_t55xx.bin"
# define DEFAULT_T55XX_KEYS_LEN (0x1000) #define T55XX_KEY_LENGTH 4
# define DEFAULT_T55XX_KEYS_OFFSET (T55XX_CONFIG_OFFSET - DEFAULT_T55XX_KEYS_LEN)
# define DEFAULT_T55XX_KEYS_MAX ((DEFAULT_T55XX_KEYS_LEN - 2) / 4)
#endif
#ifndef DEFAULT_T55XX_KEYS_OFFSET_P
# define DEFAULT_T55XX_KEYS_OFFSET_P(p64k) (T55XX_CONFIG_OFFSET_P(p64k) - DEFAULT_T55XX_KEYS_LEN)
#endif
// Reserved space for iClass keys = 4 kb // iClass keys stored in spiffs
#ifndef DEFAULT_ICLASS_KEYS_OFFSET #define ICLASS_KEYS_FILE "dict_iclass.bin"
# define DEFAULT_ICLASS_KEYS_LEN (0x1000) #define ICLASS_KEY_LENGTH 8
# define DEFAULT_ICLASS_KEYS_OFFSET (DEFAULT_T55XX_KEYS_OFFSET - DEFAULT_ICLASS_KEYS_LEN)
# define DEFAULT_ICLASS_KEYS_MAX ((DEFAULT_ICLASS_KEYS_LEN - 2) / 8)
#endif
#ifndef DEFAULT_ICLASS_KEYS_OFFSET_P
# define DEFAULT_ICLASS_KEYS_OFFSET_P(p64k) (DEFAULT_T55XX_KEYS_OFFSET_P(p64k) - DEFAULT_ICLASS_KEYS_LEN)
#endif
// Reserved space for MIFARE Keys = 24 kb // Mifare keys stored in spiffs
#ifndef DEFAULT_MF_KEYS_OFFSET #define MF_KEYS_FILE "dict_mf.bin"
# define DEFAULT_MF_KEYS_LEN (0x6000) #define MF_KEY_LENGTH 6
# define DEFAULT_MF_KEYS_OFFSET (DEFAULT_ICLASS_KEYS_OFFSET - DEFAULT_MF_KEYS_LEN)
# define DEFAULT_MF_KEYS_MAX ((DEFAULT_MF_KEYS_LEN - 2) / 6)
#endif
#ifndef DEFAULT_MF_KEYS_OFFSET_P
# define DEFAULT_MF_KEYS_OFFSET_P(p64k) (DEFAULT_ICLASS_KEYS_OFFSET_P(p64k) - DEFAULT_MF_KEYS_LEN)
#endif
// RDV40, validation structure to help identifying that client/firmware is talking with RDV40 // RDV40, validation structure to help identifying that client/firmware is talking with RDV40
typedef struct { typedef struct {