fix little endian vs big endian in the macros... again... but this time correct
[RRG-proxmark3.git] / client / src / cmdhffelica.c
blob70999787a4347bb43e583d49e8eea48a08830626
1 //-----------------------------------------------------------------------------
2 // Copyright (C) 2017 October, Satsuoni
3 // 2017,2021 iceman
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
6 // the license.
7 //-----------------------------------------------------------------------------
8 // High frequency ISO18092 / FeliCa commands
9 //-----------------------------------------------------------------------------
10 #include "cmdhffelica.h"
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <ctype.h>
15 #include <inttypes.h>
16 #include "cmdparser.h" // command_t
17 #include "comms.h"
18 #include "cmdtrace.h"
19 #include "crc16.h"
20 #include "util.h"
21 #include "ui.h"
22 #include "iso18.h" // felica_card_select_t struct
23 #include "des.h"
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");
129 return PM3_SUCCESS;
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.");
150 return PM3_SUCCESS;
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.");
167 return PM3_SUCCESS;
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);
178 if (verbose) {
179 PrintAndLogEx(SUCCESS, "client received %i octets", len);
180 if (len == 0 || len == 1) {
181 PrintAndLogEx(ERR, "Could not receive data correctly!");
182 return false;
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!");
190 return false;
193 return true;
194 } else {
195 PrintAndLogEx(WARNING, "timeout while waiting for reply.");
197 return false;
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));
210 return true;
212 return false;
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;
223 do {
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;
231 if (loop) {
232 if (status != 0) {
233 continue;
235 } else {
236 // when not in continuous mode
237 if (status != 0) {
238 if (verbose) PrintAndLogEx(WARNING, "FeliCa card select failed");
239 res = PM3_EOPABORTED;
240 break;
244 felica_card_select_t card;
245 memcpy(&card, (felica_card_select_t *)resp.data.asBytes, sizeof(felica_card_select_t));
246 if (loop == false) {
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);
254 DropField();
255 return res;
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");
264 void *argtable[] = {
265 arg_param_begin,
266 arg_lit0("s", "silent", "silent (no messages)"),
267 arg_lit0("@", NULL, "optional - continuous reader mode"),
268 arg_param_end
270 CLIExecWithReturn(ctx, Cmd, argtable, true);
271 bool verbose = (arg_get_lit(ctx, 1) == false);
272 bool cm = arg_get_lit(ctx, 2);
273 CLIParserFree(ctx);
275 if (cm) {
276 PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
279 CLIParserFree(ctx);
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");
290 return PM3_ESOFT;
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];
297 switch (status) {
298 case 1: {
299 if (verbose)
300 PrintAndLogEx(WARNING, "card timeout");
301 return PM3_ETIMEOUT;
303 case 2: {
304 if (verbose)
305 PrintAndLogEx(WARNING, "card answered wrong");
306 return PM3_ESOFT;
308 case 3: {
309 if (verbose)
310 PrintAndLogEx(WARNING, "CRC check failed");
311 return PM3_ESOFT;
313 case 0: {
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);
326 break;
329 return PM3_SUCCESS;
332 static int CmdHFFelicaInfo(const char *Cmd) {
333 CLIParserContext *ctx;
334 CLIParserInit(&ctx, "hf felica info",
335 "Reader for FeliCa based tags",
336 "hf felica info");
338 void *argtable[] = {
339 arg_param_begin,
340 arg_param_end
342 CLIExecWithReturn(ctx, Cmd, argtable, true);
343 CLIParserFree(ctx);
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();
353 if (verbose) {
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));
370 char bl_data[256];
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);
378 } else {
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;
391 if (datalen > 0) {
392 if (!waitCmdFelica(0, &resp, 1)) {
393 PrintAndLogEx(ERR, "\nGot no response from card");
394 return PM3_ERFTRANS;
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)));
405 return PM3_SUCCESS;
407 return PM3_ERFTRANS;
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");
424 return PM3_ERFTRANS;
425 } else {
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];
428 return PM3_SUCCESS;
433 * Checks if last known card can be added to data and adds it if possible.
434 * @param custom_IDm
435 * @param data
436 * @return
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");
441 return false;
444 PrintAndLogEx(INFO, "Using last known IDm... " _GREEN_("%s"), sprint_hex_inrow(data, datalen));
445 return true;
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");
462 return PM3_ERFTRANS;
465 memcpy(wr_noCry_resp, (felica_status_response_t *)resp.data.asBytes, sizeof(felica_status_response_t));
466 return PM3_SUCCESS;
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"
496 void *argtable[] = {
497 arg_param_begin,
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"),
505 arg_param_end
507 CLIExecWithReturn(ctx, Cmd, argtable, true);
509 uint8_t an[1] = {0};
510 int anlen = 0;
511 int res = CLIParamHexToBuf(arg_get_str(ctx, 1), an, sizeof(an), &anlen);
512 if (res) {
513 CLIParserFree(ctx);
514 return PM3_EINVARG;
517 uint8_t acl[2] = {0};
518 int acllen = 0;
519 res = CLIParamHexToBuf(arg_get_str(ctx, 2), acl, sizeof(acl), &acllen);
520 if (res) {
521 CLIParserFree(ctx);
522 return PM3_EINVARG;
525 uint8_t idm[8] = {0};
526 int ilen = 0;
527 res = CLIParamHexToBuf(arg_get_str(ctx, 3), idm, sizeof(idm), &ilen);
528 if (res) {
529 CLIParserFree(ctx);
530 return PM3_EINVARG;
533 uint8_t sn[1] = {0};
534 int snlen = 0;
535 res = CLIParamHexToBuf(arg_get_str(ctx, 4), sn, sizeof(sn), &snlen);
536 if (res) {
537 CLIParserFree(ctx);
538 return PM3_EINVARG;
541 uint8_t scl[2] = {0};
542 int scllen = 0;
543 res = CLIParamHexToBuf(arg_get_str(ctx, 5), scl, sizeof(scl), &scllen);
544 if (res) {
545 CLIParserFree(ctx);
546 return PM3_EINVARG;
549 uint8_t key[24] = {0};
550 int keylen = 0;
551 res = CLIParamHexToBuf(arg_get_str(ctx, 6), key, sizeof(key), &keylen);
552 if (res) {
553 CLIParserFree(ctx);
554 return PM3_EINVARG;
557 bool verbose = arg_get_lit(ctx, 7);
558 CLIParserFree(ctx);
559 if (verbose) {
560 print_authentication1();
561 return PM3_SUCCESS;
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;
571 if (ilen) {
572 custom_IDm = true;
573 memcpy(data + 2, idm, 8);
576 // Length (1),
577 // Command ID (1),
578 // IDm (8),
579 // Number of Area (1),
580 // Area Code List (2),
581 // Number of Service (1),
582 // Service Code List (2),
583 // M1c (16)
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) {
589 return PM3_EINVARG;
592 if (anlen) {
593 data[10] = an[0];
595 if (acllen) {
596 data[11] = acl[0];
597 data[12] = acl[1];
599 if (snlen) {
600 data[13] = sn[0];
602 if (scllen) {
603 data[14] = scl[0];
604 data[15] = scl[1];
606 if (keylen) {
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);
619 if (keylen == 24) {
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));
629 } else {
630 PrintAndLogEx(ERR, "Invalid key length");
631 mbedtls_des3_free(&des3_ctx);
632 return PM3_EINVARG;
635 uint8_t output[8];
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);
645 datalen += 2;
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");
654 return PM3_ERFTRANS;
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;
678 break;
679 } else {
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");
687 } else {
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");
694 return PM3_SUCCESS;
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"
712 void *argtable[] = {
713 arg_param_begin,
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"),
718 arg_param_end
720 CLIExecWithReturn(ctx, Cmd, argtable, true);
722 uint8_t idm[8] = {0};
723 int ilen = 0;
724 int res = CLIParamHexToBuf(arg_get_str(ctx, 1), idm, sizeof(idm), &ilen);
725 if (res) {
726 CLIParserFree(ctx);
727 return PM3_EINVARG;
730 uint8_t cc[8] = {0};
731 int cclen = 0;
732 res = CLIParamHexToBuf(arg_get_str(ctx, 2), cc, sizeof(cc), &cclen);
733 if (res) {
734 CLIParserFree(ctx);
735 return PM3_EINVARG;
738 uint8_t key[16] = {0};
739 int keylen = 0;
740 res = CLIParamHexToBuf(arg_get_str(ctx, 3), key, sizeof(key), &keylen);
741 if (res) {
742 CLIParserFree(ctx);
743 return PM3_EINVARG;
746 bool verbose = arg_get_lit(ctx, 4);
747 CLIParserFree(ctx);
748 if (verbose) {
749 print_authentication2();
750 return PM3_SUCCESS;
753 uint8_t data[PM3_CMD_DATA_SIZE];
754 memset(data, 0, sizeof(data));
756 bool custom_IDm = false;
758 if (ilen) {
759 custom_IDm = true;
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) {
768 return PM3_EINVARG;
771 if (cclen) {
772 memcpy(data + 16, cc, cclen);
775 if (keylen) {
776 memcpy(data + 16, key, keylen);
780 if (custom_IDm == false && check_last_idm(data, datalen) == false) {
781 return PM3_EINVARG;
784 // M3c (8) == cc
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);
794 if (keylen == 16) {
796 // set encryption context
797 mbedtls_des3_set2key_enc(&des3_ctx_enc, key);
799 // Create M4c challenge response with 3DES
800 uint8_t rev_key[16];
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)));
809 } else {
810 PrintAndLogEx(ERR, "Invalid key length");
811 mbedtls_des3_free(&des3_ctx_enc);
812 mbedtls_des3_free(&des3_ctx_dec);
813 return PM3_EINVARG;
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)));
826 // free contexts
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);
834 datalen += 2;
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");
843 return PM3_ERFTRANS;
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)));
853 } else {
854 PrintAndLogEx(ERR, "Got wrong frame format");
856 return PM3_SUCCESS;
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"
875 void *argtable[] = {
876 arg_param_begin,
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"),
884 arg_param_end
886 CLIExecWithReturn(ctx, Cmd, argtable, true);
888 uint8_t userdata[16] = {0};
889 int udlen = 0;
890 int res = CLIParamHexToBuf(arg_get_str(ctx, 1), userdata, sizeof(userdata), &udlen);
891 if (res) {
892 CLIParserFree(ctx);
893 return PM3_EINVARG;
896 uint8_t idm[8] = {0};
897 int ilen = 0;
898 res = CLIParamHexToBuf(arg_get_str(ctx, 2), idm, sizeof(idm), &ilen);
899 if (res) {
900 CLIParserFree(ctx);
901 return PM3_EINVARG;
904 uint8_t sn[1] = {0};
905 int snlen = 0;
906 res = CLIParamHexToBuf(arg_get_str(ctx, 3), sn, sizeof(sn), &snlen);
907 if (res) {
908 CLIParserFree(ctx);
909 return PM3_EINVARG;
912 uint8_t scl[2] = {0};
913 int scllen = 0;
914 res = CLIParamHexToBuf(arg_get_str(ctx, 4), scl, sizeof(scl), &scllen);
915 if (res) {
916 CLIParserFree(ctx);
917 return PM3_EINVARG;
920 uint8_t bn[1] = {0};
921 int bnlen = 0;
922 res = CLIParamHexToBuf(arg_get_str(ctx, 5), bn, sizeof(bn), &bnlen);
923 if (res) {
924 CLIParserFree(ctx);
925 return PM3_EINVARG;
928 uint8_t ble[3] = {0};
929 int blelen = 0;
930 res = CLIParamHexToBuf(arg_get_str(ctx, 6), ble, sizeof(ble), &blelen);
931 if (res) {
932 CLIParserFree(ctx);
933 return PM3_EINVARG;
936 bool verbose = arg_get_lit(ctx, 7);
937 CLIParserFree(ctx);
939 if (verbose) {
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();
946 return PM3_SUCCESS;
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;
955 if (ilen) {
956 custom_IDm = true;
957 memcpy(data + 2, idm, sizeof(idm));
960 // Length (1)
961 // Command ID (1)
962 // IDm (8)
963 // Number of Service (1)
964 // Service Code List(2)
965 // Number of Block(1)
966 // Block List(3)
967 // Block Data(16)
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) {
971 return PM3_EINVARG;
974 if (blelen == 3) {
975 datalen++;
978 // Number of Service 1, Service Code List 2, Number of Block 1, Block List Element 2, Data 16
980 // Service Number 1 byte
981 if (snlen) {
982 data[10] = sn[0];
984 // Service Code List 2 bytes
985 if (scllen) {
986 data[11] = scl[0];
987 data[12] = scl[1];
990 // Block number 1 byte
991 if (bnlen) {
992 data[13] = bn[0];
995 // Block List Element 2|3 bytes
996 if (blelen) {
997 memcpy(data + 14, ble, blelen);
1000 // data to be written, 16 bytes
1001 if (udlen) {
1002 memcpy(data + 14 + blelen, userdata, sizeof(userdata));
1005 uint8_t flags = (FELICA_APPEND_CRC | FELICA_RAW);
1006 AddCrc(data, datalen);
1007 datalen += 2;
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!");
1016 } else {
1017 PrintAndLogEx(FAILED, "Something went wrong! Check status flags.");
1021 return PM3_SUCCESS;
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[] = {
1041 arg_param_begin,
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"),
1050 arg_param_end
1052 CLIExecWithReturn(ctx, Cmd, argtable, true);
1054 bool all_block_list_elements = arg_get_lit(ctx, 1);
1056 uint8_t idm[8] = {0};
1057 int ilen = 0;
1058 int res = CLIParamHexToBuf(arg_get_str(ctx, 2), idm, sizeof(idm), &ilen);
1059 if (res) {
1060 CLIParserFree(ctx);
1061 return PM3_EINVARG;
1064 uint8_t long_block_numbers = arg_get_lit(ctx, 3);
1066 uint8_t sn[1] = {0};
1067 int snlen = 0;
1068 res = CLIParamHexToBuf(arg_get_str(ctx, 4), sn, sizeof(sn), &snlen);
1069 if (res) {
1070 CLIParserFree(ctx);
1071 return PM3_EINVARG;
1074 uint8_t scl[2] = {0};
1075 int scllen = 0;
1076 res = CLIParamHexToBuf(arg_get_str(ctx, 5), scl, sizeof(scl), &scllen);
1077 if (res) {
1078 CLIParserFree(ctx);
1079 return PM3_EINVARG;
1082 uint8_t bn[1] = {0};
1083 int bnlen = 0;
1084 res = CLIParamHexToBuf(arg_get_str(ctx, 6), bn, sizeof(bn), &bnlen);
1085 if (res) {
1086 CLIParserFree(ctx);
1087 return PM3_EINVARG;
1090 uint8_t ble[3] = {0};
1091 int blelen = 0;
1092 res = CLIParamHexToBuf(arg_get_str(ctx, 7), ble, sizeof(ble), &blelen);
1093 if (res) {
1094 CLIParserFree(ctx);
1095 return PM3_EINVARG;
1098 bool verbose = arg_get_lit(ctx, 8);
1099 CLIParserFree(ctx);
1100 if (verbose) {
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();
1107 return PM3_SUCCESS;
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;
1116 if (ilen) {
1117 custom_IDm = true;
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) {
1123 return PM3_EINVARG;
1126 if (long_block_numbers) {
1127 datalen++;
1130 // Number of Service 1, Service Code List 2, Number of Block 1, Block List Element 2|3
1131 if (snlen) {
1132 data[10] = sn[0];
1134 if (scllen) {
1135 data[11] = scl[0];
1136 data[12] = scl[1];
1138 if (bnlen) {
1139 data[13] = bn[0];
1141 if (blelen)
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++) {
1158 data[15] = i;
1159 AddCrc(data, datalen);
1160 datalen += 2;
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);
1166 } else {
1167 break;
1169 datalen -= 2;
1171 } else {
1172 AddCrc(data, datalen);
1173 datalen += 2;
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);
1179 return PM3_SUCCESS;
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[] = {
1196 arg_param_begin,
1197 arg_str0("i", NULL, "<hex>", "set custom IDm"),
1198 arg_param_end
1200 CLIExecWithReturn(ctx, Cmd, argtable, true);
1202 uint8_t idm[8] = {0};
1203 int ilen = 0;
1204 int res = CLIParamHexToBuf(arg_get_str(ctx, 1), idm, sizeof(idm), &ilen);
1205 if (res) {
1206 CLIParserFree(ctx);
1207 return PM3_EINVARG;
1210 CLIParserFree(ctx);
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;
1218 if (ilen) {
1219 custom_IDm = true;
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)) {
1225 return PM3_EINVARG;
1228 AddCrc(data, datalen);
1229 datalen += 2;
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)));
1248 return PM3_SUCCESS;
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"
1261 "Response:\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[] = {
1274 arg_param_begin,
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"),
1278 arg_param_end
1280 CLIExecWithReturn(ctx, Cmd, argtable, true);
1282 uint8_t idm[8] = {0};
1283 int ilen = 0;
1284 int res = CLIParamHexToBuf(arg_get_str(ctx, 1), idm, sizeof(idm), &ilen);
1285 if (res) {
1286 CLIParserFree(ctx);
1287 return PM3_EINVARG;
1290 uint8_t reserved[2] = {0, 0};
1291 int rlen = 0;
1292 res = CLIParamHexToBuf(arg_get_str(ctx, 2), reserved, sizeof(reserved), &rlen);
1293 if (res) {
1294 CLIParserFree(ctx);
1295 return PM3_EINVARG;
1298 bool verbose = arg_get_lit(ctx, 3);
1299 if (verbose) {
1300 print_status_flag1_interpretation();
1301 print_status_flag2_interpration();
1303 CLIParserFree(ctx);
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;
1312 // add custom idm
1313 if (ilen) {
1314 custom_IDm = true;
1315 memcpy(data + 2, idm, sizeof(idm));
1318 // add custom reserved
1319 if (rlen) {
1320 memcpy(data + 10, reserved, sizeof(reserved));
1321 } else {
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) {
1328 return PM3_EINVARG;
1331 AddCrc(data, datalen);
1332 datalen += 2;
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));
1364 return PM3_SUCCESS;
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[] = {
1381 arg_param_begin,
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"),
1385 arg_param_end
1387 CLIExecWithReturn(ctx, Cmd, argtable, true);
1389 uint8_t idm[8] = {0};
1390 int ilen = 0;
1391 int res = CLIParamHexToBuf(arg_get_str(ctx, 1), idm, sizeof(idm), &ilen);
1392 if (res) {
1393 CLIParserFree(ctx);
1394 return PM3_EINVARG;
1397 uint8_t reserved[2] = {0, 0};
1398 int rlen = 0;
1399 res = CLIParamHexToBuf(arg_get_str(ctx, 2), reserved, sizeof(reserved), &rlen);
1400 if (res) {
1401 CLIParserFree(ctx);
1402 return PM3_EINVARG;
1405 bool verbose = arg_get_lit(ctx, 3);
1406 if (verbose) {
1407 print_status_flag1_interpretation();
1408 print_status_flag2_interpration();
1410 CLIParserFree(ctx);
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;
1419 if (ilen) {
1420 custom_IDm = true;
1421 memcpy(data + 2, idm, 8);
1423 if (rlen) {
1424 memcpy(data + 10, reserved, 2);
1425 } else {
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) {
1432 return PM3_EINVARG;
1435 AddCrc(data, datalen);
1436 datalen += 2;
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)));
1455 return PM3_SUCCESS;
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[] = {
1474 arg_param_begin,
1475 arg_str0("i", NULL, "<hex>", "set custom IDm"),
1476 arg_param_end
1478 CLIExecWithReturn(ctx, Cmd, argtable, true);
1480 uint8_t idm[8] = {0};
1481 int ilen = 0;
1482 int res = CLIParamHexToBuf(arg_get_str(ctx, 1), idm, sizeof(idm), &ilen);
1483 if (res) {
1484 CLIParserFree(ctx);
1485 return PM3_EINVARG;
1487 CLIParserFree(ctx);
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;
1496 if (ilen) {
1497 custom_IDm = true;
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) {
1503 return PM3_EINVARG;
1506 AddCrc(data, datalen);
1507 datalen += 2;
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));
1532 return PM3_SUCCESS;
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[] = {
1556 arg_param_begin,
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"),
1561 arg_param_end
1563 CLIExecWithReturn(ctx, Cmd, argtable, true);
1564 bool all_nodes = arg_get_lit(ctx, 1);
1566 uint8_t node[1] = {0};
1567 int nlen = 0;
1568 int res = CLIParamHexToBuf(arg_get_str(ctx, 2), node, sizeof(node), &nlen);
1569 if (res) {
1570 CLIParserFree(ctx);
1571 return PM3_EINVARG;
1574 uint8_t code[2] = {0, 0};
1575 int clen = 0;
1576 res = CLIParamHexToBuf(arg_get_str(ctx, 3), code, sizeof(code), &clen);
1577 if (res) {
1578 CLIParserFree(ctx);
1579 return PM3_EINVARG;
1582 uint8_t idm[8] = {0};
1583 int ilen = 0;
1584 res = CLIParamHexToBuf(arg_get_str(ctx, 4), idm, sizeof(idm), &ilen);
1585 if (res) {
1586 CLIParserFree(ctx);
1587 return PM3_EINVARG;
1589 CLIParserFree(ctx);
1591 uint8_t data[PM3_CMD_DATA_SIZE];
1592 memset(data, 0, sizeof(data));
1594 bool custom_IDm = false;
1596 if (ilen) {
1597 custom_IDm = true;
1598 memcpy(data + 2, idm, 8);
1601 if (all_nodes == false) {
1602 // Node Number
1603 if (nlen == 1) {
1604 memcpy(data + 10, node, sizeof(node));
1607 // code
1608 if (clen == 2) {
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;
1616 if (custom_IDm) {
1617 flags |= FELICA_NO_SELECT;
1620 if (datalen > 0) {
1621 flags |= FELICA_RAW;
1623 // Todo activate once datalen isn't hardcoded anymore...
1624 if (custom_IDm == false && check_last_idm(data, datalen) == false) {
1625 return PM3_EINVARG;
1628 data[0] = (datalen & 0xFF);
1629 data[1] = 0x02; // Service Request Command ID
1630 if (all_nodes) {
1632 // send 32 calls
1633 for (uint8_t i = 1; i < 32; i++) {
1634 data[10] = i;
1635 AddCrc(data, datalen);
1636 send_request_service(flags, datalen + 2, data, 1);
1639 } else {
1640 AddCrc(data, datalen);
1641 send_request_service(flags, datalen + 2, data, 1);
1644 return PM3_SUCCESS;
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[] = {
1654 arg_param_begin,
1655 arg_param_end
1657 CLIExecWithReturn(ctx, Cmd, argtable, false);
1658 CLIParserFree(ctx);
1659 return PM3_SUCCESS;
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`",
1667 "hf felica sniff\n"
1668 "hf felica sniff -s 10 -t 19"
1670 void *argtable[] = {
1671 arg_param_begin,
1672 arg_u64_0("s", "samples", "<dec>", "samples to skip"),
1673 arg_u64_0("t", "trig", "<dec>", "triggers to skip "),
1674 arg_param_end
1676 CLIExecWithReturn(ctx, Cmd, argtable, true);
1678 struct p {
1679 uint32_t samples;
1680 uint32_t triggers;
1681 } PACKED payload;
1683 payload.samples = arg_get_u32_def(ctx, 1, 10);
1684 payload.triggers = arg_get_u32_def(ctx, 2, 5000);
1685 CLIParserFree(ctx);
1687 if (payload.samples > 9999) {
1688 payload.samples = 9999;
1689 PrintAndLogEx(INFO, "Too large samples to skip value, using max value 9999");
1690 return PM3_EINVARG;
1693 if (payload.triggers > 9999) {
1694 payload.triggers = 9999;
1695 PrintAndLogEx(INFO, "Too large trigger to skip value, using max value 9999");
1696 return PM3_EINVARG;
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;
1706 for (;;) {
1707 if (kbd_enter_pressed()) {
1708 SendCommandNG(CMD_BREAK_LOOP, NULL, 0);
1709 PrintAndLogEx(DEBUG, "User aborted");
1710 msleep(300);
1711 break;
1714 if (WaitForResponseTimeout(CMD_HF_FELICA_SNIFF, &resp, 1000)) {
1715 if (resp.status == PM3_EOPABORTED) {
1716 PrintAndLogEx(DEBUG, "Button pressed, user aborted");
1717 break;
1722 PrintAndLogEx(HINT, "try `" _YELLOW_("hf felica list") "` to view");
1723 PrintAndLogEx(INFO, "Done");
1724 return PM3_SUCCESS;
1727 // uid hex
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[] = {
1735 arg_param_begin,
1736 arg_str1("u", "uid", "<hex>", "UID/NDEF2 8 hex bytes"),
1737 arg_param_end
1739 CLIExecWithReturn(ctx, Cmd, argtable, false);
1740 int uid_len = 0;
1741 struct p {
1742 uint8_t uid[8];
1743 } PACKED payload;
1744 CLIGetHexWithReturn(ctx, 1, payload.uid, &uid_len);
1745 CLIParserFree(ctx);
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;
1754 for (;;) {
1755 if (kbd_enter_pressed()) {
1756 SendCommandNG(CMD_BREAK_LOOP, NULL, 0);
1757 PrintAndLogEx(DEBUG, "User aborted");
1758 msleep(300);
1759 break;
1762 if (WaitForResponseTimeout(CMD_HF_FELICALITE_SIMULATE, &resp, 1000)) {
1763 if (resp.status == PM3_EOPABORTED) {
1764 PrintAndLogEx(DEBUG, "Button pressed, user aborted");
1765 break;
1770 PrintAndLogEx(INFO, "Done");
1771 return PM3_SUCCESS;
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)
1780 return tracelen;
1782 trace += tracepos;
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);
1793 switch (blocknum) {
1794 case 0x00:
1795 PrintAndLogEx(NORMAL, "S_PAD0: %s", line);
1796 break;
1797 case 0x01:
1798 PrintAndLogEx(NORMAL, "S_PAD1: %s", line);
1799 break;
1800 case 0x02:
1801 PrintAndLogEx(NORMAL, "S_PAD2: %s", line);
1802 break;
1803 case 0x03:
1804 PrintAndLogEx(NORMAL, "S_PAD3: %s", line);
1805 break;
1806 case 0x04:
1807 PrintAndLogEx(NORMAL, "S_PAD4: %s", line);
1808 break;
1809 case 0x05:
1810 PrintAndLogEx(NORMAL, "S_PAD5: %s", line);
1811 break;
1812 case 0x06:
1813 PrintAndLogEx(NORMAL, "S_PAD6: %s", line);
1814 break;
1815 case 0x07:
1816 PrintAndLogEx(NORMAL, "S_PAD7: %s", line);
1817 break;
1818 case 0x08:
1819 PrintAndLogEx(NORMAL, "S_PAD8: %s", line);
1820 break;
1821 case 0x09:
1822 PrintAndLogEx(NORMAL, "S_PAD9: %s", line);
1823 break;
1824 case 0x0a:
1825 PrintAndLogEx(NORMAL, "S_PAD10: %s", line);
1826 break;
1827 case 0x0b:
1828 PrintAndLogEx(NORMAL, "S_PAD11: %s", line);
1829 break;
1830 case 0x0c:
1831 PrintAndLogEx(NORMAL, "S_PAD12: %s", line);
1832 break;
1833 case 0x0d:
1834 PrintAndLogEx(NORMAL, "S_PAD13: %s", line);
1835 break;
1836 case 0x0E: {
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;
1839 line[0] = 0;
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);
1845 break;
1846 case 0x80:
1847 PrintAndLogEx(NORMAL, "Random Challenge, WO: %s ", line);
1848 break;
1849 case 0x81:
1850 PrintAndLogEx(NORMAL, "MAC, only set on dual read: %s ", line);
1851 break;
1852 case 0x82: {
1853 char idd[20];
1854 char idm[20];
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);
1863 break;
1864 case 0x83: {
1865 char idm[20];
1866 char pmm[20];
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);
1875 break;
1876 case 0x84:
1877 PrintAndLogEx(NORMAL, "SER_C: 0x%02x%02x ", trace[3], trace[4]);
1878 break;
1879 case 0x85:
1880 PrintAndLogEx(NORMAL, "SYS_Cl 0x%02x%02x ", trace[3], trace[4]);
1881 break;
1882 case 0x86:
1883 PrintAndLogEx(NORMAL, "CKV (key version): 0x%02x%02x ", trace[3], trace[4]);
1884 break;
1885 case 0x87:
1886 PrintAndLogEx(NORMAL, "CK (card key), WO: %s ", line);
1887 break;
1888 case 0x88: {
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));
1901 break;
1902 case 0x90: {
1903 PrintAndLogEx(NORMAL, "Write count, RO: %02x %02x %02x ", trace[3], trace[4], trace[5]);
1905 break;
1906 case 0x91: {
1907 PrintAndLogEx(NORMAL, "MAC_A, RW (auth): %s ", line);
1909 break;
1910 case 0x92:
1911 PrintAndLogEx(NORMAL, "State:");
1912 PrintAndLogEx(NORMAL, "Polling disabled: %s", trace[3 + 8] ? "yes" : "no");
1913 PrintAndLogEx(NORMAL, "Authenticated: %s", trace[3] ? "yes" : "no");
1914 break;
1915 case 0xa0:
1916 PrintAndLogEx(NORMAL, "CRC of all blocks match : %s", (trace[3 + 2] == 0xff) ? "no" : "yes");
1917 break;
1918 default:
1919 PrintAndLogEx(WARNING, "INVALID %d: %s", blocknum, line);
1920 break;
1922 return tracepos + 19;
1925 static int CmdHFFelicaDumpLite(const char *Cmd) {
1928 iceman 2021,
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[] = {
1941 arg_param_begin,
1942 arg_param_end
1944 CLIExecWithReturn(ctx, Cmd, argtable, true);
1945 CLIParserFree(ctx);
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;
1964 timeout++;
1965 PrintAndLogEx(INPLACE, "% 3i", timeout);
1967 fflush(stdout);
1968 if (kbd_enter_pressed()) {
1969 PrintAndLogEx(WARNING, "\naborted via keyboard!\n");
1970 DropField();
1971 return PM3_EOPABORTED;
1973 if (timeout > 10) {
1974 PrintAndLogEx(WARNING, "\ntimeout while waiting for reply.");
1975 DropField();
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?");
1990 return PM3_ESOFT;
1993 uint8_t *trace = calloc(tracelen, sizeof(uint8_t));
1994 if (trace == NULL) {
1995 PrintAndLogEx(WARNING, "failed to allocate memory ");
1996 return PM3_EMALLOC;
1999 if (!GetFromDevice(BIG_BUF, trace, tracelen, 0, NULL, 0, NULL, 2500, false)) {
2000 PrintAndLogEx(WARNING, "command execution time out");
2001 free(trace);
2002 return PM3_ETIMEOUT;
2006 PrintAndLogEx(SUCCESS, "Recorded Activity (trace len = %"PRIu32" bytes)", tracelen);
2007 print_hex_break(trace, tracelen, 32);
2008 printSep();
2010 uint16_t tracepos = 0;
2011 while (tracepos < tracelen)
2012 tracepos = PrintFliteBlock(tracepos, trace, tracelen);
2014 printSep();
2016 free(trace);
2017 return PM3_SUCCESS;
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[] = {
2030 arg_param_begin,
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"),
2038 arg_param_end
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);
2049 int datalen = 0;
2050 uint8_t data[PM3_CMD_DATA_SIZE];
2051 memset(data, 0, sizeof(data));
2053 CLIGetHexWithReturn(ctx, 7, data, &datalen);
2054 CLIParserFree(ctx);
2056 if (crc) {
2057 AddCrc(data, datalen);
2058 datalen += 2;
2061 uint8_t flags = 0;
2062 if (active || active_select) {
2063 flags |= FELICA_CONNECT;
2064 if (active)
2065 flags |= FELICA_NO_SELECT;
2068 if (keep_field_on) {
2069 flags |= FELICA_NO_DISCONNECT;
2072 if (datalen > 0) {
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);
2084 if (reply) {
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;
2092 if (datalen > 0) {
2093 PacketResponseNG resp_frame;
2094 if (waitCmdFelica(0, &resp_frame, true) == false) {
2095 return PM3_ERFTRANS;
2099 return PM3_SUCCESS;
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);
2141 return PM3_SUCCESS;
2144 int CmdHFFelica(const char *Cmd) {
2145 clearCommandBuffer();
2146 return CmdsParse(CommandTable, Cmd);