From 1f7dd3e2a7e9f290bc24bb58688d4e3db1841053 Mon Sep 17 00:00:00 2001 From: Thomas Sutter Date: Wed, 23 Oct 2019 14:48:23 +0200 Subject: [PATCH 1/7] Add request response command for felica Mode. --- CHANGELOG.md | 3 + client/cmdhffelica.c | 142 ++++++++++++++++++++++++++++++++++--------- include/mifare.h | 8 +++ 3 files changed, 123 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cc6237f6a..168199c2b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,9 @@ All notable changes to this project will be documented in this file. This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... ## [unreleased][unreleased] + - Added hf felica rqresponse (@7homasSutter) + - Added hf felica rqservice (@7homasSutter) + - Added polling for felica standard (@7homasSutter) - Added lf t55xx dump save and lf t55xx restore for .bin and .eml files (@mwalker33) - Added lf t55xx detected to try without password first (@mwalker33) - Chg `lf indala read` - added indala 26bit decoding (@martinbeier) diff --git a/client/cmdhffelica.c b/client/cmdhffelica.c index bad416212..1b46f68e5 100644 --- a/client/cmdhffelica.c +++ b/client/cmdhffelica.c @@ -95,9 +95,9 @@ static int usage_hf_felica_request_service(void) { "of acquisition of Key Version shall be enumerated in Little Endian format. " "If Key Version of System is the target of acquisition, FFFFh shall be specified " "in the command packet."); - PrintAndLogEx(NORMAL, "\nUsage: hf felica rqservice [-h] [-i] <01 Number of Node hex> <0A 0B Node Code List hex (Little Endian)>"); + PrintAndLogEx(NORMAL, "\nUsage: hf felica rqservice [-h] [-i] <01 Number of Node hex> <0A0B Node Code List hex (Little Endian)>"); PrintAndLogEx(NORMAL, " -h this help"); - PrintAndLogEx(NORMAL, " -i <0A 0B 0C ... hex> set custom IDm to use"); + PrintAndLogEx(NORMAL, " -i <0A0B0C ... hex> set custom IDm to use"); PrintAndLogEx(NORMAL, " -a auto node number mode - iterates through all possible nodes 1 < n < 32"); PrintAndLogEx(NORMAL, "\nExamples: "); PrintAndLogEx(NORMAL, " hf felica rqservice 01 FFFF"); @@ -106,6 +106,16 @@ static int usage_hf_felica_request_service(void) { return PM3_SUCCESS; } +static int usage_hf_felica_request_response(void) { + PrintAndLogEx(NORMAL, "\nInfo: Use this command to verify the existence of a card and its Mode."); + PrintAndLogEx(NORMAL, " - Current Mode of the card is returned."); + PrintAndLogEx(NORMAL, "\nUsage: hf felica rqresponse [-h]"); + PrintAndLogEx(NORMAL, " -h this help"); + PrintAndLogEx(NORMAL, " -i <0A0B0C ... hex> set custom IDm to use"); + + return PM3_SUCCESS; +} + /** * Wait for response from pm3 or timeout. * Checks if receveid bytes have a valid CRC. @@ -181,13 +191,20 @@ static int CmdHFFelicaReader(const char *Cmd) { } /** - * Sends a request service frame to the pm3. + * Clears command buffer and sends the given data to pm3 with mix mode. */ -void send_request_service(uint8_t flags, uint16_t datalen, uint8_t *data) { +static void clear_and_send_command(uint8_t flags, uint16_t datalen, uint8_t *data) { uint16_t numbits = 0; clearCommandBuffer(); PrintAndLogEx(NORMAL, "Send Service Request Frame: %s", sprint_hex(data, datalen)); SendCommandMIX(CMD_HF_FELICA_COMMAND, flags, (datalen & 0xFFFF) | (uint32_t)(numbits << 16), 0, data, datalen); +} + +/** + * Sends a request service frame to the pm3. + */ +void send_request_service(uint8_t flags, uint16_t datalen, uint8_t *data) { + clear_and_send_command(flags, datalen, data); PacketResponseNG resp; if (datalen > 0) { if (!waitCmdFelica(0, &resp)) { @@ -206,6 +223,71 @@ void send_request_service(uint8_t flags, uint16_t datalen, uint8_t *data) { } } +/** + * Command parser for rqresponse + * @param Cmd input data of the user. + * @return client result code. + */ +static int CmdHFFelicaRequestResponse(const char *Cmd) { + uint8_t data[PM3_CMD_DATA_SIZE]; + bool custom_IDm = false; + strip_cmds(Cmd); + uint16_t datalen = 10; // Length (1), Command ID (1), IDm (8) + 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 (param_getlength(Cmd, paramCount) == 16) { + param_gethex(Cmd, paramCount++, data + 2, 16); + } else { + PrintAndLogEx(ERR, "Incorrect IDm length! IDm must be 8-Byte."); + return PM3_EINVARG; + } + break; + } + } + i++; + } + 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)); + } + } + AddCrc(data, datalen); + datalen += 2; + flags |= FELICA_APPEND_CRC; + flags |= FELICA_RAW; + clear_and_send_command(flags, datalen, data); + PacketResponseNG resp; + if (!waitCmdFelica(0, &resp)) { + PrintAndLogEx(ERR, "\nGot no Response from card"); + return PM3_ERFTRANS; + } 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) { + PrintAndLogEx(SUCCESS, "\nGot Request Response:"); + PrintAndLogEx(NORMAL, "IDm: %s", sprint_hex(rq_response.IDm, sizeof(rq_response.IDm))); + PrintAndLogEx(NORMAL, " -Mode: %s\n\n", sprint_hex(rq_response.mode, sizeof(rq_response.mode))); + } + } + return PM3_SUCCESS; +} + + /** * Command parser for rqservice. * @param Cmd input data of the user. @@ -806,36 +888,36 @@ int readFelicaUid(bool verbose) { static command_t CommandTable[] = { {"----------- General -----------", CmdHelp, IfPm3Iso14443a, ""}, - {"help", CmdHelp, AlwaysAvailable, "This help"}, - {"list", CmdHFFelicaList, AlwaysAvailable, "List ISO 18092/FeliCa history"}, - {"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"}, + {"help", CmdHelp, AlwaysAvailable, "This help"}, + {"list", CmdHFFelicaList, AlwaysAvailable, "List ISO 18092/FeliCa history"}, + {"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", CmdHFFelicaNotImplementedYet, IfPm3Felica, "verify the existence of a card and its Mode."}, - //{"rdNoEncryption", CmdHFFelicaNotImplementedYet, IfPm3Felica, "read Block Data from authentication-not-required Service."}, + //{"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."}, + {"rdNoEncryption", CmdHFFelicaNotImplementedYet, IfPm3Felica, "read Block Data from authentication-not-required Service."}, //{"wrNoEncryption", CmdHFFelicaNotImplementedYet, IfPm3Felica, "write Block Data to an authentication-required Service."}, - //{"searchSvCode", 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."}, + //{"searchSvCode", 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."}, //{"searchSvCodeV2", 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)."}, + //{"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"}, - // {"sim", CmdHFFelicaSim, IfPm3Felica, " -- Simulate ISO 18092/FeliCa tag"} + {"litesim", CmdHFFelicaSimLite, IfPm3Felica, " - only reply to poll request"}, + {"litedump", CmdHFFelicaDumpLite, IfPm3Felica, "Wait for and try dumping FelicaLite"}, + // {"sim", CmdHFFelicaSim, IfPm3Felica, " -- Simulate ISO 18092/FeliCa tag"} {NULL, NULL, NULL, NULL} }; diff --git a/include/mifare.h b/include/mifare.h index 5461bd19f..754a0c82f 100644 --- a/include/mifare.h +++ b/include/mifare.h @@ -178,6 +178,14 @@ typedef struct { 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]; + uint8_t mode[1]; +} PACKED felica_request_request_response_t; + typedef enum FELICA_COMMAND { FELICA_CONNECT = (1 << 0), FELICA_NO_DISCONNECT = (1 << 1), From 3b0447fbb3ccf06799b45df298631058f5db738c Mon Sep 17 00:00:00 2001 From: Thomas Sutter Date: Thu, 24 Oct 2019 08:44:20 +0200 Subject: [PATCH 2/7] Draft read without encryption --- client/cmdhffelica.c | 54 ++++++++++++++++++++++++++++++++++++++++++-- include/mifare.h | 11 +++++++++ 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/client/cmdhffelica.c b/client/cmdhffelica.c index 1b46f68e5..f0c699b9b 100644 --- a/client/cmdhffelica.c +++ b/client/cmdhffelica.c @@ -116,6 +116,16 @@ static int usage_hf_felica_request_response(void) { return PM3_SUCCESS; } +static int usage_hf_felica_read_without_encryption(void) { + PrintAndLogEx(NORMAL, "\nInfo: Use this command to read Block Data from authentication-not-required Service."); + PrintAndLogEx(NORMAL, " - Mode shall be Mode0."); + PrintAndLogEx(NORMAL, "\nUsage: hf felica rdNoEncryption [-h]"); + PrintAndLogEx(NORMAL, " -h this help"); + PrintAndLogEx(NORMAL, " -i <0A0B0C ... hex> set custom IDm to use"); + + return PM3_SUCCESS; +} + /** * Wait for response from pm3 or timeout. * Checks if receveid bytes have a valid CRC. @@ -223,6 +233,46 @@ void send_request_service(uint8_t flags, uint16_t datalen, uint8_t *data) { } } +/** + * Command parser for rdNoEncryption. + * @param Cmd input data of the user. + * @return client result code. + */ +static int CmdHFFelicaReadWithoutEncryption(const char *Cmd) { + if (strlen(Cmd) < 4) + return usage_hf_felica_read_without_encryption; + uint8_t data[PM3_CMD_DATA_SIZE]; + bool custom_IDm = false; + strip_cmds(Cmd); + uint16_t datalen = 17; // Length (1), Command ID (1), IDm (8), Number of Service (1), Service Code List(2), Number of Block(1), Block List(3) + 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 (param_getlength(Cmd, paramCount) == 16) { + param_gethex(Cmd, paramCount++, data + 2, 16); + } else { + PrintAndLogEx(ERR, "Incorrect IDm length! IDm must be 8-Byte."); + return PM3_EINVARG; + } + break; + } + } + i++; + } + + + return PM3_SUCCESS; +} + /** * Command parser for rqresponse * @param Cmd input data of the user. @@ -897,8 +947,8 @@ static command_t CommandTable[] = { //{"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."}, - {"rdNoEncryption", CmdHFFelicaNotImplementedYet, IfPm3Felica, "read Block Data from authentication-not-required Service."}, - //{"wrNoEncryption", CmdHFFelicaNotImplementedYet, IfPm3Felica, "write Block Data to an authentication-required Service."}, + {"rdNoEncryption", CmdHFFelicaReadWithoutEncryption, IfPm3Felica, "read Block Data from authentication-not-required Service."}, + {"wrNoEncryption", CmdHFFelicaNotImplementedYet, IfPm3Felica, "write Block Data to an authentication-required Service."}, //{"searchSvCode", CmdHFFelicaNotImplementedYet, IfPm3Felica, "acquire Area Code and Service Code."}, //{"rqSysCode", CmdHFFelicaNotImplementedYet, IfPm3Felica, "acquire System Code registered to the card."}, //{"auth1", CmdHFFelicaNotImplementedYet, IfPm3Felica, "authenticate a card."}, diff --git a/include/mifare.h b/include/mifare.h index 754a0c82f..e472d5c59 100644 --- a/include/mifare.h +++ b/include/mifare.h @@ -186,6 +186,17 @@ typedef struct { 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]; + uint8_t number_of_block[1]; + uint8_t block_data[16]; +} PACKED felica_read_without_encryption_response_t; + typedef enum FELICA_COMMAND { FELICA_CONNECT = (1 << 0), FELICA_NO_DISCONNECT = (1 << 1), From 003aada18f7727cef11ec082c86843d93d6a3711 Mon Sep 17 00:00:00 2001 From: Thomas Sutter Date: Thu, 24 Oct 2019 11:30:52 +0200 Subject: [PATCH 3/7] Add basic read_without_encryption command. --- client/cmdhffelica.c | 113 +++++++++++++++++++++++++++++++++---------- 1 file changed, 88 insertions(+), 25 deletions(-) diff --git a/client/cmdhffelica.c b/client/cmdhffelica.c index f0c699b9b..ea52e5112 100644 --- a/client/cmdhffelica.c +++ b/client/cmdhffelica.c @@ -112,17 +112,19 @@ 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"); - return PM3_SUCCESS; } static int usage_hf_felica_read_without_encryption(void) { PrintAndLogEx(NORMAL, "\nInfo: Use this command to read Block Data from authentication-not-required Service."); PrintAndLogEx(NORMAL, " - Mode shall be Mode0."); - PrintAndLogEx(NORMAL, "\nUsage: hf felica rdNoEncryption [-h]"); + + PrintAndLogEx(NORMAL, "\nUsage: hf felica rdunencrypted [-h] <01 Number of Service hex> <0A0B Service Code List hex> <01 Number of Block hex> <0A0B or 0A0B0C Block List Element hex>"); PrintAndLogEx(NORMAL, " -h this help"); PrintAndLogEx(NORMAL, " -i <0A0B0C ... hex> set custom IDm to use"); - + PrintAndLogEx(NORMAL, "\nExamples: "); + PrintAndLogEx(NORMAL, " hf felica rdunencrypted 01 8B00 01 8000"); + PrintAndLogEx(NORMAL, " hf felica rdunencrypted -i 01100910c11bc407 01 8B00 01 8000\n\n"); return PM3_SUCCESS; } @@ -211,7 +213,35 @@ static void clear_and_send_command(uint8_t flags, uint16_t datalen, uint8_t *dat } /** - * Sends a request service frame to the pm3. + * Prints the given block data. + */ +static void print_block_data(uint8_t *number_of_block, uint8_t *block_data, size_t block_size){ + PrintAndLogEx(NORMAL, "Block Nr.: %i", *number_of_block); + PrintAndLogEx(NORMAL, "Data: %s", sprint_hex(block_data, block_size)); +}; + + +/** + * Adds a parameter to the frame and checks if the parameter has the specific length. + * @param Cmd User input with the parameter. + * @param paramCount number of the parameter within the user input. + * @param data frame in which the data is stored. + * @param dataPosition position within frame where the data will be stored. + * @param length which the parameter should have and will be tested against. + * @return + */ +static bool add_param(const char *Cmd, uint8_t paramCount, uint8_t *data, uint8_t dataPosition, uint8_t length){ + if (param_getlength(Cmd, paramCount) == length) { + param_gethex(Cmd, paramCount, data + dataPosition, length); + return true; + } else { + PrintAndLogEx(ERR, "Incorrect Parameter length! Param %i", paramCount); + return false; + } +} + +/** + * Sends a request service frame to the pm3 and prints response. */ void send_request_service(uint8_t flags, uint16_t datalen, uint8_t *data) { clear_and_send_command(flags, datalen, data); @@ -234,17 +264,17 @@ void send_request_service(uint8_t flags, uint16_t datalen, uint8_t *data) { } /** - * Command parser for rdNoEncryption. + * Command parser for rdunencrypted. * @param Cmd input data of the user. * @return client result code. */ static int CmdHFFelicaReadWithoutEncryption(const char *Cmd) { if (strlen(Cmd) < 4) - return usage_hf_felica_read_without_encryption; + return usage_hf_felica_read_without_encryption(); uint8_t data[PM3_CMD_DATA_SIZE]; bool custom_IDm = false; strip_cmds(Cmd); - uint16_t datalen = 17; // Length (1), Command ID (1), IDm (8), Number of Service (1), Service Code List(2), Number of Block(1), Block List(3) + uint16_t datalen = 16; // Length (1), Command ID (1), IDm (8), Number of Service (1), Service Code List(2), Number of Block(1), Block List(3) uint8_t paramCount = 0; uint8_t flags = 0; int i = 0; @@ -257,10 +287,7 @@ static int CmdHFFelicaReadWithoutEncryption(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, 3, 8)){ return PM3_EINVARG; } break; @@ -268,8 +295,44 @@ static int CmdHFFelicaReadWithoutEncryption(const char *Cmd) { } i++; } + 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)); + } + } + // 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; + } + } + AddCrc(data, datalen); + datalen += 2; + flags |= FELICA_APPEND_CRC; + flags |= FELICA_RAW; + clear_and_send_command(flags, datalen, data); + PacketResponseNG resp; + if (!waitCmdFelica(0, &resp)) { + PrintAndLogEx(ERR, "\nGot no Response from card"); + return PM3_ERFTRANS; + } else { + PrintAndLogEx(SUCCESS, "\nGot Response from card"); + felica_read_without_encryption_response_t rd_noCry_resp; + memcpy(&rd_noCry_resp, (felica_read_without_encryption_response_t *)resp.data.asBytes, sizeof(felica_read_without_encryption_response_t)); - + if (rd_noCry_resp.IDm[0] != 0) { + print_block_data(rd_noCry_resp.number_of_block, rd_noCry_resp.block_data, sizeof(rd_noCry_resp.block_data)); + } + } return PM3_SUCCESS; } @@ -947,23 +1010,23 @@ static command_t CommandTable[] = { //{"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."}, - {"rdNoEncryption", CmdHFFelicaReadWithoutEncryption, IfPm3Felica, "read Block Data from authentication-not-required Service."}, - {"wrNoEncryption", CmdHFFelicaNotImplementedYet, IfPm3Felica, "write Block Data to an authentication-required Service."}, - //{"searchSvCode", CmdHFFelicaNotImplementedYet, IfPm3Felica, "acquire Area Code and Service Code."}, - //{"rqSysCode", CmdHFFelicaNotImplementedYet, IfPm3Felica, "acquire System Code registered to the card."}, + {"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."}, - //{"searchSvCodeV2", 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)."}, + //{"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 94ec36de2007bf277f9fff0925c26be03db9094e Mon Sep 17 00:00:00 2001 From: Thomas Sutter Date: Thu, 24 Oct 2019 11:59:58 +0200 Subject: [PATCH 4/7] Add status flag interpretation. --- client/cmdhffelica.c | 60 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 3 deletions(-) diff --git a/client/cmdhffelica.c b/client/cmdhffelica.c index ea52e5112..176031d3f 100644 --- a/client/cmdhffelica.c +++ b/client/cmdhffelica.c @@ -115,11 +115,58 @@ static int usage_hf_felica_request_response(void) { return PM3_SUCCESS; } +static void print_status_flag1_interpretation(){ + PrintAndLogEx(NORMAL, "Status Flag1:"); + PrintAndLogEx(NORMAL, " - 00h : Indicates the successful completion of a command."); + PrintAndLogEx(NORMAL, " - FFh : If an error occurs during the processing of a command that includes no list in the command packet, or if " + "an error occurs independently of any list, the card returns a response by setting FFh to Status Flag1."); + PrintAndLogEx(NORMAL, " - XXh : If an error occurs while processing a command that includes Service Code List or Block List " + "in the command packet, the card returns a response by setting a number in the list to Status Flag1, " + "indicating the location of the error. Have a look at the FeliCa User Manual for more information."); +} + +static void print_status_flag2_interpration(){ + PrintAndLogEx(NORMAL, "Status Flag2:"); + PrintAndLogEx(NORMAL, " - 00h : Indicates the successful completion of a command."); + PrintAndLogEx(NORMAL, " - 01h : The calculated result is either less than zero when the purse data is decremented, or exceeds 4" + "Bytes when the purse data is incremented."); + PrintAndLogEx(NORMAL, " - 02h : The specified data exceeds the value of cashback data at cashback of purse."); + PrintAndLogEx(NORMAL, " - 70h : Memory error (fatal error)."); + PrintAndLogEx(NORMAL, " - 71h : The number of memory rewrites exceeds the upper limit (this is only a warning; data writing is " + "performed as normal). The maximum number of rewrites can differ, depending on the product being used." + " In addition, Status Flag1 is either 00h or FFh depending on the product being used."); + PrintAndLogEx(NORMAL, " - A1h : Illegal Number of Service: Number of Service or Number of Node specified by the command falls outside the range of the prescribed value."); + PrintAndLogEx(NORMAL, " - A2h : Illegal command packet (specified Number of Block): Number of Block specified by the command falls outside the range of the prescribed values for the product."); + PrintAndLogEx(NORMAL, " - A3h : Illegal Block List (specified order of Service): Service Code List Order specified by Block List Element falls outside the Number of Service specified by the " + "command (or the Number of Service specified at the times of mutual authentication)."); + PrintAndLogEx(NORMAL, " - A4h : Illegal Service type: Area Attribute specified by the command or Service Attribute of Service Code is incorrect."); + PrintAndLogEx(NORMAL, " - A5h : Access is not allowed: Area or Service specified by the command cannot be accessed. " + "The parameter specified by the command does not satisfy the conditions for success."); + PrintAndLogEx(NORMAL, " - A6h : Illegal Service Code List: Target to be accessed, identified by Service Code List Order, specified by Block " + "List Element does not exist. Or, Node specified by Node Code List does not exist."); + PrintAndLogEx(NORMAL, " - A7h : Illegal Block List (Access Mode): Access Mode specified by Block List Element is incorrect."); + PrintAndLogEx(NORMAL, " - A8h : Illegal Block Number Block Number (access to the specified data is inhibited): specified by Block List Element exceeds the number of Blocks assigned to Service."); + PrintAndLogEx(NORMAL, " - A9h : Data write failure: This is the error that occurs in issuance commands."); + PrintAndLogEx(NORMAL, " - AAh : Key-change failure: Key change failed."); + PrintAndLogEx(NORMAL, " - ABh : Illegal Package Parity or illegal Package MAC: This is the error that occurs in issuance commands."); + PrintAndLogEx(NORMAL, " - ACh : Illegal parameter: This is the error that occurs in issuance commands."); + PrintAndLogEx(NORMAL, " - ADh : Service exists already: This is the error that occurs in issuance commands."); + PrintAndLogEx(NORMAL, " - AEh : Illegal System Code: This is the error that occurs in issuance commands."); + PrintAndLogEx(NORMAL, " - AFh : Too many simultaneous cyclic write operations: Number of simultaneous write Blocks specified by the command to Cyclic Service " + "exceeds the number of Blocks assigned to Service."); + PrintAndLogEx(NORMAL, " - C0h : Illegal Package Identifier: This is the error that occurs in issuance commands."); + PrintAndLogEx(NORMAL, " - C1h : Discrepancy of parameters inside and outside Package: This is the error that occurs in issuance commands."); + PrintAndLogEx(NORMAL, " - C2h : Command is disabled already: This is the error that occurs in issuance commands."); +} + static int usage_hf_felica_read_without_encryption(void) { PrintAndLogEx(NORMAL, "\nInfo: Use this command to read Block Data from authentication-not-required Service."); PrintAndLogEx(NORMAL, " - Mode shall be Mode0."); - - PrintAndLogEx(NORMAL, "\nUsage: hf felica rdunencrypted [-h] <01 Number of Service hex> <0A0B Service Code List hex> <01 Number of Block hex> <0A0B or 0A0B0C Block List Element hex>"); + PrintAndLogEx(NORMAL, " - Successful read: Card responses the block data"); + PrintAndLogEx(NORMAL, " - Unsuccessful read: Card responses with Status Flag1 and Flag2"); + print_status_flag1_interpretation(); + print_status_flag2_interpration(); + PrintAndLogEx(NORMAL, "\nUsage: hf felica rdunencrypted [-h] <01 Number of Service hex> <0A0B Service Code List (Little Endian) hex> <01 Number of Block hex> <0A0B Block List Element hex>"); PrintAndLogEx(NORMAL, " -h this help"); PrintAndLogEx(NORMAL, " -i <0A0B0C ... hex> set custom IDm to use"); PrintAndLogEx(NORMAL, "\nExamples: "); @@ -330,7 +377,14 @@ static int CmdHFFelicaReadWithoutEncryption(const char *Cmd) { memcpy(&rd_noCry_resp, (felica_read_without_encryption_response_t *)resp.data.asBytes, sizeof(felica_read_without_encryption_response_t)); if (rd_noCry_resp.IDm[0] != 0) { - print_block_data(rd_noCry_resp.number_of_block, rd_noCry_resp.block_data, sizeof(rd_noCry_resp.block_data)); + 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_flag2, sizeof(rd_noCry_resp.status_flag2))); + if(rd_noCry_resp.status_flag1[0] == 00 && rd_noCry_resp.status_flag2[0] == 00){ + print_block_data(rd_noCry_resp.number_of_block, rd_noCry_resp.block_data, sizeof(rd_noCry_resp.block_data)); + }else{ + PrintAndLogEx(ERR, "Could not read data! See -h for more information about the status flags."); + } } } return PM3_SUCCESS; From bfd5214cd5ab5ddfae2e2293b059f9216d6c1700 Mon Sep 17 00:00:00 2001 From: Thomas Sutter Date: Thu, 24 Oct 2019 16:08:44 +0200 Subject: [PATCH 5/7] Add read_without_encryption command. --- armsrc/felica.c | 20 ----- armsrc/felica.h | 5 -- client/cmdhffelica.c | 181 ++++++++++++++++++++++++++++++------------- client/cmdhffelica.h | 4 +- include/mifare.h | 1 + 5 files changed, 133 insertions(+), 78 deletions(-) diff --git a/armsrc/felica.c b/armsrc/felica.c index 09e2b582f..7ec40efcf 100644 --- a/armsrc/felica.c +++ b/armsrc/felica.c @@ -751,26 +751,6 @@ void felica_sim_lite(uint64_t uid) { #define RES_SVC_LEN 11 + 3 -void felica_dump() { - uint8_t ndef[8]; - uint8_t poll[10] = { 0xb2, 0x4d, 0x06, FELICA_POLL_REQ, 0xff, 0xff, 0x00, 0x00, 0x09, 0x21}; // B24D0600FFFF00000921 - iso18092_setup(FPGA_HF_ISO18092_FLAG_READER | FPGA_HF_ISO18092_FLAG_NOMOD); - - TransmitFor18092_AsReader(poll, 10, NULL, 1, 0); - - // iceman, no exit path in this loop - while (!BUTTON_PRESS() && !data_available()) { - WDT_HIT(); - TransmitFor18092_AsReader(poll, 10, NULL, 1, 0); - if (WaitForFelicaReply(512) && FelicaFrame.framebytes[3] == FELICA_POLL_ACK) { - memcpy(ndef, FelicaFrame.framebytes + 4, 8); - uint8_t *request_service = felica_create_request_service_frame(0x01, ndef); - felica_send_request_service(request_service); - } - } - -} - void felica_dump_lite_s() { uint8_t ndef[8]; uint8_t poll[10] = { 0xb2, 0x4d, 0x06, FELICA_POLL_REQ, 0xff, 0xff, 0x00, 0x00, 0x09, 0x21}; diff --git a/armsrc/felica.h b/armsrc/felica.h index 7bbc48614..95e13a588 100644 --- a/armsrc/felica.h +++ b/armsrc/felica.h @@ -18,12 +18,7 @@ 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_dump(); void felica_create_read_block_frame(uint16_t blockNr); -void felica_create_authentication1_frame(); -void felica_create_authentication2_frame(); void felica_send_request_service(uint8_t *request_service); -void felica_reset_frame_mode(); -uint8_t *felica_create_request_service_frame(uint8_t nodeNumber, uint8_t *idm); #endif diff --git a/client/cmdhffelica.c b/client/cmdhffelica.c index 176031d3f..8a1926276 100644 --- a/client/cmdhffelica.c +++ b/client/cmdhffelica.c @@ -159,9 +159,19 @@ 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(void) { +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."); + 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."); + PrintAndLogEx(NORMAL, " - The target specified by Service Code shall not be Area or System."); + 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."); PrintAndLogEx(NORMAL, " - Successful read: Card responses the block data"); PrintAndLogEx(NORMAL, " - Unsuccessful read: Card responses with Status Flag1 and Flag2"); print_status_flag1_interpretation(); @@ -169,6 +179,7 @@ static int usage_hf_felica_read_without_encryption(void) { PrintAndLogEx(NORMAL, "\nUsage: hf felica rdunencrypted [-h] <01 Number of Service hex> <0A0B Service Code List (Little Endian) hex> <01 Number of Block hex> <0A0B Block List Element hex>"); PrintAndLogEx(NORMAL, " -h this help"); PrintAndLogEx(NORMAL, " -i <0A0B0C ... hex> set custom IDm to use"); + PrintAndLogEx(NORMAL, " -b get all Block List Elements of service"); PrintAndLogEx(NORMAL, "\nExamples: "); PrintAndLogEx(NORMAL, " hf felica rdunencrypted 01 8B00 01 8000"); PrintAndLogEx(NORMAL, " hf felica rdunencrypted -i 01100910c11bc407 01 8B00 01 8000\n\n"); @@ -178,17 +189,20 @@ static int usage_hf_felica_read_without_encryption(void) { /** * Wait for response from pm3 or timeout. * Checks if receveid bytes have a valid CRC. + * @param verbose prints out the response received. */ -static bool waitCmdFelica(uint8_t iSelect, PacketResponseNG *resp) { +static bool waitCmdFelica(uint8_t iSelect, PacketResponseNG *resp, bool verbose) { if (WaitForResponseTimeout(CMD_ACK, resp, 2000)) { uint16_t len = iSelect ? (resp->oldarg[1] & 0xffff) : (resp->oldarg[0] & 0xffff); - PrintAndLogEx(NORMAL, "Client Received %i octets", len); - if (!len || len < 2) { - PrintAndLogEx(ERR, "Could not receive data correctly!"); - } - PrintAndLogEx(NORMAL, "%s", sprint_hex(resp->data.asBytes, len)); - if (!check_crc(CRC_FELICA, resp->data.asBytes + 2, len - 2)) { - PrintAndLogEx(WARNING, "Wrong or no CRC bytes"); + if(verbose){ + PrintAndLogEx(NORMAL, "Client Received %i octets", len); + if (!len || len < 2) { + PrintAndLogEx(ERR, "Could not receive data correctly!"); + } + PrintAndLogEx(NORMAL, "%s", sprint_hex(resp->data.asBytes, len)); + if (!check_crc(CRC_FELICA, resp->data.asBytes + 2, len - 2)) { + PrintAndLogEx(WARNING, "Wrong or no CRC bytes"); + } } return true; } else { @@ -252,22 +266,15 @@ static int CmdHFFelicaReader(const char *Cmd) { /** * Clears command buffer and sends the given data to pm3 with mix mode. */ -static void clear_and_send_command(uint8_t flags, uint16_t datalen, uint8_t *data) { +static void clear_and_send_command(uint8_t flags, uint16_t datalen, uint8_t *data, bool verbose) { uint16_t numbits = 0; clearCommandBuffer(); - PrintAndLogEx(NORMAL, "Send Service Request Frame: %s", sprint_hex(data, datalen)); + if(verbose){ + PrintAndLogEx(NORMAL, "Send Service Request Frame: %s", sprint_hex(data, datalen)); + } SendCommandMIX(CMD_HF_FELICA_COMMAND, flags, (datalen & 0xFFFF) | (uint32_t)(numbits << 16), 0, data, datalen); } -/** - * Prints the given block data. - */ -static void print_block_data(uint8_t *number_of_block, uint8_t *block_data, size_t block_size){ - PrintAndLogEx(NORMAL, "Block Nr.: %i", *number_of_block); - PrintAndLogEx(NORMAL, "Data: %s", sprint_hex(block_data, block_size)); -}; - - /** * Adds a parameter to the frame and checks if the parameter has the specific length. * @param Cmd User input with the parameter. @@ -275,7 +282,7 @@ static void print_block_data(uint8_t *number_of_block, uint8_t *block_data, size * @param data frame in which the data is stored. * @param dataPosition position within frame where the data will be stored. * @param length which the parameter should have and will be tested against. - * @return + * @return true if parameters was added. */ static bool add_param(const char *Cmd, uint8_t paramCount, uint8_t *data, uint8_t dataPosition, uint8_t length){ if (param_getlength(Cmd, paramCount) == length) { @@ -287,16 +294,42 @@ static bool add_param(const char *Cmd, uint8_t paramCount, uint8_t *data, uint8_ } } +/** + * Prints read-without-encryption response. + * @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){ + char bl_number[4]; + char *temp = sprint_hex(rd_noCry_resp->number_of_block, sizeof(rd_noCry_resp->number_of_block)); + strcpy(bl_number, temp); + + temp = sprint_hex(rd_noCry_resp->block_data, sizeof(rd_noCry_resp->block_data)); + char bl_data[256]; + strcpy(bl_data, temp); + + char bl_element_number[4]; + temp = sprint_hex(rd_noCry_resp->block_element_number, sizeof(rd_noCry_resp->block_element_number)); + strcpy(bl_element_number, temp); + + PrintAndLogEx(NORMAL, "%s: %s: %s", bl_number, 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))); + } +} + /** * Sends a request service frame to the pm3 and prints response. */ -void send_request_service(uint8_t flags, uint16_t datalen, uint8_t *data) { - clear_and_send_command(flags, datalen, data); +int send_request_service(uint8_t flags, uint16_t datalen, uint8_t *data, bool verbose) { + clear_and_send_command(flags, datalen, data, verbose); PacketResponseNG resp; if (datalen > 0) { - if (!waitCmdFelica(0, &resp)) { + if (!waitCmdFelica(0, &resp, 1)) { PrintAndLogEx(ERR, "\nGot no Response from card"); - return; + return PM3_ERFTRANS; } felica_request_service_response_t rqs_response; memcpy(&rqs_response, (felica_request_service_response_t *)resp.data.asBytes, sizeof(felica_request_service_response_t)); @@ -307,6 +340,30 @@ void send_request_service(uint8_t flags, uint16_t datalen, uint8_t *data) { 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))); } + return PM3_SUCCESS; + } + return PM3_ERFTRANS; +} + +/** + * 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 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){ + 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(rd_noCry_resp, (felica_read_without_encryption_response_t *)resp.data.asBytes, sizeof(felica_read_without_encryption_response_t)); + rd_noCry_resp->block_element_number[0] = data[15]; + return PM3_SUCCESS; } } @@ -324,6 +381,8 @@ static int CmdHFFelicaReadWithoutEncryption(const char *Cmd) { uint16_t datalen = 16; // Length (1), Command ID (1), IDm (8), Number of Service (1), Service Code List(2), Number of Block(1), Block List(3) uint8_t paramCount = 0; uint8_t flags = 0; + uint8_t all_block_list_elements = false; + uint8_t long_block_numbers = false; int i = 0; while (Cmd[i] != '\0') { if (Cmd[i] == '-') { @@ -338,6 +397,14 @@ static int CmdHFFelicaReadWithoutEncryption(const char *Cmd) { return PM3_EINVARG; } break; + case 'b': + paramCount++; + all_block_list_elements = true; + break; + case 'l': + paramCount++; + long_block_numbers = true; + break; } } i++; @@ -355,6 +422,10 @@ static int CmdHFFelicaReadWithoutEncryption(const char *Cmd) { // 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}; + if(long_block_numbers){ + datalen += 1; + lengths[3] = 6; + } for(int i=0; i < 4; i++){ if(add_param(Cmd, paramCount, data, dataPositions[i], lengths[i])){ paramCount++; @@ -362,30 +433,36 @@ static int CmdHFFelicaReadWithoutEncryption(const char *Cmd) { return PM3_EINVARG; } } - AddCrc(data, datalen); - datalen += 2; + flags |= FELICA_APPEND_CRC; flags |= FELICA_RAW; - clear_and_send_command(flags, datalen, data); - PacketResponseNG resp; - if (!waitCmdFelica(0, &resp)) { - PrintAndLogEx(ERR, "\nGot no Response from card"); - return PM3_ERFTRANS; - } else { - PrintAndLogEx(SUCCESS, "\nGot Response from card"); - felica_read_without_encryption_response_t rd_noCry_resp; - memcpy(&rd_noCry_resp, (felica_read_without_encryption_response_t *)resp.data.asBytes, sizeof(felica_read_without_encryption_response_t)); - - if (rd_noCry_resp.IDm[0] != 0) { - 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_flag2, sizeof(rd_noCry_resp.status_flag2))); - if(rd_noCry_resp.status_flag1[0] == 00 && rd_noCry_resp.status_flag2[0] == 00){ - print_block_data(rd_noCry_resp.number_of_block, rd_noCry_resp.block_data, sizeof(rd_noCry_resp.block_data)); - }else{ - PrintAndLogEx(ERR, "Could not read data! See -h for more information about the status flags."); - } + if(all_block_list_elements){ + uint16_t last_block_number = 0xFF; + if(long_block_numbers){ + last_block_number = 0xFFFF; } + for(int i=0x00; i < last_block_number; i++){ + data[15] = i; + AddCrc(data, datalen); + 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){ + print_rd_noEncrpytion_response(&rd_noCry_resp); + }else{ + break; + } + }else{ + break; + } + datalen -= 2; + } + }else{ + AddCrc(data, datalen); + datalen += 2; + felica_read_without_encryption_response_t rd_noCry_resp; + send_rd_unencrypted(flags, datalen, data, 1, &rd_noCry_resp); + print_rd_noEncrpytion_response(&rd_noCry_resp); } return PM3_SUCCESS; } @@ -437,9 +514,9 @@ static int CmdHFFelicaRequestResponse(const char *Cmd) { datalen += 2; flags |= FELICA_APPEND_CRC; flags |= FELICA_RAW; - clear_and_send_command(flags, datalen, data); + clear_and_send_command(flags, datalen, data, 0); PacketResponseNG resp; - if (!waitCmdFelica(0, &resp)) { + if (!waitCmdFelica(0, &resp, 1)) { PrintAndLogEx(ERR, "\nGot no Response from card"); return PM3_ERFTRANS; } else { @@ -539,13 +616,13 @@ static int CmdHFFelicaRequestService(const char *Cmd) { data[10] = int_to_hex(&y); AddCrc(data, datalen); datalen += 2; - send_request_service(flags, datalen, data); + send_request_service(flags, datalen, data, 1); datalen -= 2; // Remove CRC bytes before adding new ones } } else { AddCrc(data, datalen); datalen += 2; - send_request_service(flags, datalen, data); + send_request_service(flags, datalen, data, 1); } return PM3_SUCCESS; @@ -993,11 +1070,11 @@ static int CmdHFFelicaCmdRaw(const char *Cmd) { if (active_select) { PrintAndLogEx(NORMAL, "Active select wait for FeliCa."); PacketResponseNG resp_IDm; - waitCmdFelica(1, &resp_IDm); + waitCmdFelica(1, &resp_IDm, 1); } if (datalen > 0) { PacketResponseNG resp_frame; - waitCmdFelica(0, &resp_frame); + waitCmdFelica(0, &resp_frame, 1); } } return PM3_SUCCESS; diff --git a/client/cmdhffelica.h b/client/cmdhffelica.h index dd127cfaf..7626d002b 100644 --- a/client/cmdhffelica.h +++ b/client/cmdhffelica.h @@ -12,8 +12,10 @@ #define CMDHFFELICA_H__ #include "common.h" +#include "mifare.h" int CmdHFFelica(const char *Cmd); int readFelicaUid(bool verbose); -void send_request_service(uint8_t flags, uint16_t datalen, uint8_t *data); +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 e472d5c59..7a40a26e4 100644 --- a/include/mifare.h +++ b/include/mifare.h @@ -195,6 +195,7 @@ typedef struct { uint8_t status_flag2[1]; 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 enum FELICA_COMMAND { From 12cd208253b61bef7fdd4565b8eabfbfd16b696f Mon Sep 17 00:00:00 2001 From: Thomas Sutter Date: Thu, 24 Oct 2019 17:07:27 +0200 Subject: [PATCH 6/7] Make style. Format help text. --- client/cmdhffelica.c | 94 ++++++++++++++++++++++---------------------- 1 file changed, 48 insertions(+), 46 deletions(-) diff --git a/client/cmdhffelica.c b/client/cmdhffelica.c index 8a1926276..bd0099923 100644 --- a/client/cmdhffelica.c +++ b/client/cmdhffelica.c @@ -115,35 +115,35 @@ static int usage_hf_felica_request_response(void) { return PM3_SUCCESS; } -static void print_status_flag1_interpretation(){ - PrintAndLogEx(NORMAL, "Status Flag1:"); +static void print_status_flag1_interpretation() { + PrintAndLogEx(NORMAL, "\nStatus Flag1:"); PrintAndLogEx(NORMAL, " - 00h : Indicates the successful completion of a command."); PrintAndLogEx(NORMAL, " - FFh : If an error occurs during the processing of a command that includes no list in the command packet, or if " - "an error occurs independently of any list, the card returns a response by setting FFh to Status Flag1."); + "an error occurs independently of any list, the card returns a response by setting FFh to Status Flag1."); PrintAndLogEx(NORMAL, " - XXh : If an error occurs while processing a command that includes Service Code List or Block List " - "in the command packet, the card returns a response by setting a number in the list to Status Flag1, " - "indicating the location of the error. Have a look at the FeliCa User Manual for more information."); + "in the command packet, the card returns a response by setting a number in the list to Status Flag1, " + "indicating the location of the error."); } -static void print_status_flag2_interpration(){ - PrintAndLogEx(NORMAL, "Status Flag2:"); +static void print_status_flag2_interpration() { + PrintAndLogEx(NORMAL, "\nStatus Flag2:"); PrintAndLogEx(NORMAL, " - 00h : Indicates the successful completion of a command."); PrintAndLogEx(NORMAL, " - 01h : The calculated result is either less than zero when the purse data is decremented, or exceeds 4" - "Bytes when the purse data is incremented."); + "Bytes when the purse data is incremented."); PrintAndLogEx(NORMAL, " - 02h : The specified data exceeds the value of cashback data at cashback of purse."); PrintAndLogEx(NORMAL, " - 70h : Memory error (fatal error)."); PrintAndLogEx(NORMAL, " - 71h : The number of memory rewrites exceeds the upper limit (this is only a warning; data writing is " - "performed as normal). The maximum number of rewrites can differ, depending on the product being used." - " In addition, Status Flag1 is either 00h or FFh depending on the product being used."); + "performed as normal). The maximum number of rewrites can differ, depending on the product being used."); + PrintAndLogEx(NORMAL, " In addition, Status Flag1 is either 00h or FFh depending on the product being used."); PrintAndLogEx(NORMAL, " - A1h : Illegal Number of Service: Number of Service or Number of Node specified by the command falls outside the range of the prescribed value."); PrintAndLogEx(NORMAL, " - A2h : Illegal command packet (specified Number of Block): Number of Block specified by the command falls outside the range of the prescribed values for the product."); PrintAndLogEx(NORMAL, " - A3h : Illegal Block List (specified order of Service): Service Code List Order specified by Block List Element falls outside the Number of Service specified by the " - "command (or the Number of Service specified at the times of mutual authentication)."); + "command (or the Number of Service specified at the times of mutual authentication)."); PrintAndLogEx(NORMAL, " - A4h : Illegal Service type: Area Attribute specified by the command or Service Attribute of Service Code is incorrect."); PrintAndLogEx(NORMAL, " - A5h : Access is not allowed: Area or Service specified by the command cannot be accessed. " - "The parameter specified by the command does not satisfy the conditions for success."); + "The parameter specified by the command does not satisfy the conditions for success."); PrintAndLogEx(NORMAL, " - A6h : Illegal Service Code List: Target to be accessed, identified by Service Code List Order, specified by Block " - "List Element does not exist. Or, Node specified by Node Code List does not exist."); + "List Element does not exist. Or, Node specified by Node Code List does not exist."); PrintAndLogEx(NORMAL, " - A7h : Illegal Block List (Access Mode): Access Mode specified by Block List Element is incorrect."); PrintAndLogEx(NORMAL, " - A8h : Illegal Block Number Block Number (access to the specified data is inhibited): specified by Block List Element exceeds the number of Blocks assigned to Service."); PrintAndLogEx(NORMAL, " - A9h : Data write failure: This is the error that occurs in issuance commands."); @@ -153,7 +153,7 @@ static void print_status_flag2_interpration(){ PrintAndLogEx(NORMAL, " - ADh : Service exists already: This is the error that occurs in issuance commands."); PrintAndLogEx(NORMAL, " - AEh : Illegal System Code: This is the error that occurs in issuance commands."); PrintAndLogEx(NORMAL, " - AFh : Too many simultaneous cyclic write operations: Number of simultaneous write Blocks specified by the command to Cyclic Service " - "exceeds the number of Blocks assigned to Service."); + "exceeds the number of Blocks assigned to Service."); PrintAndLogEx(NORMAL, " - C0h : Illegal Package Identifier: This is the error that occurs in issuance commands."); PrintAndLogEx(NORMAL, " - C1h : Discrepancy of parameters inside and outside Package: This is the error that occurs in issuance commands."); PrintAndLogEx(NORMAL, " - C2h : Command is disabled already: This is the error that occurs in issuance commands."); @@ -162,9 +162,12 @@ static void print_status_flag2_interpration(){ 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."); + 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."); 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."); @@ -179,10 +182,12 @@ static int usage_hf_felica_read_without_encryption() { PrintAndLogEx(NORMAL, "\nUsage: hf felica rdunencrypted [-h] <01 Number of Service hex> <0A0B Service Code List (Little Endian) hex> <01 Number of Block hex> <0A0B Block List Element hex>"); PrintAndLogEx(NORMAL, " -h this help"); PrintAndLogEx(NORMAL, " -i <0A0B0C ... hex> set custom IDm to use"); - PrintAndLogEx(NORMAL, " -b get all Block List Elements of service"); + PrintAndLogEx(NORMAL, " -b get all Block List Elements starting from 00 to FF - stops when a block return an error status flags"); + PrintAndLogEx(NORMAL, " -l use 3-byte block list element block number"); PrintAndLogEx(NORMAL, "\nExamples: "); PrintAndLogEx(NORMAL, " hf felica rdunencrypted 01 8B00 01 8000"); - PrintAndLogEx(NORMAL, " hf felica rdunencrypted -i 01100910c11bc407 01 8B00 01 8000\n\n"); + PrintAndLogEx(NORMAL, " hf felica rdunencrypted -i 01100910c11bc407 01 8B00 01 8000"); + PrintAndLogEx(NORMAL, " hf felica rdunencrypted -b 01 8B00 01 8000\n\n"); return PM3_SUCCESS; } @@ -194,7 +199,7 @@ static int usage_hf_felica_read_without_encryption() { static bool waitCmdFelica(uint8_t iSelect, PacketResponseNG *resp, bool verbose) { if (WaitForResponseTimeout(CMD_ACK, resp, 2000)) { uint16_t len = iSelect ? (resp->oldarg[1] & 0xffff) : (resp->oldarg[0] & 0xffff); - if(verbose){ + if (verbose) { PrintAndLogEx(NORMAL, "Client Received %i octets", len); if (!len || len < 2) { PrintAndLogEx(ERR, "Could not receive data correctly!"); @@ -269,7 +274,7 @@ static int CmdHFFelicaReader(const char *Cmd) { static void clear_and_send_command(uint8_t flags, uint16_t datalen, uint8_t *data, bool verbose) { uint16_t numbits = 0; clearCommandBuffer(); - if(verbose){ + if (verbose) { PrintAndLogEx(NORMAL, "Send Service Request Frame: %s", sprint_hex(data, datalen)); } SendCommandMIX(CMD_HF_FELICA_COMMAND, flags, (datalen & 0xFFFF) | (uint32_t)(numbits << 16), 0, data, datalen); @@ -284,7 +289,7 @@ static void clear_and_send_command(uint8_t flags, uint16_t datalen, uint8_t *dat * @param length which the parameter should have and will be tested against. * @return true if parameters was added. */ -static bool add_param(const char *Cmd, uint8_t paramCount, uint8_t *data, uint8_t dataPosition, uint8_t length){ +static bool add_param(const char *Cmd, uint8_t paramCount, uint8_t *data, uint8_t dataPosition, uint8_t length) { if (param_getlength(Cmd, paramCount) == length) { param_gethex(Cmd, paramCount, data + dataPosition, length); return true; @@ -298,22 +303,17 @@ static bool add_param(const char *Cmd, uint8_t paramCount, uint8_t *data, uint8_ * Prints read-without-encryption response. * @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){ - char bl_number[4]; - char *temp = sprint_hex(rd_noCry_resp->number_of_block, sizeof(rd_noCry_resp->number_of_block)); - strcpy(bl_number, temp); - - temp = sprint_hex(rd_noCry_resp->block_data, sizeof(rd_noCry_resp->block_data)); +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) { + char *temp = sprint_hex(rd_noCry_resp->block_data, sizeof(rd_noCry_resp->block_data)); char bl_data[256]; strcpy(bl_data, temp); char bl_element_number[4]; temp = sprint_hex(rd_noCry_resp->block_element_number, sizeof(rd_noCry_resp->block_element_number)); strcpy(bl_element_number, temp); - - PrintAndLogEx(NORMAL, "%s: %s: %s", bl_number, bl_element_number, bl_data); - }else{ + 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))); @@ -354,7 +354,7 @@ int send_request_service(uint8_t flags, uint16_t datalen, uint8_t *data, bool ve * @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){ +int send_rd_unencrypted(uint8_t flags, uint16_t datalen, uint8_t *data, bool verbose, felica_read_without_encryption_response_t *rd_noCry_resp) { clear_and_send_command(flags, datalen, data, verbose); PacketResponseNG resp; if (!waitCmdFelica(0, &resp, verbose)) { @@ -393,7 +393,7 @@ 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, 3, 8)) { return PM3_EINVARG; } break; @@ -422,46 +422,48 @@ static int CmdHFFelicaReadWithoutEncryption(const char *Cmd) { // 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}; - if(long_block_numbers){ + if (long_block_numbers) { datalen += 1; lengths[3] = 6; } - for(int i=0; i < 4; i++){ - if(add_param(Cmd, paramCount, data, dataPositions[i], lengths[i])){ + for (int i = 0; i < 4; i++) { + if (add_param(Cmd, paramCount, data, dataPositions[i], lengths[i])) { paramCount++; - }else{ + } else { return PM3_EINVARG; } } flags |= FELICA_APPEND_CRC; flags |= FELICA_RAW; - if(all_block_list_elements){ + if (all_block_list_elements) { uint16_t last_block_number = 0xFF; - if(long_block_numbers){ + if (long_block_numbers) { last_block_number = 0xFFFF; } - for(int i=0x00; i < last_block_number; i++){ + PrintAndLogEx(NORMAL, "Block Element\t| Data "); + for (int i = 0x00; i < last_block_number; i++) { data[15] = i; AddCrc(data, datalen); 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 ((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) { print_rd_noEncrpytion_response(&rd_noCry_resp); - }else{ + } else { break; } - }else{ + } else { break; } datalen -= 2; } - }else{ + } else { 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); } return PM3_SUCCESS; From b4bcec581cbc9a4e05fcdf42ec41ec167d74c8eb Mon Sep 17 00:00:00 2001 From: Thomas Sutter Date: Thu, 24 Oct 2019 17:10:56 +0200 Subject: [PATCH 7/7] Add changelong text --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 168199c2b..c0ef300cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file. This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... ## [unreleased][unreleased] + - Added hf felica rdunencrypted (@7homasSutter) - Added hf felica rqresponse (@7homasSutter) - Added hf felica rqservice (@7homasSutter) - Added polling for felica standard (@7homasSutter)