diff --git a/client/luascripts/t55_chk_date.lua b/client/luascripts/lf_t55xx_chk_date.lua similarity index 100% rename from client/luascripts/t55_chk_date.lua rename to client/luascripts/lf_t55xx_chk_date.lua diff --git a/client/luascripts/t55_fix.lua b/client/luascripts/lf_t55xx_fix.lua similarity index 100% rename from client/luascripts/t55_fix.lua rename to client/luascripts/lf_t55xx_fix.lua diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 9b2bab31d..2160c9b06 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1877,14 +1877,13 @@ static int emrtd_print_ef_sod_info(uint8_t *dg_hashes_calc, uint8_t *dg_hashes_s PrintAndLogEx(INFO, "------------------------ " _CYAN_("EF_SOD") " ------------------------"); PrintAndLogEx(INFO, "Document Security Object"); PrintAndLogEx(INFO, "contains the digital signatures of the passport data"); + PrintAndLogEx(INFO, ""); if (hash_algo == -1) { PrintAndLogEx(SUCCESS, "Hash algorithm... " _YELLOW_("Unknown")); - PrintAndLogEx(INFO, ""); } else { PrintAndLogEx(SUCCESS, "Hash algorithm... " _YELLOW_("%s"), hashalg_table[hash_algo].name); - PrintAndLogEx(INFO, ""); uint8_t all_zeroes[64] = { 0x00 }; diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c index 0a46e4cd9..e84e55169 100644 --- a/client/src/cmdhfmfu.c +++ b/client/src/cmdhfmfu.c @@ -2067,6 +2067,7 @@ uint64_t GetHF14AMfU_Type(void) { uint8_t version[10] = {0x00}; int len = ulev1_getVersion(version, sizeof(version)); DropField(); + switch (len) { case 0x0A: { /* @@ -2158,6 +2159,7 @@ uint64_t GetHF14AMfU_Type(void) { tagtype = MFU_TT_UNKNOWN; break; } + // This is a test from cards that doesn't answer to GET_VERSION command // UL vs UL-C vs NTAG203 vs FUDAN FM11NT021 (which is NTAG213 compatiable) if (tagtype & (MFU_TT_UL | MFU_TT_UL_C | MFU_TT_NTAG_203)) { diff --git a/client/src/crypto/asn1utils.c b/client/src/crypto/asn1utils.c index 1fa839a7f..67392f534 100644 --- a/client/src/crypto/asn1utils.c +++ b/client/src/crypto/asn1utils.c @@ -107,6 +107,37 @@ int asn1_print(uint8_t *asn1buf, size_t asn1buflen, const char *indent) { return PM3_SUCCESS; } +int asn1_get_tag_length(const uint8_t *data, size_t *n, size_t *offset, size_t total_length) { + + if (*offset >= total_length) { + return -1; + } + + if (data[*offset] & 0x80) { + + // Long form: number of length bytes is indicated by the lower 7 bits + size_t len_bytes = data[*offset] & 0x7F; + + *offset += 1; + + if (*offset + len_bytes > total_length) { + return -1; + } + + *n = 0; + for (size_t i = 0; i < len_bytes; i++) { + *n = (*n << 8) | data[*offset]; + *offset += 1; + } + } else { + // Short form: length is directly represented + *n = data[*offset]; + *offset += 1; + } + + return 0; +} + typedef struct { const char *hex; diff --git a/client/src/crypto/asn1utils.h b/client/src/crypto/asn1utils.h index e55a2926f..57d443e6a 100644 --- a/client/src/crypto/asn1utils.h +++ b/client/src/crypto/asn1utils.h @@ -25,6 +25,8 @@ int asn1_print(uint8_t *asn1buf, size_t asn1buflen, const char *indent); int ecdsa_asn1_get_signature(uint8_t *signature, size_t signaturelen, uint8_t *rval, uint8_t *sval); + +int asn1_get_tag_length(const uint8_t *data, size_t *n, size_t *offset, size_t total_length); int asn1_selftest(void); #endif /* asn1utils.h */ diff --git a/client/src/fileutils.c b/client/src/fileutils.c index db151f3a1..86a3d06b5 100644 --- a/client/src/fileutils.c +++ b/client/src/fileutils.c @@ -1105,7 +1105,9 @@ int loadFileEML_safe(const char *preferredName, void **pdata, size_t *datalen) { int loadFileNFC_safe(const char *preferredName, void *data, size_t maxdatalen, size_t *datalen, nfc_df_e ft) { - if (data == NULL) return PM3_EINVARG; + if (data == NULL) { + return PM3_EINVARG; + } *datalen = 0; int retval = PM3_SUCCESS; @@ -1137,16 +1139,17 @@ int loadFileNFC_safe(const char *preferredName, void *data, size_t maxdatalen, s memset(line, 0, sizeof(line)); if (fgets(line, sizeof(line), f) == NULL) { - if (feof(f)) + if (feof(f)) { break; - + } fclose(f); PrintAndLogEx(FAILED, "file reading error"); return PM3_EFILE; } - if (line[0] == '#') + if (line[0] == '#') { continue; + } str_cleanrn(line, sizeof(line)); str_lower(line); @@ -2626,6 +2629,7 @@ int detect_nfc_dump_format(const char *preferredName, nfc_df_e *dump_type, bool fclose(f); if (verbose) { + switch (*dump_type) { case NFC_DF_MFU: PrintAndLogEx(INFO, "Detected MIFARE Ultralight / NTAG based dump format"); @@ -3107,7 +3111,7 @@ int pm3_load_dump(const char *fn, void **pdump, size_t *dumplen, size_t maxdumpl break; } case FLIPPER: { - nfc_df_e dumptype; + nfc_df_e dumptype = NFC_DF_UNKNOWN; res = detect_nfc_dump_format(fn, &dumptype, true); if (res != PM3_SUCCESS) { break; diff --git a/client/src/fileutils.h b/client/src/fileutils.h index ae04b8265..6fc450dd1 100644 --- a/client/src/fileutils.h +++ b/client/src/fileutils.h @@ -282,8 +282,31 @@ int loadFileDICTIONARYEx(const char *preferredName, void *data, size_t maxdatale */ int loadFileDICTIONARY_safe(const char *preferredName, void **pdata, uint8_t keylen, uint32_t *keycnt); +/** + * @brief Utility function to load data safely from a DICTIONARY textfile. This method takes a preferred name. + * E.g. mfc_default_keys.dic + * + * @param preferredName + * @param suffix + * @param pdata A pointer to a pointer (for reverencing the loaded dictionary) + * @param keylen the number of bytes a key per row is + * @param verbose print messages if true + * @return 0 for ok, 1 for failz +*/ int loadFileDICTIONARY_safe_ex(const char *preferredName, const char *suffix, void **pdata, uint8_t keylen, uint32_t *keycnt, bool verbose); +/** + * @brief Utility function to load data from a XML textfile. This method takes a preferred name. + * E.g. dumpdata-15.xml + * + * @param preferredName + * @param data The data array to store the loaded bytes from file + * @param maxdatalen maximum size of data array in bytes + * @param datalen the number of bytes loaded from file + * @return 0 for ok, 1 for failz +*/ +int loadFileXML_safe(const char *preferredName, const char *suffix, void **pdata, size_t *datalen); + int loadFileBinaryKey(const char *preferredName, const char *suffix, void **keya, void **keyb, size_t *alen, size_t *blen); /** diff --git a/client/t55_chk.lua b/client/t55_chk.lua deleted file mode 100644 index 8f88cdf3c..000000000 --- a/client/t55_chk.lua +++ /dev/null @@ -1,133 +0,0 @@ -local os = require("os") -local ac = require('ansicolors') -local getopt = require('getopt') -local dir = os.getenv('HOME') .. '/proxmark3/client/dictionaries/' -local dictionary_path = dir .. 'T5577date.dic' -local cyan = ac.cyan -local res = ac.reset - -author = ' Author: jareckib - created 02.02.2025' -version = ' version v1.01' -desc = [[ - A simple script for searching the password for T5577. The script creates a - dictionary starting from the entered starting year to the entered ending year. - There are two search methods - DDMMYYYY or YYYYMMDD. Checking the entire year - takes about 1 minute and 50 seconds. Date from 1900 to 2100. The script may be - useful if the password is, for example, a date of birth. -]] - -usage = [[ - script run t55_chk [-s start_year] [-e end_year] [-d | -y] -]] -options = [[ - -h Show this help message - -s Starting year (required) - -e Ending year (default: current year) - -d Search method: DDMMYYYY - -y Search method: YYYYMMDD -]] -examples = [[ - script run t55_chk -s 1999 -d - start from 1999, end year is current year, method 01011999 - script run t55_chk -s 1999 -y - start from 1999, end year is current year, method 19990101 - script run t55_chk -s 1999 -e 2001 -y - start from 1999, end year 2001, method 19990101 - script run t55_chk -s 1999 -e 2001 -d - start from 1999, end year 2001, method 01011999 -]] - -local function help() - print(ac.green..author..res) - print(version) - print(desc) - print(cyan..' Usage:'..res) - print(usage) - print(cyan..' Options:'..res) - print(options) - print(cyan..' Examples:'..res) - print(examples) -end - -local days_in_month = { - [1] = 31, [2] = 28, [3] = 31, [4] = 30, [5] = 31, [6] = 30, - [7] = 31, [8] = 31, [9] = 30, [10] = 31, [11] = 30, [12] = 31 -} - -local function generate_dictionary(start_year, end_year, mode) - local file = io.open(dictionary_path, "w") - if not file then - print(ac.yellow .. ' ERROR: ' .. ac.reset .. 'Cannot create T5577date.dic') - return false - end - - for year = start_year, end_year do - for month = 1, 12 do - local days_in_current_month = days_in_month[month] - if month == 2 and ((year % 4 == 0 and year % 100 ~= 0) or (year % 400 == 0)) then - days_in_current_month = 29 - end - - for day = 1, days_in_current_month do - local month_str = string.format("%02d", month) - local day_str = string.format("%02d", day) - local year_str = tostring(year) - local entry = (mode == "1") and (year_str .. month_str .. day_str) or (day_str .. month_str .. year_str) - file:write(entry .. "\n") - end - end - end - - file:close() - return true -end - -local function oops(err) - core.console('clear') - print( string.rep('--',39) ) - print( string.rep('--',39) ) - print(ac.red..' ERROR:'..res.. err) - print( string.rep('--',39) ) - print( string.rep('--',39) ) - return nil, err -end - -local function main(args) - if #args == 0 then return help() end - - local start_year, end_year, mode = nil, nil, nil - local current_year = tonumber(os.date("%Y")) - - for o, a in getopt.getopt(args, 'hs:e:dy') do - if o == 'h' then return help() end - if o == 's' then - start_year = tonumber(a) - if not start_year then return oops('Invalid start year') end - end - if o == 'e' then - end_year = tonumber(a) - if not end_year then return oops('Invalid end year (-e)') end - end - if o == 'd' then mode = "d" end - if o == 'y' then mode = "y" end - end - - if not start_year then return oops('Starting year is required') end - if start_year < 1900 or start_year > 2100 then - return oops('Start year must be between 1900 and 2100') - end - if args[#args] == "-e" then return oops('Ending year cannot be empty') end - if not end_year then end_year = current_year end - if end_year < 1900 or end_year > 2100 then - return oops('End year must be between 1900 and 2100') - end - - if end_year < start_year then return oops('End year cannot be earlier than start year') end - if not mode then return oops('You must select searching method'..cyan..' -d'..res.. ' or '..cyan.. '-y'..res) end - - if generate_dictionary(start_year, end_year, mode) then - print(ac.green .. " File created: " .. dictionary_path .. res) - print(cyan .. " Starting password testing on T5577..." .. res) - core.console('lf t55 chk -f ' .. dictionary_path) - else - return oops('Problem saving the file') - end -end - -main(args) \ No newline at end of file