diff --git a/armsrc/BigBuf.h b/armsrc/BigBuf.h index ff444f3c8..6bdf4e331 100644 --- a/armsrc/BigBuf.h +++ b/armsrc/BigBuf.h @@ -19,7 +19,7 @@ #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 -#define DMA_BUFFER_SIZE 256 +#define DMA_BUFFER_SIZE 512 // 8 data bits and 1 parity bit per payload byte, 1 correction bit, 1 SOC bit, 2 EOC bits #define TOSEND_BUFFER_SIZE (9 * MAX_FRAME_SIZE + 1 + 1 + 2) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 6a6058d3b..d9162dda8 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -2202,6 +2202,10 @@ static void PacketReceived(PacketCommandNG *packet) { Flash_CheckBusy(BUSY_TIMEOUT); Flash_WriteEnable(); Flash_Erase4k(3, 0xB); + } else if (startidx == FLASH_MEM_SIGNATURE_OFFSET) { + Flash_CheckBusy(BUSY_TIMEOUT); + Flash_WriteEnable(); + Flash_Erase4k(3, 0xF); } res = Flash_Write(startidx, data, len); diff --git a/armsrc/hitag2.c b/armsrc/hitag2.c index 66b3f4573..c2916bfe2 100644 --- a/armsrc/hitag2.c +++ b/armsrc/hitag2.c @@ -53,13 +53,21 @@ static bool bCollision; static bool bPwd; static bool bSuccessful; +/* +Password Mode : 0x06 - 0000 0110 +Crypto Mode : 0x0E - 0000 1110 +Public Mode A : 0x02 - 0000 0010 +Public Mode B : 0x00 - 0000 0000 +Public Mode C : 0x04 - 0000 0100 +*/ + static struct hitag2_tag tag = { .state = TAG_STATE_RESET, - .sectors = { // Password mode: | Crypto mode: + .sectors = { // Password mode: | Crypto mode: [0] = { 0x02, 0x4e, 0x02, 0x20}, // UID | UID [1] = { 0x4d, 0x49, 0x4b, 0x52}, // Password RWD | 32 bit LSB key [2] = { 0x20, 0xf0, 0x4f, 0x4e}, // Reserved | 16 bit MSB key, 16 bit reserved - [3] = { 0x0e, 0xaa, 0x48, 0x54}, // Configuration, password TAG | Configuration, password TAG + [3] = { 0x06, 0xaa, 0x48, 0x54}, // Configuration, password TAG | Configuration, password TAG [4] = { 0x46, 0x5f, 0x4f, 0x4b}, // Data: F_OK [5] = { 0x55, 0x55, 0x55, 0x55}, // Data: UUUU [6] = { 0xaa, 0xaa, 0xaa, 0xaa}, // Data: .... @@ -91,7 +99,7 @@ static uint8_t key[8]; static uint8_t writedata[4]; static uint8_t logdata_0[4], logdata_1[4]; static uint8_t nonce[4]; -static bool key_no; +static uint8_t key_no; static uint64_t cipher_state; static int16_t blocknr; @@ -375,16 +383,15 @@ static uint32_t hitag_reader_send_frame(const uint8_t *frame, size_t frame_len) return wait; } -static uint8_t hitag_crc(uint8_t *data, size_t length) { - uint8_t crc = 0xff; - unsigned int byte, bit; - for (byte = 0; byte < ((length + 7) / 8); byte++) { - crc ^= *(data + byte); - bit = length < (8 * (byte + 1)) ? (length % 8) : 8; +static uint8_t hitag_crc(uint8_t *data, size_t n) { + uint8_t crc = 0xFF; + for (size_t i = 0; i < ((n + 7) / 8); i++) { + crc ^= *(data + i); + uint8_t bit = n < (8 * (i + 1)) ? (n % 8) : 8; while (bit--) { if (crc & 0x80) { crc <<= 1; - crc ^= 0x1d; + crc ^= 0x1D; } else { crc <<= 1; } @@ -414,7 +421,6 @@ void fix_ac_decoding(uint8_t *input, size_t len) { // 0 = collision? // 32 = good response static bool hitag_plain(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen, bool hitag_s) { - uint8_t crc; *txlen = 0; switch (rxlen) { case 0: { @@ -435,6 +441,7 @@ static bool hitag_plain(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *tx return true; } case 32: { + uint8_t crc; if (bCollision) { // Select card by serial from response tx[0] = 0x00 | rx[0] >> 5; @@ -1001,7 +1008,6 @@ void SniffHitag2(void) { g_logging = false; - size_t periods = 0; uint8_t periods_bytes[4]; // int16_t checked = 0; @@ -1010,7 +1016,7 @@ void SniffHitag2(void) { LED_C_ON(); uint32_t signal_size = 10000; - while (!BUTTON_PRESS()) { + while (BUTTON_PRESS() == false) { // use malloc initSampleBufferEx(&signal_size, false); @@ -1035,7 +1041,7 @@ void SniffHitag2(void) { // lf_reset_counter(); // Wait "infinite" for reader modulation - periods = lf_detect_gap(10000); + size_t periods = lf_detect_gap(10000); // Test if we detected the first reader modulation edge if (periods != 0) { @@ -1070,9 +1076,7 @@ void SimulateHitag2(bool tag_mem_supplied, uint8_t *data) { int response = 0; uint8_t rx[HITAG_FRAME_LEN] = {0}; - size_t rxlen = 0; uint8_t tx[HITAG_FRAME_LEN] = {0}; - size_t txlen = 0; auth_table_len = 0; auth_table_pos = 0; @@ -1106,10 +1110,8 @@ void SimulateHitag2(bool tag_mem_supplied, uint8_t *data) { Dbprintf("| %d | %08x |", i, block); } - uint8_t reader_modulation; size_t max_nrzs = 8 * HITAG_FRAME_LEN + 5; uint8_t nrz_samples[max_nrzs]; - size_t nrzs = 0, periods = 0; // uint32_t command_start = 0, command_duration = 0; // int16_t checked = 0; @@ -1139,8 +1141,7 @@ void SimulateHitag2(bool tag_mem_supplied, uint8_t *data) { } ++checked; */ - - rxlen = 0; + size_t rxlen = 0, txlen = 0; // Keep administration of the first edge detection bool waiting_for_first_edge = true; @@ -1149,14 +1150,14 @@ void SimulateHitag2(bool tag_mem_supplied, uint8_t *data) { bool detected_modulation = false; // Use the current modulation state as starting point - reader_modulation = lf_get_reader_modulation(); + uint8_t reader_modulation = lf_get_reader_modulation(); // Receive frame, watch for at most max_nrzs periods // Reset the number of NRZ samples and use edge detection to detect them - nrzs = 0; + size_t nrzs = 0; while (nrzs < max_nrzs) { // Get the timing of the next edge in number of wave periods - periods = lf_count_edge_periods(128); + size_t periods = lf_count_edge_periods(128); // Just break out of loop after an initial time-out (tag is probably not available) // The function lf_count_edge_periods() returns 0 when a time-out occurs @@ -1336,7 +1337,7 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) { memset(logdata_1, 0x00, 4); byte_value = 0; key_no = htd->ht1auth.key_no; - DBG Dbprintf("Authenticating using key #%d:", key_no); + DBG Dbprintf("Authenticating using key #%u :", key_no); DBG Dbhexdump(4, key, false); DBG DbpString("Nonce:"); DBG Dbhexdump(4, nonce, false); diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c index c3c61e980..09c5e775e 100644 --- a/armsrc/iso14443b.c +++ b/armsrc/iso14443b.c @@ -41,7 +41,7 @@ // defaults to 2000ms #ifndef FWT_TIMEOUT_14B -# define FWT_TIMEOUT_14B 35312 +# define FWT_TIMEOUT_14B 35312U #endif // 1 tick == 1/13.56 mhz @@ -178,7 +178,7 @@ static void CodeIso14443bAsTag(const uint8_t *cmd, int len) { // Send TR1. // 10-11 ETU * 4times samples ONES - for (i = 0; i < 20; i++) { + for (i = 0; i < 10; i++) { SEND4STUFFBIT(1); } @@ -321,7 +321,7 @@ static void Demod14bInit(uint8_t *data, uint16_t max_len) { * @param timeout is in frame wait time, fwt, measured in ETUs */ static void iso14b_set_timeout(uint32_t timeout) { -#define MAX_TIMEOUT 40542464 // 13560000Hz * 1000ms / (2^32-1) * (8*16) +#define MAX_TIMEOUT 40542464U // 13560000Hz * 1000ms / (2^32-1) * (8*16) if (timeout > MAX_TIMEOUT) timeout = MAX_TIMEOUT; diff --git a/armsrc/usart.c b/armsrc/usart.c index 75b005b6d..c26a28ea8 100644 --- a/armsrc/usart.c +++ b/armsrc/usart.c @@ -146,9 +146,9 @@ uint32_t usart_read_ng(uint8_t *data, size_t len) { } len -= packetSize; while (packetSize--) { - data[bytes_rcv++] = us_rxfifo[us_rxfifo_low++]; if (us_rxfifo_low == sizeof(us_rxfifo)) us_rxfifo_low = 0; + data[bytes_rcv++] = us_rxfifo[us_rxfifo_low++]; } if (try++ == maxtry) { // Dbprintf_usb("Dbg USART TIMEOUT"); diff --git a/client/deps/cliparser/argtable3.c b/client/deps/cliparser/argtable3.c index 783bd303b..dfcccb81b 100644 --- a/client/deps/cliparser/argtable3.c +++ b/client/deps/cliparser/argtable3.c @@ -4639,11 +4639,13 @@ void arg_print_syntax(FILE *fp, void * *argtable, const char *suffix) { /* print GNU style [OPTION] string */ arg_print_gnuswitch(fp, table); + size_t len = 0; + /* print remaining options in abbreviated style */ for (tabindex = 0; table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) { - char syntax[200] = ""; + char syntax[400] = ""; const char *shortopts, *longopts, *datatype; /* skip short options without arg values (they were printed by arg_print_gnu_switch) */ @@ -4681,6 +4683,12 @@ void arg_print_syntax(FILE *fp, void * *argtable, const char *suffix) { break; } } + + len += strlen(syntax); + if (len > 60) { + fprintf(fp, "\n "); + len = 0; + } } if (suffix) diff --git a/client/dictionaries/mfc_default_keys.dic b/client/dictionaries/mfc_default_keys.dic index 21319bc3e..a0c8b9943 100644 --- a/client/dictionaries/mfc_default_keys.dic +++ b/client/dictionaries/mfc_default_keys.dic @@ -433,6 +433,9 @@ cc6b3b3cd263 157c9a513fa5 e2a5dc8e066f # +# Data from forum, schlage 9691T fob +ef1232ab18a0 +# # Data from a oyster card 374bf468607f bfc8e353af63 @@ -1293,3 +1296,75 @@ ff9a84635bd2 f1a1239a4487 # b882fd4a9f78 +CD7FFFF81C4A +AA0857C641A3 +C8AACD7CF3D1 +9FFDA233B496 +26B85DCA4321 +D4B2D140CB2D +A7395CCB42A0 +541C417E57C0 +D14E615E0545 +69D92108C8B5 +703265497350 +D75971531042 +10510049D725 +35C649004000 +5B0C7EC83645 +05F5EC05133C +521B517352C7 +94B6A644DFF6 +2CA4A4D68B8E +A7765C952DDF +E2F14D0A0E28 +DC018FC1D126 +4927C97F1D57 +046154274C11 +155332417E00 +6B13935CD550 +C151D998C669 +D973D917A4C7 +130662240200 +9386E2A48280 +52750A0E592A +541C417E57C0 +D14E615E0545 +075D1A4DD323 +32CA52054416 +460661C93045 +5429D67E1F57 +0C734F230E13 +1F0128447C00 +411053C05273 +42454C4C4147 +C428C4550A75 +730956C72BC2 +28D70900734C +4F75030AD12B +6307417353C1 +D65561530174 +D1F71E05AD9D +F7FA2F629BB1 +0E620691B9FE +43E69C28F08C +735175696421 +424C0FFBF657 +D01AFEEB890A +75CCB59C9BED +4B791BEA7BCC +51E97FFF51E9 +E7316853E731 +5C8FF9990DA2 +00460740D722 +35D152154017 +5D0762D13401 +0F35D5660653 +1170553E4304 +0C4233587119 +F678905568C3 +50240A68D1D8 +69D92108C8B5 +2E71D3BD262A +540D5E6355CC +D1417E431949 +4BF6DE347FB6 \ No newline at end of file diff --git a/client/luascripts/tests/lf_t55xx_defaultask.lua b/client/luascripts/tests/lf_t55xx_defaultask.lua index efb6ce8fe..9e81110b3 100644 --- a/client/luascripts/tests/lf_t55xx_defaultask.lua +++ b/client/luascripts/tests/lf_t55xx_defaultask.lua @@ -20,7 +20,7 @@ The outlined procedure is as following: -- manchester -- bit rate -"lf t55xx write b 0 d 00008040" +"lf t55xx write -b 0 -d 00008040" "lf t55xx detect" "lf t55xx info" @@ -118,7 +118,7 @@ local function test() elseif _ == 1 then local config = pcmd:format(config1, y, config2) - dbg(('lf t55xx write b 0 d %s'):format(config)) + dbg(('lf t55xx write -b 0 -d %s'):format(config)) local data = ('%s%s%s%s'):format(utils.SwapEndiannessStr(config, 32), password, block, flags) local wc = Command:newNG{cmd = cmds.CMD_LF_T55XX_WRITEBL, data = data} diff --git a/client/luascripts/tests/lf_t55xx_defaultbi.lua b/client/luascripts/tests/lf_t55xx_defaultbi.lua index 495faef02..2590dc38b 100644 --- a/client/luascripts/tests/lf_t55xx_defaultbi.lua +++ b/client/luascripts/tests/lf_t55xx_defaultbi.lua @@ -14,7 +14,7 @@ The outlined procedure is as following: --BIPHASE 00010040 -- -"lf t55xx write b 0 d 00010040" +"lf t55xx write -b 0 -d 00010040" "lf t55xx detect" "lf t55xx info" @@ -112,7 +112,7 @@ local function test() elseif _ == 1 then local config = pcmd:format(config1, y, config2) - dbg(('lf t55xx write b 0 d %s'):format(config)) + dbg(('lf t55xx write -b 0 -d %s'):format(config)) local data = ('%s%s%s%s'):format(utils.SwapEndiannessStr(config, 32), password, block, flags) diff --git a/client/luascripts/tests/lf_t55xx_defaultfsk.lua b/client/luascripts/tests/lf_t55xx_defaultfsk.lua index 2a5c272c4..9aa50f641 100644 --- a/client/luascripts/tests/lf_t55xx_defaultfsk.lua +++ b/client/luascripts/tests/lf_t55xx_defaultfsk.lua @@ -17,7 +17,7 @@ The outlined procedure is as following: -- FSK1 -- bit rate -"lf t55xx write b 0 d 00007040" +"lf t55xx write -b 0 -d 00007040" "lf t55xx detect" "lf t55xx info" @@ -114,7 +114,7 @@ local function test(modulation) elseif _ == 1 then local config = pcmd:format(config1, y, modulation, config2) - dbg(('lf t55xx write b 0 d %s'):format(config)) + dbg(('lf t55xx write -b 0 -d %s'):format(config)) local data = ('%s%s%s%s'):format(utils.SwapEndiannessStr(config, 32), password, block, flags) local wc = Command:newNG{cmd = cmds.CMD_LF_T55XX_WRITEBL, data = data} diff --git a/client/luascripts/tests/lf_t55xx_defaultpsk.lua b/client/luascripts/tests/lf_t55xx_defaultpsk.lua index 8b4f0447a..09a4063e8 100644 --- a/client/luascripts/tests/lf_t55xx_defaultpsk.lua +++ b/client/luascripts/tests/lf_t55xx_defaultpsk.lua @@ -11,7 +11,7 @@ desc = [[ This script will program a T55x7 TAG with the configuration: block 0x00 data 0x00088040 The outlined procedure is as following: -"lf t55xx write b 0 d 00088040" +"lf t55xx write -b 0 -d 00088040" "lf t55xx detect" "lf t55xx info" @@ -118,7 +118,7 @@ local function test(modulation) dbg('Writing to T55x7 TAG') local config = cmd:format(bitrate, modulation, clockrate) - dbg(('lf t55xx write b 0 d %s'):format(config)) + dbg(('lf t55xx write -b 0 -d %s'):format(config)) local data = ('%s%s%s%s'):format(utils.SwapEndiannessStr(config, 32), password, block, flags) diff --git a/client/luascripts/tests/lf_t55xx_writetest.lua b/client/luascripts/tests/lf_t55xx_writetest.lua index cfe46d565..48053db5d 100644 --- a/client/luascripts/tests/lf_t55xx_writetest.lua +++ b/client/luascripts/tests/lf_t55xx_writetest.lua @@ -17,10 +17,10 @@ It will then try to detect and read back those block data and compare if read da lf t55xx wipe lf t55xx detect -lf t55xx write b 1 d 00000000 -lf t55xx write b 2 d ffffffff -lf t55xx write b 3 d 80000000 -lf t55xx write b 4 d 00000001 +lf t55xx write -b 1 -d 00000000 +lf t55xx write -b 2 -d ffffffff +lf t55xx write -b 3 -d 80000000 +lf t55xx write -b 4 -d 00000001 Loop: @@ -278,7 +278,7 @@ local function WipeCard() core.console('rem [ERR:DETECT:WIPED] Failed to detect after wipe') return false else - local wipe_data_cmd = 'lf t55xx write b %s d %s' + local wipe_data_cmd = 'lf t55xx write -b %s -d %s' for _ = 1, #data_blocks_cmds do local val = data_blocks_cmds[_] local c = string.format(wipe_data_cmd, _, val) @@ -321,7 +321,7 @@ local function test(modulation) core.clearCommandBuffer() -- Write Config block - dbg(('lf t55xx write b 0 d %s'):format(p_config_cmd)) + dbg(('lf t55xx write -b 0 -d %s'):format(p_config_cmd)) local data = ('%s%s%s%s'):format(utils.SwapEndiannessStr(p_config_cmd, 32), password, block, flags) diff --git a/client/src/cmdflashmem.c b/client/src/cmdflashmem.c index 23acad47d..5bb3b8cd9 100644 --- a/client/src/cmdflashmem.c +++ b/client/src/cmdflashmem.c @@ -39,7 +39,10 @@ static int CmdHelp(const char *Cmd); "9337F21C0C066FFB703D8BFCB5067F309E056772096642C2B1A8F50305D5EC33" \ "DB7FB5A3C8AC42EB635AE3C148C910750ABAA280CE82DC2F180F49F30A1393B5" +//------------------------------------------------------------------------------------- +// Sample private RSA Key // Following example RSA-1024 keypair, for test purposes (from common/polarssl/rsa.c) + // private key - Exponent D #define RSA_D "24BF6185468786FDD303083D25E64EFC" \ "66CA472BC44D253102F8B4A9D3BFA750" \ @@ -136,7 +139,7 @@ static int rdv4_sign_write(uint8_t *signature, uint8_t slen){ if (!resp.oldarg[0]) { PrintAndLogEx(FAILED, "Writing signature ( "_RED_("fail") ")"); } else { - PrintAndLogEx(SUCCESS, "Writing signature ( "_GREEN_("ok") " ) at offset %u", FLASH_MEM_SIGNATURE_OFFSET); + PrintAndLogEx(SUCCESS, "Writing signature at offset %u ( "_GREEN_("ok") " )", FLASH_MEM_SIGNATURE_OFFSET); return PM3_SUCCESS; } } @@ -445,29 +448,39 @@ static int CmdFlashMemInfo(const char *Cmd) { CLIParserInit(&ctx, "mem info", "Collect signature and verify it from flash memory", "mem info" -// "mem info -s" +// "mem info -s -d 0102030405060708" ); void *argtable[] = { arg_param_begin, -// arg_lit0("s", NULL, "create a signature"), -// arg_lit0("w", NULL, "write signature to flash memory"), + arg_lit0("s", "sign", "create a signature"), + arg_str0("d", NULL, "", "flash memory id, 8 hex bytes"), +// arg_lit0("w", "write", "write signature to flash memory"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); bool shall_sign = false, shall_write = false; -// shall_sign = arg_get_lit(ctx, 1); -// shall_write = arg_get_lit(ctx, 2); + shall_sign = arg_get_lit(ctx, 1); + + int dlen = 0; + uint8_t id[8] = {0}; + int res = CLIParamHexToBuf(arg_get_str(ctx, 2), id, sizeof(id), &dlen); + +// shall_write = arg_get_lit(ctx, 3); CLIParserFree(ctx); - // validate signature data + if (dlen > 0 && dlen < sizeof(id) ) { + PrintAndLogEx(FAILED, "Error parsing flash memory id, expect 8, got %d", dlen); + return PM3_EINVARG; + } + + // validate devicesignature data rdv40_validation_t mem; - int res = rdv4_get_signature(&mem); + res = rdv4_get_signature(&mem); if (res != PM3_SUCCESS) { return res; } - res = rdv4_validate(&mem); // Flash ID hash (sha1) @@ -479,6 +492,11 @@ static int CmdFlashMemInfo(const char *Cmd) { PrintAndLogEx(INFO, "--- " _CYAN_("Flash memory Information") " ---------"); PrintAndLogEx(INFO, "ID................... %s", sprint_hex_inrow(mem.flashid, sizeof(mem.flashid))); PrintAndLogEx(INFO, "SHA1................. %s", sprint_hex_inrow(sha_hash, sizeof(sha_hash))); + PrintAndLogEx( + (res == PM3_SUCCESS) ? SUCCESS : FAILED, + "Signature............ ( %s )", + (res == PM3_SUCCESS) ? _GREEN_("ok") : _RED_("fail") + ); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "--- " _CYAN_("RDV4 RSA signature") " ---------------"); for (int i = 0; i < (sizeof(mem.signature) / 32); i++) { @@ -520,13 +538,21 @@ static int CmdFlashMemInfo(const char *Cmd) { PrintAndLogEx(INFO, " %.64s", str_pk + 192); PrintAndLogEx(NORMAL, ""); - bool is_keyok = (mbedtls_rsa_check_pubkey(&rsa) == 0 || mbedtls_rsa_check_privkey(&rsa) == 0); + bool is_keyok = (mbedtls_rsa_check_pubkey(&rsa) == 0); PrintAndLogEx( (is_keyok) ? SUCCESS : FAILED, - "RSA key validation... ( %s )", + "RSA public key validation.... ( %s )", (is_keyok) ? _GREEN_("ok") : _RED_("fail") ); + is_keyok = (mbedtls_rsa_check_privkey(&rsa) == 0); + PrintAndLogEx( + (is_keyok) ? SUCCESS : FAILED, + "RSA private key validation... ( %s )", + (is_keyok) ? _GREEN_("ok") : _RED_("fail") + ); + + // to be verified uint8_t from_device[RRG_RSA_KEY_LEN]; memcpy(from_device, mem.signature, RRG_RSA_KEY_LEN); @@ -537,6 +563,13 @@ static int CmdFlashMemInfo(const char *Cmd) { // Signing (private key) if (shall_sign) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "--- " _CYAN_("Enter signing") " --------------------"); + + if (dlen == 8) { + mbedtls_sha1(id, sizeof(id), sha_hash); + } + PrintAndLogEx(INFO, "Signing %s", sprint_hex_inrow(sha_hash, sizeof(sha_hash))); int is_signed = mbedtls_rsa_pkcs1_sign(&rsa, NULL, NULL, MBEDTLS_RSA_PRIVATE, MBEDTLS_MD_SHA1, 20, sha_hash, sign); PrintAndLogEx( @@ -555,14 +588,17 @@ static int CmdFlashMemInfo(const char *Cmd) { } // Verify (public key) - int is_verified = mbedtls_rsa_pkcs1_verify(&rsa, NULL, NULL, MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA1, 20, sha_hash, from_device); + bool is_verified = (mbedtls_rsa_pkcs1_verify(&rsa, NULL, NULL, MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA1, 20, sha_hash, from_device) == 0); mbedtls_rsa_free(&rsa); PrintAndLogEx( - (is_verified == 0) ? SUCCESS : FAILED, - "RSA verification..... ( %s )", - (is_verified == 0) ? _GREEN_("ok") : _RED_("fail") + (is_verified) ? SUCCESS : FAILED, + "RSA verification..... ( %s )", + (is_verified) ? _GREEN_("ok") : _RED_("fail") ); + if (is_verified) { + PrintAndLogEx(SUCCESS, "Genuine Proxmark3 RDV4 signature detected"); + } PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c index 8227a55c0..4e4f5c6f4 100644 --- a/client/src/cmdhfmfu.c +++ b/client/src/cmdhfmfu.c @@ -23,6 +23,8 @@ #include "mifare/ndef.h" #include "cliparser.h" #include "cmdmain.h" +#include "amiibo.h" // amiiboo fcts +#include "base64.h" #define MAX_UL_BLOCKS 0x0F #define MAX_ULC_BLOCKS 0x2F @@ -3717,6 +3719,13 @@ static int CmdHF14AMfuEv1CounterTearoff(const char *Cmd) { */ +// +// name, identifying bytes, decode function, hints text +// identifying bits +// 1. getversion data must match. +// 2. magic bytes in the readable payload + + static int CmdHF14MfuNDEF(const char *Cmd) { int keylen; @@ -3845,6 +3854,25 @@ static int CmdHF14MfuNDEF(const char *Cmd) { } } } + char *mattel = strstr((char*)records, ".pid.mattel/"); + if (mattel) { + mattel += 12; + while (mattel) { + if ((*mattel) != '/') + mattel++; + else { + mattel++; + char b64[33] = {0}; + strncpy(b64, mattel, 32); + uint8_t arr[24] = {0}; + size_t arrlen = 0; + mbedtls_base64_decode(arr, sizeof(arr), &arrlen, (const unsigned char *)b64, 32); + + PrintAndLogEx(INFO, "decoded... %s", sprint_hex(arr, arrlen)); + break; + } + } + } free(records); return status; @@ -3893,17 +3921,57 @@ static int CmdHF14AMfuEView(const char *Cmd) { return PM3_SUCCESS; } +/* +static int CmdHF14AMfUCDecryptAmiibo(const char *Cmd){ + + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf mfu decrypt", + "Tries to read all memory from amiibo tag and decrypt it", + "hf mfu decrypt" + ); + + void *argtable[] = { + arg_param_begin, + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIParserFree(ctx); + + uint16_t elen = 0, dlen = 0; + uint8_t *encrypted = NULL; + + int res = mfu_dump_tag( MAX_NTAG_215, (void **)&encrypted, &elen); + if (res == PM3_SUCCESS) { + + PrintAndLogEx(INFO, "32 first bytes of tag dump"); + PrintAndLogEx(INFO, "%s", sprint_hex(encrypted, 32)); + PrintAndLogEx(INFO, "-----------------------"); + + uint8_t decrypted[NFC3D_AMIIBO_SIZE] = {0}; + res = mfu_decrypt_amiibo(encrypted, elen, decrypted, &dlen); + if ( res == PM3_SUCCESS) { + + for (uint8_t i = 0; i < dlen/16; i++ ) { + PrintAndLogEx(INFO, "[%d] %s", i, sprint_hex_ascii(decrypted + (i * 16), 16)); + } + } + free(encrypted); + } + return PM3_SUCCESS; +} +*/ + //------------------------------------ // Menu Stuff //------------------------------------ static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, - {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("recovery") " -----------------------"}, + {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("recovery") " -------------------------"}, {"keygen", CmdHF14AMfUGenDiverseKeys, AlwaysAvailable, "Generate 3DES MIFARE diversified keys"}, {"pwdgen", CmdHF14AMfUPwdGen, AlwaysAvailable, "Generate pwd from known algos"}, {"otptear", CmdHF14AMfuOtpTearoff, IfPm3Iso14443a, "Tear-off test on OTP bits"}, // {"tear_cnt", CmdHF14AMfuEv1CounterTearoff, IfPm3Iso14443a, "Tear-off test on Ev1/NTAG Counter bits"}, - {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("operations") " -----------------------"}, + {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("operations") " -----------------------"}, {"cauth", CmdHF14AMfUCAuth, IfPm3Iso14443a, "Authentication - Ultralight-C"}, {"dump", CmdHF14AMfUDump, IfPm3Iso14443a, "Dump MIFARE Ultralight family tag to binary file"}, {"info", CmdHF14AMfUInfo, IfPm3Iso14443a, "Tag information"}, @@ -3911,12 +3979,15 @@ static command_t CommandTable[] = { {"rdbl", CmdHF14AMfURdBl, IfPm3Iso14443a, "Read block"}, {"restore", CmdHF14AMfURestore, IfPm3Iso14443a, "Restore a dump onto a MFU MAGIC tag"}, {"wrbl", CmdHF14AMfUWrBl, IfPm3Iso14443a, "Write block"}, - {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("simulation") " -----------------------"}, + {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("simulation") " -----------------------"}, {"eload", CmdHF14AMfUeLoad, IfPm3Iso14443a, "load Ultralight .eml dump file into emulator memory"}, {"eview", CmdHF14AMfuEView, IfPm3Iso14443a, "View emulator memory"}, {"sim", CmdHF14AMfUSim, IfPm3Iso14443a, "Simulate MIFARE Ultralight from emulator memory"}, + {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("magic") " ----------------------------"}, {"setpwd", CmdHF14AMfUCSetPwd, IfPm3Iso14443a, "Set 3DES key - Ultralight-C"}, {"setuid", CmdHF14AMfUCSetUid, IfPm3Iso14443a, "Set UID - MAGIC tags only"}, + {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("amiibo") " ----------------------------"}, +// {"decrypt", CmdHF14AMfUCDecryptAmiibo, IfPm3Iso14443a, "Decrypt a amiibo tag"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdlfhitag.c b/client/src/cmdlfhitag.c index b98d83705..cb711a65c 100644 --- a/client/src/cmdlfhitag.c +++ b/client/src/cmdlfhitag.c @@ -113,19 +113,6 @@ static int usage_hitag_writer(void) { PrintAndLogEx(NORMAL, " 27 Write page, password mode. Default: 4D494B52 (\"MIKR\")"); return PM3_SUCCESS; } -static int usage_hitag_checkchallenges(void) { - PrintAndLogEx(NORMAL, "Check challenges, load a file with save hitag crypto challenges and test them all."); - PrintAndLogEx(NORMAL, "The file should be 8 * 60 bytes long, the file extension defaults to " _YELLOW_("`.cc`")); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf hitag cc [h] f "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h This help"); - PrintAndLogEx(NORMAL, " f Load data from BIN file"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " lf hitag cc f lf-hitag-challenges"); - return PM3_SUCCESS; -} static int CmdLFHitagList(const char *Cmd) { char args[128] = {0}; @@ -614,50 +601,46 @@ static int CmdLFHitagReader(const char *Cmd) { static int CmdLFHitagCheckChallenges(const char *Cmd) { - char filename[FILE_PATH_SIZE] = { 0x00 }; - size_t datalen = 0; - int res = 0; - bool file_given = false; - bool errors = false; - uint8_t cmdp = 0; - uint8_t *data = calloc(8 * 60, sizeof(uint8_t)); + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf hitag cc", + "Check challenges, load a file with saved hitag crypto challenges and test them all.\n" + "The file should be 8 * 60 bytes long, the file extension defaults to " _YELLOW_("`.cc`") " ", + "lf hitag cc -f my_hitag_challenges" + ); - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - free(data); - return usage_hitag_checkchallenges(); - case 'f': - //file with all the challenges to try - param_getstr(Cmd, cmdp + 1, filename, sizeof(filename)); - res = loadFile(filename, ".cc", data, 8 * 60, &datalen); - if (res > 0) { - errors = true; - break; - } - file_given = true; - cmdp += 2; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } + void *argtable[] = { + arg_param_begin, + arg_str0("f", "filename", "", "filename to load from"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); - //Validations - if (errors || strlen(Cmd) == 0) { - free(data); - return usage_hitag_checkchallenges(); - } + int fnlen = 0; + char filename[FILE_PATH_SIZE] = {0}; + CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); + + CLIParserFree(ctx); clearCommandBuffer(); - if (file_given) - SendCommandOLD(CMD_LF_HITAGS_TEST_TRACES, 1, 0, 0, data, datalen); - else - SendCommandMIX(CMD_LF_HITAGS_TEST_TRACES, 0, 0, 0, NULL, 0); - free(data); + if (fnlen > 0) { + uint8_t *data = NULL; + size_t datalen = 0; + int res = loadFile_safe(filename, ".cc", (void **)&data, &datalen); + if (res == PM3_SUCCESS) { + if (datalen == (8 * 60) ) { + SendCommandOLD(CMD_LF_HITAGS_TEST_TRACES, 1, 0, 0, data, datalen); + } else { + PrintAndLogEx(ERR, "Error, file length mismatch. Expected %d, got %d", 8*60, datalen); + } + } + if (data) { + free(data); + } + } else { + SendCommandMIX(CMD_LF_HITAGS_TEST_TRACES, 0, 0, 0, NULL, 0); + } + return PM3_SUCCESS; } diff --git a/client/src/cmdlft55xx.c b/client/src/cmdlft55xx.c index 1c3993454..7e86e1c78 100644 --- a/client/src/cmdlft55xx.c +++ b/client/src/cmdlft55xx.c @@ -50,7 +50,7 @@ t55xx_conf_block_t config = { .inverted = false, .offset = 0x00, .block0 = 0x00, - .block0Status = notSet, + .block0Status = NOTSET, .Q5 = false, .usepwd = false, .downlink_mode = refFixedBit @@ -66,18 +66,7 @@ void Set_t55xx_Config(t55xx_conf_block_t conf) { config = conf; } -static void print_usage_t55xx_downloadlink(uint8_t ShowAll, uint8_t dl_mode_default) { - if (ShowAll == T55XX_DLMODE_ALL) - PrintAndLogEx(NORMAL, " r - downlink encoding 0|1|2|3|4"); - else - PrintAndLogEx(NORMAL, " r - downlink encoding 0|1|2|3"); - PrintAndLogEx(NORMAL, " 0 - fixed bit length%s", (dl_mode_default == 0) ? " (detected default)" : ""); // default will be whats in config struct - PrintAndLogEx(NORMAL, " 1 - long leading reference%s", (dl_mode_default == 1) ? " (detected default)" : ""); - PrintAndLogEx(NORMAL, " 2 - leading zero%s", (dl_mode_default == 2) ? " (detected default)" : ""); - PrintAndLogEx(NORMAL, " 3 - 1 of 4 coding reference%s", (dl_mode_default == 3) ? " (detected default)" : ""); - if (ShowAll == T55XX_DLMODE_ALL) - PrintAndLogEx(NORMAL, " 4 - Try all downlink modes%s", (dl_mode_default == 4) ? " (default)" : ""); -} +static int CmdHelp(const char *Cmd); static void arg_add_t55xx_downloadlink(void *at[], uint8_t *idx, uint8_t show, uint8_t dl_mode_def) { @@ -106,144 +95,15 @@ static void arg_add_t55xx_downloadlink(void *at[], uint8_t *idx, uint8_t show, u *idx = n; } -static int usage_t55xx_config(void) { - PrintAndLogEx(NORMAL, "Usage: lf t55xx config [c ] [d ] [i [0/1]] [o ] [Q5 [0/1]] [ST [0/1]]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - This help"); - PrintAndLogEx(NORMAL, " c - set configuration from a block0"); - PrintAndLogEx(NORMAL, " b <8|16|32|40|50|64|100|128> - Set bitrate"); - PrintAndLogEx(NORMAL, " d - Set demodulation FSK / ASK / PSK / NRZ / Biphase / Biphase A"); - PrintAndLogEx(NORMAL, " i [0/1] - Set/reset data signal inversion"); - PrintAndLogEx(NORMAL, " o [offset] - Set offset, where data should start decode in bitstream"); - PrintAndLogEx(NORMAL, " Q5 [0/1] - Set/reset as Q5/T5555 chip instead of T55x7"); - PrintAndLogEx(NORMAL, " ST [0/1] - Set/reset Sequence Terminator on"); - PrintAndLogEx(NORMAL, ""); // layout is a little differnet, so seperate until a better fix - print_usage_t55xx_downloadlink(T55XX_DLMODE_SINGLE, config.downlink_mode); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf t55xx config d FSK") " - FSK demodulation"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf t55xx config d FSK i 1") " - FSK demodulation, inverse data"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf t55xx config d FSK i 1 o 3") " - FSK demodulation, inverse data, offset=3,start from position 3 to decode data"); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} -static int usage_t55xx_read(void) { - PrintAndLogEx(NORMAL, "Usage: lf t55xx read [r ] b [p ] [o] "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " b - block number to read. Between 0-7"); - PrintAndLogEx(NORMAL, " p - OPTIONAL password (8 hex characters)"); - PrintAndLogEx(NORMAL, " o - OPTIONAL override safety check"); - PrintAndLogEx(NORMAL, " 1 - OPTIONAL 0|1 read Page 1 instead of Page 0"); - print_usage_t55xx_downloadlink(T55XX_DLMODE_SINGLE, config.downlink_mode); - PrintAndLogEx(NORMAL, " " _RED_("**** WARNING ****")); - PrintAndLogEx(NORMAL, " Use of read with password on a tag not configured"); - PrintAndLogEx(NORMAL, " for a password can damage the tag"); - PrintAndLogEx(NORMAL, " " _RED_("*****************")); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf t55xx read b 0") " - read data from block 0"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf t55xx read b 0 p feedbeef") " - read data from block 0 password feedbeef"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf t55xx read b 0 p feedbeef o") " - read data from block 0 password feedbeef safety check"); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} -static int usage_t55xx_resetread(void) { - PrintAndLogEx(NORMAL, "Send Reset Cmd then lf read the stream to attempt to identify the start of it (needs a demod and/or plot after)"); - PrintAndLogEx(NORMAL, "Usage: lf t55xx resetread [r ]"); - PrintAndLogEx(NORMAL, "Options:"); - print_usage_t55xx_downloadlink(T55XX_DLMODE_SINGLE, config.downlink_mode); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf t55xx resetread")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} -static int usage_t55xx_write(void) { - PrintAndLogEx(NORMAL, "Usage: lf t55xx write [r ] b d [p ] [1] [t] [v]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " b - block number to write. Between 0-7"); - PrintAndLogEx(NORMAL, " d - 4 bytes of data to write (8 hex characters)"); - PrintAndLogEx(NORMAL, " p - OPTIONAL password 4bytes (8 hex characters)"); - PrintAndLogEx(NORMAL, " 1 - OPTIONAL write Page 1 instead of Page 0"); - PrintAndLogEx(NORMAL, " t - OPTIONAL test mode write - ****DANGER****"); - PrintAndLogEx(NORMAL, " v - OPTIONAL validate data afterwards"); - print_usage_t55xx_downloadlink(T55XX_DLMODE_SINGLE, config.downlink_mode); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf t55xx write b 3 d 11223344") " - write 11223344 to block 3"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf t55xx write b 3 d 11223344 p feedbeef") " - write 11223344 to block 3 password feedbeef"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf t55xx write b 3 d 11223344 v") " - write 11223344 to block 3 and try to validate data"); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} -static int usage_t55xx_trace(void) { - PrintAndLogEx(NORMAL, "Usage: lf t55xx trace [1] [r mode]"); - PrintAndLogEx(NORMAL, "Options:"); - print_usage_t55xx_downloadlink(T55XX_DLMODE_SINGLE, config.downlink_mode); - PrintAndLogEx(NORMAL, " 1 - if set, use Graphbuffer otherwise read data from tag."); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf t55xx trace")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf t55xx trace 1")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} -static int usage_t55xx_info(void) { - PrintAndLogEx(NORMAL, "Usage: lf t55xx info [1] [r ] [c [q]]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " (default) - read data from tag."); - PrintAndLogEx(NORMAL, " p - OPTIONAL password 4bytes (8 hex symbols)"); - PrintAndLogEx(NORMAL, " 1 - if set, use Graphbuffer instead of reading tag."); - PrintAndLogEx(NORMAL, " c - set configuration from a block0"); - PrintAndLogEx(NORMAL, " if set, use these data instead of reading tag."); - PrintAndLogEx(NORMAL, " q - if set, provided data are interpreted as Q5 config."); - print_usage_t55xx_downloadlink(T55XX_DLMODE_SINGLE, config.downlink_mode); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf t55xx info")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf t55xx info 1")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf t55xx info d 00083040")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf t55xx info d 6001805A q")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf t55xx info p 11223344")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} -static int usage_t55xx_dump(void) { - PrintAndLogEx(NORMAL, "Usage: lf t55xx dump [r ] [p [o]]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " p - OPTIONAL password 4bytes (8 hex symbols)"); - PrintAndLogEx(NORMAL, " o - OPTIONAL override, force pwd read despite danger to card"); - PrintAndLogEx(NORMAL, " f - override filename prefix (optional). Default is based on blk 0"); - print_usage_t55xx_downloadlink(T55XX_DLMODE_SINGLE, config.downlink_mode); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf t55xx dump")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf t55xx dump p feedbeef o")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} -static int usage_t55xx_restore(void) { - PrintAndLogEx(NORMAL, "Usage: lf t55xx restore f [p password]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " f - filename of the dump file (.bin/.eml)"); - PrintAndLogEx(NORMAL, " p - optional password if target card has password set"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, _YELLOW_(" Assumes lf t55 detect has been run first!")); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf t55xx restore f lf-t55xx-00148040-dump.bin")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} - -static int usage_t55xx_clonehelp(void) { +static int CmdT55xxCloneHelp(const char *Cmd) { + (void)Cmd; // Cmd is not used so far PrintAndLogEx(NORMAL, "For cloning specific techs on T55xx tags, see commands available in corresponding LF sub-menus, e.g.:"); PrintAndLogEx(NORMAL, _GREEN_("lf awid clone")); PrintAndLogEx(NORMAL, _GREEN_("lf destron clone")); - PrintAndLogEx(NORMAL, _GREEN_("lf em 410x_clone")); + PrintAndLogEx(NORMAL, _GREEN_("lf em 410x clone")); // todo: implement restore -// PrintAndLogEx(NORMAL, _GREEN_("lf em 4x05_write")); -// PrintAndLogEx(NORMAL, _GREEN_("lf em 4x50_write")); +// PrintAndLogEx(NORMAL, _GREEN_("lf em 4x05 write")); +// PrintAndLogEx(NORMAL, _GREEN_("lf em 4x50 write")); PrintAndLogEx(NORMAL, _GREEN_("lf fdxb clone")); PrintAndLogEx(NORMAL, _GREEN_("lf gallagher clone")); PrintAndLogEx(NORMAL, _GREEN_("lf gproxii clone")); @@ -252,9 +112,10 @@ static int usage_t55xx_clonehelp(void) { PrintAndLogEx(NORMAL, _GREEN_("lf io clone")); PrintAndLogEx(NORMAL, _GREEN_("lf jablotron clone")); PrintAndLogEx(NORMAL, _GREEN_("lf keri clone")); - PrintAndLogEx(NORMAL, _GREEN_("lf nedap clone")); - PrintAndLogEx(NORMAL, _GREEN_("lf noralsy clone")); PrintAndLogEx(NORMAL, _GREEN_("lf motorola clone")); + PrintAndLogEx(NORMAL, _GREEN_("lf nedap clone")); + PrintAndLogEx(NORMAL, _GREEN_("lf nexwatch clone")); + PrintAndLogEx(NORMAL, _GREEN_("lf noralsy clone")); PrintAndLogEx(NORMAL, _GREEN_("lf pac clone")); PrintAndLogEx(NORMAL, _GREEN_("lf paradox clone")); PrintAndLogEx(NORMAL, _GREEN_("lf presco clone")); @@ -265,13 +126,6 @@ static int usage_t55xx_clonehelp(void) { return PM3_SUCCESS; } -static int CmdHelp(const char *Cmd); - -static int CmdT55xxCloneHelp(const char *Cmd) { - (void)Cmd; // Cmd is not used so far - return usage_t55xx_clonehelp(); -} - static void T55x7_SaveBlockData(uint8_t idx, uint32_t data) { if (idx < T55x7_BLOCK_COUNT) { cardmem[idx].valid = true; @@ -558,141 +412,183 @@ void SetConfigWithBlock0Ex(uint32_t block0, uint8_t offset, bool Q5) { } static int CmdT55xxSetConfig(const char *Cmd) { - // No args - if (strlen(Cmd) == 0) return printConfiguration(config); + if (strlen(Cmd) == 0) { + PrintAndLogEx(INFO, "--- " _CYAN_("current t55xx config") " --------------------------"); + return printConfiguration(config); + } + + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf t55xx config", + "Set/Get T55XX configuration of the pm3 client. Like modulation, inverted, offset, rate etc.\n" + "Offset is start position to decode data.", + "lf t55xx config --FSK --> FSK demodulation\n" + "lf t55xx config --FSK -i --> FSK demodulation, inverse data\n" + "lf t55xx config --FSK -i -o 3 --> FSK demodulation, inverse data, offset 3\n" + ); + + // 1 (help) + 19 (user specified params) + (5 T55XX_DLMODE_SINGLE) + void *argtable[1 + 12 + 6 + 5] = { + arg_param_begin, + arg_lit0(NULL, "FSK", "set demodulation FSK"), + arg_lit0(NULL, "FSK1", "set demodulation FSK 1"), + arg_lit0(NULL, "FSK1A", "set demodulation FSK 1a (inv)"), + arg_lit0(NULL, "FSK2", "set demodulation FSK 2"), + arg_lit0(NULL, "FSK2A", "set demodulation FSK 2a (inv)"), + arg_lit0(NULL, "ASK", "set demodulation ASK"), + arg_lit0(NULL, "PSK1", "set demodulation PSK 1"), + arg_lit0(NULL, "PSK2", "set demodulation PSK 2"), + arg_lit0(NULL, "PSK3", "set demodulation PSK 3"), + arg_lit0(NULL, "NRZ", "set demodulation NRZ"), + arg_lit0(NULL, "BI", "set demodulation Biphase"), + arg_lit0(NULL, "BIA", "set demodulation Diphase (inverted biphase)"), + arg_lit0("i", "inv", "set/reset data signal inversion"), + arg_lit0(NULL, "q5", "set/reset as Q5/T5555 chip instead of T55x7"), + arg_lit0(NULL, "st", "set/reset Sequence Terminator on"), + arg_int0(NULL, "rate", "", "set bitrate <8|16|32|40|50|64|100|128>"), + arg_str0("c", "blk0", "", "set configuration from a block0 (4 hex bytes)"), + arg_int0("o", "offset", "", "set offset, where data should start decode in bitstream"), + }; + + uint8_t idx = 19; + arg_add_t55xx_downloadlink(argtable, &idx, T55XX_DLMODE_SINGLE, config.downlink_mode); + CLIExecWithReturn(ctx, Cmd, argtable, true); + + idx = 1; + bool mods[12]; + int verify_mods = 0; + while (idx - 1 < sizeof(mods)) { + mods[idx - 1] = arg_get_lit(ctx, idx); + verify_mods += mods[idx - 1]; + idx++; + } + + bool invert = arg_get_lit(ctx, idx++); + bool use_q5 = arg_get_lit(ctx, idx++); + bool use_st = arg_get_lit(ctx, idx++); + + int bitrate = arg_get_int_def(ctx, idx++, -1); - uint8_t offset = 0, bitRate = 0; - char modulation[6] = {0x00}; - uint8_t rates[9] = {8, 16, 32, 40, 50, 64, 100, 128, 0}; - uint8_t cmdp = 0; - uint8_t downlink_mode = 0; - bool errors = false; - uint32_t block0 = 0; bool gotconf = false; + uint32_t block0 = 0; + int res = arg_get_u32_hexstr_def_nlen(ctx, idx++, 0, &block0, 4, true); + if (res == 0 || res == 2) { + PrintAndLogEx(ERR, "block0 data must be 4 hex bytes"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + if (res == 1) { + gotconf = true; + } - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - char tmp = tolower(param_getchar(Cmd, cmdp)); - switch (tmp) { - case 'h': - return usage_t55xx_config(); - case 'b': - errors |= param_getdec(Cmd, cmdp + 1, &bitRate); - if (!errors) { - uint8_t i = 0; - for (; i < 9; i++) { - if (rates[i] == bitRate) { - config.bitrate = i; - config.block0 = ((config.block0 & ~(0x1c0000)) | (i << 18)); - break; - } - } - if (i == 9) errors = true; - } - cmdp += 2; - break; - case 'c': - block0 = param_get32ex(Cmd, cmdp + 1, 0, 16); - gotconf = true; - cmdp += 2; - break; - case 'd': - param_getstr(Cmd, cmdp + 1, modulation, sizeof(modulation)); - cmdp += 2; + int offset = arg_get_int_def(ctx, idx++, -1); - if (strcmp(modulation, "FSK") == 0) { - config.modulation = DEMOD_FSK; - } else if (strcmp(modulation, "FSK1") == 0) { - config.modulation = DEMOD_FSK1; - config.inverted = 1; - } else if (strcmp(modulation, "FSK1a") == 0) { - config.modulation = DEMOD_FSK1a; - config.inverted = 0; - } else if (strcmp(modulation, "FSK2") == 0) { - config.modulation = DEMOD_FSK2; - config.inverted = 0; - } else if (strcmp(modulation, "FSK2a") == 0) { - config.modulation = DEMOD_FSK2a; - config.inverted = 1; - } else if (strcmp(modulation, "ASK") == 0) { - config.modulation = DEMOD_ASK; - } else if (strcmp(modulation, "NRZ") == 0) { - config.modulation = DEMOD_NRZ; - } else if (strcmp(modulation, "PSK1") == 0) { - config.modulation = DEMOD_PSK1; - } else if (strcmp(modulation, "PSK2") == 0) { - config.modulation = DEMOD_PSK2; - } else if (strcmp(modulation, "PSK3") == 0) { - config.modulation = DEMOD_PSK3; - } else if (strcmp(modulation, "BIa") == 0) { - config.modulation = DEMOD_BIa; - config.inverted = 1; - } else if (strcmp(modulation, "BI") == 0) { - config.modulation = DEMOD_BI; - config.inverted = 0; - } else { - PrintAndLogEx(WARNING, "Unknown modulation '%s'", modulation); - errors = true; - } - config.block0 = ((config.block0 & ~(0x1f000)) | (config.modulation << 12)); - break; - case 'i': - if ((param_getchar(Cmd, cmdp + 1) == '0') || (param_getchar(Cmd, cmdp + 1) == '1')) { - config.inverted = param_getchar(Cmd, cmdp + 1) == '1'; - cmdp += 2; - } else { - config.inverted = true; - cmdp += 1; - } - break; - case 'o': - errors |= param_getdec(Cmd, cmdp + 1, &offset); - if (!errors) - config.offset = offset; - cmdp += 2; - break; - case 'q': - if ((param_getchar(Cmd, cmdp + 1) == '0') || (param_getchar(Cmd, cmdp + 1) == '1')) { - config.Q5 = param_getchar(Cmd, cmdp + 1) == '1'; - cmdp += 2; - } else { - config.Q5 = true; - cmdp += 1; - } - break; - case 's': - if ((param_getchar(Cmd, cmdp + 1) == '0') || (param_getchar(Cmd, cmdp + 1) == '1')) { - config.ST = param_getchar(Cmd, cmdp + 1) == '1'; - cmdp += 2; - } else { - config.ST = true; - cmdp += 1; - } - config.block0 = ((config.block0 & ~(0x8)) | (config.ST << 3)); - break; - case 'r': - errors = param_getdec(Cmd, cmdp + 1, &downlink_mode); - if (downlink_mode > 3) - downlink_mode = 0; - if (!errors) - config.downlink_mode = downlink_mode; - cmdp += 2; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; + bool r0 = arg_get_lit(ctx, idx++); + bool r1 = arg_get_lit(ctx, idx++); + bool r2 = arg_get_lit(ctx, idx++); + bool r3 = arg_get_lit(ctx, idx++); + CLIParserFree(ctx); + + // validate user specified downlink mode + if ((r0 + r1 + r2 + r3) > 1) { + PrintAndLogEx(FAILED, "Error multiple downlink encoding"); + return PM3_EINVARG; + } + + // validate user specified modulation FSK,FSK1,...BIA + if (verify_mods > 1) { + PrintAndLogEx(FAILED, "Error multiple demodulations, select one"); + return PM3_EINVARG; + } + + // validate user specified bitrate + uint8_t rates[9] = {8, 16, 32, 40, 50, 64, 100, 128, 0}; + if (bitrate != -1) { + uint8_t i = 0; + for (; i < ARRAYLEN(rates); i++) { + if (rates[i] == bitrate) { + config.bitrate = i; + config.block0 = ((config.block0 & ~(0x1c0000)) | (i << 18)); break; + } + } + if (i == 9){ + PrintAndLogEx(FAILED, "Error select a valid bitrate"); + return PM3_EINVARG; } } - //Validations - if (errors) return usage_t55xx_config(); + // validate user specified offset + if (offset > -1) { + config.offset = offset; + } - config.block0Status = userSet; + // validate user specific T5555 / Q5 + config.Q5 = use_q5; + + // validate user specific sequence terminator + config.ST = use_st; + if (use_st) { + config.block0 = ((config.block0 & ~(0x8)) | (config.ST << 3)); + } + + // validate user specific invert + config.inverted = invert; + + // validate user specific downlink mode + uint8_t downlink_mode = config.downlink_mode; + if (r0) + downlink_mode = refFixedBit; + else if (r1) + downlink_mode = refLongLeading; + else if (r2) + downlink_mode = refLeading0; + else if (r3) + downlink_mode = ref1of4; + + config.downlink_mode = downlink_mode; + + // validate user specific modulation + if (mods[0]){ + config.modulation = DEMOD_FSK; + } else if (mods[1]) { + config.modulation = DEMOD_FSK1; + config.inverted = 0; + } else if (mods[2]) { + config.modulation = DEMOD_FSK1a; + config.inverted = 1; + } else if (mods[3]) { + config.modulation = DEMOD_FSK2; + config.inverted = 0; + } else if (mods[4]) { + config.modulation = DEMOD_FSK2a; + config.inverted = 1; + } else if (mods[5]) { + config.modulation = DEMOD_ASK; + } else if (mods[6]) { + config.modulation = DEMOD_PSK1; + } else if (mods[7]) { + config.modulation = DEMOD_PSK2; + } else if (mods[8]) { + config.modulation = DEMOD_PSK3; + } else if (mods[9]) { + config.modulation = DEMOD_NRZ; + } else if (mods[10]) { + config.modulation = DEMOD_BI; + config.inverted = 0; + } else if (mods[11]) { + config.modulation = DEMOD_BIa; + config.inverted = 1; + } + + config.block0 = ((config.block0 & ~(0x1f000)) | (config.modulation << 12)); + + config.block0Status = USERSET; if (gotconf) { SetConfigWithBlock0Ex(block0, config.offset, config.Q5); } + PrintAndLogEx(INFO, "--- " _CYAN_("current t55xx config") " --------------------------"); return printConfiguration(config); } int T55xxReadBlock(uint8_t block, bool page1, bool usepwd, uint8_t override, uint32_t password, uint8_t downlink_mode) { @@ -711,6 +607,7 @@ int T55xxReadBlockEx(uint8_t block, bool page1, bool usepwd, uint8_t override, u if (t55xxTryDetectModulationEx(downlink_mode, false, 0, password) == false) { PrintAndLogEx(WARNING, "Safety check: Could not detect if PWD bit is set in config block. Exits."); + PrintAndLogEx(HINT, "Consider using the override parameter to force read."); return PM3_EWRONGANSWER; } else { PrintAndLogEx(WARNING, "Safety check: PWD bit is NOT set in config block. Reading without password..."); @@ -735,51 +632,67 @@ int T55xxReadBlockEx(uint8_t block, bool page1, bool usepwd, uint8_t override, u } static int CmdT55xxReadBlock(const char *Cmd) { - uint8_t block = REGULAR_READ_MODE_BLOCK; - uint8_t override = 0; - uint8_t cmdp = 0; - uint8_t downlink_mode = config.downlink_mode; - uint32_t password = 0; //default to blank Block 7 + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf t55xx read", + "Read T55xx block data. This commands defaults to page 0.\n\n" + _RED_(" * * * WARNING * * *") "\n" + _CYAN_("Use of read with password on a tag not configured") "\n" + _CYAN_("for a password can damage the tag") "\n" + _RED_(" * * * * * * * * * *"), + "lf t55xx read -b 0 --> read data from block 0\n" + "lf t55xx read -b 0 --pwd 01020304 --> read data from block 0, pwd 01020304\n" + "lf t55xx read -b 0 --pwd 01020304 -o --> read data from block 0, pwd 01020304, override\n" + ); + + // 1 (help) + 4(four user specified params) + (5 T55XX_DLMODE_SINGLE) + void *argtable[5 + 5] = { + arg_param_begin, + arg_int1("b", "blk", "<0-7>", "block number to read"), + arg_str0("p", "pwd", "", "password (4 hex bytes)"), + arg_lit0("o", "override", "override safety check"), + arg_lit0(NULL, "pg1", "read page 1"), + }; + uint8_t idx = 5; + arg_add_t55xx_downloadlink(argtable, &idx, T55XX_DLMODE_SINGLE, config.downlink_mode); + CLIExecWithReturn(ctx, Cmd, argtable, true); + + int block = arg_get_int_def(ctx, 1, REGULAR_READ_MODE_BLOCK); + bool usepwd = false; - bool page1 = false; - bool errors = false; - - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_t55xx_read(); - case 'b': - errors |= param_getdec(Cmd, cmdp + 1, &block); - cmdp += 2; - break; - case 'o': - override = 1; - cmdp++; - break; - case 'p': - password = param_get32ex(Cmd, cmdp + 1, 0, 16); - usepwd = true; - cmdp += 2; - break; - case '1': - page1 = true; - cmdp++; - break; - case 'r': - downlink_mode = param_get8ex(Cmd, cmdp + 1, 0, 10); - if (downlink_mode > 3) - downlink_mode = 0; - - cmdp += 2; - break; - - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } + uint32_t password = 0; + int res = arg_get_u32_hexstr_def_nlen(ctx, 2, 0, &password, 4, true); + if (res == 0 || res == 2) { + PrintAndLogEx(ERR, "Password should be 4 hex bytes"); + CLIParserFree(ctx); + return PM3_EINVARG; } - if (errors || cmdp == 0) return usage_t55xx_read(); + if (res == 1) { + usepwd = true; + } + + uint8_t override = arg_get_lit(ctx, 3); + bool page1 = arg_get_lit(ctx, 4); + + bool r0 = arg_get_lit(ctx, 5); + bool r1 = arg_get_lit(ctx, 6); + bool r2 = arg_get_lit(ctx, 7); + bool r3 = arg_get_lit(ctx, 8); + CLIParserFree(ctx); + + if ((r0 + r1 + r2 + r3) > 1) { + PrintAndLogEx(FAILED, "Error multiple downlink encoding"); + return PM3_EINVARG; + } + + uint8_t downlink_mode = config.downlink_mode; + if (r0) + downlink_mode = refFixedBit; + else if (r1) + downlink_mode = refLongLeading; + else if (r2) + downlink_mode = refLeading0; + else if (r3) + downlink_mode = ref1of4; if (block > 7 && block != REGULAR_READ_MODE_BLOCK) { PrintAndLogEx(NORMAL, "Block must be between 0 and 7"); @@ -997,10 +910,10 @@ static int CmdT55xxDetect(const char *Cmd) { downlink_mode = refLeading0; else if (r3) downlink_mode = ref1of4; - - if (ra) + else // This will set the default to user all d/l modes which will cover the ra flag as well. try_all_dl_modes = true; + bool try_with_pwd = false; bool found = false; bool usewake = false; @@ -1026,9 +939,9 @@ static int CmdT55xxDetect(const char *Cmd) { do { // do ... while to check without password then loop back if password supplied do { - if (try_all_dl_modes) { - for (uint8_t m = downlink_mode; m < 4; m++) { + // Loop from 1st d/l mode refFixedBit to the last d/l mode ref1of4 + for (uint8_t m = refFixedBit; m <= ref1of4; m++) { if (usewake) { // call wake if (try_with_pwd) @@ -1270,7 +1183,7 @@ bool t55xxTryDetectModulationEx(uint8_t downlink_mode, bool print_config, uint32 config.pwd = pwd & 0xffffffff; } - config.block0Status = autoDetect; + config.block0Status = AUTODETECT; if (print_config) printConfiguration(config); @@ -1306,7 +1219,7 @@ bool t55xxTryDetectModulationEx(uint8_t downlink_mode, bool print_config, uint32 PrintAndLogEx(NORMAL, "--[%d]---------------", i + 1); } - config.block0Status = autoDetect; + config.block0Status = AUTODETECT; if (print_config) printConfiguration(tests[i]); } @@ -1362,17 +1275,16 @@ bool GetT55xxBlockData(uint32_t *blockdata) { void printT55xxBlock(uint8_t blockNum, bool page1) { - uint32_t blockData = 0; - uint8_t bytes[4] = {0}; - - if (GetT55xxBlockData(&blockData) == false) + uint32_t val = 0; + if (GetT55xxBlockData(&val) == false) return; - num_to_bytes(blockData, 4, bytes); + uint8_t bytes[4] = {0}; + num_to_bytes(val, 4, bytes); - T55x7_SaveBlockData((page1) ? blockNum + 8 : blockNum, blockData); + T55x7_SaveBlockData((page1) ? blockNum + 8 : blockNum, val); - PrintAndLogEx(SUCCESS, " %02d | %08X | %s | %s", blockNum, blockData, sprint_bin(DemodBuffer + config.offset, 32), sprint_ascii(bytes, 4)); + PrintAndLogEx(SUCCESS, " %02d | %08X | %s | %s", blockNum, val, sprint_bin(DemodBuffer + config.offset, 32), sprint_ascii(bytes, 4)); } static bool testModulation(uint8_t mode, uint8_t modread) { @@ -1583,91 +1495,103 @@ int CmdT55xxSpecial(const char *Cmd) { } int printConfiguration(t55xx_conf_block_t b) { - PrintAndLogEx(INFO, " Chip Type : " _GREEN_("%s"), (b.Q5) ? "Q5/T5555" : "T55x7"); - PrintAndLogEx(INFO, " Modulation : " _GREEN_("%s"), GetSelectedModulationStr(b.modulation)); - PrintAndLogEx(INFO, " Bit Rate : %s", GetBitRateStr(b.bitrate, (b.block0 & T55x7_X_MODE && (b.block0 >> 28 == 6 || b.block0 >> 28 == 9)))); - PrintAndLogEx(INFO, " Inverted : %s", (b.inverted) ? _GREEN_("Yes") : "No"); - PrintAndLogEx(INFO, " Offset : %d", b.offset); - PrintAndLogEx(INFO, " Seq. Term. : %s", (b.ST) ? _GREEN_("Yes") : "No"); - PrintAndLogEx(INFO, " Block0 : 0x%08X %s", b.block0, GetConfigBlock0Source(b.block0Status)); - PrintAndLogEx(INFO, " Downlink Mode : %s", GetDownlinkModeStr(b.downlink_mode)); - PrintAndLogEx(INFO, " Password Set : %s", (b.usepwd) ? _RED_("Yes") : _GREEN_("No")); + PrintAndLogEx(INFO, " Chip type......... " _GREEN_("%s"), (b.Q5) ? "Q5/T5555" : "T55x7"); + PrintAndLogEx(INFO, " Modulation........ " _GREEN_("%s"), GetSelectedModulationStr(b.modulation)); + PrintAndLogEx(INFO, " Bit rate.......... %s", GetBitRateStr(b.bitrate, (b.block0 & T55x7_X_MODE && (b.block0 >> 28 == 6 || b.block0 >> 28 == 9)))); + PrintAndLogEx(INFO, " Inverted.......... %s", (b.inverted) ? _GREEN_("Yes") : "No"); + PrintAndLogEx(INFO, " Offset............ %d", b.offset); + PrintAndLogEx(INFO, " Seq. terminator... %s", (b.ST) ? _GREEN_("Yes") : "No"); + PrintAndLogEx(INFO, " Block0............ %08X %s", b.block0, GetConfigBlock0Source(b.block0Status)); + PrintAndLogEx(INFO, " Downlink mode..... %s", GetDownlinkModeStr(b.downlink_mode)); + PrintAndLogEx(INFO, " Password set...... %s", (b.usepwd) ? _RED_("Yes") : _GREEN_("No")); if (b.usepwd) { - PrintAndLogEx(INFO, " Password : %08X", b.pwd); + PrintAndLogEx(INFO, " Password.......... %08X", b.pwd); } PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } static int CmdT55xxWriteBlock(const char *Cmd) { - uint8_t block = 0xFF; // default to invalid block - uint32_t data = 0; // default to blank Block - uint32_t password = 0; // default to blank Block 7 - bool usepwd = false; - bool page1 = false; - bool gotdata = false; - bool testMode = false; - bool errors = false; - bool validate = false; - uint8_t cmdp = 0; - uint32_t downlink_mode = config.downlink_mode; + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf t55xx write", + "Write T55xx block data", + "lf t55xx write -b 3 -d 11223344 --> write 11223344 to block 3\n" + "lf t55xx write -b 3 -d 11223344 --pwd 01020304 --> write 11223344 to block 3, pwd 01020304\n" + "lf t55xx write -b 3 -d 11223344 --pwd 01020304 --verify --> write 11223344 to block 3 and try validating write" + ); - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_t55xx_write(); - case 'b': - errors |= param_getdec(Cmd, cmdp + 1, &block); - cmdp += 2; + // 1 (help) + 6 (six user specified params) + (5 T55XX_DLMODE_SINGLE) + void *argtable[7 + 5] = { + arg_param_begin, + arg_int1("b", "blk", "<0-7>", "block number to write"), + arg_str0("d", "data", "", "data to write (4 hex bytes)"), + arg_str0("p", "pwd", "", "password (4 hex bytes)"), + arg_lit0("t", "tm", "test mode write ( " _RED_("danger") " )"), + arg_lit0(NULL, "pg1", "write page 1"), + arg_lit0(NULL, "verify", "try validate data afterward"), + }; + uint8_t idx = 7; + arg_add_t55xx_downloadlink(argtable, &idx, T55XX_DLMODE_SINGLE, config.downlink_mode); + CLIExecWithReturn(ctx, Cmd, argtable, true); - if (block > 7) { - PrintAndLogEx(WARNING, "Block number must be between 0 and 7"); - errors = true; - } - break; - case 'd': - data = param_get32ex(Cmd, cmdp + 1, 0, 16); - gotdata = true; - cmdp += 2; - break; - case 'p': - password = param_get32ex(Cmd, cmdp + 1, 0, 16); - usepwd = true; - cmdp += 2; - break; - case 't': - testMode = true; - cmdp++; - break; - case '1': - page1 = true; - cmdp++; - break; - case 'r': - downlink_mode = param_get8ex(Cmd, cmdp + 1, 0, 10); - if (downlink_mode > 3) - downlink_mode = 0; + int block = arg_get_int_def(ctx, 1, REGULAR_READ_MODE_BLOCK); - cmdp += 2; - break; - case 'v': - validate = true; - cmdp++; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } + uint32_t data = 0; // default to blank Block + int res = arg_get_u32_hexstr_def_nlen(ctx, 2, 0, &data, 4, true); + if (res == 0 || res == 2) { + PrintAndLogEx(ERR, "data must be 4 hex bytes"); + CLIParserFree(ctx); + return PM3_EINVARG; } - if (errors || !gotdata) return usage_t55xx_write(); - char pwdStr[16] = {0}; - snprintf(pwdStr, sizeof(pwdStr), "pwd: 0x%08X", password); + bool usepwd = false; + uint32_t password = 0; // default to blank Block 7 + res = arg_get_u32_hexstr_def_nlen(ctx, 3, 0, &password, 4, true); + if (res == 0 || res == 2) { + PrintAndLogEx(ERR, "Password should be 4 hex bytes"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + if (res == 1) { + usepwd = true; + } - PrintAndLogEx(INFO, "Writing page %d block: %02d data: 0x%08X %s", page1, block, data, (usepwd) ? pwdStr : ""); + bool testmode = arg_get_lit(ctx, 4); + bool page1 = arg_get_lit(ctx, 5); + bool validate = arg_get_lit(ctx, 6); - if (t55xxWrite(block, page1, usepwd, testMode, password, downlink_mode, data) != PM3_SUCCESS) { + bool r0 = arg_get_lit(ctx, 7); + bool r1 = arg_get_lit(ctx, 8); + bool r2 = arg_get_lit(ctx, 9); + bool r3 = arg_get_lit(ctx, 10); + CLIParserFree(ctx); + + if ((r0 + r1 + r2 + r3) > 1) { + PrintAndLogEx(FAILED, "Error multiple downlink encoding"); + return PM3_EINVARG; + } + + uint8_t downlink_mode = config.downlink_mode; + if (r0) + downlink_mode = refFixedBit; + else if (r1) + downlink_mode = refLongLeading; + else if (r2) + downlink_mode = refLeading0; + else if (r3) + downlink_mode = ref1of4; + + if (block > 7 && block != REGULAR_READ_MODE_BLOCK) { + PrintAndLogEx(NORMAL, "Block must be between 0 and 7"); + return PM3_ESOFT; + } + + char pwdstr[16] = {0}; + snprintf(pwdstr, sizeof(pwdstr), "pwd: 0x%08X", password); + + PrintAndLogEx(INFO, "Writing page %d block: %02d data: 0x%08X %s", page1, block, data, (usepwd) ? pwdstr : ""); + + if (t55xxWrite(block, page1, usepwd, testmode, password, downlink_mode, data) != PM3_SUCCESS) { PrintAndLogEx(ERR, "Write failed"); return PM3_ESOFT; } @@ -1738,36 +1662,46 @@ static int CmdT55xxDangerousRaw(const char *Cmd) { static int CmdT55xxReadTrace(const char *Cmd) { - bool frombuff = false; - uint8_t downlink_mode = config.downlink_mode; - uint8_t cmdp = 0; - bool errors = false; + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf t55xx trace", + "Show T55x7 configuration data (page 0/ blk 0) from reading the configuration block", + "lf t55xx trace\n" + "lf t55xx trace -1" + ); - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_t55xx_trace(); - case 'r': - downlink_mode = param_get8ex(Cmd, cmdp + 1, 0, 10); - if (downlink_mode > 3) - downlink_mode = 0; + // 1 (help) + 1 (one user specified params) + (5 T55XX_DLMODE_SINGLE) + void *argtable[2 + 5] = { + arg_param_begin, + arg_lit0("1", NULL, "extract using data from graphbuffer"), + }; + uint8_t idx = 2; + arg_add_t55xx_downloadlink(argtable, &idx, T55XX_DLMODE_SINGLE, config.downlink_mode); + CLIExecWithReturn(ctx, Cmd, argtable, true); - cmdp += 2; - break; - case '1': - frombuff = true; - cmdp += 2; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } + bool use_gb = arg_get_lit(ctx, 1); + + bool r0 = arg_get_lit(ctx, 2); + bool r1 = arg_get_lit(ctx, 3); + bool r2 = arg_get_lit(ctx, 4); + bool r3 = arg_get_lit(ctx, 5); + CLIParserFree(ctx); + + if ((r0 + r1 + r2 + r3) > 1) { + PrintAndLogEx(FAILED, "Error multiple downlink encoding"); + return PM3_EINVARG; } - if (errors) return usage_t55xx_trace(); + uint8_t downlink_mode = config.downlink_mode; + if (r0) + downlink_mode = refFixedBit; + else if (r1) + downlink_mode = refLongLeading; + else if (r2) + downlink_mode = refLeading0; + else if (r3) + downlink_mode = ref1of4; - if (!frombuff) { + if (use_gb == false) { // sanity check. if (SanityOfflineCheck(false) != PM3_SUCCESS) return PM3_ENODATA; @@ -1780,12 +1714,18 @@ static int CmdT55xxReadTrace(const char *Cmd) { } if (config.Q5) { - if (!DecodeT5555TraceBlock()) return PM3_ESOFT; + if (DecodeT5555TraceBlock() == false) { + return PM3_ESOFT; + } } else { - if (!DecodeT55xxBlock()) return PM3_ESOFT; + if (DecodeT55xxBlock() == false) { + return PM3_ESOFT; + } } - if (!DemodBufferLen) return PM3_ESOFT; + if (DemodBufferLen == 0){ + return PM3_ESOFT; + } RepaintGraphWindow(); uint8_t repeat = (config.offset > 5) ? 32 : 0; @@ -1890,22 +1830,21 @@ static int CmdT55xxReadTrace(const char *Cmd) { } void printT55x7Trace(t55x7_tracedata_t data, uint8_t repeat) { - PrintAndLogEx(NORMAL, "--- " _CYAN_("T55x7 Trace Information") " ----------------------------------"); - PrintAndLogEx(NORMAL, "-------------------------------------------------------------"); - PrintAndLogEx(NORMAL, " ACL Allocation class (ISO/IEC 15963-1) : 0x%02X (%d)", data.acl, data.acl); - PrintAndLogEx(NORMAL, " MFC Manufacturer ID (ISO/IEC 7816-6) : 0x%02X (%d) - %s", data.mfc, data.mfc, getTagInfo(data.mfc)); - PrintAndLogEx(NORMAL, " CID : 0x%02X (%d) - %s", data.cid, data.cid, GetModelStrFromCID(data.cid)); - PrintAndLogEx(NORMAL, " ICR IC Revision : %d", data.icr); - PrintAndLogEx(NORMAL, " Manufactured"); - PrintAndLogEx(NORMAL, " Year/Quarter : %d/%d", data.year, data.quarter); - PrintAndLogEx(NORMAL, " Lot ID : %d", data.lotid); - PrintAndLogEx(NORMAL, " Wafer number : %d", data.wafer); - PrintAndLogEx(NORMAL, " Die Number : %d", data.dw); - PrintAndLogEx(NORMAL, "-------------------------------------------------------------"); - PrintAndLogEx(NORMAL, " Raw Data - Page 1"); - PrintAndLogEx(NORMAL, " Block 1 : 0x%08X %s", data.bl1, sprint_bin(DemodBuffer + config.offset + repeat, 32)); - PrintAndLogEx(NORMAL, " Block 2 : 0x%08X %s", data.bl2, sprint_bin(DemodBuffer + config.offset + repeat + 32, 32)); - PrintAndLogEx(NORMAL, "-------------------------------------------------------------"); + PrintAndLogEx(INFO, "--- " _CYAN_("T55x7 Trace Information") " ----------------------------------"); + PrintAndLogEx(INFO, " ACL Allocation class (ISO/IEC 15963-1) : 0x%02X ( %d )", data.acl, data.acl); + PrintAndLogEx(INFO, " MFC Manufacturer ID (ISO/IEC 7816-6) : 0x%02X ( %d ) - %s", data.mfc, data.mfc, getTagInfo(data.mfc)); + PrintAndLogEx(INFO, " CID : 0x%02X ( %d ) - %s", data.cid, data.cid, GetModelStrFromCID(data.cid)); + PrintAndLogEx(INFO, " ICR IC Revision : %d", data.icr); + PrintAndLogEx(INFO, " Manufactured"); + PrintAndLogEx(INFO, " Year/Quarter... %d/%d", data.year, data.quarter); + PrintAndLogEx(INFO, " Lot ID......... %d", data.lotid); + PrintAndLogEx(INFO, " Wafer number... %d", data.wafer); + PrintAndLogEx(INFO, " Die Number..... %d", data.dw); + PrintAndLogEx(INFO, "-------------------------------------------------------------"); + PrintAndLogEx(INFO, " Raw Data - Page 1"); + PrintAndLogEx(INFO, " Block 1... %08X - %s", data.bl1, sprint_bin(DemodBuffer + config.offset + repeat, 32)); + PrintAndLogEx(INFO, " Block 2... %08X - %s", data.bl2, sprint_bin(DemodBuffer + config.offset + repeat + 32, 32)); + PrintAndLogEx(NORMAL, ""); /* Trace info. @@ -1937,16 +1876,15 @@ void printT55x7Trace(t55x7_tracedata_t data, uint8_t repeat) { } void printT5555Trace(t5555_tracedata_t data, uint8_t repeat) { - PrintAndLogEx(NORMAL, "--- " _CYAN_("Q5/T5555 Trace Information") " ---------------------------"); - PrintAndLogEx(NORMAL, "-------------------------------------------------------------"); - PrintAndLogEx(NORMAL, " ICR IC Revision : %d", data.icr); - PrintAndLogEx(NORMAL, " Lot : %c%d", data.lotidc, data.lotid); - PrintAndLogEx(NORMAL, " Wafer number : %d", data.wafer); - PrintAndLogEx(NORMAL, " Die Number : %d", data.dw); - PrintAndLogEx(NORMAL, "-------------------------------------------------------------"); - PrintAndLogEx(NORMAL, " Raw Data - Page 1"); - PrintAndLogEx(NORMAL, " Block 1 : 0x%08X %s", data.bl1, sprint_bin(DemodBuffer + config.offset + repeat, 32)); - PrintAndLogEx(NORMAL, " Block 2 : 0x%08X %s", data.bl2, sprint_bin(DemodBuffer + config.offset + repeat + 32, 32)); + PrintAndLogEx(INFO, "--- " _CYAN_("Q5/T5555 Trace Information") " ---------------------------"); + PrintAndLogEx(INFO, " ICR IC Revision.... %d", data.icr); + PrintAndLogEx(INFO, " Lot ID......... %c%d", data.lotidc, data.lotid); + PrintAndLogEx(INFO, " Wafer number... %d", data.wafer); + PrintAndLogEx(INFO, " Die Number..... %d", data.dw); + PrintAndLogEx(INFO, "-------------------------------------------------------------"); + PrintAndLogEx(INFO, " Raw Data - Page 1"); + PrintAndLogEx(INFO, " Block 1... %08X - %s", data.bl1, sprint_bin(DemodBuffer + config.offset + repeat, 32)); + PrintAndLogEx(INFO, " Block 2... %08X - %s", data.bl2, sprint_bin(DemodBuffer + config.offset + repeat + 32, 32)); /* ** Q5 ** @@ -2040,75 +1978,121 @@ static void printT5x7KnownBlock0(uint32_t b0) { break; } - if (strlen(s) > 0) - PrintAndLogEx(SUCCESS, "\nConfig block match : " _YELLOW_("%s"), s); + if (strlen(s) > 0) { + PrintAndLogEx(SUCCESS, "Config block match : " _YELLOW_("%s"), s); + } } static int CmdT55xxInfo(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf t55xx info", + "Show T55x7 configuration data (page 0/ blk 0) from reading the configuration block\n" + "from tag. Use `-c` to specify a config block data to be used instead of reading tag.", + "lf t55xx info\n" + "lf t55xx info -1\n" + "lf t55xx info -p 11223344\n" + "lf t55xx info -c 00083040\n" + "lf t55xx info -c 6001805A --q5" + ); + + // 1 (help) + 4 (four user specified params) + (5 T55XX_DLMODE_SINGLE) + void *argtable[5 + 5] = { + arg_param_begin, + arg_lit0("1", NULL, "extract using data from graphbuffer"), + arg_str0("p", "pwd", "", "password (4 hex bytes)"), + arg_str0("c", "blk0", "", "use these data instead (4 hex bytes)"), + arg_lit0(NULL, "q5", "interprete provided data as T5555/Q5 config"), + }; + uint8_t idx = 5; + arg_add_t55xx_downloadlink(argtable, &idx, T55XX_DLMODE_SINGLE, config.downlink_mode); + CLIExecWithReturn(ctx, Cmd, argtable, true); + + bool use_gb = arg_get_lit(ctx, 1); + + bool usepwd = false; + uint32_t password = 0; + int res = arg_get_u32_hexstr_def_nlen(ctx, 2, 0, &password, 4, true); + if (res == 0 || res == 2) { + PrintAndLogEx(ERR, "Password must be 4 hex bytes"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + if (res == 1) { + usepwd = true; + } + + bool gotdata = false; + uint32_t block0 = 0; + res = arg_get_u32_hexstr_def_nlen(ctx, 3, 0, &block0, 4, true); + if (res == 0 || res == 2) { + PrintAndLogEx(ERR, "block0 data must be 4 hex bytes"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + if (res == 1) { + gotdata = true; + } + + bool dataasq5 = arg_get_lit(ctx, 4); + + bool r0 = arg_get_lit(ctx, 5); + bool r1 = arg_get_lit(ctx, 6); + bool r2 = arg_get_lit(ctx, 7); + bool r3 = arg_get_lit(ctx, 8); + CLIParserFree(ctx); + + if (gotdata && use_gb) { + PrintAndLogEx(FAILED, "Must select one of user supplied data and use graphbuffer"); + return PM3_EINVARG; + } + + if (dataasq5 && gotdata == false) { + PrintAndLogEx(FAILED, "Must specify user supplied Q5 data"); + return PM3_EINVARG; + } + + if ((r0 + r1 + r2 + r3) > 1) { + PrintAndLogEx(FAILED, "Error multiple downlink encoding"); + return PM3_EINVARG; + } + + uint8_t downlink_mode = config.downlink_mode; + if (r0) + downlink_mode = refFixedBit; + else if (r1) + downlink_mode = refLongLeading; + else if (r2) + downlink_mode = refLeading0; + else if (r3) + downlink_mode = ref1of4; + + /* Page 0 Block 0 Configuration data. Normal mode Extended mode */ - bool frombuff = false, gotdata = false, dataasq5 = false, usepwd = false; - uint8_t cmdp = 0; - uint8_t downlink_mode = config.downlink_mode; - uint32_t block0 = 0, password = 0; - while (param_getchar(Cmd, cmdp) != 0x00) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_t55xx_info(); - case 'c': - block0 = param_get32ex(Cmd, cmdp + 1, 0, 16); - gotdata = true; - cmdp += 2; - break; - case 'p': - password = param_get32ex(Cmd, cmdp + 1, 0, 16); - usepwd = true; - cmdp += 2; - break; - case '1': - frombuff = true; - cmdp += 2; - break; - case 'q': - dataasq5 = true; - cmdp += 2; - break; - case 'r': - downlink_mode = param_get8ex(Cmd, cmdp + 1, 0, 10); - if (downlink_mode > 3) - downlink_mode = 0; + if (use_gb == false && gotdata == false) { + // sanity check. + if (SanityOfflineCheck(false) != PM3_SUCCESS) { + return PM3_ENODATA; + } - cmdp += 2; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - return usage_t55xx_info(); + if (!AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password, downlink_mode)) { + return PM3_ENODATA; } } - if (gotdata && frombuff) - return usage_t55xx_info(); - - if (dataasq5 && !gotdata) - return usage_t55xx_info(); - - if (!frombuff && !gotdata) { - // sanity check. - if (SanityOfflineCheck(false) != PM3_SUCCESS) return PM3_ENODATA; - - if (!AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password, downlink_mode)) - return PM3_ENODATA; - } - - if (!gotdata) { - if (!DecodeT55xxBlock()) return PM3_ESOFT; + if (gotdata == false) { + if (DecodeT55xxBlock() == false) { + return PM3_ESOFT; + } // too little space to start with - if (DemodBufferLen < 32 + config.offset) return PM3_ESOFT; + if (DemodBufferLen < 32 + config.offset) { + return PM3_ESOFT; + } //PrintAndLogEx(NORMAL, "Offset+32 ==%d\n DemodLen == %d", config.offset + 32, DemodBufferLen); block0 = PackBits(config.offset, 32, DemodBuffer); @@ -2127,19 +2111,18 @@ static int CmdT55xxInfo(const char *Cmd) { uint32_t datamod = (block0 >> (32 - 28)) & 0x07; uint32_t maxblk = (block0 >> (32 - 31)) & 0x07; uint32_t st = block0 & 0x01; - PrintAndLogEx(NORMAL, "--- " _CYAN_("Q5 Configuration & Information") " ------------"); - PrintAndLogEx(NORMAL, "-------------------------------------------------------------"); - PrintAndLogEx(NORMAL, " Header : 0x%03X%s", header, (header != 0x600) ? _RED_(" - Warning") : ""); - PrintAndLogEx(NORMAL, " Page select : %d", ps); - PrintAndLogEx(NORMAL, " Fast Write : %s", (fw) ? _GREEN_("Yes") : "No"); - PrintAndLogEx(NORMAL, " Data bit rate : %s", GetBitRateStr(dbr, 1)); - PrintAndLogEx(NORMAL, " AOR - Answer on Request : %s", (aor) ? _GREEN_("Yes") : "No"); - PrintAndLogEx(NORMAL, " Password mode : %s", (pwd) ? _GREEN_("Yes") : "No"); - PrintAndLogEx(NORMAL, " PSK clock frequency : %s", GetPskCfStr(pskcf, 1)); - PrintAndLogEx(NORMAL, " Inverse data : %s", (inv) ? _GREEN_("Yes") : "No"); - PrintAndLogEx(NORMAL, " Modulation : %s", GetQ5ModulationStr(datamod)); - PrintAndLogEx(NORMAL, " Max block : %d", maxblk); - PrintAndLogEx(NORMAL, " Sequence Terminator : %s", (st) ? _GREEN_("Yes") : "No"); + PrintAndLogEx(INFO, "--- " _CYAN_("Q5 Configuration & Information") " ------------"); + PrintAndLogEx(INFO, " Header : 0x%03X%s", header, (header != 0x600) ? _RED_(" - Warning") : ""); + PrintAndLogEx(INFO, " Page select : %d", ps); + PrintAndLogEx(INFO, " Fast Write : %s", (fw) ? _GREEN_("Yes") : "No"); + PrintAndLogEx(INFO, " Data bit rate : %s", GetBitRateStr(dbr, 1)); + PrintAndLogEx(INFO, " AOR - Answer on Request : %s", (aor) ? _GREEN_("Yes") : "No"); + PrintAndLogEx(INFO, " Password mode : %s", (pwd) ? _GREEN_("Yes") : "No"); + PrintAndLogEx(INFO, " PSK clock frequency : %s", GetPskCfStr(pskcf, 1)); + PrintAndLogEx(INFO, " Inverse data : %s", (inv) ? _GREEN_("Yes") : "No"); + PrintAndLogEx(INFO, " Modulation : %s", GetQ5ModulationStr(datamod)); + PrintAndLogEx(INFO, " Max block : %d", maxblk); + PrintAndLogEx(INFO, " Sequence Terminator : %s", (st) ? _GREEN_("Yes") : "No"); } else { uint32_t safer = (block0 >> (32 - 4)) & 0x0F; uint32_t extend = (block0 >> (32 - 15)) & 0x01; @@ -2162,82 +2145,101 @@ static int CmdT55xxInfo(const char *Cmd) { uint32_t inv = (block0 >> (32 - 31)) & 0x01; uint32_t por = (block0 >> (32 - 32)) & 0x01; - PrintAndLogEx(NORMAL, "--- " _CYAN_("T55x7 Configuration & Information") " ---------"); - PrintAndLogEx(NORMAL, "-------------------------------------------------------------"); - PrintAndLogEx(NORMAL, " Safer key : %s", GetSaferStr(safer)); - PrintAndLogEx(NORMAL, " reserved : %d", resv); - PrintAndLogEx(NORMAL, " Data bit rate : %s", GetBitRateStr(dbr, extend)); - PrintAndLogEx(NORMAL, " eXtended mode : %s", (extend) ? _YELLOW_("Yes - Warning") : "No"); - PrintAndLogEx(NORMAL, " Modulation : %s", GetModulationStr(datamod, extend)); - PrintAndLogEx(NORMAL, " PSK clock frequency : %s", GetPskCfStr(pskcf, 0)); - PrintAndLogEx(NORMAL, " AOR - Answer on Request : %s", (aor) ? _GREEN_("Yes") : "No"); - PrintAndLogEx(NORMAL, " OTP - One Time Pad : %s", (otp) ? ((extend) ? _YELLOW_("Yes - Warning") : _RED_("Yes - Warning")) : "No"); - PrintAndLogEx(NORMAL, " Max block : %d", maxblk); - PrintAndLogEx(NORMAL, " Password mode : %s", (pwd) ? _GREEN_("Yes") : "No"); - PrintAndLogEx(NORMAL, " Sequence %-12s : %s", (extend) ? "Start Marker" : "Terminator", (sst) ? _GREEN_("Yes") : "No"); - PrintAndLogEx(NORMAL, " Fast Write : %s", (fw) ? ((extend) ? _GREEN_("Yes") : _RED_("Yes - Warning")) : "No"); - PrintAndLogEx(NORMAL, " Inverse data : %s", (inv) ? ((extend) ? _GREEN_("Yes") : _RED_("Yes - Warning")) : "No"); - PrintAndLogEx(NORMAL, " POR-Delay : %s", (por) ? _GREEN_("Yes") : "No"); + PrintAndLogEx(INFO, "--- " _CYAN_("T55x7 Configuration & Information") " ---------"); + PrintAndLogEx(INFO, " Safer key : %s", GetSaferStr(safer)); + PrintAndLogEx(INFO, " reserved : %d", resv); + PrintAndLogEx(INFO, " Data bit rate : %s", GetBitRateStr(dbr, extend)); + PrintAndLogEx(INFO, " eXtended mode : %s", (extend) ? _YELLOW_("Yes - Warning") : "No"); + PrintAndLogEx(INFO, " Modulation : %s", GetModulationStr(datamod, extend)); + PrintAndLogEx(INFO, " PSK clock frequency : %s", GetPskCfStr(pskcf, 0)); + PrintAndLogEx(INFO, " AOR - Answer on Request : %s", (aor) ? _GREEN_("Yes") : "No"); + PrintAndLogEx(INFO, " OTP - One Time Pad : %s", (otp) ? ((extend) ? _YELLOW_("Yes - Warning") : _RED_("Yes - Warning")) : "No"); + PrintAndLogEx(INFO, " Max block : %d", maxblk); + PrintAndLogEx(INFO, " Password mode : %s", (pwd) ? _GREEN_("Yes") : "No"); + PrintAndLogEx(INFO, " Sequence %-12s : %s", (extend) ? "Start Marker" : "Terminator", (sst) ? _GREEN_("Yes") : "No"); + PrintAndLogEx(INFO, " Fast Write : %s", (fw) ? ((extend) ? _GREEN_("Yes") : _RED_("Yes - Warning")) : "No"); + PrintAndLogEx(INFO, " Inverse data : %s", (inv) ? ((extend) ? _GREEN_("Yes") : _RED_("Yes - Warning")) : "No"); + PrintAndLogEx(INFO, " POR-Delay : %s", (por) ? _GREEN_("Yes") : "No"); } - PrintAndLogEx(NORMAL, "-------------------------------------------------------------"); - PrintAndLogEx(NORMAL, " Raw Data - Page 0, block 0"); + PrintAndLogEx(INFO, "-------------------------------------------------------------"); + PrintAndLogEx(INFO, " Raw Data - Page 0, block 0"); if (gotdata) - PrintAndLogEx(NORMAL, " 0x" _GREEN_("%08X"), block0); + PrintAndLogEx(INFO, " " _GREEN_("%08X"), block0); else - PrintAndLogEx(NORMAL, " 0x" _GREEN_("%08X") " %s", block0, sprint_bin(DemodBuffer + config.offset, 32)); + PrintAndLogEx(INFO, " " _GREEN_("%08X") " - %s", block0, sprint_bin(DemodBuffer + config.offset, 32)); - if (((!gotdata) && (!config.Q5)) || (gotdata && (!dataasq5))) + if (((!gotdata) && (!config.Q5)) || (gotdata && (!dataasq5))) { + PrintAndLogEx(INFO, "--- " _CYAN_("Fingerprint") " ------------"); printT5x7KnownBlock0(block0); + } - PrintAndLogEx(NORMAL, "-------------------------------------------------------------"); - + PrintAndLogEx(NORMAL, ""); + //PrintAndLogEx(INFO, "-------------------------------------------------------------"); return PM3_SUCCESS; } static int CmdT55xxDump(const char *Cmd) { - uint32_t password = 0; - uint8_t override = 0; - uint8_t downlink_mode = config.downlink_mode; + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf t55xx dump", + "This command dumps a T55xx card Page 0 block 0-7.\n" + "It will create three files (bin/eml/json)", + "lf t55xx dump\n" + "lf t55xx dump -p aabbccdd --override\n" + "lf t55xx dump -f my_lf_dump" + ); + + // 1 (help) + 3 (two user specified params) + (5 T55XX_DLMODE_SINGLE) + void *argtable[4 + 5] = { + arg_param_begin, + arg_str0("f", "filename", "", "filename (default is generated on blk 0)"), + arg_lit0("o", "override", "override, force pwd read despite danger to card"), + arg_str0("p", "pwd", "", "password (4 hex bytes)"), + }; + uint8_t idx = 4; + arg_add_t55xx_downloadlink(argtable, &idx, T55XX_DLMODE_SINGLE, T55XX_DLMODE_SINGLE); + CLIExecWithReturn(ctx, Cmd, argtable, true); + + int fnlen = 0; + char filename[FILE_PATH_SIZE] = {0}; + CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, sizeof(filename), &fnlen); + + uint8_t override = arg_get_lit(ctx, 2) ? 1 : 0; + bool usepwd = false; - bool errors = false; - uint8_t cmdp = 0; - char preferredName[FILE_PATH_SIZE] = {0}; - bool success = true; - - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_t55xx_dump(); - case 'r': - downlink_mode = param_get8ex(Cmd, cmdp + 1, 0, 10); - if (downlink_mode > 3) - downlink_mode = 0; - - cmdp += 2; - break; - case 'p': - password = param_get32ex(Cmd, cmdp + 1, 0, 16); - usepwd = true; - cmdp += 2; - break; - case 'o': - override = 1; - cmdp++; - break; - case 'f': - param_getstr(Cmd, cmdp + 1, preferredName, FILE_PATH_SIZE); - cmdp += 2; - if (strlen(preferredName) == 0) - errors = true; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } + uint32_t password = 0; + int res = arg_get_u32_hexstr_def_nlen(ctx, 3, 0, &password, 4, true); + if (res == 0 || res == 2) { + PrintAndLogEx(ERR, "Password should be 4 hex bytes"); + CLIParserFree(ctx); + return PM3_EINVARG; } - if (errors) return usage_t55xx_dump(); + if (res == 1) { + usepwd = true; + } + + bool r0 = arg_get_lit(ctx, 4); + bool r1 = arg_get_lit(ctx, 5); + bool r2 = arg_get_lit(ctx, 6); + bool r3 = arg_get_lit(ctx, 7); + CLIParserFree(ctx); + + if ((r0 + r1 + r2 + r3) > 1) { + PrintAndLogEx(FAILED, "Error multiple downlink encoding"); + return PM3_EINVARG; + } + + uint8_t downlink_mode = config.downlink_mode; + if (r0) + downlink_mode = refFixedBit; + else if (r1) + downlink_mode = refLongLeading; + else if (r2) + downlink_mode = refLeading0; + else if (r3) + downlink_mode = ref1of4; + + bool success = true; // Due to the few different T55xx cards and number of blocks supported // will save the dump file if ALL page 0 is OK @@ -2245,157 +2247,175 @@ static int CmdT55xxDump(const char *Cmd) { for (uint8_t i = 0; i < 8; ++i) { if (T55xxReadBlock(i, 0, usepwd, override, password, downlink_mode) != PM3_SUCCESS) success = false; - // idea for better user experience and display. + // only show override warning on the first block read - if (override == 1) override++; // flag not to show safty for 2nd and on. + if (override == 1) { + override++; + } } printT5xxHeader(1); for (uint8_t i = 0; i < 4; i++) if (T55xxReadBlock(i, 1, usepwd, override, password, downlink_mode) != PM3_SUCCESS) T55x7_SaveBlockData(8 + i, 0x00); + // all ok, save dump to file + if (success) { - if (success) { // all ok save dump to file - // saveFileEML will add .eml extension to filename - // saveFile (binary) passes in the .bin extension. - if (strcmp(preferredName, "") == 0) { // Set default filename, if not set by user - strcpy(preferredName, "lf-t55xx"); + // set default filename, if not set by user + if (strlen(filename) == 0) { + strcpy(filename, "lf-t55xx"); for (uint8_t i = 1; i <= 7; i++) { - if ((cardmem[i].blockdata != 0x00) && (cardmem[i].blockdata != 0xFFFFFFFF)) - snprintf(preferredName + strlen(preferredName), sizeof(preferredName) - strlen(preferredName), "-%08X", cardmem[i].blockdata); - else + if ((cardmem[i].blockdata != 0x00) && (cardmem[i].blockdata != 0xFFFFFFFF)) { + snprintf(filename + strlen(filename), sizeof(filename) - strlen(filename), "-%08X", cardmem[i].blockdata); + } else { break; + } } - strcat(preferredName, "-dump"); + strcat(filename, "-dump"); } // Swap endian so the files match the txt display uint32_t data[T55x7_BLOCK_COUNT]; - for (int i = 0; i < T55x7_BLOCK_COUNT; i++) + for (int i = 0; i < T55x7_BLOCK_COUNT; i++) { data[i] = BSWAP_32(cardmem[i].blockdata); + } - saveFileJSON(preferredName, jsfT55x7, (uint8_t *)data, T55x7_BLOCK_COUNT * sizeof(uint32_t), NULL); - saveFileEML(preferredName, (uint8_t *)data, T55x7_BLOCK_COUNT * sizeof(uint32_t), sizeof(uint32_t)); - saveFile(preferredName, ".bin", data, sizeof(data)); + // saveFileEML will add .eml extension to filename + // saveFile (binary) passes in the .bin extension. + saveFileJSON(filename, jsfT55x7, (uint8_t *)data, T55x7_BLOCK_COUNT * sizeof(uint32_t), NULL); + saveFileEML(filename, (uint8_t *)data, T55x7_BLOCK_COUNT * sizeof(uint32_t), sizeof(uint32_t)); + saveFile(filename, ".bin", data, sizeof(data)); } return PM3_SUCCESS; } static int CmdT55xxRestore(const char *Cmd) { - bool errors = false; - uint8_t cmdp = 0; - char preferredName[FILE_PATH_SIZE] = {0}; - char ext[FILE_PATH_SIZE] = {0}; - int success = PM3_ESOFT; - uint32_t password = 0x00; - bool usepwd = false; - uint32_t data[12] = {0}; - size_t datalen = 0; - uint8_t blockidx; - uint8_t downlink_mode; - char writeCmdOpt[100]; - char pwdOpt [11] = {0}; // p XXXXXXXX + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf t55xx restore", + "This command restores T55xx card page 0/1 n blocks", + "lf t55xx restore -f lf-t55xx-00148040-dump.bin" + ); - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_t55xx_restore(); - case 'f': - param_getstr(Cmd, cmdp + 1, preferredName, FILE_PATH_SIZE); - if (strlen(preferredName) == 0) - errors = true; - cmdp += 2; - break; - case 'p': - password = param_get32ex(Cmd, cmdp + 1, 0, 16); - usepwd = true; - cmdp += 2; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } + void *argtable[] = { + arg_param_begin, + arg_str0("f", "filename", "", "filename of the dump file (bin|eml)"), + arg_str0("p", "pwd", "", "password if target card has password set (4 hex bytes)"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + int fnlen = 0; + char filename[FILE_PATH_SIZE] = {0}; + CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, sizeof(filename), &fnlen); + + bool usepwd = false; + uint32_t password = 0; + int res = arg_get_u32_hexstr_def_nlen(ctx, 2, 0, &password, 4, true); + if (res == 0 || res == 2) { + PrintAndLogEx(ERR, "Password should be 4 hex bytes"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + if (res == 1) { + usepwd = true; + } + CLIParserFree(ctx); + + if (fnlen == 0) { + PrintAndLogEx(ERR, "Must specify a filename"); + return PM3_EINVARG; } - // File name expected to be .eml .bin or .json so sould be at least 4 - if (errors || (strlen(preferredName) == 0)) return usage_t55xx_restore(); + char ext[FILE_PATH_SIZE] = {0}; + uint32_t data[12] = {0}; + size_t datalen = 0; - // split file name into prefix and ext. - int fnLength; - - fnLength = strlen(preferredName); - - success = PM3_ESOFT; - if (fnLength > 4) { // Holds extension [.bin|.eml] - memcpy(ext, &preferredName[fnLength - 4], 4); + int retval = PM3_ESOFT; + if (fnlen > 4) { // Holds extension [.bin|.eml] + memcpy(ext, &filename[fnlen - 4], 4); ext[5] = 0x00; // check if valid file extension and attempt to load data - if (memcmp(ext, ".bin", 4) == 0) { - preferredName[fnLength - 4] = 0x00; - success = loadFile(preferredName, ".bin", data, sizeof(data), &datalen); + filename[fnlen - 4] = 0x00; + retval = loadFile(filename, ".bin", data, sizeof(data), &datalen); } else if (memcmp(ext, ".eml", 4) == 0) { - preferredName[fnLength - 4] = 0x00; + filename[fnlen - 4] = 0x00; datalen = 12; - success = loadFileEML(preferredName, (uint8_t *)data, &datalen); + retval = loadFileEML(filename, (uint8_t *)data, &datalen); - } else - PrintAndLogEx(WARNING, "\nWarning: invalid dump filename "_YELLOW_("%s")" to restore!\n", preferredName); - } - - if (success == PM3_SUCCESS) { // Got data, so write to cards - if (datalen == T55x7_BLOCK_COUNT * 4) { // 12 blocks * 4 bytes per block - if (usepwd) - snprintf(pwdOpt, sizeof(pwdOpt), "p %08X", password); - - // Restore endien for writing to card - for (blockidx = 0; blockidx < 12; blockidx++) - data[blockidx] = BSWAP_32(data[blockidx]); - - // Have data ready, lets write - // Order - // write blocks 1..7 page 0 - // write blocks 1..3 page 1 - // update downlink mode (if needed) and write b 0 - downlink_mode = 0; - if ((((data[11] >> 28) & 0xf) == 6) || (((data[11] >> 28) & 0xf) == 9)) - downlink_mode = (data[11] >> 10) & 3; - - // write out blocks 1-7 page 0 - for (blockidx = 1; blockidx <= 7; blockidx++) { - snprintf(writeCmdOpt, sizeof(writeCmdOpt), "b %d d %08X %s", blockidx, data[blockidx], pwdOpt); - - if (CmdT55xxWriteBlock(writeCmdOpt) != PM3_SUCCESS) - PrintAndLogEx(WARNING, "Warning: error writing blk %d", blockidx); - } - - // if password was set on the "blank" update as we may have just changed it - if (usepwd) - snprintf(pwdOpt, sizeof(pwdOpt), "p %08X", data[7]); - - // write out blocks 1-3 page 1 - for (blockidx = 9; blockidx <= 11; blockidx++) { - snprintf(writeCmdOpt, sizeof(writeCmdOpt), "b %d 1 d %08X %s", blockidx - 8, data[blockidx], pwdOpt); - - if (CmdT55xxWriteBlock(writeCmdOpt) != PM3_SUCCESS) - PrintAndLogEx(WARNING, "Warning: error writing blk %d", blockidx); - } - - // Update downlink mode for the page 0 config write. - config.downlink_mode = downlink_mode; - - // Write the page 0 config - snprintf(writeCmdOpt, sizeof(writeCmdOpt), "b 0 d %08X %s", data[0], pwdOpt); - if (CmdT55xxWriteBlock(writeCmdOpt) != PM3_SUCCESS) - PrintAndLogEx(WARNING, "Warning: error writing blk 0"); + } else { + PrintAndLogEx(WARNING, "\nWarning: invalid dump filename "_YELLOW_("%s")" to restore!\n", filename); } } + if (retval != PM3_SUCCESS) { + return retval; + } + + if (datalen == T55x7_BLOCK_COUNT * 4) { + // 12 blocks * 4 bytes per block + + // this fct creats strings to call "lf t55 write" command. + // + // + uint8_t downlink_mode; + char wcmd[100]; + char pwdopt [14] = {0}; // p XXXXXXXX + + if (usepwd) + snprintf(pwdopt, sizeof(pwdopt), "-p %08X", password); + + uint8_t idx; + // Restore endien for writing to card + for (idx = 0; idx < 12; idx++) { + data[idx] = BSWAP_32(data[idx]); + } + + // Have data ready, lets write + // Order + // write blocks 1..7 page 0 + // write blocks 1..3 page 1 + // update downlink mode (if needed) and write b 0 + downlink_mode = 0; + if ((((data[11] >> 28) & 0xf) == 6) || (((data[11] >> 28) & 0xf) == 9)) + downlink_mode = (data[11] >> 10) & 3; + + // write out blocks 1-7 page 0 + for (idx = 1; idx <= 7; idx++) { + snprintf(wcmd, sizeof(wcmd), "-b %d -d %08X %s", idx, data[idx], pwdopt); + + if (CmdT55xxWriteBlock(wcmd) != PM3_SUCCESS) { + PrintAndLogEx(WARNING, "Warning: error writing blk %d", idx); + } + } + + // if password was set on the "blank" update as we may have just changed it + if (usepwd) { + snprintf(pwdopt, sizeof(pwdopt), "-p %08X", data[7]); + } + + // write out blocks 1-3 page 1 + for (idx = 9; idx <= 11; idx++) { + snprintf(wcmd, sizeof(wcmd), "-b %d --pg1 -d %08X %s", idx - 8, data[idx], pwdopt); + + if (CmdT55xxWriteBlock(wcmd) != PM3_SUCCESS) { + PrintAndLogEx(WARNING, "Warning: error writing blk %d", idx); + } + } + + // Update downlink mode for the page 0 config write. + config.downlink_mode = downlink_mode; + + // Write the page 0 config + snprintf(wcmd, sizeof(wcmd), "-b 0 -d %08X %s", data[0], pwdopt); + if (CmdT55xxWriteBlock(wcmd) != PM3_SUCCESS) { + PrintAndLogEx(WARNING, "Warning: error writing blk 0"); + } + } return PM3_SUCCESS; } /* @@ -2687,17 +2707,17 @@ char *GetConfigBlock0Source(uint8_t id) { char *retStr = buf; switch (id) { - case autoDetect: - snprintf(retStr, sizeof(buf), _YELLOW_("(Auto detect)")); + case AUTODETECT: + snprintf(retStr, sizeof(buf), _YELLOW_("(auto detect)")); break; - case userSet: - snprintf(retStr, sizeof(buf), _YELLOW_("(User set)")); + case USERSET: + snprintf(retStr, sizeof(buf), _YELLOW_("(user set)")); break; - case tagRead: - snprintf(retStr, sizeof(buf), _GREEN_("(Tag read)")); + case TAGREAD: + snprintf(retStr, sizeof(buf), _GREEN_("(tag read)")); break; default: - snprintf(retStr, sizeof(buf), _RED_("(Unknown)")); + snprintf(retStr, sizeof(buf), _RED_("(n/a)")); break; } return buf; @@ -2781,38 +2801,51 @@ static void t55x7_create_config_block(int tagtype) { static int CmdResetRead(const char *Cmd) { - uint8_t downlink_mode = config.downlink_mode; - uint8_t flags = 0; - uint8_t cmdp = 0; - bool errors = false; + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf t55xx resetread", + "Send Reset Cmd then `lf read` the stream to attempt\n" + "to identify the start of it (needs a demod and/or plot after)", + "lf t55xx resetread" + ); - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_t55xx_resetread(); - case 'r': - downlink_mode = param_get8ex(Cmd, cmdp + 1, 0, 10); - if (downlink_mode > 3) - downlink_mode = 0; + // 1 (help) + 0(one user specified params) + (5 T55XX_DLMODE_SINGLE) + void *argtable[0 + 5] = { + arg_param_begin, + arg_lit0("1", NULL, "extract using data from graphbuffer"), + }; + uint8_t idx = 1; + arg_add_t55xx_downloadlink(argtable, &idx, T55XX_DLMODE_SINGLE, config.downlink_mode); + CLIExecWithReturn(ctx, Cmd, argtable, true); - cmdp += 2; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } + bool r0 = arg_get_lit(ctx, 1); + bool r1 = arg_get_lit(ctx, 2); + bool r2 = arg_get_lit(ctx, 3); + bool r3 = arg_get_lit(ctx, 4); + CLIParserFree(ctx); + + if ((r0 + r1 + r2 + r3) > 1) { + PrintAndLogEx(FAILED, "Error multiple downlink encoding"); + return PM3_EINVARG; } - if (errors) return usage_t55xx_resetread(); + uint8_t downlink_mode = config.downlink_mode; + if (r0) + downlink_mode = refFixedBit; + else if (r1) + downlink_mode = refLongLeading; + else if (r2) + downlink_mode = refLeading0; + else if (r3) + downlink_mode = ref1of4; - flags = downlink_mode << 3; + uint8_t flags = downlink_mode << 3; + + PrintAndLogEx(INFO, "Sending reset command..."); PacketResponseNG resp; - clearCommandBuffer(); SendCommandNG(CMD_LF_T55XX_RESET_READ, &flags, sizeof(flags)); - if (!WaitForResponseTimeout(CMD_LF_T55XX_RESET_READ, &resp, 2500)) { + if (WaitForResponseTimeout(CMD_LF_T55XX_RESET_READ, &resp, 2500) == false) { PrintAndLogEx(WARNING, "command execution time out"); return PM3_ETIMEOUT; } @@ -2826,6 +2859,7 @@ static int CmdResetRead(const char *Cmd) { return PM3_EMALLOC; } + PrintAndLogEx(INFO, "Downloading samples..."); if (!GetFromDevice(BIG_BUF, got, gotsize, 0, NULL, 0, NULL, 2500, false)) { PrintAndLogEx(WARNING, "command execution time out"); free(got); @@ -2834,6 +2868,8 @@ static int CmdResetRead(const char *Cmd) { setGraphBuf(got, gotsize); free(got); } + + PrintAndLogEx(INFO, "Done"); return PM3_SUCCESS; } @@ -2905,7 +2941,7 @@ static int CmdT55xxWipe(const char *Cmd) { // Creating cmd string for write block :) char writeData[36] = {0}; char *ptrData = writeData; - snprintf(ptrData, sizeof(writeData), "b 0 "); + snprintf(ptrData, sizeof(writeData), "-b 0 "); if (usepwd) { snprintf(ptrData + strlen(writeData), sizeof(writeData) - strlen(writeData), "p %08x ", password); @@ -2917,7 +2953,7 @@ static int CmdT55xxWipe(const char *Cmd) { for (uint8_t blk = 1; blk < 8; blk++) { - snprintf(ptrData, sizeof(writeData), "b %d d 0", blk); + snprintf(ptrData, sizeof(writeData), "-b %d -d 0", blk); if (CmdT55xxWriteBlock(ptrData) != PM3_SUCCESS) PrintAndLogEx(WARNING, "Warning: error writing blk %d", blk); @@ -2927,7 +2963,7 @@ static int CmdT55xxWipe(const char *Cmd) { // Check and rest t55xx downlink mode. if (config.downlink_mode != T55XX_DLMODE_FIXED) { // Detect found a different mode so card must support - snprintf(ptrData, sizeof(writeData), "b 3 1 d 00000000"); + snprintf(ptrData, sizeof(writeData), "-b 3 --pg1 -d 00000000"); if (CmdT55xxWriteBlock(ptrData) != PM3_SUCCESS) { PrintAndLogEx(WARNING, "Warning: failed writing block 3 page 1 (config)"); } @@ -4191,8 +4227,12 @@ static int CmdT55xxSniff(const char *Cmd) { } static command_t CommandTable[] = { - {"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("operations") " ---------------------"}, + {"-----------", CmdHelp, AlwaysAvailable, "---------------------------- " _CYAN_("notice") " -----------------------------"}, + {"", CmdHelp, AlwaysAvailable, "Remember to run `" _YELLOW_("lf t55xx detect") "` first whenever a new card"}, + {"", CmdHelp, AlwaysAvailable, "is placed on the Proxmark3 or the config block changed."}, + {"", CmdHelp, AlwaysAvailable, ""}, {"help", CmdHelp, AlwaysAvailable, "This help"}, + {"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("operations") " ---------------------"}, {"clonehelp", CmdT55xxCloneHelp, IfPm3Lf, "Shows the available clone commands"}, {"config", CmdT55xxSetConfig, AlwaysAvailable, "Set/Get T55XX configuration (modulation, inverted, offset, rate)"}, {"dangerraw", CmdT55xxDangerousRaw, IfPm3Lf, "Sends raw bitstream. Dangerous, do not use!!"}, @@ -4202,7 +4242,7 @@ static command_t CommandTable[] = { {"info", CmdT55xxInfo, AlwaysAvailable, "Show T55x7 configuration data (page 0/ blk 0)"}, {"p1detect", CmdT55xxDetectPage1, IfPm3Lf, "Try detecting if this is a t55xx tag by reading page 1"}, {"read", CmdT55xxReadBlock, IfPm3Lf, "Read T55xx block data"}, - {"resetread", CmdResetRead, IfPm3Lf, "Send Reset Cmd then lf read the stream to attempt to identify the start of it (needs a demod and/or plot after)"}, + {"resetread", CmdResetRead, IfPm3Lf, "Send Reset Cmd then lf read the stream to attempt to identify the start of it"}, {"restore", CmdT55xxRestore, IfPm3Lf, "Restore T55xx card Page 0 / Page 1 blocks"}, {"trace", CmdT55xxReadTrace, AlwaysAvailable, "Show T55x7 traceability data (page 1/ blk 0-1)"}, {"wakeup", CmdT55xxWakeUp, IfPm3Lf, "Send AOR wakeup command"}, diff --git a/client/src/cmdlft55xx.h b/client/src/cmdlft55xx.h index 83a35b848..d9061d039 100644 --- a/client/src/cmdlft55xx.h +++ b/client/src/cmdlft55xx.h @@ -32,6 +32,7 @@ #define T55X7_NORALSY_CONFIG_BLOCK 0x00088C6A // ASK, compat mode, (NORALSY - KCP3000), data rate 32, 3 data blocks #define T55X7_PRESCO_CONFIG_BLOCK 0x00088088 // ASK, data rate 32, Manchester, 4 data blocks, STT #define T55X7_SECURAKEY_CONFIG_BLOCK 0x000C8060 // ASK, Manchester, data rate 40, 3 data blocks +#define T55X7_UNK_CONFIG_BLOCK 0x000880FA // ASK, Manchester, data rate 32, 7 data blocks STT, Inverse ... // FDXB requires data inversion and BiPhase 57 is simply BiPhase 50 inverted, so we can either do it using the modulation scheme or the inversion flag // we've done both below to prove that it works either way, and the modulation value for BiPhase 50 in the Atmel data sheet of binary "10001" (17) is a typo, @@ -126,10 +127,10 @@ typedef struct { uint8_t offset; uint32_t block0; enum { - notSet = 0x00, - autoDetect = 0x01, - userSet = 0x02, - tagRead = 0x03, + NOTSET = 0x00, + AUTODETECT = 0x01, + USERSET = 0x02, + TAGREAD = 0x03, } block0Status; enum { RF_8 = 0x00, diff --git a/client/src/flash.c b/client/src/flash.c index 9693d8803..2f5f037c3 100644 --- a/client/src/flash.c +++ b/client/src/flash.c @@ -412,7 +412,7 @@ static void flash_suggest_update_bootloader(void) { PrintAndLogEx(ERR, _RED_("reboot the Proxmark3 then only update the main firmware") "\n"); PrintAndLogEx(ERR, "Follow these steps :"); PrintAndLogEx(ERR, " 1) ./pm3-flash-bootrom"); - PrintAndLogEx(ERR, " 2) ./pm3-flash-flash-all"); + PrintAndLogEx(ERR, " 2) ./pm3-flash-all"); PrintAndLogEx(ERR, " 3) ./pm3"); PrintAndLogEx(INFO, "--------------------------------------------------------"); g_printed_msg = true; diff --git a/client/src/uart/uart_posix.c b/client/src/uart/uart_posix.c index 406bf6d7c..4a41b7958 100644 --- a/client/src/uart/uart_posix.c +++ b/client/src/uart/uart_posix.c @@ -130,7 +130,7 @@ serial_port uart_open(const char *pcPortName, uint32_t speed) { portstr = colon + 1; *colon = '\0'; } else { - portstr = "7901"; + portstr = "18888"; } struct addrinfo info; diff --git a/client/src/wiegand_formats.c b/client/src/wiegand_formats.c index d39d648cd..9dff61229 100644 --- a/client/src/wiegand_formats.c +++ b/client/src/wiegand_formats.c @@ -483,6 +483,9 @@ static bool Pack_C15001(wiegand_card_t *card, wiegand_message_t *packed, bool pr if (card->IssueLevel > 0) return false; // Not used in this format if (card->OEM > 0x000003FF) return false; // Can't encode OEM. + if (card->OEM == 0) + card->OEM = 900; + packed->Length = 36; // Set number of bits set_linear_field(packed, card->OEM, 1, 10); set_linear_field(packed, card->FacilityCode, 11, 8); diff --git a/doc/T5577_Guide.md b/doc/T5577_Guide.md index cdffadd20..4bd8f30c6 100644 --- a/doc/T5577_Guide.md +++ b/doc/T5577_Guide.md @@ -1,8 +1,9 @@ # T5577 Introduction Guide -### Based on RRG proxmark3 fork. +### Based on RRG/Iceman Proxmark3 repo ### Ver.1 8 Sep 2019 +### Ver.2 7 March 2021 | Contents | | ----------------------------------------------------------------------------------- | @@ -79,14 +80,16 @@ examples shown, it will be assumed you have run the detect command. ``` You should see a results simular to the following: ``` - Chip Type : T55x7 - Modulation : ASK - Bit Rate : 2 - RF/32 - Inverted : No - Offset : 32 - Seq. Term. : Yes - Block0 : 0x000880E0 - Downlink Mode : default/fixed bit length + [=] Chip type......... T55x7 + [=] Modulation........ ASK + [=] Bit rate.......... 2 - RF/32 + [=] Inverted.......... No + [=] Offset............ 33 + [=] Seq. terminator... Yes + [=] Block0............ 000880E0 (auto detect) + [=] Downlink mode..... default/fixed bit length + [=] Password set...... No + ``` Now that the proxmark3 has detected a T55x7 chip, and found some information about it, we should be able to see all the data on the chip. @@ -140,7 +143,7 @@ can see the card) as, run a low frequency (lf) command for the T55xx chip (t55xx) and read block (b) number 1. ``` - [usb] pm3 --> lf t55xx read b 1 + [usb] pm3 --> lf t55xx read -b 1 ``` result: ``` @@ -156,7 +159,7 @@ can see the card) We use the d option to supply the data ‘12345678’ ``` - [usb] pm3 --> lf t55xx write b 1 d 12345678 + [usb] pm3 --> lf t55xx write -b 1 -d 12345678 ``` result: ``` @@ -164,7 +167,7 @@ can see the card) ``` 3) Now, lets check if the data was written. ``` - [usb] pm3 --> lf t55xx read b 1 + [usb] pm3 --> lf t55xx read -b 1 ``` result: ``` @@ -202,7 +205,7 @@ can see the card) Lets try and write 89ABCDEF ``` - [usb] pm3 --> lf t55xx write b 1 d 89abcdef + [usb] pm3 --> lf t55xx write -b 1 -d 89abcdef ``` result: ``` @@ -210,7 +213,7 @@ can see the card) ``` and check ``` - [usb] pm3 --> lf t55xx read b 1 + [usb] pm3 --> lf t55xx read -b 1 ``` result: ``` @@ -272,9 +275,10 @@ required, please do not proceed. ``` Result: ``` - [=] Begin wiping T55x7 tag + [=] Target T55x7 tag + [=] Default configuration block 000880E0 - [=] Default configation block 000880E0 + [=] Begin wiping... [=] Writing page 0 block: 00 data: 0x000880E0 [=] Writing page 0 block: 01 data: 0x00000000 [=] Writing page 0 block: 02 data: 0x00000000 @@ -291,14 +295,15 @@ required, please do not proceed. ``` result: ``` - Chip Type : T55x7 - Modulation : ASK - Bit Rate : 2 - RF/32 - Inverted : No - Offset : 32 - Seq. Term. : Yes - Block0 : 0x000880E0 - Downlink Mode : default/fixed bit length + [=] Chip type......... T55x7 + [=] Modulation........ ASK + [=] Bit rate.......... 2 - RF/32 + [=] Inverted.......... No + [=] Offset............ 33 + [=] Seq. terminator... Yes + [=] Block0............ 000880E0 (auto detect) + [=] Downlink mode..... default/fixed bit length + [=] Password set...... No ``` If block 0 does not hold the hex data **0x00088040 resolve this @@ -309,7 +314,7 @@ required, please do not proceed. The password is saved in block 7 of page 0. ``` - [usb] pm3 --> lf t55xx write b 7 d 12345678 + [usb] pm3 --> lf t55xx write -b 7 -d 12345678 ``` result: ``` @@ -389,7 +394,7 @@ required, please do not proceed. If you have completed all steps and have the exact same results, we are ready to apply the new configuration. ``` - [usb] pm3 --> lf t55xx write b 0 d 00088050 + [usb] pm3 --> lf t55xx write -b 0 -d 00088050 ``` result: ``` @@ -412,23 +417,25 @@ required, please do not proceed. Lets try again, but this time supply the password. We use the option p followed by the password. ``` - [usb] pm3 --> lf t55 detect p 12345678 + [usb] pm3 --> lf t55 detect -p 12345678 ``` result: ``` - Chip Type : T55x7 - Modulation : ASK - Bit Rate : 2 - RF/32 - Inverted : No - Offset : 32 - Seq. Term. : Yes - Block0 : 0x00088050 - Downlink Mode : default/fixed bit length + [=] Chip type......... T55x7 + [=] Modulation........ ASK + [=] Bit rate.......... 2 - RF/32 + [=] Inverted.......... No + [=] Offset............ 33 + [=] Seq. terminator... Yes + [=] Block0............ 00088050 (auto detect) + [=] Downlink mode..... default/fixed bit length + [=] Password set...... Yes + [=] Password.......... 00000000 ``` 7) Write a block of data with a password ``` - [usb] pm3 --> lf t55xx write b 1 d 1234abcd p 12345678 + [usb] pm3 --> lf t55xx write -b 1 -d 1234abcd -p 12345678 ``` result: ``` @@ -445,7 +452,7 @@ required, please do not proceed. The proxmark3 has a safety check\! ``` - [usb] pm3 --> lf t55xx read b 1 p 12345678 + [usb] pm3 --> lf t55xx read -b 1 -p 12345678 ``` result: ``` @@ -453,6 +460,7 @@ required, please do not proceed. [+] blk | hex data | binary | ascii [+] ----+----------+----------------------------------+------- [!] Safety check: Could not detect if PWD bit is set in config block. Exits. + [?] Consider using the override parameter to force read. ``` Note that the proxmark3 did not read the block, the safty kicked in @@ -460,7 +468,7 @@ required, please do not proceed. Lets try again with the ‘o’ option as we know the password is set. ``` - [usb] pm3 --> lf t55xx read b 1 p 12345678 o + [usb] pm3 --> lf t55xx read -b 1 -p 12345678 -o ``` result: ``` @@ -486,7 +494,7 @@ required, please do not proceed. In our examples we know what it should be : 00088040 ``` - [usb] pm3 --> lf t55xx write b 0 d 00088040 p 12345678 + [usb] pm3 --> lf t55xx write -b 0 -d 00088040 -p 12345678 ``` result: ``` @@ -498,14 +506,15 @@ required, please do not proceed. ``` result: ``` - Chip Type : T55x7 - Modulation : ASK - Bit Rate : 2 - RF/32 - Inverted : No - Offset : 32 - Seq. Term. : Yes - Block0 : 0x00088040 - Downlink Mode : default/fixed bit length + [=] Chip type......... T55x7 + [=] Modulation........ ASK + [=] Bit rate.......... 2 - RF/32 + [=] Inverted.......... No + [=] Offset............ 33 + [=] Seq. terminator... Yes + [=] Block0............ 00088040 (auto detect) + [=] Downlink mode..... default/fixed bit length + [=] Password set...... No ``` Yes we can and we can see Block 0 is the correct config 00088040 @@ -571,14 +580,16 @@ password set (if not, review and get you card back to this state). 1) Lets turn you T5577 into an EM4100 with ID 1122334455 ``` - [usb] pm3 --> lf em 410x_write 1122334455 1 + [usb] pm3 --> lf em 410x clone --id 1122334455 ``` result: ``` - [+] Writing T55x7 tag with UID 0x1122334455 (clock rate: 64) - #db# Started writing T55x7 tag ... - #db# Clock rate: 64 - #db# Tag T55x7 written with 0xff8c65298c94a940 + [+] Preparing to clone EM4102 to T55x7 tag with ID 0F0368568B (RF/64) + [#] Clock rate: 64 + [#] Tag T55x7 written with 0xff83c03322a646e4 + + [+] Done + [?] Hint: try `lf em 410x reader` to verify ``` 2) Check this has work. @@ -586,42 +597,38 @@ password set (if not, review and get you card back to this state). [usb] pm3 --> lf search ``` result: - ``` - [=] NOTE: some demods output possible binary - [=] if it finds something that looks like a tag - [=] False Positives ARE possible - [=] - [=] Checking for known tags... - - [+] EM410x pattern found - - EM TAG ID : 1122334455 - - Possible de-scramble patterns - - Unique TAG ID : 8844CC22AA - HoneyWell IdentKey { - DEZ 8 : 03359829 - DEZ 10 : 0573785173 - DEZ 5.5 : 08755.17493 - DEZ 3.5A : 017.17493 - DEZ 3.5B : 034.17493 - DEZ 3.5C : 051.17493 - DEZ 14/IK2 : 00073588229205 - DEZ 15/IK3 : 000585269781162 - DEZ 20/ZK : 08080404121202021010 - } - Other : 17493_051_03359829 - Pattern Paxton : 289899093 [0x11478255] - Pattern 1 : 5931804 [0x5A831C] - Pattern Sebury : 17493 51 3359829 [0x4455 0x33 0x334455] - - [+] Valid EM410x ID found! - - - [+] Chipset detection : T55xx found - - [+] Try `lf t55xx` commands + ``` + [=] NOTE: some demods output possible binary + [=] if it finds something that looks like a tag + [=] False Positives ARE possible + [=] + [=] Checking for known tags... + [=] + [+] EM 410x ID 0F0368568B + [+] EM410x ( RF/64 ) + [=] -------- Possible de-scramble patterns --------- + [+] Unique TAG ID : F0C0166AD1 + [=] HoneyWell IdentKey + [+] DEZ 8 : 06837899 + [+] DEZ 10 : 0057169547 + [+] DEZ 5.5 : 00872.22155 + [+] DEZ 3.5A : 015.22155 + [+] DEZ 3.5B : 003.22155 + [+] DEZ 3.5C : 104.22155 + [+] DEZ 14/IK2 : 00064481678987 + [+] DEZ 15/IK3 : 001034014845649 + [+] DEZ 20/ZK : 15001200010606101301 + [=] + [+] Other : 22155_104_06837899 + [+] Pattern Paxton : 259822731 [0xF7C948B] + [+] Pattern 1 : 9750181 [0x94C6A5] + [+] Pattern Sebury : 22155 104 6837899 [0x568B 0x68 0x68568B] + [=] ------------------------------------------------ + + [+] Valid EM410x ID found! + + [+] Chipset detection: T55xx + [?] Hint: try `lf t55xx` commands ``` Looks good. @@ -631,44 +638,43 @@ password set (if not, review and get you card back to this state). ``` result: ``` - [usb] pm3 --> lf t55 detect - Chip Type : T55x7 - Modulation : ASK - Bit Rate : 5 - RF/64 - Inverted : No - Offset : 32 - Seq. Term. : Yes - Block0 : 0x00148040 - Downlink Mode : default/fixed bit length + [=] Chip type......... T55x7 + [=] Modulation........ ASK + [=] Bit rate.......... 5 - RF/64 + [=] Inverted.......... No + [=] Offset............ 33 + [=] Seq. terminator... Yes + [=] Block0............ 00148040 (auto detect) + [=] Downlink mode..... default/fixed bit length + [=] Password set...... No ``` ``` [usb] pm3 --> lf t55xx info ``` result: ``` - - -- T55x7 Configuration & Tag Information -------------------- - ------------------------------------------------------------- - Safer key : 0 - reserved : 0 - Data bit rate : 5 - RF/64 - eXtended mode : No - Modulation : 8 - Manchester - PSK clock frequency : 0 - RF/2 - AOR - Answer on Request : No - OTP - One Time Pad : No - Max block : 2 - Password mode : No - Sequence Terminator : No - Fast Write : No - Inverse data : No - POR-Delay : No - ------------------------------------------------------------- - Raw Data - Page 0 - Block 0 : 0x00148040 00000000000101001000000001000000 - - Config block match : EM unique, Paxton - ------------------------------------------------------------- + + [=] --- T55x7 Configuration & Information --------- + [=] Safer key : 0 + [=] reserved : 0 + [=] Data bit rate : 5 - RF/64 + [=] eXtended mode : No + [=] Modulation : 8 - Manchester + [=] PSK clock frequency : 0 - RF/2 + [=] AOR - Answer on Request : No + [=] OTP - One Time Pad : No + [=] Max block : 2 + [=] Password mode : No + [=] Sequence Terminator : No + [=] Fast Write : No + [=] Inverse data : No + [=] POR-Delay : No + [=] ------------------------------------------------------------- + [=] Raw Data - Page 0, block 0 + [=] 00148040 - 00000000000101001000000001000000 + [=] --- Fingerprint ------------ + [+] Config block match : EM unique, Paxton + ``` We can see that the info gave us more information and confirmed what we decoded by hand. But remember, the detect is still needed so the diff --git a/doc/cliparser_todo.txt b/doc/cliparser_todo.txt index 44f0bac7d..f3cc3500c 100644 --- a/doc/cliparser_todo.txt +++ b/doc/cliparser_todo.txt @@ -32,7 +32,6 @@ data print data samples data setdebugmode data tune -hf 14b sriwrite hf 15 dump hf 15 info hf 15 raw @@ -94,12 +93,4 @@ lf hitag sim lf hitag writer lf hitag dump lf hitag cc -lf t55xx config -lf t55xx dump -lf t55xx info -lf t55xx read -lf t55xx resetread -lf t55xx restore -lf t55xx trace -lf t55xx write script run diff --git a/doc/cloner_notes.md b/doc/cloner_notes.md index 71cada411..92de920ad 100644 --- a/doc/cloner_notes.md +++ b/doc/cloner_notes.md @@ -60,8 +60,8 @@ Standard password is normally (for T55xx): AA55BBBB # Restore page1 data ``` -lf t55xx write b 1 d E0150A48 1 -If t55xx write b 2 d 2D782308 1 +lf t55xx write -b 1 -d E0150A48 --pg1 +If t55xx write -b 2 -d 2D782308 --pg1 ``` # Sniffing the comms diff --git a/doc/ext_flash_notes.md b/doc/ext_flash_notes.md index 46059d9ca..76b4d9279 100644 --- a/doc/ext_flash_notes.md +++ b/doc/ext_flash_notes.md @@ -39,8 +39,8 @@ Page 3: * used by Proxmark3 RDV4 specific functions: flash signature and keys dictionaries, see below for details * to dump it: `mem dump f page3_dump o 196608 l 65536` * to erase it: - * **Beware** it will erase your flash signature (see below) so better to back it up first as you won't be able to regenerate it by yourself! - * It's possible to erase completely page 3 by erase the entire flash memory with the voluntarily undocumented command `mem wipe i`. + * **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! + * edit the source code to enable Page 3 as a valid input in the `mem wipe` command. * Updating keys dictionaries doesn't require to erase page 3. ## Page3 Layout @@ -64,7 +64,7 @@ Page3 is used as follows by the Proxmark3 RDV4 firmware: * length: 1 sector (actually only a few bytes are used to store `t55xx_config` structure) * **RSA SIGNATURE**, see below for details - * offset: page 3 sector 15 (0xF) offset 0xF7F @ 3*0x10000+15*0x1000+0xF7F=0x3FF7F + * offset: page 3 sector 15 (0xF) offset 0xF7F @ 3*0x10000+15*0x1000+0xF7F=0x3FF7F (decimal 262015) * length: 128 bytes * offset should have been 0x3FF80 but historically it's one byte off and therefore the last byte of the flash is unused @@ -73,23 +73,39 @@ Page3 is used as follows by the Proxmark3 RDV4 firmware: To ensure your Proxmark3 RDV4 is not a counterfeit product, its external flash contains a RSA signature of the flash unique ID. You can verify it with: `mem info` + +Here below is a sample output of a RDV4 device. ``` -[usb] pm3 --> mem info - -[=] --- Flash memory Information --------- - -[=] ------------------------------------------------------------- -[=] ID | xx xx xx xx xx xx xx xx -[=] SHA1 | xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx -[=] RSA SIGNATURE | -[00] | xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx -[01] | xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx -[02] | xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx -[03] | xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx -[=] KEY length | 128 -[+] RSA key validation ok -[+] RSA Verification ok +[usb] pm3 --> mem info + +[=] --- Flash memory Information --------- +[=] ID................... 25AD99A782A867D5 +[=] SHA1................. 67C3B9BA2FA90AD4B283926B70017066C082C156 +[+] Signature............ ( ok ) + +[=] --- RDV4 RSA signature --------------- +[=] C7C7DF7FA3A2391A2B36E97D227C746ED8BB475E8766F54A13BAA9AAB29299BE +[=] 37546AACCC29157ABF8AFBF3A1CFB24275442D565F7E996C6B08090528ADE25E +[=] ED1498E3089C72C68348D83CBD13F1247327BDBC9D75B09ECE3E051E19FE19BB +[=] 98CB038757F2EDFD2DC5060D05C3296BC19A6F768290D555DFD50407E0E13A70 + +[=] --- RDV4 RSA Public key -------------- +[=] Len.................. 128 +[=] Exponent............. 010001 +[=] Public key modulus N +[=] E28D809BF323171D11D1ACA4C32A5B7E0A8974FD171E75AD120D60E9B76968FF +[=] 4B0A6364AE50583F9555B8EE1A725F279E949246DF0EFCE4C02B9F3ACDCC623F +[=] 9337F21C0C066FFB703D8BFCB5067F309E056772096642C2B1A8F50305D5EC33 +[=] DB7FB5A3C8AC42EB635AE3C148C910750ABAA280CE82DC2F180F49F30A1393B5 + +[+] RSA public key validation.... ( ok ) +[+] RSA private key validation... ( ok ) +[+] RSA verification..... ( ok ) +[+] Genuine Proxmark3 RDV4 signature detected ``` -For a backup of the signature: `mem dump p f flash_signature_dump o 262015 l 128` +# backup first! +To make a backup of the signature to file: + +`mem dump p f flash_signature_dump o 262015 l 128` diff --git a/include/hitag.h b/include/hitag.h index 14231bdeb..168d3f439 100644 --- a/include/hitag.h +++ b/include/hitag.h @@ -50,7 +50,7 @@ typedef struct { } PACKED rht2d_crypto; typedef struct { - bool key_no; + uint8_t key_no; uint8_t logdata_0[4]; uint8_t logdata_1[4]; uint8_t nonce[4]; diff --git a/tools/recover_pk.py b/tools/recover_pk.py index c71064cf3..0f01337a7 100755 --- a/tools/recover_pk.py +++ b/tools/recover_pk.py @@ -130,7 +130,8 @@ def selftests(): {'name': "ICODE DNA, ICODE SLIX2", # ! tag UID is considered inverted: E0040118009B5FEE => EE5F9B00180104E0 # TODO one more ICODE-DNA... - 'samples': ["EE5F9B00180104E0", "32D9E7579CD77E6F1FA11419231E874826984C5F189FDE1421684563A9663377"], + 'samples': ["EE5F9B00180104E0", "32D9E7579CD77E6F1FA11419231E874826984C5F189FDE1421684563A9663377", + "838ED22A080104E0", "CAE8183CB4823C765AFDEB78C9D66C959990FD52A5820E76E1D6E025D76EAD79"], 'pk': "048878A2A2D3EEC336B4F261A082BD71F9BE11C4E2E896648B32EFA59CEA6E59F0"}, # {'name': "Minecraft Earth", # # uses secp256r1?, SHA-256, diff --git a/traces/README.md b/traces/README.md index b8d4d1c4d..9817b259e 100644 --- a/traces/README.md +++ b/traces/README.md @@ -89,4 +89,5 @@ |hf_14a_mfu.trace |Reading of a password-protected MFU| |hf_14a_mfu-sim.trace |Trace seen from a Proxmark3 simulating a MFU| |hf_14b_reader.trace |Execution of `hf 14b reader` against a card| -|hf_15_reader.trace |Execution of `hf 15 reader` against a card| +|hf_14b_cryptorf_select.trace |Sniff of libnfc select / anticollision ofa cryptoRF tag| +|hf_15_reader.trace |Execution of `hf 15 reader` against a card| \ No newline at end of file diff --git a/traces/hf_14b_cryptorf_select.trace b/traces/hf_14b_cryptorf_select.trace new file mode 100644 index 000000000..410403190 Binary files /dev/null and b/traces/hf_14b_cryptorf_select.trace differ