diff --git a/CHANGELOG.md b/CHANGELOG.md index fed588c8f..f4553467a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac ## [unreleased][unreleased] - Automatically set maximum read/write block when using predefined types in `hf_mf_ultimatecard` script (@piotrva) +- Changed SPI flash detection to calculate the size instead of table lookup, updated spi_flash_decode.py script with more ICs (@ANTodorov) - Fixed `hf/lf tune` segfault when called from script (@doegox) - Added option to set and get maximum read/write block number using `hf_mf_ultimatecard` script (@piotrva) - Added JEDEC information for SPI flash W25Q64JV (@ANTodorov) diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index 2eed2ca5c..9820d19a2 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -3482,7 +3482,7 @@ void MifareGen3Blk(uint8_t block_len, uint8_t *block) { retval = PM3_ESOFT; goto OUT; } - cmd[ofs] = block_len < card_info->uidlen ? card_info->sak : cmd[ofs]; + cmd[ofs] = block_len <= card_info->uidlen ? card_info->sak : cmd[ofs]; ofs++; cmd[ofs++] = card_info->atqa[0]; cmd[ofs++] = card_info->atqa[1]; diff --git a/client/pyscripts/spi_flash_decode.py b/client/pyscripts/spi_flash_decode.py index 0f125844b..2a89f57af 100644 --- a/client/pyscripts/spi_flash_decode.py +++ b/client/pyscripts/spi_flash_decode.py @@ -12,62 +12,118 @@ except ModuleNotFoundError: return str(s) spi = { + 0x68:{ + "manufacturer": "Boya", + "jedec" : { + 0x40: { + 0x15: { + "part": "BY25Q16BS", + "size": "16mbits", + "sizeB": "2MB", + }, + }, + }, + }, 0x85:{ "manufacturer": "Puya", - 0x60: { - 0x15: { - "part": "P25Q16H", - "size": "16mbits", - "sizeB": "2MB", + "jedec" : { + 0x60: { + 0x15: { + "part": "P25Q16H", + "size": "16mbits", + "sizeB": "2MB", + }, + 0x16: { + "part": "P25Q32H", + "size": "32mbits", + "sizeB": "4MB", + }, + 0x17: { + "part": "P25Q64H", + "size": "64mbits", + "sizeB": "8MB", + }, }, }, }, 0xEF:{ "manufacturer": "Winbond", - 0x30: { - 0x11: { - "part": "W25X10BV", - "size": "1mbits", - "sizeB": "128KB", + "jedec" : { + 0x30: { + 0x11: { + "part": "W25X10BV", + "size": "1mbits", + "sizeB": "128KB", + }, + 0x12: { + "part": "W25X20BV", + "size": "2mbits", + "sizeB": "256KB", + }, + 0x13: { + "part": "W25X40BV", + "size": "4mbits", + "sizeB": "512KB", + }, }, - 0x12: { - "part": "W25X20BV", - "size": "2mbits", - "sizeB": "256KB", + 0x40: { + 0x12: { + "part": "W25Q20BV", + "size": "2mbits", + "sizeB": "256KB", + }, + 0x13: { + "part": "W25Q40BV", + "size": "4mbits", + "sizeB": "512KB", + }, + 0x14: { + "part": "W25Q80BV", + "size": "8mbits", + "sizeB": "1MB", + }, + 0x15: { + "part": "W25Q16BV", + "size": "16mbits", + "sizeB": "2MB", + }, + 0x16: { + "part": "W25Q32BV", + "size": "32mbits", + "sizeB": "4MB", + }, + 0x17: { + "part": "W25Q64BV", + "size": "64mbits", + "sizeB": "8MB", + }, }, - 0x13: { - "part": "W25X40BV", - "size": "4mbits", - "sizeB": "512KB", - }, - }, - 0x40: { - 0x13: { - "part": "W25Q40BV", - "size": "4mbits", - "sizeB": "512KB", - }, - 0x14: { - "part": "W25Q80BV", - "size": "8mbits", - "sizeB": "1MB", - }, - 0x15: { - "part": "W25Q16BV", - "size": "16mbits", - "sizeB": "2MB", - }, - 0x16: { - "part": "W25Q32BV", - "size": "32mbits", - "sizeB": "4MB", - }, - }, - 0x70: { - 0x22: { - "part": "W25Q02JV-IM", - "size": "2mbits", - "sizeB": "256KB", + 0x70: { + 0x14: { + "part": "W25Q80JV", + "size": "8mbits", + "sizeB": "1MB", + }, + 0x15: { + "part": "W25Q16JV", + "size": "16mbits", + "sizeB": "2MB", + }, + 0x16: { + "part": "W25Q32JV", + "size": "32mbits", + "sizeB": "4MB", + }, + 0x17: { + "part": "W25Q64JV", + "size": "64mbits", + "sizeB": "8MB", + }, + 0x22: { + "part": "W25Q02JV-IM", + "size": "2mbits", + "sizeB": "256KB", + }, }, }, }, @@ -90,16 +146,16 @@ for line in p.grabbed_output.split('\n'): did_h = did >> 8 did_l = did & 0xff t = None - + print(f"\n JEDEC ID....... 0x{mid:X} / 0x{did:X}") if mid in spi: mfr = spi[mid]['manufacturer'] - if did_h in spi[mid]: + if did_h in spi[mid]['jedec']: - if did_l in spi[mid][did_h]: + if did_l in spi[mid]['jedec'][did_h]: - t = spi[mid][did_h][did_l] + t = spi[mid]['jedec'][did_h][did_l] print("\n Manufacturer... " + color(f"{mfr}", fg="green") + "\n Device......... " + color(f"{t['part']}", fg="green") + "\n Size........... " + color(f"{t['size']} ({t['sizeB']})", fg="yellow") diff --git a/client/resources/aid_desfire.json b/client/resources/aid_desfire.json index 53cb47992..8ecd18a6e 100644 --- a/client/resources/aid_desfire.json +++ b/client/resources/aid_desfire.json @@ -1065,10 +1065,10 @@ }, { "AID": "DD00DD", - "Vendor": "Regional Transporation District (RTD) via masabi justride", + "Vendor": "Regional Transporation District (RTD) via Masabi Ltd", "Country": "US", "Name": "MyRide Card (DEN)", - "Description": "DEN MyRide Card", + "Description": "DEN MyRide Card; Masabi Justride Tap and Ride DESFire Smartcard", "Type": "transport" }, { diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c index 2bfd6a020..e61a6a7e9 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -7202,7 +7202,8 @@ static int CmdHf14AGen3Block(const char *Cmd) { " - You can specify part of manufacturer block as\n" " 4/7-bytes for UID change only\n" "\n" - "NOTE: BCC, SAK, ATQA will be calculated automatically" + "NOTE: BCC and ATQA will be calculated automatically\n" + "SAK will be automatically set to default values if not specified" , "hf mf gen3blk --> print current data\n" "hf mf gen3blk -d 01020304 --> set 4 byte uid\n" diff --git a/client/src/cmdlfhitaghts.c b/client/src/cmdlfhitaghts.c index d1af178dd..933427ec8 100644 --- a/client/src/cmdlfhitaghts.c +++ b/client/src/cmdlfhitaghts.c @@ -444,6 +444,96 @@ static int CmdLFHitagSRead(const char *Cmd) { return PM3_SUCCESS; } +static int CmdLFHitagSDump(const char *Cmd) { + + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf hitag hts dump", + "Read all Hitag S memory and save to file\n" + " Crypto mode: \n" + " - key format ISK high + ISK low\n" + " - default key 4F4E4D494B52 (ONMIKR)\n\n" + " 8268/8310 password mode: \n" + " - default password BBDD3399\n", + "lf hitag hts dump --82xx -k BBDD3399 -> pwd mode\n" + "lf hitag hts dump --crypto -> use def crypto\n" + "lf hitag hts dump -k 4F4E4D494B52 -> crypto mode\n" + "lf hitag hts dump --nrar 0102030411223344\n" + ); + + void *argtable[] = { + arg_param_begin, + arg_lit0("8", "82xx", "8268/8310 mode"), + arg_str0(NULL, "nrar", "", "nonce / answer writer, 8 hex bytes"), + arg_lit0(NULL, "crypto", "crypto mode"), + arg_str0("k", "key", "", "pwd or key, 4 or 6 hex bytes"), + arg_int0("m", "mode", "", "response protocol mode. 0 (Standard 00110), 1 (Advanced 11000), 2 (Advanced 11001), 3 (Fast Advanced 11010) (def: 3)"), + arg_str0("f", "file", "", "specify file name"), + arg_lit0(NULL, "ns", "no save to file"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + lf_hitag_data_t packet; + memset(&packet, 0, sizeof(packet)); + + if (process_hitags_common_args(ctx, &packet) < 0) { + CLIParserFree(ctx); + return PM3_EINVARG; + } + + int fnlen = 0; + char filename[FILE_PATH_SIZE] = {0}; + CLIParamStrToBuf(arg_get_str(ctx, 6), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); + + bool nosave = arg_get_lit(ctx, 7); + CLIParserFree(ctx); + + // read all pages + packet.page = 0; + packet.page_count = 0; + + clearCommandBuffer(); + SendCommandNG(CMD_LF_HITAGS_READ, (uint8_t *) &packet, sizeof(packet)); + + PacketResponseNG resp; + if (WaitForResponseTimeout(CMD_LF_HITAGS_READ, &resp, 5000) == false) { + PrintAndLogEx(WARNING, "timeout while waiting for reply."); + return PM3_ETIMEOUT; + } + + if (resp.status != PM3_SUCCESS) { + print_error(resp.reason); + return PM3_ESOFT; + } + + lf_hts_read_response_t *card = (lf_hts_read_response_t *)resp.data.asBytes; + + const int hts_mem_sizes[] = {1, 8, 64, 64}; + int mem_size = hts_mem_sizes[card->config_page.s.MEMT] * HITAGS_PAGE_SIZE; + + hitags_config_t config = card->config_page.s; + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------"); + hitags_config_print(config); + + if (nosave) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "Called with no save option"); + PrintAndLogEx(NORMAL, ""); + return PM3_SUCCESS; + } + + if (fnlen < 1) { + char *fptr = filename; + fptr += snprintf(filename, sizeof(filename), "lf-hitags-"); + FillFileNameByUID(fptr, card->pages[HITAGS_UID_PADR], "-dump", HITAGS_PAGE_SIZE); + } + + pm3_save_dump(filename, (uint8_t *)card->pages, mem_size, jsfHitag); + + return PM3_SUCCESS; +} + static int CmdLFHitagSWrite(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "lf hitag hts wrbl", @@ -615,6 +705,7 @@ static command_t CommandTable[] = { {"-----------", CmdHelp, IfPm3Hitag, "----------------------- " _CYAN_("General") " ------------------------"}, {"reader", CmdLFHitagSReader, IfPm3Hitag, "Act like a Hitag S reader"}, {"rdbl", CmdLFHitagSRead, IfPm3Hitag, "Read Hitag S page"}, + {"dump", CmdLFHitagSDump, IfPm3Hitag, "Dump Hitag S pages to a file"}, {"wrbl", CmdLFHitagSWrite, IfPm3Hitag, "Write Hitag S page"}, {"-----------", CmdHelp, IfPm3Hitag, "----------------------- " _CYAN_("Simulation") " -----------------------"}, {"sim", CmdLFHitagSSim, IfPm3Hitag, "Simulate Hitag S transponder"}, diff --git a/common_arm/flashmem.c b/common_arm/flashmem.c index 5aa88b0eb..76b475e9c 100644 --- a/common_arm/flashmem.c +++ b/common_arm/flashmem.c @@ -366,7 +366,6 @@ void Flashmem_print_status(void) { ); } - Dbprintf(" Device.................. " _YELLOW_("%s"), spi_flash_data.device); Dbprintf(" Memory size............. " _YELLOW_("%d kB (%d pages * 64k)"), spi_flash_pages64k * 64, spi_flash_pages64k); uint8_t uid[8] = {0, 0, 0, 0, 0, 0, 0, 0}; @@ -442,21 +441,13 @@ bool FlashDetect(void) { } else { if (g_dbglevel > 3) Dbprintf("Flash_ReadID failed reading Mfr/Dev (0x90)"); } - // default device is 'unknown' - spi_flash_data.device = SpiFlashTable[0].device; - + // Check JEDEC data is valid, compare the reported device types and then calculate the number of pages + // It is covering the most (known) cases of devices but probably there are vendors with different data + // They will be handled when there is such cases if (ret) { - for (int i = 0; i < ARRAYLEN(SpiFlashTable); i++) { - if (SpiFlashTable[i].manufacturer_id == spi_flash_data.manufacturer_id) { - if (SpiFlashTable[i].jedec_id == spi_flash_data.jedec_id) { - spi_flash_pages64k = SpiFlashTable[i].pages64k; - spi_flash_data.device = SpiFlashTable[i].device; - break; - } - if (SpiFlashTable[i].device_id == spi_flash_data.device_id) { - spi_flash_data.device = SpiFlashTable[i].device; - break; - } + if (spi_flash_data.jedec_id > 0 && spi_flash_data.jedec_id < 0xFFFF) { + if (((spi_flash_data.device_id + 1) & 0x0F) == (spi_flash_data.jedec_id & 0x000F)) { + spi_flash_pages64k = 1 << (spi_flash_data.jedec_id & 0x000F); } } } diff --git a/common_arm/flashmem.h b/common_arm/flashmem.h index 616575e49..f20dd0bff 100644 --- a/common_arm/flashmem.h +++ b/common_arm/flashmem.h @@ -140,41 +140,8 @@ typedef struct { uint8_t manufacturer_id; uint8_t device_id; uint16_t jedec_id; - uint8_t pages64k; - char *device; } spi_flash_t; -static const spi_flash_t SpiFlashTable[] = { - // first element is the default of 4 * 64kB pages (256kB) - { 0x00, 0x00, 0x0000, 4, "unknown" }, // 256k - // Manufacturer: Puya - { 0x85, 0x14, 0x6015, 32, "P25Q16H" }, // 2048k - // Manufacturer: Winbond - { 0xEF, 0x00, 0x3012, 4, "W25X20BV" }, // 256k - { 0xEF, 0x00, 0x3013, 8, "W25X40BV" }, // 512k - - { 0xEF, 0x00, 0x4013, 8, "W25Q40BV" }, // 512k - { 0xEF, 0x00, 0x4014, 16, "W25Q80BV" }, // 1024k - { 0xEF, 0x14, 0x4015, 32, "W25Q16BV" }, // 2048k - { 0xEF, 0x15, 0x4016, 64, "W25Q32BV" }, // 4096k - - { 0xEF, 0x16, 0x7017, 128, "W25Q64JV" }, // 8192k - { 0xEF, 0x21, 0x7022, 4, "W25Q02JV" }, - - // identified by Manufacturer /Device ID only - /// Manufacturer: Renesas - { 0x1F, 0x46, 0x0000, 32, "AT25XE161D" }, // 2048k - { 0x1F, 0x47, 0x0000, 64, "AT25XE321D" }, // 4096k -// { 0xEF, 0x05, 0x0000, 1, "Winbond!!!" }, // 64k (too small !!!) - { 0xEF, 0x10, 0x0000, 2, "W25*10BV!" }, // 128k (small !!!) - { 0xEF, 0x11, 0x0000, 4, "W25*20BV" }, // 256k - { 0xEF, 0x12, 0x0000, 8, "W25*40BV" }, // 512k - { 0xEF, 0x13, 0x0000, 16, "W25*80BV" }, // 1024k - { 0xEF, 0x14, 0x0000, 32, "W25*16*" }, // 2048k - { 0xEF, 0x15, 0x0000, 64, "W25*32*" }, // 4096k - { 0xEF, 0x16, 0x0000, 128, "W25*64*" } // 8192k -}; - extern uint8_t spi_flash_pages64k; bool FlashDetect(void); diff --git a/fpga/xc2s50-5-tq144.ucf b/fpga/xc2s50-5-tq144.ucf new file mode 100644 index 000000000..0964e1acf --- /dev/null +++ b/fpga/xc2s50-5-tq144.ucf @@ -0,0 +1,45 @@ +# See the schematic for the pin assignment. + +NET "adc_d<0>" LOC = "P54" ; +NET "adc_d<1>" LOC = "P57" ; +NET "adc_d<2>" LOC = "P59" ; +NET "adc_d<3>" LOC = "P60" ; +NET "adc_d<4>" LOC = "P62" ; +NET "adc_d<5>" LOC = "P63" ; +NET "adc_d<6>" LOC = "P65" ; +NET "adc_d<7>" LOC = "P67" ; +#NET "cross_hi" LOC = "P88" ; +#NET "miso" LOC = "P40" ; +NET "adc_clk" LOC = "P75" ; +NET "adc_noe" LOC = "P74" ; +NET "ck_1356meg" LOC = "P15" ; +NET "ck_1356megb" LOC = "P12" ; +NET "cross_lo" LOC = "P19" ; +NET "dbg" LOC = "P112" ; +NET "mosi" LOC = "P80" ; +NET "ncs" LOC = "P79" ; +NET "pck0" LOC = "P91" ; +NET "pwr_hi" LOC = "P31" ; +NET "pwr_lo" LOC = "P30" ; +NET "pwr_oe1" LOC = "P28" ; +NET "pwr_oe2" LOC = "P27" ; +NET "pwr_oe3" LOC = "P26" ; +NET "pwr_oe4" LOC = "P21" ; +NET "spck" LOC = "P88" ; +NET "ssp_clk" LOC = "P43" ; +NET "ssp_din" LOC = "P99" ; +NET "ssp_dout" LOC = "P94" ; +NET "ssp_frame" LOC = "P100" ; + +# definition of Clock nets: +NET "ck_1356meg" TNM_NET = "clk_net_1356" ; +NET "ck_1356megb" TNM_NET = "clk_net_1356b"; +NET "pck0" TNM_NET = "clk_net_pck0" ; +NET "spck" TNM_NET = "clk_net_spck" ; + +# Timing specs of clock nets: +TIMEGRP "clk_net_1356_all" = "clk_net_1356" "clk_net_1356b" ; +TIMESPEC "TS_1356MHz" = PERIOD "clk_net_1356_all" 74 ns HIGH 37 ns ; +TIMESPEC "TS_24MHz" = PERIOD "clk_net_pck0" 42 ns HIGH 21 ns ; +TIMESPEC "TS_4MHz" = PERIOD "clk_net_spck" 250 ns HIGH 125 ns ; +