diff --git a/applications/external/picopass/helpers/iclass_elite_dict.c b/applications/external/picopass/helpers/iclass_elite_dict.c index e8c13dd1d..f92dce0aa 100644 --- a/applications/external/picopass/helpers/iclass_elite_dict.c +++ b/applications/external/picopass/helpers/iclass_elite_dict.c @@ -5,6 +5,7 @@ #define ICLASS_ELITE_DICT_FLIPPER_NAME APP_DATA_PATH("assets/iclass_elite_dict.txt") #define ICLASS_ELITE_DICT_USER_NAME APP_DATA_PATH("assets/iclass_elite_dict_user.txt") +#define ICLASS_STANDARD_DICT_FLIPPER_NAME APP_DATA_PATH("assets/iclass_standard_dict.txt") #define TAG "IclassEliteDict" @@ -25,6 +26,9 @@ bool iclass_elite_dict_check_presence(IclassEliteDictType dict_type) { (storage_common_stat(storage, ICLASS_ELITE_DICT_FLIPPER_NAME, NULL) == FSE_OK); } else if(dict_type == IclassEliteDictTypeUser) { dict_present = (storage_common_stat(storage, ICLASS_ELITE_DICT_USER_NAME, NULL) == FSE_OK); + } else if(dict_type == IclassStandardDictTypeFlipper) { + dict_present = + (storage_common_stat(storage, ICLASS_STANDARD_DICT_FLIPPER_NAME, NULL) == FSE_OK); } furi_record_close(RECORD_STORAGE); @@ -52,6 +56,15 @@ IclassEliteDict* iclass_elite_dict_alloc(IclassEliteDictType dict_type) { buffered_file_stream_close(dict->stream); break; } + } else if(dict_type == IclassStandardDictTypeFlipper) { + if(!buffered_file_stream_open( + dict->stream, + ICLASS_STANDARD_DICT_FLIPPER_NAME, + FSAM_READ, + FSOM_OPEN_EXISTING)) { + buffered_file_stream_close(dict->stream); + break; + } } // Read total amount of keys @@ -148,4 +161,4 @@ bool iclass_elite_dict_add_key(IclassEliteDict* dict, uint8_t* key) { furi_string_free(key_str); return key_added; -} \ No newline at end of file +} diff --git a/applications/external/picopass/helpers/iclass_elite_dict.h b/applications/external/picopass/helpers/iclass_elite_dict.h index e5ec8dfcb..150cd1b76 100644 --- a/applications/external/picopass/helpers/iclass_elite_dict.h +++ b/applications/external/picopass/helpers/iclass_elite_dict.h @@ -9,6 +9,7 @@ typedef enum { IclassEliteDictTypeUser, IclassEliteDictTypeFlipper, + IclassStandardDictTypeFlipper, } IclassEliteDictType; typedef struct IclassEliteDict IclassEliteDict; @@ -25,4 +26,4 @@ bool iclass_elite_dict_get_next_key(IclassEliteDict* dict, uint8_t* key); bool iclass_elite_dict_rewind(IclassEliteDict* dict); -bool iclass_elite_dict_add_key(IclassEliteDict* dict, uint8_t* key); \ No newline at end of file +bool iclass_elite_dict_add_key(IclassEliteDict* dict, uint8_t* key); diff --git a/applications/external/picopass/picopass_worker.c b/applications/external/picopass/picopass_worker.c index d141bdf6b..2f7aba35f 100644 --- a/applications/external/picopass/picopass_worker.c +++ b/applications/external/picopass/picopass_worker.c @@ -172,14 +172,18 @@ ReturnCode picopass_read_preauth(PicopassBlock* AA1) { return ERR_NONE; } -static ReturnCode picopass_auth_dict( - uint8_t* csn, - PicopassPacs* pacs, - uint8_t* div_key, - IclassEliteDictType dict_type, - bool elite) { +static ReturnCode + picopass_auth_dict(PicopassWorker* picopass_worker, IclassEliteDictType dict_type) { rfalPicoPassReadCheckRes rcRes; rfalPicoPassCheckRes chkRes; + bool elite = (dict_type != IclassStandardDictTypeFlipper); + + PicopassDeviceData* dev_data = picopass_worker->dev_data; + PicopassBlock* AA1 = dev_data->AA1; + PicopassPacs* pacs = &dev_data->pacs; + + uint8_t* csn = AA1[PICOPASS_CSN_BLOCK_INDEX].data; + uint8_t* div_key = AA1[PICOPASS_KD_BLOCK_INDEX].data; ReturnCode err = ERR_PARAM; @@ -204,7 +208,8 @@ static ReturnCode picopass_auth_dict( while(iclass_elite_dict_get_next_key(dict, key)) { FURI_LOG_D( TAG, - "Try to auth with key %zu %02x%02x%02x%02x%02x%02x%02x%02x", + "Try to %s auth with key %zu %02x%02x%02x%02x%02x%02x%02x%02x", + elite ? "elite" : "standard", index++, key[0], key[1], @@ -230,6 +235,8 @@ static ReturnCode picopass_auth_dict( memcpy(pacs->key, key, PICOPASS_BLOCK_LEN); break; } + + if(picopass_worker->state != PicopassWorkerStateDetect) break; } iclass_elite_dict_free(dict); @@ -237,38 +244,23 @@ static ReturnCode picopass_auth_dict( return err; } -ReturnCode picopass_auth(PicopassBlock* AA1, PicopassPacs* pacs) { +ReturnCode picopass_auth(PicopassWorker* picopass_worker) { ReturnCode err; FURI_LOG_I(TAG, "Starting system dictionary attack [Standard KDF]"); - err = picopass_auth_dict( - AA1[PICOPASS_CSN_BLOCK_INDEX].data, - pacs, - AA1[PICOPASS_KD_BLOCK_INDEX].data, - IclassEliteDictTypeFlipper, - false); + err = picopass_auth_dict(picopass_worker, IclassStandardDictTypeFlipper); if(err == ERR_NONE) { return ERR_NONE; } FURI_LOG_I(TAG, "Starting user dictionary attack [Elite KDF]"); - err = picopass_auth_dict( - AA1[PICOPASS_CSN_BLOCK_INDEX].data, - pacs, - AA1[PICOPASS_KD_BLOCK_INDEX].data, - IclassEliteDictTypeUser, - true); + err = picopass_auth_dict(picopass_worker, IclassEliteDictTypeUser); if(err == ERR_NONE) { return ERR_NONE; } FURI_LOG_I(TAG, "Starting system dictionary attack [Elite KDF]"); - err = picopass_auth_dict( - AA1[PICOPASS_CSN_BLOCK_INDEX].data, - pacs, - AA1[PICOPASS_KD_BLOCK_INDEX].data, - IclassEliteDictTypeFlipper, - true); + err = picopass_auth_dict(picopass_worker, IclassEliteDictTypeFlipper); if(err == ERR_NONE) { return ERR_NONE; } @@ -520,7 +512,7 @@ void picopass_worker_detect(PicopassWorker* picopass_worker) { } if(nextState == PicopassWorkerEventSuccess) { - err = picopass_auth(AA1, pacs); + err = picopass_auth(picopass_worker); if(err != ERR_NONE) { FURI_LOG_E(TAG, "picopass_try_auth error %d", err); nextState = PicopassWorkerEventFail; diff --git a/applications/main/nfc/nfc_cli.c b/applications/main/nfc/nfc_cli.c index 23335e299..6e6e04ca9 100644 --- a/applications/main/nfc/nfc_cli.c +++ b/applications/main/nfc/nfc_cli.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -12,6 +13,7 @@ static void nfc_cli_print_usage() { printf("Cmd list:\r\n"); printf("\tdetect\t - detect nfc device\r\n"); printf("\temulate\t - emulate predefined nfca card\r\n"); + printf("\tapdu\t - Send APDU and print response \r\n"); if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { printf("\tfield\t - turn field on\r\n"); } @@ -98,6 +100,67 @@ static void nfc_cli_field(Cli* cli, FuriString* args) { furi_hal_nfc_sleep(); } +static void nfc_cli_apdu(Cli* cli, FuriString* args) { + UNUSED(cli); + if(furi_hal_nfc_is_busy()) { + printf("Nfc is busy\r\n"); + return; + } + + furi_hal_nfc_exit_sleep(); + FuriString* data = NULL; + data = furi_string_alloc(); + FuriHalNfcTxRxContext tx_rx = {}; + FuriHalNfcDevData dev_data = {}; + uint8_t* req_buffer = NULL; + uint8_t* resp_buffer = NULL; + size_t apdu_size = 0; + size_t resp_size = 0; + + do { + if(!args_read_string_and_trim(args, data)) { + printf( + "Use like `nfc apdu 00a404000e325041592e5359532e444446303100 00a4040008a0000003010102` \r\n"); + break; + } + + printf("detecting tag\r\n"); + if(!furi_hal_nfc_detect(&dev_data, 300)) { + printf("Failed to detect tag\r\n"); + break; + } + do { + apdu_size = furi_string_size(data) / 2; + req_buffer = malloc(apdu_size); + hex_chars_to_uint8(furi_string_get_cstr(data), req_buffer); + + memcpy(tx_rx.tx_data, req_buffer, apdu_size); + tx_rx.tx_bits = apdu_size * 8; + tx_rx.tx_rx_type = FuriHalNfcTxRxTypeDefault; + + printf("Sending APDU:%s to Tag\r\n", furi_string_get_cstr(data)); + if(!furi_hal_nfc_tx_rx(&tx_rx, 300)) { + printf("Failed to tx_rx\r\n"); + break; + } + resp_size = (tx_rx.rx_bits / 8) * 2; + resp_buffer = malloc(resp_size); + uint8_to_hex_chars(tx_rx.rx_data, resp_buffer, resp_size); + resp_buffer[resp_size] = 0; + printf("Response: %s\r\n", resp_buffer); + free(req_buffer); + free(resp_buffer); + req_buffer = NULL; + resp_buffer = NULL; + } while(args_read_string_and_trim(args, data)); + } while(false); + + free(req_buffer); + free(resp_buffer); + furi_string_free(data); + furi_hal_nfc_sleep(); +} + static void nfc_cli(Cli* cli, FuriString* args, void* context) { UNUSED(context); FuriString* cmd; @@ -117,6 +180,11 @@ static void nfc_cli(Cli* cli, FuriString* args, void* context) { break; } + if(furi_string_cmp_str(cmd, "apdu") == 0) { + nfc_cli_apdu(cli, args); + break; + } + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { if(furi_string_cmp_str(cmd, "field") == 0) { nfc_cli_field(cli, args); diff --git a/assets/resources/apps_data/picopass/assets/iclass_elite_dict.txt b/assets/resources/apps_data/picopass/assets/iclass_elite_dict.txt index 5da2a2fa8..d11892372 100644 --- a/assets/resources/apps_data/picopass/assets/iclass_elite_dict.txt +++ b/assets/resources/apps_data/picopass/assets/iclass_elite_dict.txt @@ -1,16 +1,10 @@ ## From https://github.com/RfidResearchGroup/proxmark3/blob/master/client/dictionaries/iclass_default_keys.dic -# AA1 -AEA684A6DAB23278 # key1/Kc from PicoPass 2k documentation 7665544332211000 # SAGEM 0123456789ABCDEF -# from loclass demo file. -5b7c62c491c11b39 -# Kd from PicoPass 2k documentation -F0E1D2C3B4A59687 # PicoPass Default Exchange Key 5CBCF1DA45D5FB4F # From HID multiclassSE reader @@ -19,12 +13,6 @@ F0E1D2C3B4A59687 6EFD46EFCBB3C875 E033CA419AEE43F9 -# iCopy-x DRM keys -# iCL tags -2020666666668888 -# iCS tags reversed from the SOs -6666202066668888 - # default picopass KD / Page 0 / Book 1 FDCB5A52EA8F3090 237FF9079863DF44 diff --git a/assets/resources/apps_data/picopass/assets/iclass_standard_dict.txt b/assets/resources/apps_data/picopass/assets/iclass_standard_dict.txt new file mode 100644 index 000000000..46808ef60 --- /dev/null +++ b/assets/resources/apps_data/picopass/assets/iclass_standard_dict.txt @@ -0,0 +1,47 @@ + +## From https://github.com/RfidResearchGroup/proxmark3/blob/master/client/dictionaries/iclass_default_keys.dic + +# AA1 +AEA684A6DAB23278 +# key1/Kc from PicoPass 2k documentation +7665544332211000 +# SAGEM +0123456789ABCDEF +# from loclass demo file. +5b7c62c491c11b39 +# Kd from PicoPass 2k documentation +F0E1D2C3B4A59687 +# PicoPass Default Exchange Key +5CBCF1DA45D5FB4F +# From HID multiclassSE reader +31ad7ebd2f282168 +# From pastebin: https://pastebin.com/uHqpjiuU +6EFD46EFCBB3C875 +E033CA419AEE43F9 + +# iCopy-x DRM keys +# iCL tags +2020666666668888 +# iCS tags reversed from the SOs +6666202066668888 + +# default picopass KD / Page 0 / Book 1 +FDCB5A52EA8F3090 +237FF9079863DF44 +5ADC25FB27181D32 +83B881F2936B2E49 +43644E61EE866BA5 +897034143D016080 +82D17B44C0122963 +4895CA7DE65E2025 +DADAD4C57BE271B7 +E41E9EDEF5719ABF +293D275EC3AF9C7F +C3C169251B8A70FB +F41DAF58B20C8B91 +28877A609EC0DD2B +66584C91EE80D5E5 +C1B74D7478053AE2 + +# default iCLASS RFIDeas +6B65797374726B72 diff --git a/fbt b/fbt index f80e802b6..efe625f03 100755 --- a/fbt +++ b/fbt @@ -25,10 +25,10 @@ fi if [ -z "$FBT_NO_SYNC" ]; then if [ ! -d "$SCRIPT_PATH/.git" ]; then - echo "\".git\" directory not found, please clone repo via \"git clone --recursive\""; + echo "\".git\" directory not found, please clone repo via \"git clone\""; exit 1; fi - git submodule update --init; + git submodule update --init --depth 1; fi $SCONS_EP $SCONS_DEFAULT_FLAGS "$@" diff --git a/fbt.cmd b/fbt.cmd index 92c734860..6e839c778 100644 --- a/fbt.cmd +++ b/fbt.cmd @@ -5,9 +5,9 @@ set SCONS_EP=python -m SCons if [%FBT_NO_SYNC%] == [] ( if exist ".git" ( - git submodule update --init + git submodule update --init --depth 1 ) else ( - echo Not in a git repo, please clone with git clone --recursive + echo Not in a git repo, please clone with "git clone" exit /b 1 ) ) diff --git a/lib/nfc/parsers/plantain_4k_parser.c b/lib/nfc/parsers/plantain_4k_parser.c index aed41965c..19da0b5eb 100644 --- a/lib/nfc/parsers/plantain_4k_parser.c +++ b/lib/nfc/parsers/plantain_4k_parser.c @@ -118,7 +118,7 @@ bool plantain_4k_parser_parse(NfcDeviceData* dev_data) { } furi_string_printf( - dev_data->parsed_data, "\e#Plantain\nN:%llu-\nBalance:%ld\n", card_number, balance); + dev_data->parsed_data, "\e#Plantain\nN:%llu-\nBalance:%lu\n", card_number, balance); return true; } diff --git a/lib/nfc/parsers/plantain_parser.c b/lib/nfc/parsers/plantain_parser.c index 3a1d17732..2e4091dda 100644 --- a/lib/nfc/parsers/plantain_parser.c +++ b/lib/nfc/parsers/plantain_parser.c @@ -91,7 +91,7 @@ bool plantain_parser_parse(NfcDeviceData* dev_data) { } furi_string_printf( - dev_data->parsed_data, "\e#Plantain\nN:%llu-\nBalance:%ld\n", card_number, balance); + dev_data->parsed_data, "\e#Plantain\nN:%llu-\nBalance:%lu\n", card_number, balance); return true; } diff --git a/lib/nfc/parsers/troika_4k_parser.c b/lib/nfc/parsers/troika_4k_parser.c index d87b4eba7..1f1b85a5c 100644 --- a/lib/nfc/parsers/troika_4k_parser.c +++ b/lib/nfc/parsers/troika_4k_parser.c @@ -99,7 +99,7 @@ bool troika_4k_parser_parse(NfcDeviceData* dev_data) { number >>= 4; furi_string_printf( - dev_data->parsed_data, "\e#Troika\nNum: %ld\nBalance: %d rur.", number, balance); + dev_data->parsed_data, "\e#Troika\nNum: %lu\nBalance: %u rur.", number, balance); return true; } diff --git a/lib/nfc/parsers/troika_parser.c b/lib/nfc/parsers/troika_parser.c index 9c16296f3..bfd22364b 100644 --- a/lib/nfc/parsers/troika_parser.c +++ b/lib/nfc/parsers/troika_parser.c @@ -79,7 +79,7 @@ bool troika_parser_parse(NfcDeviceData* dev_data) { number >>= 4; furi_string_printf( - dev_data->parsed_data, "\e#Troika\nNum: %ld\nBalance: %d rur.", number, balance); + dev_data->parsed_data, "\e#Troika\nNum: %lu\nBalance: %u rur.", number, balance); troika_parsed = true; } while(false); diff --git a/lib/nfc/parsers/two_cities.c b/lib/nfc/parsers/two_cities.c index 0e2ed5690..d6d4279dd 100644 --- a/lib/nfc/parsers/two_cities.c +++ b/lib/nfc/parsers/two_cities.c @@ -136,7 +136,7 @@ bool two_cities_parser_parse(NfcDeviceData* dev_data) { furi_string_printf( dev_data->parsed_data, - "\e#Troika+Plantain\nPN: %llu-\nPB: %ld rur.\nTN: %ld\nTB: %d rur.\n", + "\e#Troika+Plantain\nPN: %llu-\nPB: %lu rur.\nTN: %lu\nTB: %u rur.\n", card_number, balance, troika_number, diff --git a/lib/subghz/protocols/secplus_v2.c b/lib/subghz/protocols/secplus_v2.c index a55930552..f6837b571 100644 --- a/lib/subghz/protocols/secplus_v2.c +++ b/lib/subghz/protocols/secplus_v2.c @@ -611,7 +611,7 @@ bool subghz_protocol_secplus_v2_create_data( if((res == SubGhzProtocolStatusOk) && !flipper_format_write_hex(flipper_format, "Secplus_packet_1", key_data, sizeof(uint64_t))) { FURI_LOG_E(TAG, "Unable to add Secplus_packet_1"); - res = SubGhzProtocolStatusError; + res = SubGhzProtocolStatusErrorParserOthers; } return res == SubGhzProtocolStatusOk; }