1 //-----------------------------------------------------------------------------
2 // Copyright (C) 2017 October, Satsuoni
4 // This code is licensed to you under the terms of the GNU GPL, version 2 or,
5 // at your option, any later version. See the LICENSE.txt file for the text of
7 //-----------------------------------------------------------------------------
8 // High frequency ISO18092 / FeliCa commands
9 //-----------------------------------------------------------------------------
10 #include "cmdhffelica.h"
16 #include "cmdparser.h" // command_t
22 #include "iso18.h" // felica_card_select_t struct
24 #include "cliparser.h" // cliparser
25 #include "util_posix.h" // msleep
27 #define AddCrc(data, len) compute_crc(CRC_FELICA, (data), (len), (data)+(len)+1, (data)+(len))
29 static int CmdHelp(const char *Cmd
);
30 static felica_card_select_t last_known_card
;
32 static void set_last_known_card(felica_card_select_t card
) {
33 last_known_card
= card
;
36 static void print_status_flag1_interpretation(void) {
37 PrintAndLogEx(NORMAL
, "");
38 PrintAndLogEx(INFO
, _CYAN_("Status Flag 1"));
39 PrintAndLogEx(INFO
, "----+--------------------------------------------------------------------------------------------------------------------");
40 PrintAndLogEx(INFO
, " 00 | Indicates the successful completion of a command.");
41 PrintAndLogEx(INFO
, " FF | If an error occurs during the processing of a command that includes no list in the command packet, \n"
42 " | or if an error occurs independently of any list, the card returns a response by setting FFh to Status Flag1.");
43 PrintAndLogEx(INFO
, " XX | If an error occurs while processing a command that includes Service Code List or Block List \n"
44 " | in the command packet, the card returns a response by setting a number in the list to Status Flag1,\n"
45 " | indicating the location of the error.");
46 PrintAndLogEx(INFO
, "----+--------------------------------------------------------------------------------------------------------------------");
49 static void print_status_flag2_interpration(void) {
50 PrintAndLogEx(INFO
, _CYAN_("Status Flag 2"));
51 PrintAndLogEx(INFO
, "----+--------------------------------------------------------------------------------------------------------------------");
52 PrintAndLogEx(INFO
, " 00 | Indicates the successful completion of a command.");
53 PrintAndLogEx(INFO
, " 01 | The calculated result is either less than zero when the purse data is decremented, or exceeds 4\n"
54 " | Bytes when the purse data is incremented.");
55 PrintAndLogEx(INFO
, " 02 | The specified data exceeds the value of cashback data at cashback of purse.");
56 PrintAndLogEx(INFO
, " 70 | Memory error (fatal error).");
57 PrintAndLogEx(INFO
, " 71 | The number of memory rewrites exceeds the upper limit (this is only a warning; data writing is performed as normal).\n"
58 " | The maximum number of rewrites can differ, depending on the product being used.\n"
59 " | In addition, Status Flag1 is either 00h or FFh depending on the product being used.");
61 PrintAndLogEx(INFO
, " A1 | Illegal Number of Service| Number of Service or Number of Node specified by the command \n"
62 " | falls outside the range of the prescribed value.");
63 PrintAndLogEx(INFO
, " A2 | Illegal command packet (specified Number of Block) : Number of Block specified by the \n"
64 " | command falls outside the range of the prescribed values for the product.");
65 PrintAndLogEx(INFO
, " A3 | Illegal Block List (specified order of Service) : Service Code List Order specified by \n"
66 " | Block List Element falls outside the Number of Service specified by the command \n"
67 " | (or the Number of Service specified at the times of mutual authentication).");
68 PrintAndLogEx(INFO
, " A4 | Illegal Service type : Area Attribute specified by the command or Service Attribute of Service Code is incorrect.");
69 PrintAndLogEx(INFO
, " A5 | Access is not allowed : Area or Service specified by the command cannot be accessed.\n"
70 " | The parameter specified by the command does not satisfy the conditions for success.");
71 PrintAndLogEx(INFO
, " A6 | Illegal Service Code List : Target to be accessed, identified by Service Code List Order, specified by Block\n"
72 " | List Element does not exist. Or, Node specified by Node Code List does not exist.");
73 PrintAndLogEx(INFO
, " A7 | Illegal Block List (Access Mode) : Access Mode specified by Block List Element is incorrect.");
74 PrintAndLogEx(INFO
, " A8 | Illegal Block Number Block Number (access to the specified data is inhibited) :\n"
75 " | specified by Block List Element exceeds the number of Blocks assigned to Service.");
76 PrintAndLogEx(INFO
, " A9 | Data write failure : This is the error that occurs in issuance commands.");
77 PrintAndLogEx(INFO
, " AA | Key-change failure : Key change failed.");
78 PrintAndLogEx(INFO
, " AB | Illegal Package Parity or illegal Package MAC : This is the error that occurs in issuance commands.");
79 PrintAndLogEx(INFO
, " AC | Illegal parameter : This is the error that occurs in issuance commands.");
80 PrintAndLogEx(INFO
, " AD | Service exists already : This is the error that occurs in issuance commands.");
81 PrintAndLogEx(INFO
, " AE | Illegal System Code : This is the error that occurs in issuance commands.");
82 PrintAndLogEx(INFO
, " AF | Too many simultaneous cyclic write operations : Number of simultaneous write Blocks\n"
83 " | specified by the command to Cyclic Service exceeds the number of Blocks assigned to Service.");
84 PrintAndLogEx(INFO
, " C0 | Illegal Package Identifier : This is the error that occurs in issuance commands.");
85 PrintAndLogEx(INFO
, " C1 | Discrepancy of parameters inside and outside Package : This is the error that occurs in issuance commands.");
86 PrintAndLogEx(INFO
, " C2 | Command is disabled already : This is the error that occurs in issuance commands.");
87 PrintAndLogEx(INFO
, "----+--------------------------------------------------------------------------------------------------------------------");
88 PrintAndLogEx(NORMAL
, "");
91 static void print_block_list_element_constraints(void) {
92 PrintAndLogEx(INFO
, " - Each Block List Element shall satisfy the following conditions:");
93 PrintAndLogEx(INFO
, " - The value of Service Code List Order shall not exceed Number of Service.");
94 PrintAndLogEx(INFO
, " - Access Mode shall be 000b.");
95 PrintAndLogEx(INFO
, " - The target specified by Service Code shall not be Area or System.");
96 PrintAndLogEx(INFO
, " - Service specified in Service Code List shall exist in System.");
97 PrintAndLogEx(INFO
, " - Service Attribute of Service specified in Service Code List shall be authentication-not-required Service.");
98 PrintAndLogEx(INFO
, " - Block Number shall be in the range of the number of Blocks assigned to the specified Service.");
101 static void print_number_of_service_constraints(void) {
102 PrintAndLogEx(INFO
, " - Number of Service: shall be a positive integer in the range of 1 to 16, inclusive.");
105 static void print_number_of_block_constraints(void) {
106 PrintAndLogEx(INFO
, " - Number of Block: shall be less than or equal to the maximum number of Blocks that can be read simultaneously.\n"
107 " The maximum number of Blocks that can be read simultaneously can differ, depending on the product being used.\n"
108 " Use as default 01");
111 static void print_service_code_list_constraints(void) {
112 PrintAndLogEx(INFO
, " - Service Code List: For Service Code List, only Service Code existing in the product shall be specified:");
113 PrintAndLogEx(INFO
, " - Even when Service Code exists in the product, Service Code not referenced from Block List shall not \n"
114 " be specified to Service Code List.");
115 PrintAndLogEx(INFO
, " - For existence or nonexistence of Service in a product, please check using the Request Service \n"
116 " (or Request Service v2) command.");
120 static int usage_hf_felica_sim(void) {
121 PrintAndLogEx(INFO, "\n Emulating ISO/18092 FeliCa tag \n");
122 PrintAndLogEx(INFO, "Usage: hf felica sim -t <type> [-v]");
123 PrintAndLogEx(INFO, "Options:");
124 PrintAndLogEx(INFO, " t : 1 = FeliCa");
125 PrintAndLogEx(INFO, " : 2 = FeliCaLiteS");
126 PrintAndLogEx(INFO, " v : (Optional) Verbose");
127 PrintAndLogEx(INFO, "Examples:");
128 PrintAndLogEx(INFO, " hf felica sim -t 1");
133 static int print_authentication1(void) {
134 PrintAndLogEx(INFO
, "Initiate mutual authentication. This command must always be executed before Auth2 command");
135 PrintAndLogEx(INFO
, "and mutual authentication is achieve only after Auth2 command has succeeded.");
136 PrintAndLogEx(INFO
, " - Auth1 Parameters:");
137 PrintAndLogEx(INFO
, " - Number of Areas n: 1-byte (1 <= n <= 8)");
138 PrintAndLogEx(INFO
, " - Area Code List: 2n byte");
139 PrintAndLogEx(INFO
, " - Number of Services m: 1-byte (1 <= n <= 8)");
140 PrintAndLogEx(INFO
, " - Service Code List: 2n byte");
141 PrintAndLogEx(INFO
, " - 3DES-Key: 128-bit master secret used for the encryption");
142 PrintAndLogEx(INFO
, " - M1c: Encrypted random number - challenge for tag authentication (8-byte)");
143 PrintAndLogEx(INFO
, " - Response:");
144 PrintAndLogEx(INFO
, " - Response Code: 11h 1-byte");
145 PrintAndLogEx(INFO
, " - Manufacture ID(IDm): 8-byte");
146 PrintAndLogEx(INFO
, " - M2c: 8-byte");
147 PrintAndLogEx(INFO
, " - M3c: 8-byte");
148 PrintAndLogEx(INFO
, " - Success: Card Mode switches to Mode1. You can check this with the request response command.");
149 PrintAndLogEx(INFO
, " - Unsuccessful: Card should not respond at all.");
153 static int print_authentication2(void) {
154 PrintAndLogEx(INFO
, "Complete mutual authentication.");
155 PrintAndLogEx(INFO
, "This command can only be executed subsquent to Auth1 command.");
156 PrintAndLogEx(INFO
, " - Auth2 Parameters:");
157 PrintAndLogEx(INFO
, " - Manufacturer IDm: (8-byte)");
158 PrintAndLogEx(INFO
, " - M3c: card challenge (8-byte)");
159 PrintAndLogEx(INFO
, " - 3DES Key: key used for decryption of M3c (16-byte)");
160 PrintAndLogEx(INFO
, " - Response (encrypted):");
161 PrintAndLogEx(INFO
, " - Response Code: 13h (1-byte)");
162 PrintAndLogEx(INFO
, " - IDtc: (8-byte)");
163 PrintAndLogEx(INFO
, " - IDi (encrypted): (8-byte)");
164 PrintAndLogEx(INFO
, " - PMi (encrypted): (8-byte)");
165 PrintAndLogEx(INFO
, " - Success: Card switches to mode2 and sends response frame.");
166 PrintAndLogEx(INFO
, " - Unsuccessful: Card should not respond at all.");
171 * Wait for response from pm3 or timeout.
172 * Checks if receveid bytes have a valid CRC.
173 * @param verbose prints out the response received.
175 static bool waitCmdFelica(uint8_t iSelect
, PacketResponseNG
*resp
, bool verbose
) {
176 if (WaitForResponseTimeout(CMD_ACK
, resp
, 2000)) {
177 uint16_t len
= iSelect
? (resp
->oldarg
[1] & 0xffff) : (resp
->oldarg
[0] & 0xffff);
179 PrintAndLogEx(SUCCESS
, "client received %i octets", len
);
180 if (len
== 0 || len
== 1) {
181 PrintAndLogEx(ERR
, "Could not receive data correctly!");
184 PrintAndLogEx(SUCCESS
, "%s", sprint_hex(resp
->data
.asBytes
, len
));
185 if (!check_crc(CRC_FELICA
, resp
->data
.asBytes
+ 2, len
- 2)) {
186 PrintAndLogEx(WARNING
, "wrong or no CRC bytes");
188 if (resp
->data
.asBytes
[0] != 0xB2 && resp
->data
.asBytes
[1] != 0x4D) {
189 PrintAndLogEx(ERR
, "received incorrect frame format!");
195 PrintAndLogEx(WARNING
, "timeout while waiting for reply.");
202 * Adds the last known IDm (8-Byte) to the data frame.
203 * @param position start of where the IDm is added within the frame.
204 * @param data frame in where the IDM is added.
205 * @return true if IDm was added;
207 static bool add_last_IDm(uint8_t position
, uint8_t *data
) {
208 if (last_known_card
.IDm
[0] != 0 && last_known_card
.IDm
[1] != 0) {
209 memcpy(data
+ position
, last_known_card
.IDm
, sizeof(last_known_card
.IDm
));
215 static int CmdHFFelicaList(const char *Cmd
) {
216 return CmdTraceListAlias(Cmd
, "hf felica", "felica");
219 int read_felica_uid(bool loop
, bool verbose
) {
221 int res
= PM3_SUCCESS
;
224 clearCommandBuffer();
225 SendCommandMIX(CMD_HF_FELICA_COMMAND
, FELICA_CONNECT
, 0, 0, NULL
, 0);
226 PacketResponseNG resp
;
227 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 2000)) {
229 uint8_t status
= resp
.oldarg
[0] & 0xFF;
236 // when not in continuous mode
238 if (verbose
) PrintAndLogEx(WARNING
, "FeliCa card select failed");
239 res
= PM3_EOPABORTED
;
244 felica_card_select_t card
;
245 memcpy(&card
, (felica_card_select_t
*)resp
.data
.asBytes
, sizeof(felica_card_select_t
));
247 PrintAndLogEx(NORMAL
, "");
249 PrintAndLogEx(SUCCESS
, "IDm: " _GREEN_("%s"), sprint_hex_inrow(card
.IDm
, sizeof(card
.IDm
)));
250 set_last_known_card(card
);
252 } while (loop
&& kbd_enter_pressed() == false);
258 static int CmdHFFelicaReader(const char *Cmd
) {
259 CLIParserContext
*ctx
;
260 CLIParserInit(&ctx
, "hf felica reader",
261 "Act as a ISO 18092 / FeliCa reader. Look for FeliCa tags until Enter or the pm3 button is pressed",
262 "hf felica reader -@ -> Continuous mode");
266 arg_lit0("s", "silent", "silent (no messages)"),
267 arg_lit0("@", NULL
, "optional - continuous reader mode"),
270 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
271 bool verbose
= (arg_get_lit(ctx
, 1) == false);
272 bool cm
= arg_get_lit(ctx
, 2);
276 PrintAndLogEx(INFO
, "Press " _GREEN_("<Enter>") " to exit");
280 return read_felica_uid(cm
, verbose
);
283 static int info_felica(bool verbose
) {
285 clearCommandBuffer();
286 SendCommandMIX(CMD_HF_FELICA_COMMAND
, FELICA_CONNECT
, 0, 0, NULL
, 0);
287 PacketResponseNG resp
;
288 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 2500) == false) {
289 if (verbose
) PrintAndLogEx(WARNING
, "FeliCa card select failed");
293 felica_card_select_t card
;
294 memcpy(&card
, (felica_card_select_t
*)resp
.data
.asBytes
, sizeof(felica_card_select_t
));
295 uint64_t status
= resp
.oldarg
[0];
300 PrintAndLogEx(WARNING
, "card timeout");
305 PrintAndLogEx(WARNING
, "card answered wrong");
310 PrintAndLogEx(WARNING
, "CRC check failed");
314 PrintAndLogEx(NORMAL
, "");
315 PrintAndLogEx(INFO
, "--- " _CYAN_("Tag Information") " ---------------------------");
316 PrintAndLogEx(INFO
, "IDm............ " _GREEN_("%s"), sprint_hex_inrow(card
.IDm
, sizeof(card
.IDm
)));
317 PrintAndLogEx(INFO
, "Code........... %s ", sprint_hex_inrow(card
.code
, sizeof(card
.code
)));
318 PrintAndLogEx(INFO
, "NFCID2......... %s", sprint_hex_inrow(card
.uid
, sizeof(card
.uid
)));
319 PrintAndLogEx(INFO
, "Parameter");
320 PrintAndLogEx(INFO
, "PAD............ " _YELLOW_("%s"), sprint_hex_inrow(card
.PMm
, sizeof(card
.PMm
)));
321 PrintAndLogEx(INFO
, "IC code........ %s", sprint_hex_inrow(card
.iccode
, sizeof(card
.iccode
)));
322 PrintAndLogEx(INFO
, "MRT............ %s", sprint_hex_inrow(card
.mrt
, sizeof(card
.mrt
)));
323 PrintAndLogEx(INFO
, "Service code... " _YELLOW_("%s"), sprint_hex(card
.servicecode
, sizeof(card
.servicecode
)));
324 PrintAndLogEx(NORMAL
, "");
325 set_last_known_card(card
);
332 static int CmdHFFelicaInfo(const char *Cmd
) {
333 CLIParserContext
*ctx
;
334 CLIParserInit(&ctx
, "hf felica info",
335 "Reader for FeliCa based tags",
342 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
344 return info_felica(false);
348 * Clears command buffer and sends the given data to pm3 with mix mode.
350 static void clear_and_send_command(uint8_t flags
, uint16_t datalen
, uint8_t *data
, bool verbose
) {
351 uint16_t numbits
= 0;
352 clearCommandBuffer();
354 PrintAndLogEx(INFO
, "Send raw command - Frame: %s", sprint_hex(data
, datalen
));
356 SendCommandMIX(CMD_HF_FELICA_COMMAND
, flags
, (datalen
& 0xFFFF) | (uint32_t)(numbits
<< 16), 0, data
, datalen
);
360 * Prints read-without-encryption response.
361 * @param rd_noCry_resp Response frame.
363 static void print_rd_plain_response(felica_read_without_encryption_response_t
*rd_noCry_resp
) {
365 if (rd_noCry_resp
->status_flags
.status_flag1
[0] == 00 &&
366 rd_noCry_resp
->status_flags
.status_flag2
[0] == 00) {
368 char *temp
= sprint_hex(rd_noCry_resp
->block_data
, sizeof(rd_noCry_resp
->block_data
));
371 strncpy(bl_data
, temp
, sizeof(bl_data
) - 1);
373 char bl_element_number
[4];
374 temp
= sprint_hex(rd_noCry_resp
->block_element_number
, sizeof(rd_noCry_resp
->block_element_number
));
375 strncpy(bl_element_number
, temp
, sizeof(bl_element_number
) - 1);
377 PrintAndLogEx(INFO
, " %s | %s ", bl_element_number
, bl_data
);
379 PrintAndLogEx(SUCCESS
, "IDm... %s", sprint_hex_inrow(rd_noCry_resp
->frame_response
.IDm
, sizeof(rd_noCry_resp
->frame_response
.IDm
)));
380 PrintAndLogEx(SUCCESS
, " Status flag 1... %s", sprint_hex(rd_noCry_resp
->status_flags
.status_flag1
, sizeof(rd_noCry_resp
->status_flags
.status_flag1
)));
381 PrintAndLogEx(SUCCESS
, " Status flag 2... %s", sprint_hex(rd_noCry_resp
->status_flags
.status_flag1
, sizeof(rd_noCry_resp
->status_flags
.status_flag1
)));
386 * Sends a request service frame to the pm3 and prints response.
388 int send_request_service(uint8_t flags
, uint16_t datalen
, uint8_t *data
, bool verbose
) {
389 clear_and_send_command(flags
, datalen
, data
, verbose
);
390 PacketResponseNG resp
;
392 if (!waitCmdFelica(0, &resp
, 1)) {
393 PrintAndLogEx(ERR
, "\nGot no response from card");
396 felica_request_service_response_t r
;
397 memcpy(&r
, (felica_request_service_response_t
*)resp
.data
.asBytes
, sizeof(felica_request_service_response_t
));
399 if (r
.frame_response
.IDm
[0] != 0) {
400 PrintAndLogEx(SUCCESS
, "Service Response:");
401 PrintAndLogEx(SUCCESS
, "IDm... %s", sprint_hex_inrow(r
.frame_response
.IDm
, sizeof(r
.frame_response
.IDm
)));
402 PrintAndLogEx(SUCCESS
, " Node number............. %s", sprint_hex(r
.node_number
, sizeof(r
.node_number
)));
403 PrintAndLogEx(SUCCESS
, " Node key version list... %s\n", sprint_hex(r
.node_key_versions
, sizeof(r
.node_key_versions
)));
411 * Sends a read_without_encryption frame to the pm3 and prints response.
412 * @param flags to use for pm3 communication.
413 * @param datalen frame length.
414 * @param data frame to be send.
415 * @param verbose display additional output.
416 * @param rd_noCry_resp frame in which the response will be saved.
417 * @return success if response was received.
419 int send_rd_plain(uint8_t flags
, uint16_t datalen
, uint8_t *data
, bool verbose
, felica_read_without_encryption_response_t
*rd_noCry_resp
) {
420 clear_and_send_command(flags
, datalen
, data
, verbose
);
421 PacketResponseNG resp
;
422 if (!waitCmdFelica(0, &resp
, verbose
)) {
423 PrintAndLogEx(ERR
, "No response from card");
426 memcpy(rd_noCry_resp
, (felica_read_without_encryption_response_t
*)resp
.data
.asBytes
, sizeof(felica_read_without_encryption_response_t
));
427 rd_noCry_resp
->block_element_number
[0] = data
[15];
433 * Checks if last known card can be added to data and adds it if possible.
438 static bool check_last_idm(uint8_t *data
, uint16_t datalen
) {
439 if (add_last_IDm(2, data
) == false) {
440 PrintAndLogEx(WARNING
, "No last known card! Use `" _YELLOW_("hf felica reader") "` first or set a custom IDm");
444 PrintAndLogEx(INFO
, "Using last known IDm... " _GREEN_("%s"), sprint_hex_inrow(data
, datalen
));
449 * Sends a read_without_encryption frame to the pm3 and prints response.
450 * @param flags to use for pm3 communication.
451 * @param datalen frame length.
452 * @param data frame to be send.
453 * @param verbose display additional output.
454 * @param wr_noCry_resp frame in which the response will be saved.
455 * @return success if response was received.
457 static int send_wr_plain(uint8_t flags
, uint16_t datalen
, uint8_t *data
, bool verbose
, felica_status_response_t
*wr_noCry_resp
) {
458 clear_and_send_command(flags
, datalen
, data
, verbose
);
459 PacketResponseNG resp
;
460 if (waitCmdFelica(0, &resp
, verbose
) == false) {
461 PrintAndLogEx(ERR
, "no response from card");
465 memcpy(wr_noCry_resp
, (felica_status_response_t
*)resp
.data
.asBytes
, sizeof(felica_status_response_t
));
470 * Reverses the master secret. Example: AA AA AA AA AA AA AA BB to BB AA AA AA AA AA AA AA
471 * @param master_key the secret which order will be reversed.
472 * @param length in bytes of the master secret.
473 * @param reverse_master_key output in which the reversed secret is stored.
475 static void reverse_3des_key(uint8_t *master_key
, int length
, uint8_t *reverse_master_key
) {
476 for (int i
= 0; i
< length
; i
++) {
477 reverse_master_key
[i
] = master_key
[(length
- 1) - i
];
482 * Command parser for auth1
483 * @param Cmd input data of the user.
484 * @return client result code.
486 static int CmdHFFelicaAuthentication1(const char *Cmd
) {
487 CLIParserContext
*ctx
;
488 CLIParserInit(&ctx
, "hf felica auth1",
489 "Initiate mutual authentication. This command must always be executed before Auth2 command\n"
490 "and mutual authentication is achieve only after Auth2 command has succeeded.\n"
491 _RED_("INCOMPLETE / EXPERIMENTAL COMMAND!!!"),
492 "hf felica auth1 --an 01 --acl 0000 --sn 01 --scl 8B00 --key AAAAAAAAAAAAAAAABBBBBBBBBBBBBBBB\n"
493 "hf felica auth1 --an 01 --acl 0000 --sn 01 --scl 8B00 --key AAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAA\n"
494 "hf felica auth1 -i 11100910C11BC407 --an 01 --acl 0000 --sn 01 ..scl 8B00 --key AAAAAAAAAAAAAAAABBBBBBBBBBBBBBBB\n"
498 arg_str0(NULL
, "an", "<hex>", "number of areas, 1 byte"),
499 arg_str0(NULL
, "acl", "<hex>", "area code list, 2 bytes"),
500 arg_str0("i", NULL
, "<hex>", "set custom IDm"),
501 arg_str0(NULL
, "sn", "<hex>", "number of service, 1 byte"),
502 arg_str0(NULL
, "scl", "<hex>", "service code list, 2 bytes"),
503 arg_str0("k", "key", "<hex>", "3des key, 16 bytes"),
504 arg_lit0("v", "verbose", "verbose helptext"),
507 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
511 int res
= CLIParamHexToBuf(arg_get_str(ctx
, 1), an
, sizeof(an
), &anlen
);
517 uint8_t acl
[2] = {0};
519 res
= CLIParamHexToBuf(arg_get_str(ctx
, 2), acl
, sizeof(acl
), &acllen
);
525 uint8_t idm
[8] = {0};
527 res
= CLIParamHexToBuf(arg_get_str(ctx
, 3), idm
, sizeof(idm
), &ilen
);
535 res
= CLIParamHexToBuf(arg_get_str(ctx
, 4), sn
, sizeof(sn
), &snlen
);
541 uint8_t scl
[2] = {0};
543 res
= CLIParamHexToBuf(arg_get_str(ctx
, 5), scl
, sizeof(scl
), &scllen
);
549 uint8_t key
[24] = {0};
551 res
= CLIParamHexToBuf(arg_get_str(ctx
, 6), key
, sizeof(key
), &keylen
);
557 bool verbose
= arg_get_lit(ctx
, 7);
560 print_authentication1();
564 uint8_t data
[PM3_CMD_DATA_SIZE
];
565 memset(data
, 0, sizeof(data
));
566 data
[0] = 0x0C; // Static length
567 data
[1] = 0x3E; // Command ID
569 bool custom_IDm
= false;
573 memcpy(data
+ 2, idm
, 8);
579 // Number of Area (1),
580 // Area Code List (2),
581 // Number of Service (1),
582 // Service Code List (2),
584 uint16_t datalen
= 32;
585 data
[0] = (datalen
& 0xFF);
586 data
[1] = 0x10; // Command ID
588 if (custom_IDm
== false && check_last_idm(data
, datalen
) == false) {
607 memcpy(data
+ 16, key
, keylen
);
610 // READER CHALLENGE - (RANDOM To Encrypt = Rac)
611 uint8_t nonce
[8] = {1, 2, 3, 4, 5, 6, 7, 8};
612 PrintAndLogEx(INFO
, "Reader challenge (unencrypted): %s", sprint_hex(nonce
, 8));
614 // Create M1c Challenge with 3DES (3 Keys = 24, 2 Keys = 16)
615 uint8_t master_key
[24];
616 mbedtls_des3_context des3_ctx
;
617 mbedtls_des3_init(&des3_ctx
);
621 mbedtls_des3_set3key_enc(&des3_ctx
, master_key
);
622 PrintAndLogEx(INFO
, "3DES Master Secret: %s", sprint_hex(master_key
, keylen
));
624 } else if (keylen
== 16) {
626 // Assumption: Master secret split in half for Kac, Kbc
627 mbedtls_des3_set2key_enc(&des3_ctx
, master_key
);
628 PrintAndLogEx(INFO
, "3DES Master Secret: %s", sprint_hex(master_key
, keylen
));
630 PrintAndLogEx(ERR
, "Invalid key length");
631 mbedtls_des3_free(&des3_ctx
);
636 mbedtls_des3_crypt_ecb(&des3_ctx
, nonce
, output
);
637 mbedtls_des3_free(&des3_ctx
);
639 PrintAndLogEx(INFO
, "3DES ENCRYPTED M1c: %s", sprint_hex(output
, sizeof(output
)));
641 // Add M1c Challenge to frame
642 memcpy(data
+ 16, output
, sizeof(output
));
644 AddCrc(data
, datalen
);
646 uint8_t flags
= (FELICA_APPEND_CRC
| FELICA_RAW
);
648 PrintAndLogEx(INFO
, "Client send AUTH1 frame: %s", sprint_hex(data
, datalen
));
649 clear_and_send_command(flags
, datalen
, data
, 0);
651 PacketResponseNG resp
;
652 if (waitCmdFelica(0, &resp
, 1) == false) {
653 PrintAndLogEx(ERR
, "no response from card");
657 felica_auth1_response_t auth1_response
;
658 memcpy(&auth1_response
, (felica_auth1_response_t
*)resp
.data
.asBytes
, sizeof(felica_auth1_response_t
));
660 if (auth1_response
.frame_response
.IDm
[0]) {
661 PrintAndLogEx(SUCCESS
, "Auth1 response:");
662 PrintAndLogEx(SUCCESS
, "IDm... %s", sprint_hex(auth1_response
.frame_response
.IDm
, sizeof(auth1_response
.frame_response
.IDm
)));
663 PrintAndLogEx(SUCCESS
, "M2C... %s", sprint_hex(auth1_response
.m2c
, sizeof(auth1_response
.m2c
)));
664 PrintAndLogEx(SUCCESS
, "M3C... %s", sprint_hex(auth1_response
.m3c
, sizeof(auth1_response
.m3c
)));
666 // Assumption: Key swap method used
667 uint8_t rev_master_key
[PM3_CMD_DATA_SIZE
];
668 reverse_3des_key(master_key
, 16, rev_master_key
);
669 mbedtls_des3_set2key_dec(&des3_ctx
, rev_master_key
);
671 bool is_key_correct
= false;
672 unsigned char p2c
[8];
673 mbedtls_des3_crypt_ecb(&des3_ctx
, auth1_response
.m2c
, p2c
);
675 for (uint8_t i
= 0; i
< 8; i
++) {
676 if (p2c
[i
] != nonce
[i
]) {
677 is_key_correct
= false;
680 is_key_correct
= true;
684 if (is_key_correct
) {
685 PrintAndLogEx(SUCCESS
, "Auth1 done with correct key material!");
686 PrintAndLogEx(SUCCESS
, "Use Auth2 now with M3C and same key");
688 PrintAndLogEx(INFO
, "3DES secret (swapped decryption): %s", sprint_hex(rev_master_key
, 16));
689 PrintAndLogEx(INFO
, "P2c: %s", sprint_hex(p2c
, 8));
690 PrintAndLogEx(ERR
, "Can't decrypt M2C with master secret (P1c != P2c)!");
691 PrintAndLogEx(ERR
, "Probably wrong keys or wrong decryption method");
698 * Command parser for auth2
699 * @param Cmd input data of the user.
700 * @return client result code.
702 static int CmdHFFelicaAuthentication2(const char *Cmd
) {
704 CLIParserContext
*ctx
;
705 CLIParserInit(&ctx
, "hf felica auth2",
706 "Complete mutual authentication. This command can only be executed subsquent to Auth1\n"
707 _RED_("INCOMPLETE / EXPERIMENTAL COMMAND!!!\n")
708 _RED_("EXPERIMENTAL COMMAND - M2c/P2c will be not checked"),
709 "hf felica auth2 --cc 0102030405060708 --key AAAAAAAAAAAAAAAABBBBBBBBBBBBBBBB\n"
710 "hf felica auth2 -i 11100910C11BC407 --cc 0102030405060708 --key AAAAAAAAAAAAAAAABBBBBBBBBBBBBBBB\n"
714 arg_str0("i", NULL
, "<hex>", "set custom IDm"),
715 arg_str0("c", "cc", "<hex>", "M3c card challenge, 8 bytes"),
716 arg_str0("k", "key", "<hex>", "3des M3c decryption key, 16 bytes"),
717 arg_lit0("v", "verbose", "verbose helptext"),
720 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
722 uint8_t idm
[8] = {0};
724 int res
= CLIParamHexToBuf(arg_get_str(ctx
, 1), idm
, sizeof(idm
), &ilen
);
732 res
= CLIParamHexToBuf(arg_get_str(ctx
, 2), cc
, sizeof(cc
), &cclen
);
738 uint8_t key
[16] = {0};
740 res
= CLIParamHexToBuf(arg_get_str(ctx
, 3), key
, sizeof(key
), &keylen
);
746 bool verbose
= arg_get_lit(ctx
, 4);
749 print_authentication2();
753 uint8_t data
[PM3_CMD_DATA_SIZE
];
754 memset(data
, 0, sizeof(data
));
756 bool custom_IDm
= false;
760 memcpy(data
+ 2, idm
, 8);
763 uint16_t datalen
= 18; // Length (1), Command ID (1), IDm (8), M4c (8)
764 data
[0] = (datalen
& 0xFF);
765 data
[1] = 0x12; // Command ID
767 if (custom_IDm
== false && check_last_idm(data
, datalen
) == false) {
772 memcpy(data
+ 16, cc
, cclen
);
776 memcpy(data
+ 16, key
, keylen
);
780 if (custom_IDm
== false && check_last_idm(data
, datalen
) == false) {
785 // unsigned char m3c[8]; == cc
788 mbedtls_des3_context des3_ctx_enc
;
789 mbedtls_des3_context des3_ctx_dec
;
791 mbedtls_des3_init(&des3_ctx_enc
);
792 mbedtls_des3_init(&des3_ctx_dec
);
796 // set encryption context
797 mbedtls_des3_set2key_enc(&des3_ctx_enc
, key
);
799 // Create M4c challenge response with 3DES
801 reverse_3des_key(key
, sizeof(key
), rev_key
);
803 // set decryption context
804 mbedtls_des3_set2key_dec(&des3_ctx_dec
, rev_key
);
806 // Assumption: Key swap method used for E2
807 PrintAndLogEx(INFO
, "3DES Master Secret (encryption)... %s", sprint_hex_inrow(key
, sizeof(key
)));
808 PrintAndLogEx(INFO
, "3DES Master Secret (decryption)... %s", sprint_hex_inrow(rev_key
, sizeof(rev_key
)));
810 PrintAndLogEx(ERR
, "Invalid key length");
811 mbedtls_des3_free(&des3_ctx_enc
);
812 mbedtls_des3_free(&des3_ctx_dec
);
816 // Decrypt m3c with reverse_master_key
817 unsigned char p3c
[8];
818 mbedtls_des3_crypt_ecb(&des3_ctx_dec
, cc
, p3c
);
819 PrintAndLogEx(INFO
, "3DES decrypted M3c = P3c... %s", sprint_hex_inrow(p3c
, sizeof(p3c
)));
821 // Encrypt p3c with master_key
822 unsigned char m4c
[8];
823 mbedtls_des3_crypt_ecb(&des3_ctx_enc
, p3c
, m4c
);
824 PrintAndLogEx(INFO
, "3DES encrypted M4c......... %s", sprint_hex_inrow(m4c
, sizeof(m4c
)));
827 mbedtls_des3_free(&des3_ctx_enc
);
828 mbedtls_des3_free(&des3_ctx_dec
);
830 // Add M4c Challenge to frame
831 memcpy(data
+ 10, m4c
, sizeof(m4c
));
833 AddCrc(data
, datalen
);
835 uint8_t flags
= (FELICA_APPEND_CRC
| FELICA_RAW
);
837 PrintAndLogEx(INFO
, "Client Send AUTH2 Frame: %s", sprint_hex(data
, datalen
));
838 clear_and_send_command(flags
, datalen
, data
, 0);
840 PacketResponseNG resp
;
841 if (waitCmdFelica(0, &resp
, 1) == false) {
842 PrintAndLogEx(ERR
, "no response from card");
846 felica_auth2_response_t auth2_response
;
847 memcpy(&auth2_response
, (felica_auth2_response_t
*)resp
.data
.asBytes
, sizeof(felica_auth2_response_t
));
848 if (auth2_response
.code
[0] != 0x12) {
849 PrintAndLogEx(SUCCESS
, "Auth2 response:");
850 PrintAndLogEx(SUCCESS
, "IDtc.............. %s", sprint_hex(auth2_response
.IDtc
, sizeof(auth2_response
.IDtc
)));
851 PrintAndLogEx(SUCCESS
, "IDi (encrypted)... %s", sprint_hex(auth2_response
.IDi
, sizeof(auth2_response
.IDi
)));
852 PrintAndLogEx(SUCCESS
, "PMi (encrypted)... %s", sprint_hex(auth2_response
.PMi
, sizeof(auth2_response
.PMi
)));
854 PrintAndLogEx(ERR
, "Got wrong frame format");
861 * Command parser for wrunencrypted.
862 * @param Cmd input data of the user.
863 * @return client result code.
865 static int CmdHFFelicaWritePlain(const char *Cmd
) {
867 CLIParserContext
*ctx
;
868 CLIParserInit(&ctx
, "hf felica wrbl",
869 "Use this command to write block data to authentication-not-required Service.\n\n"
870 " - Mode shall be Mode0.\n"
871 " - Un-/Ssuccessful == Status Flag1 and Flag2",
872 "hf felica wrbl --sn 01 --scl CB10 --bn 01 --ble 8001 -d 0102030405060708090A0B0C0D0E0F10\n"
873 "hf felica wrbl -i 01100910c11bc407 --sn 01 --scl CB10 --bn 01 --ble 8001 -d 0102030405060708090A0B0C0D0E0F10\n"
877 arg_str0("d", "data", "<hex>", "data, 16 hex bytes"),
878 arg_str0("i", NULL
, "<hex>", "set custom IDm"),
879 arg_str0(NULL
, "sn", "<hex>", "number of service"),
880 arg_str0(NULL
, "scl", "<hex>", "service code list"),
881 arg_str0(NULL
, "bn", "<hex>", "number of block"),
882 arg_str0(NULL
, "ble", "<hex>", "block list element (def 2|3 bytes)"),
883 arg_lit0("v", "verbose", "verbose helptext"),
886 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
888 uint8_t userdata
[16] = {0};
890 int res
= CLIParamHexToBuf(arg_get_str(ctx
, 1), userdata
, sizeof(userdata
), &udlen
);
896 uint8_t idm
[8] = {0};
898 res
= CLIParamHexToBuf(arg_get_str(ctx
, 2), idm
, sizeof(idm
), &ilen
);
906 res
= CLIParamHexToBuf(arg_get_str(ctx
, 3), sn
, sizeof(sn
), &snlen
);
912 uint8_t scl
[2] = {0};
914 res
= CLIParamHexToBuf(arg_get_str(ctx
, 4), scl
, sizeof(scl
), &scllen
);
922 res
= CLIParamHexToBuf(arg_get_str(ctx
, 5), bn
, sizeof(bn
), &bnlen
);
928 uint8_t ble
[3] = {0};
930 res
= CLIParamHexToBuf(arg_get_str(ctx
, 6), ble
, sizeof(ble
), &blelen
);
936 bool verbose
= arg_get_lit(ctx
, 7);
940 print_number_of_service_constraints();
941 print_number_of_block_constraints();
942 print_service_code_list_constraints();
943 print_block_list_element_constraints();
944 print_status_flag1_interpretation();
945 print_status_flag2_interpration();
949 uint8_t data
[PM3_CMD_DATA_SIZE
];
950 memset(data
, 0, sizeof(data
));
951 data
[0] = 0x20; // Static length
952 data
[1] = 0x08; // Command ID
954 bool custom_IDm
= false;
957 memcpy(data
+ 2, idm
, sizeof(idm
));
963 // Number of Service (1)
964 // Service Code List(2)
965 // Number of Block(1)
969 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)
970 if (custom_IDm
== false && check_last_idm(data
, datalen
) == false) {
978 // Number of Service 1, Service Code List 2, Number of Block 1, Block List Element 2, Data 16
980 // Service Number 1 byte
984 // Service Code List 2 bytes
990 // Block number 1 byte
995 // Block List Element 2|3 bytes
997 memcpy(data
+ 14, ble
, blelen
);
1000 // data to be written, 16 bytes
1002 memcpy(data
+ 14 + blelen
, userdata
, sizeof(userdata
));
1005 uint8_t flags
= (FELICA_APPEND_CRC
| FELICA_RAW
);
1006 AddCrc(data
, datalen
);
1009 felica_status_response_t wr_noCry_resp
;
1010 if (send_wr_plain(flags
, datalen
, data
, 1, &wr_noCry_resp
) == PM3_SUCCESS
) {
1011 PrintAndLogEx(SUCCESS
, "IDm............ %s", sprint_hex(wr_noCry_resp
.frame_response
.IDm
, sizeof(wr_noCry_resp
.frame_response
.IDm
)));
1012 PrintAndLogEx(SUCCESS
, "Status Flag1... %s", sprint_hex(wr_noCry_resp
.status_flags
.status_flag1
, sizeof(wr_noCry_resp
.status_flags
.status_flag1
)));
1013 PrintAndLogEx(SUCCESS
, "Status Flag2... %s\n", sprint_hex(wr_noCry_resp
.status_flags
.status_flag2
, sizeof(wr_noCry_resp
.status_flags
.status_flag2
)));
1014 if (wr_noCry_resp
.status_flags
.status_flag1
[0] == 0x00 && wr_noCry_resp
.status_flags
.status_flag2
[0] == 0x00) {
1015 PrintAndLogEx(SUCCESS
, "Writing data successful!");
1017 PrintAndLogEx(FAILED
, "Something went wrong! Check status flags.");
1025 * Command parser for rdunencrypted.
1026 * @param Cmd input data of the user.
1027 * @return client result code.
1029 static int CmdHFFelicaReadPlain(const char *Cmd
) {
1030 CLIParserContext
*ctx
;
1031 CLIParserInit(&ctx
, "hf felica rdbl",
1032 "Use this command to read block data from authentication-not-required Service.\n\n"
1033 " - Mode shall be Mode0.\n"
1034 " - Successful == block data\n"
1035 " - Unsuccessful == Status Flag1 and Flag2",
1036 "hf felica rdbl --sn 01 --scl 8B00 --bn 01 --ble 8000\n"
1037 "hf felica rdbl --sn 01 --scl 4B18 --bn 01 --ble 8000 -b\n"
1038 "hf felica rdbl -i 01100910c11bc407 --sn 01 --scl 8B00 --bn 01 --ble 8000\n"
1040 void *argtable
[] = {
1042 arg_lit0("b", NULL
, "get all block list elements 00 -> FF"),
1043 arg_str0("i", NULL
, "<hex>", "set custom IDm"),
1044 arg_lit0("l", "long", "use 3 byte block list element block number"),
1045 arg_str0(NULL
, "sn", "<hex>", "number of service"),
1046 arg_str0(NULL
, "scl", "<hex>", "service code list"),
1047 arg_str0(NULL
, "bn", "<hex>", "number of block"),
1048 arg_str0(NULL
, "ble", "<hex>", "block list element (def 2|3 bytes)"),
1049 arg_lit0("v", "verbose", "verbose helptext"),
1052 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
1054 bool all_block_list_elements
= arg_get_lit(ctx
, 1);
1056 uint8_t idm
[8] = {0};
1058 int res
= CLIParamHexToBuf(arg_get_str(ctx
, 2), idm
, sizeof(idm
), &ilen
);
1064 uint8_t long_block_numbers
= arg_get_lit(ctx
, 3);
1066 uint8_t sn
[1] = {0};
1068 res
= CLIParamHexToBuf(arg_get_str(ctx
, 4), sn
, sizeof(sn
), &snlen
);
1074 uint8_t scl
[2] = {0};
1076 res
= CLIParamHexToBuf(arg_get_str(ctx
, 5), scl
, sizeof(scl
), &scllen
);
1082 uint8_t bn
[1] = {0};
1084 res
= CLIParamHexToBuf(arg_get_str(ctx
, 6), bn
, sizeof(bn
), &bnlen
);
1090 uint8_t ble
[3] = {0};
1092 res
= CLIParamHexToBuf(arg_get_str(ctx
, 7), ble
, sizeof(ble
), &blelen
);
1098 bool verbose
= arg_get_lit(ctx
, 8);
1101 print_number_of_service_constraints();
1102 print_number_of_block_constraints();
1103 print_service_code_list_constraints();
1104 print_block_list_element_constraints();
1105 print_status_flag1_interpretation();
1106 print_status_flag2_interpration();
1110 uint8_t data
[PM3_CMD_DATA_SIZE
];
1111 memset(data
, 0, sizeof(data
));
1112 data
[0] = 0x10; // Static length
1113 data
[1] = 0x06; // Command ID
1115 bool custom_IDm
= false;
1118 memcpy(data
+ 2, idm
, sizeof(idm
));
1121 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)
1122 if (custom_IDm
== false && check_last_idm(data
, datalen
) == false) {
1126 if (long_block_numbers
) {
1130 // Number of Service 1, Service Code List 2, Number of Block 1, Block List Element 2|3
1142 memcpy(data
+ 14, ble
, blelen
);
1144 uint8_t flags
= (FELICA_APPEND_CRC
| FELICA_RAW
);
1146 PrintAndLogEx(INFO
, "block | data ");
1147 PrintAndLogEx(INFO
, "------+----------------------------------------");
1149 // main loop block reads
1150 if (all_block_list_elements
) {
1152 uint16_t last_blockno
= 0xFF;
1153 if (long_block_numbers
) {
1154 last_blockno
= 0xFFFF;
1157 for (uint16_t i
= 0x00; i
< last_blockno
; i
++) {
1159 AddCrc(data
, datalen
);
1161 felica_read_without_encryption_response_t rd_noCry_resp
;
1162 if ((send_rd_plain(flags
, datalen
, data
, 0, &rd_noCry_resp
) == PM3_SUCCESS
)) {
1163 if (rd_noCry_resp
.status_flags
.status_flag1
[0] == 0 && rd_noCry_resp
.status_flags
.status_flag2
[0] == 0) {
1164 print_rd_plain_response(&rd_noCry_resp
);
1172 AddCrc(data
, datalen
);
1174 felica_read_without_encryption_response_t rd_noCry_resp
;
1175 if (send_rd_plain(flags
, datalen
, data
, 1, &rd_noCry_resp
) == PM3_SUCCESS
) {
1176 print_rd_plain_response(&rd_noCry_resp
);
1183 * Command parser for rqresponse
1184 * @param Cmd input data of the user.
1185 * @return client result code.
1187 static int CmdHFFelicaRequestResponse(const char *Cmd
) {
1189 CLIParserContext
*ctx
;
1190 CLIParserInit(&ctx
, "hf felica rqresponse",
1191 "Use this command to verify the existence of a card and its Mode.\n"
1192 " - current mode of the card is returned",
1193 "hf felica rqresponse -i 11100910C11BC407\n"
1195 void *argtable
[] = {
1197 arg_str0("i", NULL
, "<hex>", "set custom IDm"),
1200 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
1202 uint8_t idm
[8] = {0};
1204 int res
= CLIParamHexToBuf(arg_get_str(ctx
, 1), idm
, sizeof(idm
), &ilen
);
1212 uint8_t data
[PM3_CMD_DATA_SIZE
];
1213 memset(data
, 0, sizeof(data
));
1214 data
[0] = 0x0A; // Static length
1215 data
[1] = 0x04; // Command ID
1217 bool custom_IDm
= false;
1220 memcpy(data
+ 2, idm
, sizeof(idm
));
1223 uint8_t datalen
= 10; // Length (1), Command ID (1), IDm (8)
1224 if (!custom_IDm
&& !check_last_idm(data
, datalen
)) {
1228 AddCrc(data
, datalen
);
1231 uint8_t flags
= (FELICA_APPEND_CRC
| FELICA_RAW
);
1232 clear_and_send_command(flags
, datalen
, data
, 0);
1234 PacketResponseNG resp
;
1235 if (waitCmdFelica(0, &resp
, 1) == false) {
1236 PrintAndLogEx(ERR
, "Got no response from card");
1237 return PM3_ERFTRANS
;
1240 felica_request_request_response_t rq_response
;
1241 memcpy(&rq_response
, (felica_request_request_response_t
*)resp
.data
.asBytes
, sizeof(felica_request_request_response_t
));
1242 if (rq_response
.frame_response
.IDm
[0] != 0) {
1243 PrintAndLogEx(SUCCESS
, "Request Response");
1244 PrintAndLogEx(SUCCESS
, "IDm...... %s", sprint_hex(rq_response
.frame_response
.IDm
, sizeof(rq_response
.frame_response
.IDm
)));
1245 PrintAndLogEx(SUCCESS
, " Mode... %s", sprint_hex(rq_response
.mode
, sizeof(rq_response
.mode
)));
1252 * Command parser for rqspecver
1253 * @param Cmd input data of the user.
1254 * @return client result code.
1256 static int CmdHFFelicaRequestSpecificationVersion(const char *Cmd
) {
1258 CLIParserContext
*ctx
;
1259 CLIParserInit(&ctx
, "hf felica rqspecver",
1260 "Use this command to acquire the version of card OS.\n"
1262 " - Format version: Fixed value 00h. Provided only if Status Flag1 = 00h\n"
1263 " - Basic version: Each value of version is expressed in BCD notation. Provided only if Status Flag1 = 00h\n"
1264 " - Number of Option: value = 0: AES card, value = 1: AES/DES card. Provided only if Status Flag1 = 00h\n"
1265 " - Option version list: Provided only if Status Flag1 = 00h\n"
1266 " - AES card: not added\n"
1267 " - AES/DES card: DES option version is added - BCD notation",
1269 "hf felica rqspecver\n"
1270 "hf felica rqspecver -r 0001\n"
1271 "hf felica rqspecver -i 11100910C11BC407 \n"
1273 void *argtable
[] = {
1275 arg_str0("i", NULL
, "<hex>", "set custom IDm"),
1276 arg_str0("r", NULL
, "<hex>", "set custom reserve"),
1277 arg_lit0("v", "verbose", "verbose helptext"),
1280 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
1282 uint8_t idm
[8] = {0};
1284 int res
= CLIParamHexToBuf(arg_get_str(ctx
, 1), idm
, sizeof(idm
), &ilen
);
1290 uint8_t reserved
[2] = {0, 0};
1292 res
= CLIParamHexToBuf(arg_get_str(ctx
, 2), reserved
, sizeof(reserved
), &rlen
);
1298 bool verbose
= arg_get_lit(ctx
, 3);
1300 print_status_flag1_interpretation();
1301 print_status_flag2_interpration();
1305 uint8_t data
[PM3_CMD_DATA_SIZE
];
1306 memset(data
, 0, sizeof(data
));
1307 data
[0] = 0x0C; // Static length
1308 data
[1] = 0x3C; // Command ID
1310 bool custom_IDm
= false;
1315 memcpy(data
+ 2, idm
, sizeof(idm
));
1318 // add custom reserved
1320 memcpy(data
+ 10, reserved
, sizeof(reserved
));
1322 data
[10] = 0x00; // Reserved Value
1323 data
[11] = 0x00; // Reserved Value
1326 uint16_t datalen
= 12; // Length (1), Command ID (1), IDm (8), Reserved (2)
1327 if (custom_IDm
== false && check_last_idm(data
, datalen
) == false) {
1331 AddCrc(data
, datalen
);
1333 uint8_t flags
= (FELICA_APPEND_CRC
| FELICA_RAW
);
1335 clear_and_send_command(flags
, datalen
, data
, 0);
1337 PacketResponseNG resp
;
1338 if (waitCmdFelica(0, &resp
, 1) == false) {
1339 PrintAndLogEx(FAILED
, "Got no response from card");
1340 return PM3_ERFTRANS
;
1343 felica_request_spec_response_t spec_response
;
1344 memcpy(&spec_response
, (felica_request_spec_response_t
*)resp
.data
.asBytes
, sizeof(felica_request_spec_response_t
));
1346 if (spec_response
.frame_response
.IDm
[0] != 0) {
1347 PrintAndLogEx(SUCCESS
, "Got Request Response");
1348 PrintAndLogEx(SUCCESS
, "IDm............ %s", sprint_hex(spec_response
.frame_response
.IDm
, sizeof(spec_response
.frame_response
.IDm
)));
1349 PrintAndLogEx(SUCCESS
, "Status Flag1... %s", sprint_hex(spec_response
.status_flags
.status_flag1
, sizeof(spec_response
.status_flags
.status_flag1
)));
1350 PrintAndLogEx(SUCCESS
, "Status Flag2... %s", sprint_hex(spec_response
.status_flags
.status_flag2
, sizeof(spec_response
.status_flags
.status_flag2
)));
1352 if (spec_response
.status_flags
.status_flag1
[0] == 0) {
1353 PrintAndLogEx(SUCCESS
, "Format Version..... %s", sprint_hex(spec_response
.format_version
, sizeof(spec_response
.format_version
)));
1354 PrintAndLogEx(SUCCESS
, "Basic Version...... %s", sprint_hex(spec_response
.basic_version
, sizeof(spec_response
.basic_version
)));
1355 PrintAndLogEx(SUCCESS
, "Number of Option... %s", sprint_hex(spec_response
.number_of_option
, sizeof(spec_response
.number_of_option
)));
1356 if (spec_response
.number_of_option
[0] == 1) {
1357 PrintAndLogEx(SUCCESS
, "Option Version List...");
1358 for (int i
= 0; i
< spec_response
.number_of_option
[0]; i
++) {
1359 PrintAndLogEx(SUCCESS
, " - %s", sprint_hex(spec_response
.option_version_list
+ i
* 2, 2));
1368 * Command parser for resetmode
1369 * @param Cmd input data of the user.
1370 * @return client result code.
1372 static int CmdHFFelicaResetMode(const char *Cmd
) {
1373 CLIParserContext
*ctx
;
1374 CLIParserInit(&ctx
, "hf felica resetmode",
1375 "Use this command to reset Mode to Mode 0.",
1376 "hf felica resetmode\n"
1377 "hf felica resetmode -r 0001\n"
1378 "hf felica resetmode -i 11100910C11BC407 \n"
1380 void *argtable
[] = {
1382 arg_str0("i", NULL
, "<hex>", "set custom IDm"),
1383 arg_str0("r", NULL
, "<hex>", "set custom reserve"),
1384 arg_lit0("v", "verbose", "verbose helptext"),
1387 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
1389 uint8_t idm
[8] = {0};
1391 int res
= CLIParamHexToBuf(arg_get_str(ctx
, 1), idm
, sizeof(idm
), &ilen
);
1397 uint8_t reserved
[2] = {0, 0};
1399 res
= CLIParamHexToBuf(arg_get_str(ctx
, 2), reserved
, sizeof(reserved
), &rlen
);
1405 bool verbose
= arg_get_lit(ctx
, 3);
1407 print_status_flag1_interpretation();
1408 print_status_flag2_interpration();
1412 uint8_t data
[PM3_CMD_DATA_SIZE
];
1413 memset(data
, 0, sizeof(data
));
1414 data
[0] = 0x0C; // Static length
1415 data
[1] = 0x3E; // Command ID
1417 bool custom_IDm
= false;
1421 memcpy(data
+ 2, idm
, 8);
1424 memcpy(data
+ 10, reserved
, 2);
1426 data
[10] = 0x00; // Reserved Value
1427 data
[11] = 0x00; // Reserved Value
1430 uint16_t datalen
= 12; // Length (1), Command ID (1), IDm (8), Reserved (2)
1431 if (custom_IDm
== false && check_last_idm(data
, datalen
) == false) {
1435 AddCrc(data
, datalen
);
1437 uint8_t flags
= (FELICA_APPEND_CRC
| FELICA_RAW
);
1439 clear_and_send_command(flags
, datalen
, data
, 0);
1441 PacketResponseNG resp
;
1442 if (waitCmdFelica(0, &resp
, 1) == false) {
1443 PrintAndLogEx(ERR
, "Got no response from card");
1444 return PM3_ERFTRANS
;
1447 felica_status_response_t reset_mode_response
;
1448 memcpy(&reset_mode_response
, (felica_status_response_t
*)resp
.data
.asBytes
, sizeof(felica_status_response_t
));
1449 if (reset_mode_response
.frame_response
.IDm
[0] != 0) {
1450 PrintAndLogEx(SUCCESS
, "Request Response");
1451 PrintAndLogEx(SUCCESS
, "IDm............ %s", sprint_hex(reset_mode_response
.frame_response
.IDm
, sizeof(reset_mode_response
.frame_response
.IDm
)));
1452 PrintAndLogEx(SUCCESS
, "Status Flag1... %s", sprint_hex(reset_mode_response
.status_flags
.status_flag1
, sizeof(reset_mode_response
.status_flags
.status_flag1
)));
1453 PrintAndLogEx(SUCCESS
, "Status Flag2... %s", sprint_hex(reset_mode_response
.status_flags
.status_flag2
, sizeof(reset_mode_response
.status_flags
.status_flag2
)));
1459 * Command parser for rqsyscode
1460 * @param Cmd input data of the user.
1461 * @return client result code.
1463 static int CmdHFFelicaRequestSystemCode(const char *Cmd
) {
1465 CLIParserContext
*ctx
;
1466 CLIParserInit(&ctx
, "hf felica rqsyscode",
1467 "Use this command to acquire System Code registered to the card."
1468 " - if a card is divided into more than one System, \n"
1469 " this command acquires System Code of each System existing in the card.",
1470 "hf felica rqsyscode\n"
1471 "hf felica rqsyscode -i 11100910C11BC407 \n"
1473 void *argtable
[] = {
1475 arg_str0("i", NULL
, "<hex>", "set custom IDm"),
1478 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
1480 uint8_t idm
[8] = {0};
1482 int res
= CLIParamHexToBuf(arg_get_str(ctx
, 1), idm
, sizeof(idm
), &ilen
);
1490 uint8_t data
[PM3_CMD_DATA_SIZE
];
1491 memset(data
, 0, sizeof(data
));
1492 data
[0] = 0x0A; // Static length
1493 data
[1] = 0x0C; // Command ID
1495 bool custom_IDm
= false;
1498 memcpy(data
+ 2, idm
, sizeof(idm
));
1501 uint16_t datalen
= 10; // Length (1), Command ID (1), IDm (8)
1502 if (custom_IDm
== false && check_last_idm(data
, datalen
) == false) {
1506 AddCrc(data
, datalen
);
1508 uint8_t flags
= (FELICA_APPEND_CRC
| FELICA_RAW
);
1510 clear_and_send_command(flags
, datalen
, data
, 0);
1512 PacketResponseNG resp
;
1513 if (waitCmdFelica(0, &resp
, true) == false) {
1514 PrintAndLogEx(ERR
, "Got no response from card");
1515 return PM3_ERFTRANS
;
1518 felica_syscode_response_t rq_syscode_response
;
1519 memcpy(&rq_syscode_response
, (felica_syscode_response_t
*)resp
.data
.asBytes
, sizeof(felica_syscode_response_t
));
1521 if (rq_syscode_response
.frame_response
.IDm
[0] != 0) {
1522 PrintAndLogEx(SUCCESS
, "Request Response");
1523 PrintAndLogEx(SUCCESS
, "IDm... %s", sprint_hex(rq_syscode_response
.frame_response
.IDm
, sizeof(rq_syscode_response
.frame_response
.IDm
)));
1524 PrintAndLogEx(SUCCESS
, " - Number of Systems: %s", sprint_hex(rq_syscode_response
.number_of_systems
, sizeof(rq_syscode_response
.number_of_systems
)));
1525 PrintAndLogEx(SUCCESS
, " - System Codes: enumerated in ascending order starting from System 0.");
1527 for (int i
= 0; i
< rq_syscode_response
.number_of_systems
[0]; i
++) {
1528 PrintAndLogEx(SUCCESS
, " - %s", sprint_hex(rq_syscode_response
.system_code_list
+ i
* 2, 2));
1536 * Command parser for rqservice.
1537 * @param Cmd input data of the user.
1538 * @return client result code.
1540 static int CmdHFFelicaRequestService(const char *Cmd
) {
1541 CLIParserContext
*ctx
;
1542 CLIParserInit(&ctx
, "hf felica rqservice",
1543 "Use this command to verify the existence of Area and Service, and to acquire Key Version:\n"
1544 " - When the specified Area or Service exists, the card returns Key Version.\n"
1545 " - When the specified Area or Service does not exist, the card returns FFFFh as Key Version.\n"
1546 "For Node Code List of a command packet, Area Code or Service Code of the target\n"
1547 "of acquisition of Key Version shall be enumerated in Little Endian format.\n"
1548 "If Key Version of System is the target of acquisition, FFFFh shall be specified\n"
1549 "in the command packet.",
1550 "hf felcia rqservice --node 01 --code FFFF\n"
1551 "hf felcia rqservice -a --code FFFF\n"
1552 "hf felica rqservice -i 011204126417E405 --node 01 --code FFFF"
1555 void *argtable
[] = {
1557 arg_lit0("a", "all", "auto node number mode, iterates through all nodes 1 < n < 32"),
1558 arg_str0("n", "node", "<hex>", "Number of Node"),
1559 arg_str0("c", "code", "<hex>", "Node Code List (little endian)"),
1560 arg_str0("i", "idm", "<hex>", "use custom IDm"),
1563 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
1564 bool all_nodes
= arg_get_lit(ctx
, 1);
1566 uint8_t node
[1] = {0};
1568 int res
= CLIParamHexToBuf(arg_get_str(ctx
, 2), node
, sizeof(node
), &nlen
);
1574 uint8_t code
[2] = {0, 0};
1576 res
= CLIParamHexToBuf(arg_get_str(ctx
, 3), code
, sizeof(code
), &clen
);
1582 uint8_t idm
[8] = {0};
1584 res
= CLIParamHexToBuf(arg_get_str(ctx
, 4), idm
, sizeof(idm
), &ilen
);
1591 uint8_t data
[PM3_CMD_DATA_SIZE
];
1592 memset(data
, 0, sizeof(data
));
1594 bool custom_IDm
= false;
1598 memcpy(data
+ 2, idm
, 8);
1601 if (all_nodes
== false) {
1604 memcpy(data
+ 10, node
, sizeof(node
));
1609 memcpy(data
+ 11, code
, sizeof(code
));
1613 uint8_t datalen
= 13; // length (1) + CMD (1) + IDm(8) + Node Number (1) + Node Code List (2)
1615 uint8_t flags
= FELICA_APPEND_CRC
;
1617 flags
|= FELICA_NO_SELECT
;
1621 flags
|= FELICA_RAW
;
1623 // Todo activate once datalen isn't hardcoded anymore...
1624 if (custom_IDm
== false && check_last_idm(data
, datalen
) == false) {
1628 data
[0] = (datalen
& 0xFF);
1629 data
[1] = 0x02; // Service Request Command ID
1633 for (uint8_t i
= 1; i
< 32; i
++) {
1635 AddCrc(data
, datalen
);
1636 send_request_service(flags
, datalen
+ 2, data
, 1);
1640 AddCrc(data
, datalen
);
1641 send_request_service(flags
, datalen
+ 2, data
, 1);
1647 static int CmdHFFelicaNotImplementedYet(const char *Cmd
) {
1648 CLIParserContext
*ctx
;
1649 CLIParserInit(&ctx
, "hf felica scsvcode",
1650 "Feature not implemented yet. Feel free to contribute!",
1651 "hf felica scsvcode"
1653 void *argtable
[] = {
1657 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
1662 static int CmdHFFelicaSniff(const char *Cmd
) {
1663 CLIParserContext
*ctx
;
1664 CLIParserInit(&ctx
, "hf felica sniff",
1665 "Collect data from the field and save into command buffer.\n"
1666 "Buffer accessible from `hf felica list`",
1668 "hf felica sniff -s 10 -t 19"
1670 void *argtable
[] = {
1672 arg_u64_0("s", "samples", "<dec>", "samples to skip"),
1673 arg_u64_0("t", "trig", "<dec>", "triggers to skip "),
1676 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
1683 payload
.samples
= arg_get_u32_def(ctx
, 1, 10);
1684 payload
.triggers
= arg_get_u32_def(ctx
, 2, 5000);
1687 if (payload
.samples
> 9999) {
1688 payload
.samples
= 9999;
1689 PrintAndLogEx(INFO
, "Too large samples to skip value, using max value 9999");
1693 if (payload
.triggers
> 9999) {
1694 payload
.triggers
= 9999;
1695 PrintAndLogEx(INFO
, "Too large trigger to skip value, using max value 9999");
1700 PrintAndLogEx(INFO
, "Sniff Felica, getting first %" PRIu32
" frames, skipping after %" PRIu32
" triggers", payload
.samples
, payload
.triggers
);
1701 PrintAndLogEx(INFO
, "Press " _GREEN_("<Enter>") " or pm3-button to abort sniffing");
1702 clearCommandBuffer();
1703 SendCommandNG(CMD_HF_FELICA_SNIFF
, (uint8_t *)&payload
, sizeof(payload
));
1704 PacketResponseNG resp
;
1707 if (kbd_enter_pressed()) {
1708 SendCommandNG(CMD_BREAK_LOOP
, NULL
, 0);
1709 PrintAndLogEx(DEBUG
, "User aborted");
1714 if (WaitForResponseTimeout(CMD_HF_FELICA_SNIFF
, &resp
, 1000)) {
1715 if (resp
.status
== PM3_EOPABORTED
) {
1716 PrintAndLogEx(DEBUG
, "Button pressed, user aborted");
1722 PrintAndLogEx(HINT
, "try `" _YELLOW_("hf felica list") "` to view");
1723 PrintAndLogEx(INFO
, "Done");
1728 static int CmdHFFelicaSimLite(const char *Cmd
) {
1729 CLIParserContext
*ctx
;
1730 CLIParserInit(&ctx
, "hf felica litesim",
1731 "Emulating ISO/18092 FeliCa Lite tag",
1732 "hf felica litesim -u 1122334455667788"
1734 void *argtable
[] = {
1736 arg_str1("u", "uid", "<hex>", "UID/NDEF2 8 hex bytes"),
1739 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
1744 CLIGetHexWithReturn(ctx
, 1, payload
.uid
, &uid_len
);
1747 PrintAndLogEx(NORMAL
, "");
1748 PrintAndLogEx(INFO
, "Press " _GREEN_("<Enter>") " or pm3-button to abort simulation");
1750 clearCommandBuffer();
1751 SendCommandNG(CMD_HF_FELICALITE_SIMULATE
, payload
.uid
, sizeof(payload
));
1752 PacketResponseNG resp
;
1755 if (kbd_enter_pressed()) {
1756 SendCommandNG(CMD_BREAK_LOOP
, NULL
, 0);
1757 PrintAndLogEx(DEBUG
, "User aborted");
1762 if (WaitForResponseTimeout(CMD_HF_FELICALITE_SIMULATE
, &resp
, 1000)) {
1763 if (resp
.status
== PM3_EOPABORTED
) {
1764 PrintAndLogEx(DEBUG
, "Button pressed, user aborted");
1770 PrintAndLogEx(INFO
, "Done");
1774 static void printSep(void) {
1775 PrintAndLogEx(INFO
, "------------------------------------------------------------------------------------");
1778 static uint16_t PrintFliteBlock(uint16_t tracepos
, uint8_t *trace
, uint16_t tracelen
) {
1779 if (tracepos
+ 19 >= tracelen
)
1783 uint8_t blocknum
= trace
[0];
1784 uint8_t status1
= trace
[1];
1785 uint8_t status2
= trace
[2];
1787 char line
[110] = {0};
1788 for (int j
= 0; j
< 16; j
++) {
1789 snprintf(line
+ (j
* 4), sizeof(line
) - 1 - (j
* 4), "%02x ", trace
[j
+ 3]);
1792 PrintAndLogEx(NORMAL
, "block number %02x, status: %02x %02x", blocknum
, status1
, status2
);
1795 PrintAndLogEx(NORMAL
, "S_PAD0: %s", line
);
1798 PrintAndLogEx(NORMAL
, "S_PAD1: %s", line
);
1801 PrintAndLogEx(NORMAL
, "S_PAD2: %s", line
);
1804 PrintAndLogEx(NORMAL
, "S_PAD3: %s", line
);
1807 PrintAndLogEx(NORMAL
, "S_PAD4: %s", line
);
1810 PrintAndLogEx(NORMAL
, "S_PAD5: %s", line
);
1813 PrintAndLogEx(NORMAL
, "S_PAD6: %s", line
);
1816 PrintAndLogEx(NORMAL
, "S_PAD7: %s", line
);
1819 PrintAndLogEx(NORMAL
, "S_PAD8: %s", line
);
1822 PrintAndLogEx(NORMAL
, "S_PAD9: %s", line
);
1825 PrintAndLogEx(NORMAL
, "S_PAD10: %s", line
);
1828 PrintAndLogEx(NORMAL
, "S_PAD11: %s", line
);
1831 PrintAndLogEx(NORMAL
, "S_PAD12: %s", line
);
1834 PrintAndLogEx(NORMAL
, "S_PAD13: %s", line
);
1837 uint32_t regA
= trace
[3] | trace
[4] << 8 | trace
[5] << 16 | trace
[ 6] << 24;
1838 uint32_t regB
= trace
[7] | trace
[8] << 8 | trace
[9] << 16 | trace
[10] << 24;
1840 for (int j
= 0; j
< 8; j
++)
1841 snprintf(line
+ (j
* 2), sizeof(line
) - 1 - (j
* 2), "%02x", trace
[j
+ 11]);
1843 PrintAndLogEx(NORMAL
, "REG: regA: %d regB: %d regC: %s ", regA
, regB
, line
);
1847 PrintAndLogEx(NORMAL
, "Random Challenge, WO: %s ", line
);
1850 PrintAndLogEx(NORMAL
, "MAC, only set on dual read: %s ", line
);
1855 for (int j
= 0; j
< 8; j
++)
1856 snprintf(idd
+ (j
* 2), sizeof(idd
) - 1 - (j
* 2), "%02x", trace
[j
+ 3]);
1858 for (int j
= 0; j
< 6; j
++)
1859 snprintf(idm
+ (j
* 2), sizeof(idm
) - 1 - (j
* 2), "%02x", trace
[j
+ 13]);
1861 PrintAndLogEx(NORMAL
, "ID Block, IDd: 0x%s DFC: 0x%02x%02x Arb: %s ", idd
, trace
[11], trace
[12], idm
);
1867 for (int j
= 0; j
< 8; j
++)
1868 snprintf(idm
+ (j
* 2), sizeof(idm
) - 1 - (j
* 2), "%02x", trace
[j
+ 3]);
1870 for (int j
= 0; j
< 8; j
++)
1871 snprintf(pmm
+ (j
* 2), sizeof(pmm
) - 1 - (j
* 2), "%02x", trace
[j
+ 11]);
1873 PrintAndLogEx(NORMAL
, "DeviceId: IDm: 0x%s PMm: 0x%s ", idm
, pmm
);
1877 PrintAndLogEx(NORMAL
, "SER_C: 0x%02x%02x ", trace
[3], trace
[4]);
1880 PrintAndLogEx(NORMAL
, "SYS_Cl 0x%02x%02x ", trace
[3], trace
[4]);
1883 PrintAndLogEx(NORMAL
, "CKV (key version): 0x%02x%02x ", trace
[3], trace
[4]);
1886 PrintAndLogEx(NORMAL
, "CK (card key), WO: %s ", line
);
1889 PrintAndLogEx(NORMAL
, "Memory Configuration (MC):");
1890 PrintAndLogEx(NORMAL
, "MAC needed to write state: %s", trace
[3 + 12] ? "on" : "off");
1891 //order might be off here...
1892 PrintAndLogEx(NORMAL
, "Write with MAC for S_PAD : %s ", sprint_bin(trace
+ 3 + 10, 2));
1893 PrintAndLogEx(NORMAL
, "Write with AUTH for S_PAD : %s ", sprint_bin(trace
+ 3 + 8, 2));
1894 PrintAndLogEx(NORMAL
, "Read after AUTH for S_PAD : %s ", sprint_bin(trace
+ 3 + 6, 2));
1895 PrintAndLogEx(NORMAL
, "MAC needed to write CK and CKV: %s", trace
[3 + 5] ? "on" : "off");
1896 PrintAndLogEx(NORMAL
, "RF parameter: %02x", (trace
[3 + 4] & 0x7));
1897 PrintAndLogEx(NORMAL
, "Compatible with NDEF: %s", trace
[3 + 3] ? "yes" : "no");
1898 PrintAndLogEx(NORMAL
, "Memory config writable : %s", (trace
[3 + 2] == 0xff) ? "yes" : "no");
1899 PrintAndLogEx(NORMAL
, "RW access for S_PAD : %s ", sprint_bin(trace
+ 3, 2));
1903 PrintAndLogEx(NORMAL
, "Write count, RO: %02x %02x %02x ", trace
[3], trace
[4], trace
[5]);
1907 PrintAndLogEx(NORMAL
, "MAC_A, RW (auth): %s ", line
);
1911 PrintAndLogEx(NORMAL
, "State:");
1912 PrintAndLogEx(NORMAL
, "Polling disabled: %s", trace
[3 + 8] ? "yes" : "no");
1913 PrintAndLogEx(NORMAL
, "Authenticated: %s", trace
[3] ? "yes" : "no");
1916 PrintAndLogEx(NORMAL
, "CRC of all blocks match : %s", (trace
[3 + 2] == 0xff) ? "no" : "yes");
1919 PrintAndLogEx(WARNING
, "INVALID %d: %s", blocknum
, line
);
1922 return tracepos
+ 19;
1925 static int CmdHFFelicaDumpLite(const char *Cmd
) {
1929 Why does this command say it dumps a FeliCa lite card
1930 and then tries to print a trace?!?
1931 Is this a trace list or a FeliCa dump cmd?
1935 CLIParserContext
*ctx
;
1936 CLIParserInit(&ctx
, "hf felica litedump",
1937 "Dump ISO/18092 FeliCa Lite tag. It will timeout after 200sec",
1938 "hf felica litedump"
1940 void *argtable
[] = {
1944 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
1947 PrintAndLogEx(SUCCESS
, "FeliCa lite - dump started");
1949 clearCommandBuffer();
1950 SendCommandNG(CMD_HF_FELICALITE_DUMP
, NULL
, 0);
1951 PacketResponseNG resp
;
1953 PrintAndLogEx(INFO
, "Press " _GREEN_("<Enter>") " or pm3-button to abort dumping");
1955 uint8_t timeout
= 0;
1956 while (WaitForResponseTimeout(CMD_ACK
, &resp
, 2000) == false) {
1958 if (kbd_enter_pressed()) {
1959 SendCommandNG(CMD_BREAK_LOOP
, NULL
, 0);
1960 PrintAndLogEx(DEBUG
, "User aborted");
1961 return PM3_EOPABORTED
;
1965 PrintAndLogEx(INPLACE
, "% 3i", timeout
);
1968 if (kbd_enter_pressed()) {
1969 PrintAndLogEx(WARNING
, "\naborted via keyboard!\n");
1971 return PM3_EOPABORTED
;
1974 PrintAndLogEx(WARNING
, "\ntimeout while waiting for reply.");
1976 return PM3_ETIMEOUT
;
1980 PrintAndLogEx(NORMAL
, "");
1982 if (resp
.oldarg
[0] == 0) {
1983 PrintAndLogEx(WARNING
, "Button pressed, aborted");
1984 return PM3_EOPABORTED
;
1987 uint32_t tracelen
= resp
.oldarg
[1];
1988 if (tracelen
== 0) {
1989 PrintAndLogEx(WARNING
, "No trace data! Maybe not a FeliCa Lite card?");
1993 uint8_t *trace
= calloc(tracelen
, sizeof(uint8_t));
1994 if (trace
== NULL
) {
1995 PrintAndLogEx(WARNING
, "failed to allocate memory ");
1999 if (!GetFromDevice(BIG_BUF
, trace
, tracelen
, 0, NULL
, 0, NULL
, 2500, false)) {
2000 PrintAndLogEx(WARNING
, "command execution time out");
2002 return PM3_ETIMEOUT
;
2006 PrintAndLogEx(SUCCESS
, "Recorded Activity (trace len = %"PRIu32
" bytes)", tracelen
);
2007 print_hex_break(trace
, tracelen
, 32);
2010 uint16_t tracepos
= 0;
2011 while (tracepos
< tracelen
)
2012 tracepos
= PrintFliteBlock(tracepos
, trace
, tracelen
);
2020 static int CmdHFFelicaCmdRaw(const char *Cmd
) {
2022 CLIParserContext
*ctx
;
2023 CLIParserInit(&ctx
, "hf felica raw ",
2024 "Send raw hex data to tag",
2025 "hf felica raw -cs 20\n"
2026 "hf felica raw -cs 2008"
2029 void *argtable
[] = {
2031 arg_lit0("a", NULL
, "active signal field ON without select"),
2032 arg_lit0("c", NULL
, "calculate and append CRC"),
2033 arg_lit0("k", NULL
, "keep signal field ON after receive"),
2034 arg_u64_0("n", NULL
, "<dec>", "number of bits"),
2035 arg_lit0("r", NULL
, "do not read response"),
2036 arg_lit0("s", NULL
, "active signal field ON with select"),
2037 arg_strx1(NULL
, NULL
, "<hex>", "raw bytes to send"),
2040 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
2042 bool active
= arg_get_lit(ctx
, 1);
2043 bool crc
= arg_get_lit(ctx
, 2);
2044 bool keep_field_on
= arg_get_lit(ctx
, 3);
2045 uint16_t numbits
= arg_get_u32_def(ctx
, 4, 0) & 0xFFFF;
2046 bool reply
= (arg_get_lit(ctx
, 5) == false);
2047 bool active_select
= arg_get_lit(ctx
, 6);
2050 uint8_t data
[PM3_CMD_DATA_SIZE
];
2051 memset(data
, 0, sizeof(data
));
2053 CLIGetHexWithReturn(ctx
, 7, data
, &datalen
);
2057 AddCrc(data
, datalen
);
2062 if (active
|| active_select
) {
2063 flags
|= FELICA_CONNECT
;
2065 flags
|= FELICA_NO_SELECT
;
2068 if (keep_field_on
) {
2069 flags
|= FELICA_NO_DISCONNECT
;
2073 flags
|= FELICA_RAW
;
2076 // Max buffer is PM3_CMD_DATA_SIZE
2077 datalen
= (datalen
> PM3_CMD_DATA_SIZE
) ? PM3_CMD_DATA_SIZE
: datalen
;
2079 clearCommandBuffer();
2080 PrintAndLogEx(SUCCESS
, "Data: %s", sprint_hex(data
, datalen
));
2082 SendCommandMIX(CMD_HF_FELICA_COMMAND
, flags
, (datalen
& 0xFFFF) | (uint32_t)(numbits
<< 16), 0, data
, datalen
);
2085 if (active_select
) {
2086 PrintAndLogEx(SUCCESS
, "Active select wait for FeliCa.");
2087 PacketResponseNG resp_IDm
;
2088 if (waitCmdFelica(1, &resp_IDm
, true) == false) {
2089 return PM3_ERFTRANS
;
2093 PacketResponseNG resp_frame
;
2094 if (waitCmdFelica(0, &resp_frame
, true) == false) {
2095 return PM3_ERFTRANS
;
2102 static command_t CommandTable
[] = {
2103 {"help", CmdHelp
, AlwaysAvailable
, "This help"},
2104 {"-----------", CmdHelp
, AlwaysAvailable
, "----------------------- " _CYAN_("General") " -----------------------"},
2105 {"list", CmdHFFelicaList
, AlwaysAvailable
, "List ISO 18092/FeliCa history"},
2106 {"reader", CmdHFFelicaReader
, IfPm3Felica
, "Act like an ISO18092/FeliCa reader"},
2107 {"info", CmdHFFelicaInfo
, IfPm3Felica
, "Tag information"},
2108 {"sniff", CmdHFFelicaSniff
, IfPm3Felica
, "Sniff ISO 18092/FeliCa traffic"},
2109 {"raw", CmdHFFelicaCmdRaw
, IfPm3Felica
, "Send raw hex data to tag"},
2110 {"rdbl", CmdHFFelicaReadPlain
, IfPm3Felica
, "read block data from authentication-not-required Service."},
2111 {"wrbl", CmdHFFelicaWritePlain
, IfPm3Felica
, "write block data to an authentication-not-required Service."},
2112 {"-----------", CmdHelp
, AlwaysAvailable
, "----------------------- " _CYAN_("FeliCa Standard") " -----------------------"},
2113 //{"dump", CmdHFFelicaDump, IfPm3Felica, "Wait for and try dumping FeliCa"},
2114 {"rqservice", CmdHFFelicaRequestService
, IfPm3Felica
, "verify the existence of Area and Service, and to acquire Key Version."},
2115 {"rqresponse", CmdHFFelicaRequestResponse
, IfPm3Felica
, "verify the existence of a card and its Mode."},
2116 {"scsvcode", CmdHFFelicaNotImplementedYet
, IfPm3Felica
, "acquire Area Code and Service Code."},
2117 {"rqsyscode", CmdHFFelicaRequestSystemCode
, IfPm3Felica
, "acquire System Code registered to the card."},
2118 {"auth1", CmdHFFelicaAuthentication1
, IfPm3Felica
, "authenticate a card. Start mutual authentication with Auth1"},
2119 {"auth2", CmdHFFelicaAuthentication2
, IfPm3Felica
, "allow a card to authenticate a Reader/Writer. Complete mutual authentication"},
2120 //{"read", CmdHFFelicaNotImplementedYet, IfPm3Felica, "read Block Data from authentication-required Service."},
2121 //{"write", CmdHFFelicaNotImplementedYet, IfPm3Felica, "write Block Data to an authentication-required Service."},
2122 //{"scsvcodev2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "verify the existence of Area or Service, and to acquire Key Version."},
2123 //{"getsysstatus", CmdHFFelicaNotImplementedYet, IfPm3Felica, "acquire the setup information in System."},
2124 {"rqspecver", CmdHFFelicaRequestSpecificationVersion
, IfPm3Felica
, "acquire the version of card OS."},
2125 {"resetmode", CmdHFFelicaResetMode
, IfPm3Felica
, "reset Mode to Mode 0."},
2126 //{"auth1v2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "authenticate a card."},
2127 //{"auth2v2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "allow a card to authenticate a Reader/Writer."},
2128 //{"readv2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "read Block Data from authentication-required Service."},
2129 //{"writev2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "write Block Data to authentication-required Service."},
2130 //{"uprandomid", CmdHFFelicaNotImplementedYet, IfPm3Felica, "update Random ID (IDr)."},
2131 {"-----------", CmdHelp
, AlwaysAvailable
, "----------------------- " _CYAN_("FeliCa Light") " -----------------------"},
2132 {"litesim", CmdHFFelicaSimLite
, IfPm3Felica
, "Emulating ISO/18092 FeliCa Lite tag"},
2133 {"litedump", CmdHFFelicaDumpLite
, IfPm3Felica
, "Wait for and try dumping FelicaLite"},
2134 // {"sim", CmdHFFelicaSim, IfPm3Felica, "<UID> -- Simulate ISO 18092/FeliCa tag"}
2135 {NULL
, NULL
, NULL
, NULL
}
2138 static int CmdHelp(const char *Cmd
) {
2139 (void)Cmd
; // Cmd is not used so far
2140 CmdsHelp(CommandTable
);
2144 int CmdHFFelica(const char *Cmd
) {
2145 clearCommandBuffer();
2146 return CmdsParse(CommandTable
, Cmd
);