From 271a8ce5481d439d7e50c1efa1a4f17c4905a897 Mon Sep 17 00:00:00 2001 From: Thomas Sutter Date: Tue, 29 Oct 2019 09:44:38 +0100 Subject: [PATCH 1/6] Add additional check for xero byte response. Add wrunencrypted usage text. --- client/cmdhffelica.c | 123 +++++++++++++++++++++++++++++++------------ 1 file changed, 89 insertions(+), 34 deletions(-) diff --git a/client/cmdhffelica.c b/client/cmdhffelica.c index b5a31b666..ead19c104 100644 --- a/client/cmdhffelica.c +++ b/client/cmdhffelica.c @@ -159,15 +159,7 @@ static void print_status_flag2_interpration() { PrintAndLogEx(NORMAL, " - C2h : Command is disabled already: This is the error that occurs in issuance commands."); } -static int usage_hf_felica_read_without_encryption() { - PrintAndLogEx(NORMAL, "\nInfo: Use this command to read Block Data from authentication-not-required Service."); - PrintAndLogEx(NORMAL, " - Mode shall be Mode0."); - PrintAndLogEx(NORMAL, " - Number of Service: shall be a positive integer in the range of 1 to 16, inclusive."); - PrintAndLogEx(NORMAL, " - Number of Block: shall be less than or equal to the maximum number of Blocks that can be read simultaneously. " - "The maximum number of Blocks that can be read simultaneously can differ, depending on the product being used. Use as default 01"); - PrintAndLogEx(NORMAL, " - Service Code List: For Service Code List, only Service Code existing in the product shall be specified:"); - PrintAndLogEx(NORMAL, " - Even when Service Code exists in the product, Service Code not referenced from Block List shall not be specified to Service Code List."); - PrintAndLogEx(NORMAL, " - For existence or nonexistence of Service in a product, please check using the Request Service (or Request Service v2) command."); +static void print_block_list_element_constraints(){ PrintAndLogEx(NORMAL, " - Each Block List Element shall satisfy the following conditions:"); PrintAndLogEx(NORMAL, " - The value of Service Code List Order shall not exceed Number of Service."); PrintAndLogEx(NORMAL, " - Access Mode shall be 000b."); @@ -175,6 +167,30 @@ static int usage_hf_felica_read_without_encryption() { PrintAndLogEx(NORMAL, " - Service specified in Service Code List shall exist in System."); PrintAndLogEx(NORMAL, " - Service Attribute of Service specified in Service Code List shall be authentication-not-required Service."); PrintAndLogEx(NORMAL, " - Block Number shall be in the range of the number of Blocks assigned to the specified Service."); +} + +static void print_number_of_service_constraints(){ + PrintAndLogEx(NORMAL, " - Number of Service: shall be a positive integer in the range of 1 to 16, inclusive."); +} + +static void print_number_of_block_constraints(){ + PrintAndLogEx(NORMAL, " - Number of Block: shall be less than or equal to the maximum number of Blocks that can be read simultaneously. " + "The maximum number of Blocks that can be read simultaneously can differ, depending on the product being used. Use as default 01"); +} + +static void print_service_code_list_constraints(){ + PrintAndLogEx(NORMAL, " - Service Code List: For Service Code List, only Service Code existing in the product shall be specified:"); + PrintAndLogEx(NORMAL, " - Even when Service Code exists in the product, Service Code not referenced from Block List shall not be specified to Service Code List."); + PrintAndLogEx(NORMAL, " - For existence or nonexistence of Service in a product, please check using the Request Service (or Request Service v2) command."); +} + +static int usage_hf_felica_read_without_encryption() { + PrintAndLogEx(NORMAL, "\nInfo: Use this command to read Block Data from authentication-not-required Service."); + PrintAndLogEx(NORMAL, " - Mode shall be Mode0."); + print_number_of_service_constraints(); + print_number_of_block_constraints(); + print_service_code_list_constraints(); + print_block_list_element_constraints(); PrintAndLogEx(NORMAL, " - Successful read: Card responses the block data"); PrintAndLogEx(NORMAL, " - Unsuccessful read: Card responses with Status Flag1 and Flag2"); print_status_flag1_interpretation(); @@ -191,6 +207,26 @@ static int usage_hf_felica_read_without_encryption() { return PM3_SUCCESS; } +static int usage_hf_felica_write_without_encryption() { + PrintAndLogEx(NORMAL, "\nInfo: Use this command to write Block Data to authentication-not-required Service."); + PrintAndLogEx(NORMAL, " - Mode shall be Mode0."); + print_number_of_service_constraints(); + print_number_of_block_constraints(); + print_service_code_list_constraints(); + print_block_list_element_constraints(); + PrintAndLogEx(NORMAL, " - Un-/Successful read: Card responses with Status Flag1 and Flag2"); + print_status_flag1_interpretation(); + print_status_flag2_interpration(); + PrintAndLogEx(NORMAL, "\nUsage: hf felica wrunencrypted [-h] <01 Number of Service hex> <0A0B Service Code List (Little Endian) hex> <01 Number of Block hex> <0A0B Block List Element hex> <0A0B0C0D0E0F... Data hex (16-Byte)>"); + PrintAndLogEx(NORMAL, " -h this help"); + PrintAndLogEx(NORMAL, " -i <0A0B0C ... hex> set custom IDm to use"); + + + PrintAndLogEx(NORMAL, "\nExamples: "); + PrintAndLogEx(NORMAL, " hf felica wrunencrypted"); + return PM3_SUCCESS; +} + /** * Wait for response from pm3 or timeout. * Checks if receveid bytes have a valid CRC. @@ -208,6 +244,10 @@ static bool waitCmdFelica(uint8_t iSelect, PacketResponseNG *resp, bool verbose) if (!check_crc(CRC_FELICA, resp->data.asBytes + 2, len - 2)) { PrintAndLogEx(WARNING, "Wrong or no CRC bytes"); } + if(resp->data.asBytes[0] != 0xB2 && resp->data.asBytes[1] != 0x4D){ + PrintAndLogEx(ERR, "Received incorrect Frame Format!"); + return false; + } } return true; } else { @@ -351,7 +391,7 @@ int send_request_service(uint8_t flags, uint16_t datalen, uint8_t *data, bool ve * @param datalen frame length. * @param data frame to be send. * @param verbose display additional output. - * @param rd_noCry_resp frame in which the response will be saved + * @param rd_noCry_resp frame in which the response will be saved. * @return success if response was received. */ int send_rd_unencrypted(uint8_t flags, uint16_t datalen, uint8_t *data, bool verbose, felica_read_without_encryption_response_t *rd_noCry_resp) { @@ -367,6 +407,19 @@ int send_rd_unencrypted(uint8_t flags, uint16_t datalen, uint8_t *data, bool ver } } +/** + * Command parser for wrunencrypted. + * @param Cmd input data of the user. + * @return client result code. + */ +static int CmdHFFelicaWriteWithoutEncryption(const char *Cmd) { + if (strlen(Cmd) < 4) + return usage_hf_felica_write_without_encryption(); + //uint8_t data[PM3_CMD_DATA_SIZE]; + + return PM3_SUCCESS; +} + /** * Command parser for rdunencrypted. * @param Cmd input data of the user. @@ -462,10 +515,12 @@ static int CmdHFFelicaReadWithoutEncryption(const char *Cmd) { AddCrc(data, datalen); datalen += 2; felica_read_without_encryption_response_t rd_noCry_resp; - send_rd_unencrypted(flags, datalen, data, 1, &rd_noCry_resp); - PrintAndLogEx(NORMAL, "Block Element\t| Data "); - print_rd_noEncrpytion_response(&rd_noCry_resp); + if(send_rd_unencrypted(flags, datalen, data, 1, &rd_noCry_resp) == PM3_SUCCESS){ + PrintAndLogEx(NORMAL, "Block Element\t| Data "); + print_rd_noEncrpytion_response(&rd_noCry_resp); + } } + return PM3_SUCCESS; } @@ -1139,27 +1194,27 @@ static command_t CommandTable[] = { {"reader", CmdHFFelicaReader, IfPm3Felica, "Act like an ISO18092/FeliCa reader"}, {"sniff", CmdHFFelicaSniff, IfPm3Felica, "Sniff ISO 18092/FeliCa traffic"}, {"raw", CmdHFFelicaCmdRaw, IfPm3Felica, "Send raw hex data to tag"}, - {"----------- FeliCa Standard (support in progress) -----------", CmdHelp, IfPm3Iso14443a, ""}, - //{"dump", CmdHFFelicaDump, IfPm3Felica, "Wait for and try dumping FeliCa"}, - {"rqservice", CmdHFFelicaRequestService, IfPm3Felica, "verify the existence of Area and Service, and to acquire Key Version."}, - {"rqresponse", CmdHFFelicaRequestResponse, IfPm3Felica, "verify the existence of a card and its Mode."}, - {"rdunencrypted", CmdHFFelicaReadWithoutEncryption, IfPm3Felica, "read Block Data from authentication-not-required Service."}, - {"wrunencrypted", CmdHFFelicaNotImplementedYet, IfPm3Felica, "write Block Data to an authentication-not-required Service."}, - //{"scsvcode", CmdHFFelicaNotImplementedYet, IfPm3Felica, "acquire Area Code and Service Code."}, - //{"rqsyscode", CmdHFFelicaNotImplementedYet, IfPm3Felica, "acquire System Code registered to the card."}, - //{"auth1", CmdHFFelicaNotImplementedYet, IfPm3Felica, "authenticate a card."}, - //{"auth2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "allow a card to authenticate a Reader/Writer."}, - //{"read", CmdHFFelicaNotImplementedYet, IfPm3Felica, "read Block Data from authentication-required Service."}, - //{"write", CmdHFFelicaNotImplementedYet, IfPm3Felica, "write Block Data to an authentication-required Service."}, - //{"scsvcodev2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "verify the existence of Area or Service, and to acquire Key Version."}, - //{"getsysstatus", CmdHFFelicaNotImplementedYet, IfPm3Felica, "acquire the setup information in System."}, - //{"rqspecver", CmdHFFelicaNotImplementedYet, IfPm3Felica, "acquire the version of card OS."}, - //{"resetmode", CmdHFFelicaNotImplementedYet, IfPm3Felica, "reset Mode to Mode 0."}, - //{"auth1v2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "authenticate a card."}, - //{"auth2v2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "allow a card to authenticate a Reader/Writer."}, - //{"readv2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "read Block Data from authentication-required Service."}, - //{"writev2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "write Block Data to authentication-required Service."}, - //{"uprandomid", CmdHFFelicaNotImplementedYet, IfPm3Felica, "update Random ID (IDr)."}, + {"----------- FeliCa Standard (support in progress) -----------", CmdHelp, IfPm3Iso14443a, ""}, + //{"dump", CmdHFFelicaDump, IfPm3Felica, "Wait for and try dumping FeliCa"}, + {"rqservice", CmdHFFelicaRequestService, IfPm3Felica, "verify the existence of Area and Service, and to acquire Key Version."}, + {"rqresponse", CmdHFFelicaRequestResponse, IfPm3Felica, "verify the existence of a card and its Mode."}, + {"rdunencrypted", CmdHFFelicaReadWithoutEncryption, IfPm3Felica, "read Block Data from authentication-not-required Service."}, + {"wrunencrypted", CmdHFFelicaWriteWithoutEncryption, IfPm3Felica, "write Block Data to an authentication-not-required Service."}, + {"scsvcode", CmdHFFelicaNotImplementedYet, IfPm3Felica, "acquire Area Code and Service Code."}, + //{"rqsyscode", CmdHFFelicaNotImplementedYet, IfPm3Felica, "acquire System Code registered to the card."}, + //{"auth1", CmdHFFelicaNotImplementedYet, IfPm3Felica, "authenticate a card."}, + //{"auth2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "allow a card to authenticate a Reader/Writer."}, + //{"read", CmdHFFelicaNotImplementedYet, IfPm3Felica, "read Block Data from authentication-required Service."}, + //{"write", CmdHFFelicaNotImplementedYet, IfPm3Felica, "write Block Data to an authentication-required Service."}, + //{"scsvcodev2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "verify the existence of Area or Service, and to acquire Key Version."}, + //{"getsysstatus", CmdHFFelicaNotImplementedYet, IfPm3Felica, "acquire the setup information in System."}, + //{"rqspecver", CmdHFFelicaNotImplementedYet, IfPm3Felica, "acquire the version of card OS."}, + //{"resetmode", CmdHFFelicaNotImplementedYet, IfPm3Felica, "reset Mode to Mode 0."}, + //{"auth1v2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "authenticate a card."}, + //{"auth2v2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "allow a card to authenticate a Reader/Writer."}, + //{"readv2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "read Block Data from authentication-required Service."}, + //{"writev2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "write Block Data to authentication-required Service."}, + //{"uprandomid", CmdHFFelicaNotImplementedYet, IfPm3Felica, "update Random ID (IDr)."}, {"----------- FeliCa Light -----------", CmdHelp, IfPm3Iso14443a, ""}, {"litesim", CmdHFFelicaSimLite, IfPm3Felica, " - only reply to poll request"}, {"litedump", CmdHFFelicaDumpLite, IfPm3Felica, "Wait for and try dumping FelicaLite"}, From 06f3f1b637015275d5d68750a60fa542b62512b0 Mon Sep 17 00:00:00 2001 From: Thomas Sutter Date: Tue, 29 Oct 2019 10:00:47 +0100 Subject: [PATCH 2/6] Remove code duplication. --- client/cmdhffelica.c | 77 +++++++++++++++++++++++++++++++------------- 1 file changed, 54 insertions(+), 23 deletions(-) diff --git a/client/cmdhffelica.c b/client/cmdhffelica.c index ead19c104..18a992ba7 100644 --- a/client/cmdhffelica.c +++ b/client/cmdhffelica.c @@ -407,15 +407,61 @@ int send_rd_unencrypted(uint8_t flags, uint16_t datalen, uint8_t *data, bool ver } } +/** + * Checks if last known card can be added to data and adds it if possible. + * @param custom_IDm + * @param data + * @return + */ +static bool check_last_idm(uint8_t *data, uint16_t datalen){ + if (!add_last_IDm(2, data)) { + PrintAndLogEx(ERR, "No last known card! Use reader first or set a custom IDm!"); + return 0; + } else { + PrintAndLogEx(INFO, "Used last known IDm.", sprint_hex(data, datalen)); + return 1; + } +} + /** * Command parser for wrunencrypted. * @param Cmd input data of the user. * @return client result code. */ static int CmdHFFelicaWriteWithoutEncryption(const char *Cmd) { - if (strlen(Cmd) < 4) + if (strlen(Cmd) < 5) return usage_hf_felica_write_without_encryption(); - //uint8_t data[PM3_CMD_DATA_SIZE]; + uint8_t data[PM3_CMD_DATA_SIZE]; + bool custom_IDm = false; + strip_cmds(Cmd); + uint16_t datalen = 32; // Length (1), Command ID (1), IDm (8), Number of Service (1), Service Code List(2), Number of Block(1), Block List(3), Block Data(16) + uint8_t paramCount = 0; + uint8_t flags = 0; + int i = 0; + while (Cmd[i] != '\0') { + if (Cmd[i] == '-') { + switch (Cmd[i + 1]) { + case 'H': + case 'h': + return usage_hf_felica_request_response(); + case 'i': + paramCount++; + custom_IDm = true; + if (!add_param(Cmd, paramCount, data, 3, 8)) { + return PM3_EINVARG; + } + break; + } + } + i++; + } + data[0] = 0x20; // Static length + data[1] = 0x08; // Command ID + if (!custom_IDm && !check_last_idm(data, datalen)) { + return PM3_EINVARG; + } + flags |= FELICA_APPEND_CRC; + flags |= FELICA_RAW; return PM3_SUCCESS; } @@ -464,13 +510,8 @@ static int CmdHFFelicaReadWithoutEncryption(const char *Cmd) { } data[0] = 0x10; // Static length data[1] = 0x06; // Command ID - if (!custom_IDm) { - if (!add_last_IDm(2, data)) { - PrintAndLogEx(ERR, "No last known card! Use reader first or set a custom IDm!"); - return PM3_EINVARG; - } else { - PrintAndLogEx(INFO, "Used last known IDm.", sprint_hex(data, datalen)); - } + if (!custom_IDm && !check_last_idm(data, datalen)) { + return PM3_EINVARG; } // Number of Service 2, Service Code List 4, Number of Block 2, Block List Element 4 uint8_t lengths[] = {2, 4, 2, 4}; @@ -559,13 +600,8 @@ static int CmdHFFelicaRequestResponse(const char *Cmd) { } data[0] = 0x0A; // Static length data[1] = 0x04; // Command ID - if (!custom_IDm) { - if (!add_last_IDm(2, data)) { - PrintAndLogEx(ERR, "No last known card! Use reader first or set a custom IDm!"); - return PM3_EINVARG; - } else { - PrintAndLogEx(INFO, "Used last known IDm.", sprint_hex(data, datalen)); - } + if (!custom_IDm && !check_last_idm(data, datalen)) { + return PM3_EINVARG; } AddCrc(data, datalen); datalen += 2; @@ -658,13 +694,8 @@ static int CmdHFFelicaRequestService(const char *Cmd) { flags |= FELICA_RAW; } datalen = (datalen > PM3_CMD_DATA_SIZE) ? PM3_CMD_DATA_SIZE : datalen; - if (!custom_IDm) { - if (!add_last_IDm(2, data)) { - PrintAndLogEx(ERR, "No last known card! Use reader first or set a custom IDm!"); - return PM3_EINVARG; - } else { - PrintAndLogEx(INFO, "Used last known IDm.", sprint_hex(data, datalen)); - } + if (!custom_IDm && !check_last_idm(data, datalen)) { + return PM3_EINVARG; } data[0] = int_to_hex(&datalen); data[1] = 0x02; // Service Request Command ID From 498c4b83776cbb777f3f58815241e1f2350b0cda Mon Sep 17 00:00:00 2001 From: Thomas Sutter Date: Tue, 29 Oct 2019 10:22:47 +0100 Subject: [PATCH 3/6] Refactor FeliCa structs. --- armsrc/felica.h | 2 -- client/cmdhffelica.c | 33 ++++++++++++++++++++++++--------- client/cmdhffelica.h | 1 + include/mifare.h | 22 ++++++++++++---------- 4 files changed, 37 insertions(+), 21 deletions(-) diff --git a/armsrc/felica.h b/armsrc/felica.h index 95e13a588..ef34dc108 100644 --- a/armsrc/felica.h +++ b/armsrc/felica.h @@ -18,7 +18,5 @@ void felica_sendraw(PacketCommandNG *c); void felica_sniff(uint32_t samplesToSkip, uint32_t triggersToSkip); void felica_sim_lite(uint64_t uid); void felica_dump_lite_s(); -void felica_create_read_block_frame(uint16_t blockNr); -void felica_send_request_service(uint8_t *request_service); #endif diff --git a/client/cmdhffelica.c b/client/cmdhffelica.c index 18a992ba7..74fea45bb 100644 --- a/client/cmdhffelica.c +++ b/client/cmdhffelica.c @@ -344,7 +344,7 @@ static bool add_param(const char *Cmd, uint8_t paramCount, uint8_t *data, uint8_ * @param rd_noCry_resp Response frame. */ static void print_rd_noEncrpytion_response(felica_read_without_encryption_response_t *rd_noCry_resp) { - if (rd_noCry_resp->status_flag1[0] == 00 && rd_noCry_resp->status_flag2[0] == 00) { + if (rd_noCry_resp->status_flags.status_flag1[0] == 00 && rd_noCry_resp->status_flags.status_flag2[0] == 00) { char *temp = sprint_hex(rd_noCry_resp->block_data, sizeof(rd_noCry_resp->block_data)); char bl_data[256]; strcpy(bl_data, temp); @@ -354,9 +354,9 @@ static void print_rd_noEncrpytion_response(felica_read_without_encryption_respon strcpy(bl_element_number, temp); PrintAndLogEx(NORMAL, "\t%s\t| %s ", bl_element_number, bl_data); } else { - PrintAndLogEx(NORMAL, "IDm: %s", sprint_hex(rd_noCry_resp->IDm, sizeof(rd_noCry_resp->IDm))); - PrintAndLogEx(NORMAL, "Status Flag1: %s", sprint_hex(rd_noCry_resp->status_flag1, sizeof(rd_noCry_resp->status_flag1))); - PrintAndLogEx(NORMAL, "Status Flag2: %s", sprint_hex(rd_noCry_resp->status_flag1, sizeof(rd_noCry_resp->status_flag1))); + PrintAndLogEx(NORMAL, "IDm: %s", sprint_hex(rd_noCry_resp->frame_response.IDm, sizeof(rd_noCry_resp->frame_response.IDm))); + PrintAndLogEx(NORMAL, "Status Flag1: %s", sprint_hex(rd_noCry_resp->status_flags.status_flag1, sizeof(rd_noCry_resp->status_flags.status_flag1))); + PrintAndLogEx(NORMAL, "Status Flag2: %s", sprint_hex(rd_noCry_resp->status_flags.status_flag1, sizeof(rd_noCry_resp->status_flags.status_flag1))); } } @@ -374,9 +374,9 @@ int send_request_service(uint8_t flags, uint16_t datalen, uint8_t *data, bool ve felica_request_service_response_t rqs_response; memcpy(&rqs_response, (felica_request_service_response_t *)resp.data.asBytes, sizeof(felica_request_service_response_t)); - if (rqs_response.IDm[0] != 0) { + if (rqs_response.frame_response.IDm[0] != 0) { PrintAndLogEx(SUCCESS, "\nGot Service Response:"); - PrintAndLogEx(NORMAL, "IDm: %s", sprint_hex(rqs_response.IDm, sizeof(rqs_response.IDm))); + PrintAndLogEx(NORMAL, "IDm: %s", sprint_hex(rqs_response.frame_response.IDm, sizeof(rqs_response.frame_response.IDm))); PrintAndLogEx(NORMAL, " -Node Number: %s", sprint_hex(rqs_response.node_number, sizeof(rqs_response.node_number))); PrintAndLogEx(NORMAL, " -Node Key Version List: %s\n", sprint_hex(rqs_response.node_key_versions, sizeof(rqs_response.node_key_versions))); } @@ -423,6 +423,10 @@ static bool check_last_idm(uint8_t *data, uint16_t datalen){ } } + + + + /** * Command parser for wrunencrypted. * @param Cmd input data of the user. @@ -460,9 +464,20 @@ static int CmdHFFelicaWriteWithoutEncryption(const char *Cmd) { if (!custom_IDm && !check_last_idm(data, datalen)) { return PM3_EINVARG; } + // Number of Service 2, Service Code List 4, Number of Block 2, Block List Element 4 + uint8_t lengths[] = {2, 4, 2, 4}; + uint8_t dataPositions[] = {10, 11, 13, 14}; + for (int i = 0; i < 4; i++) { + if (add_param(Cmd, paramCount, data, dataPositions[i], lengths[i])) { + paramCount++; + } else { + return PM3_EINVARG; + } + } flags |= FELICA_APPEND_CRC; flags |= FELICA_RAW; + return PM3_SUCCESS; } @@ -542,7 +557,7 @@ static int CmdHFFelicaReadWithoutEncryption(const char *Cmd) { datalen += 2; felica_read_without_encryption_response_t rd_noCry_resp; if ((send_rd_unencrypted(flags, datalen, data, 0, &rd_noCry_resp) == PM3_SUCCESS)) { - if (rd_noCry_resp.status_flag1[0] == 00 && rd_noCry_resp.status_flag2[0] == 00) { + if (rd_noCry_resp.status_flags.status_flag1[0] == 00 && rd_noCry_resp.status_flags.status_flag2[0] == 00) { print_rd_noEncrpytion_response(&rd_noCry_resp); } else { break; @@ -615,9 +630,9 @@ static int CmdHFFelicaRequestResponse(const char *Cmd) { } else { felica_request_request_response_t rq_response; memcpy(&rq_response, (felica_request_request_response_t *)resp.data.asBytes, sizeof(felica_request_request_response_t)); - if (rq_response.IDm[0] != 0) { + if (rq_response.frame_response.IDm[0] != 0) { PrintAndLogEx(SUCCESS, "\nGot Request Response:"); - PrintAndLogEx(NORMAL, "IDm: %s", sprint_hex(rq_response.IDm, sizeof(rq_response.IDm))); + PrintAndLogEx(NORMAL, "IDm: %s", sprint_hex(rq_response.frame_response.IDm, sizeof(rq_response.frame_response.IDm))); PrintAndLogEx(NORMAL, " -Mode: %s\n\n", sprint_hex(rq_response.mode, sizeof(rq_response.mode))); } } diff --git a/client/cmdhffelica.h b/client/cmdhffelica.h index 7626d002b..8d8156006 100644 --- a/client/cmdhffelica.h +++ b/client/cmdhffelica.h @@ -18,4 +18,5 @@ int CmdHFFelica(const char *Cmd); int readFelicaUid(bool verbose); int send_request_service(uint8_t flags, uint16_t datalen, uint8_t *data, bool verbose); int send_rd_unencrypted(uint8_t flags, uint16_t datalen, uint8_t *data, bool verbose, felica_read_without_encryption_response_t *rd_noCry_resp); + #endif diff --git a/include/mifare.h b/include/mifare.h index 7a40a26e4..699c7e1ec 100644 --- a/include/mifare.h +++ b/include/mifare.h @@ -174,25 +174,27 @@ typedef struct { uint8_t length[1]; uint8_t cmd_code[1]; uint8_t IDm[8]; +} PACKED felica_frame_response_t; + +typedef struct { + uint8_t status_flag1[1]; + uint8_t status_flag2[1]; +} PACKED felica_status_flag_response_t; + +typedef struct { + felica_frame_response_t frame_response; uint8_t node_number[1]; uint8_t node_key_versions[2]; } PACKED felica_request_service_response_t; typedef struct { - uint8_t sync[2]; - uint8_t length[1]; - uint8_t cmd_code[1]; - uint8_t IDm[8]; + felica_frame_response_t frame_response; uint8_t mode[1]; } PACKED felica_request_request_response_t; typedef struct { - uint8_t sync[2]; - uint8_t length[1]; - uint8_t cmd_code[1]; - uint8_t IDm[8]; - uint8_t status_flag1[1]; - uint8_t status_flag2[1]; + felica_frame_response_t frame_response; + felica_status_flag_response_t status_flags; uint8_t number_of_block[1]; uint8_t block_data[16]; uint8_t block_element_number[1]; From 2e60cb4fa632bea48bb0a1902ac57817cb9cbf53 Mon Sep 17 00:00:00 2001 From: Thomas Sutter Date: Tue, 29 Oct 2019 11:14:38 +0100 Subject: [PATCH 4/6] Add write without encryption command. --- client/cmdhffelica.c | 50 +++++++++++++++++++++++++++++++------------- include/mifare.h | 9 ++++++-- 2 files changed, 43 insertions(+), 16 deletions(-) diff --git a/client/cmdhffelica.c b/client/cmdhffelica.c index 74fea45bb..c47622951 100644 --- a/client/cmdhffelica.c +++ b/client/cmdhffelica.c @@ -203,7 +203,7 @@ static int usage_hf_felica_read_without_encryption() { PrintAndLogEx(NORMAL, "\nExamples: "); PrintAndLogEx(NORMAL, " hf felica rdunencrypted 01 8B00 01 8000"); PrintAndLogEx(NORMAL, " hf felica rdunencrypted -i 01100910c11bc407 01 8B00 01 8000"); - PrintAndLogEx(NORMAL, " hf felica rdunencrypted -b 01 8B00 01 8000\n\n"); + PrintAndLogEx(NORMAL, " hf felica rdunencrypted -b 01 4B18 01 8000\n\n"); return PM3_SUCCESS; } @@ -219,11 +219,11 @@ static int usage_hf_felica_write_without_encryption() { print_status_flag2_interpration(); PrintAndLogEx(NORMAL, "\nUsage: hf felica wrunencrypted [-h] <01 Number of Service hex> <0A0B Service Code List (Little Endian) hex> <01 Number of Block hex> <0A0B Block List Element hex> <0A0B0C0D0E0F... Data hex (16-Byte)>"); PrintAndLogEx(NORMAL, " -h this help"); - PrintAndLogEx(NORMAL, " -i <0A0B0C ... hex> set custom IDm to use"); - + PrintAndLogEx(NORMAL, " -i <0A0B0C ... hex> set custom IDm to use\n"); + PrintAndLogEx(NORMAL, " hf felica wrunencrypted 01 CB10 01 8001 0102030405060708090A0B0C0D0E0F10\n\n"); PrintAndLogEx(NORMAL, "\nExamples: "); - PrintAndLogEx(NORMAL, " hf felica wrunencrypted"); + PrintAndLogEx(NORMAL, " hf felica wrunencrypted "); return PM3_SUCCESS; } @@ -423,9 +423,26 @@ static bool check_last_idm(uint8_t *data, uint16_t datalen){ } } - - - +/** + * Sends a read_without_encryption frame to the pm3 and prints response. + * @param flags to use for pm3 communication. + * @param datalen frame length. + * @param data frame to be send. + * @param verbose display additional output. + * @param wr_noCry_resp frame in which the response will be saved. + * @return success if response was received. + */ +int send_wr_unencrypted(uint8_t flags, uint16_t datalen, uint8_t *data, bool verbose, felica_status_response_t *wr_noCry_resp) { + clear_and_send_command(flags, datalen, data, verbose); + PacketResponseNG resp; + if (!waitCmdFelica(0, &resp, verbose)) { + PrintAndLogEx(ERR, "\nGot no Response from card"); + return PM3_ERFTRANS; + } else { + memcpy(wr_noCry_resp, (felica_status_response_t *)resp.data.asBytes, sizeof(felica_status_response_t)); + return PM3_SUCCESS; + } +} /** * Command parser for wrunencrypted. @@ -464,10 +481,10 @@ static int CmdHFFelicaWriteWithoutEncryption(const char *Cmd) { if (!custom_IDm && !check_last_idm(data, datalen)) { return PM3_EINVARG; } - // Number of Service 2, Service Code List 4, Number of Block 2, Block List Element 4 - uint8_t lengths[] = {2, 4, 2, 4}; - uint8_t dataPositions[] = {10, 11, 13, 14}; - for (int i = 0; i < 4; i++) { + // Number of Service 2, Service Code List 4, Number of Block 2, Block List Element 4, Data 16 + uint8_t lengths[] = {2, 4, 2, 4, 32}; + uint8_t dataPositions[] = {10, 11, 13, 14, 16}; + for (int i = 0; i < 5; i++) { if (add_param(Cmd, paramCount, data, dataPositions[i], lengths[i])) { paramCount++; } else { @@ -476,8 +493,14 @@ static int CmdHFFelicaWriteWithoutEncryption(const char *Cmd) { } flags |= FELICA_APPEND_CRC; flags |= FELICA_RAW; - - + AddCrc(data, datalen); + datalen += 2; + felica_status_response_t wr_noCry_resp; + if(send_wr_unencrypted(flags, datalen, data, 1, &wr_noCry_resp) == PM3_SUCCESS){ + PrintAndLogEx(NORMAL, "\nIDm: %s", sprint_hex(wr_noCry_resp.frame_response.IDm, sizeof(wr_noCry_resp.frame_response.IDm))); + PrintAndLogEx(NORMAL, "Status Flag1: %s", sprint_hex(wr_noCry_resp.status_flags.status_flag1, sizeof(wr_noCry_resp.status_flags.status_flag1))); + PrintAndLogEx(NORMAL, "Status Flag2: %s\n\n", sprint_hex(wr_noCry_resp.status_flags.status_flag2, sizeof(wr_noCry_resp.status_flags.status_flag2))); + } return PM3_SUCCESS; } @@ -576,7 +599,6 @@ static int CmdHFFelicaReadWithoutEncryption(const char *Cmd) { print_rd_noEncrpytion_response(&rd_noCry_resp); } } - return PM3_SUCCESS; } diff --git a/include/mifare.h b/include/mifare.h index 699c7e1ec..4a65357e5 100644 --- a/include/mifare.h +++ b/include/mifare.h @@ -179,7 +179,7 @@ typedef struct { typedef struct { uint8_t status_flag1[1]; uint8_t status_flag2[1]; -} PACKED felica_status_flag_response_t; +} PACKED felica_status_flags_t; typedef struct { felica_frame_response_t frame_response; @@ -194,12 +194,17 @@ typedef struct { typedef struct { felica_frame_response_t frame_response; - felica_status_flag_response_t status_flags; + felica_status_flags_t status_flags; uint8_t number_of_block[1]; uint8_t block_data[16]; uint8_t block_element_number[1]; } PACKED felica_read_without_encryption_response_t; +typedef struct { + felica_frame_response_t frame_response; + felica_status_flags_t status_flags; +} PACKED felica_status_response_t; + typedef enum FELICA_COMMAND { FELICA_CONNECT = (1 << 0), FELICA_NO_DISCONNECT = (1 << 1), From 83c629cbecef5cfb66e5bcd198b4bb5d26e90875 Mon Sep 17 00:00:00 2001 From: Thomas Sutter Date: Tue, 29 Oct 2019 12:52:45 +0100 Subject: [PATCH 5/6] Fix parameter i parsing bug. --- client/cmdhffelica.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/client/cmdhffelica.c b/client/cmdhffelica.c index c47622951..2ed405476 100644 --- a/client/cmdhffelica.c +++ b/client/cmdhffelica.c @@ -112,6 +112,7 @@ static int usage_hf_felica_request_response(void) { PrintAndLogEx(NORMAL, "\nUsage: hf felica rqresponse [-h]"); PrintAndLogEx(NORMAL, " -h this help"); PrintAndLogEx(NORMAL, " -i <0A0B0C ... hex> set custom IDm to use"); + PrintAndLogEx(NORMAL, " hf felica rqresponse -i 01100910c11bc407"); return PM3_SUCCESS; } @@ -334,7 +335,8 @@ static bool add_param(const char *Cmd, uint8_t paramCount, uint8_t *data, uint8_ param_gethex(Cmd, paramCount, data + dataPosition, length); return true; } else { - PrintAndLogEx(ERR, "Incorrect Parameter length! Param %i", paramCount); + PrintAndLogEx(ERR, "Param %s", Cmd); + PrintAndLogEx(ERR, "Incorrect Parameter length! Param %i should be %i", paramCount, length); return false; } } @@ -468,9 +470,11 @@ static int CmdHFFelicaWriteWithoutEncryption(const char *Cmd) { case 'i': paramCount++; custom_IDm = true; - if (!add_param(Cmd, paramCount, data, 3, 8)) { + if (!add_param(Cmd, paramCount, data, 2, 16)) { return PM3_EINVARG; } + paramCount++; + i += 16; break; } } @@ -530,9 +534,11 @@ static int CmdHFFelicaReadWithoutEncryption(const char *Cmd) { case 'i': paramCount++; custom_IDm = true; - if (!add_param(Cmd, paramCount, data, 3, 8)) { + if (!add_param(Cmd, paramCount, data, 2, 16)) { return PM3_EINVARG; } + paramCount++; + i += 16; break; case 'b': paramCount++; @@ -624,12 +630,11 @@ static int CmdHFFelicaRequestResponse(const char *Cmd) { case 'i': paramCount++; custom_IDm = true; - if (param_getlength(Cmd, paramCount) == 16) { - param_gethex(Cmd, paramCount++, data + 2, 16); - } else { - PrintAndLogEx(ERR, "Incorrect IDm length! IDm must be 8-Byte."); + if (!add_param(Cmd, paramCount, data, 2, 16)) { return PM3_EINVARG; } + paramCount++; + i+=16; break; } } @@ -686,13 +691,11 @@ static int CmdHFFelicaRequestService(const char *Cmd) { case 'i': paramCount++; custom_IDm = true; - if (param_getlength(Cmd, paramCount) == 16) { - param_gethex(Cmd, paramCount++, data + 2, 16); - } else { - PrintAndLogEx(ERR, "Incorrect IDm length! IDm must be 8-Byte."); + if (!add_param(Cmd, paramCount, data, 2, 16)) { return PM3_EINVARG; } - i += 8; + paramCount++; + i += 16; break; case 'a': paramCount++; From eba19c0bd67cd4789e9952db6875ef0cbf68b1ee Mon Sep 17 00:00:00 2001 From: Thomas Sutter Date: Tue, 29 Oct 2019 13:35:09 +0100 Subject: [PATCH 6/6] Make style. --- armsrc/appmain.c | 4 ++-- client/cmdhffelica.c | 27 ++++++++++++++++----------- client/proxmark3.c | 2 +- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index dcb7d63a0..5011c1979 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1589,10 +1589,10 @@ static void PacketReceived(PacketCommandNG *packet) { BigBuf_free(); } uint16_t offset = MIN(BIGBUF_SIZE - PM3_CMD_DATA_SIZE - 3, payload->offset); - + // need to copy len bytes of data, not PM3_CMD_DATA_SIZE - 3 - offset // ensure len bytes copied wont go past end of bigbuf - uint16_t len = MIN(BIGBUF_SIZE - offset,PM3_CMD_DATA_SIZE - 3); + uint16_t len = MIN(BIGBUF_SIZE - offset, PM3_CMD_DATA_SIZE - 3); uint8_t *mem = BigBuf_get_addr(); memcpy(mem + offset, &payload->data, len); diff --git a/client/cmdhffelica.c b/client/cmdhffelica.c index 2ed405476..2afb5f3aa 100644 --- a/client/cmdhffelica.c +++ b/client/cmdhffelica.c @@ -160,7 +160,7 @@ static void print_status_flag2_interpration() { PrintAndLogEx(NORMAL, " - C2h : Command is disabled already: This is the error that occurs in issuance commands."); } -static void print_block_list_element_constraints(){ +static void print_block_list_element_constraints() { PrintAndLogEx(NORMAL, " - Each Block List Element shall satisfy the following conditions:"); PrintAndLogEx(NORMAL, " - The value of Service Code List Order shall not exceed Number of Service."); PrintAndLogEx(NORMAL, " - Access Mode shall be 000b."); @@ -170,16 +170,16 @@ static void print_block_list_element_constraints(){ PrintAndLogEx(NORMAL, " - Block Number shall be in the range of the number of Blocks assigned to the specified Service."); } -static void print_number_of_service_constraints(){ +static void print_number_of_service_constraints() { PrintAndLogEx(NORMAL, " - Number of Service: shall be a positive integer in the range of 1 to 16, inclusive."); } -static void print_number_of_block_constraints(){ +static void print_number_of_block_constraints() { PrintAndLogEx(NORMAL, " - Number of Block: shall be less than or equal to the maximum number of Blocks that can be read simultaneously. " - "The maximum number of Blocks that can be read simultaneously can differ, depending on the product being used. Use as default 01"); + "The maximum number of Blocks that can be read simultaneously can differ, depending on the product being used. Use as default 01"); } -static void print_service_code_list_constraints(){ +static void print_service_code_list_constraints() { PrintAndLogEx(NORMAL, " - Service Code List: For Service Code List, only Service Code existing in the product shall be specified:"); PrintAndLogEx(NORMAL, " - Even when Service Code exists in the product, Service Code not referenced from Block List shall not be specified to Service Code List."); PrintAndLogEx(NORMAL, " - For existence or nonexistence of Service in a product, please check using the Request Service (or Request Service v2) command."); @@ -245,7 +245,7 @@ static bool waitCmdFelica(uint8_t iSelect, PacketResponseNG *resp, bool verbose) if (!check_crc(CRC_FELICA, resp->data.asBytes + 2, len - 2)) { PrintAndLogEx(WARNING, "Wrong or no CRC bytes"); } - if(resp->data.asBytes[0] != 0xB2 && resp->data.asBytes[1] != 0x4D){ + if (resp->data.asBytes[0] != 0xB2 && resp->data.asBytes[1] != 0x4D) { PrintAndLogEx(ERR, "Received incorrect Frame Format!"); return false; } @@ -415,7 +415,7 @@ int send_rd_unencrypted(uint8_t flags, uint16_t datalen, uint8_t *data, bool ver * @param data * @return */ -static bool check_last_idm(uint8_t *data, uint16_t datalen){ +static bool check_last_idm(uint8_t *data, uint16_t datalen) { if (!add_last_IDm(2, data)) { PrintAndLogEx(ERR, "No last known card! Use reader first or set a custom IDm!"); return 0; @@ -500,10 +500,15 @@ static int CmdHFFelicaWriteWithoutEncryption(const char *Cmd) { AddCrc(data, datalen); datalen += 2; felica_status_response_t wr_noCry_resp; - if(send_wr_unencrypted(flags, datalen, data, 1, &wr_noCry_resp) == PM3_SUCCESS){ + if (send_wr_unencrypted(flags, datalen, data, 1, &wr_noCry_resp) == PM3_SUCCESS) { PrintAndLogEx(NORMAL, "\nIDm: %s", sprint_hex(wr_noCry_resp.frame_response.IDm, sizeof(wr_noCry_resp.frame_response.IDm))); PrintAndLogEx(NORMAL, "Status Flag1: %s", sprint_hex(wr_noCry_resp.status_flags.status_flag1, sizeof(wr_noCry_resp.status_flags.status_flag1))); - PrintAndLogEx(NORMAL, "Status Flag2: %s\n\n", sprint_hex(wr_noCry_resp.status_flags.status_flag2, sizeof(wr_noCry_resp.status_flags.status_flag2))); + PrintAndLogEx(NORMAL, "Status Flag2: %s\n", sprint_hex(wr_noCry_resp.status_flags.status_flag2, sizeof(wr_noCry_resp.status_flags.status_flag2))); + if (wr_noCry_resp.status_flags.status_flag1[0] == 0x00 && wr_noCry_resp.status_flags.status_flag2[0] == 0x00) { + PrintAndLogEx(SUCCESS, "Writing data successful!\n"); + } else { + PrintAndLogEx(ERR, "Something went wrong! Check status flags.\n"); + } } return PM3_SUCCESS; } @@ -600,7 +605,7 @@ static int CmdHFFelicaReadWithoutEncryption(const char *Cmd) { AddCrc(data, datalen); datalen += 2; felica_read_without_encryption_response_t rd_noCry_resp; - if(send_rd_unencrypted(flags, datalen, data, 1, &rd_noCry_resp) == PM3_SUCCESS){ + if (send_rd_unencrypted(flags, datalen, data, 1, &rd_noCry_resp) == PM3_SUCCESS) { PrintAndLogEx(NORMAL, "Block Element\t| Data "); print_rd_noEncrpytion_response(&rd_noCry_resp); } @@ -634,7 +639,7 @@ static int CmdHFFelicaRequestResponse(const char *Cmd) { return PM3_EINVARG; } paramCount++; - i+=16; + i += 16; break; } } diff --git a/client/proxmark3.c b/client/proxmark3.c index c1d6a5dc7..bb291ee6c 100644 --- a/client/proxmark3.c +++ b/client/proxmark3.c @@ -482,7 +482,7 @@ static bool DetectWindowsAnsiSupport(void) { HKEY hKey = NULL; bool virtualTerminalLevelSet = false; bool forceV2Set = false; - + if (RegOpenKeyA(HKEY_CURRENT_USER, "Console", &hKey) == ERROR_SUCCESS) { DWORD dwType = REG_SZ; BYTE KeyValue[sizeof(dwType)];