textual
[RRG-proxmark3.git] / client / src / cmdhfcipurse.c
blob427340ca47f7d10394935ccda764a0b139d17835
1 //-----------------------------------------------------------------------------
2 // Copyright (C) 2021 Merlok
3 //
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 FIDO U2F and FIDO2 contactless authenticators
9 //-----------------------------------------------------------------------------
11 // JAVA implementation here:
13 // https://github.com/duychuongvn/cipurse-card-core
14 //-----------------------------------------------------------------------------
16 #include "cmdhffido.h"
17 #include <unistd.h>
18 #include "cmdparser.h" // command_t
19 #include "commonutil.h"
20 #include "comms.h"
21 #include "proxmark3.h"
22 #include "emv/emvcore.h"
23 #include "emv/emvjson.h"
24 #include "cliparser.h"
25 #include "cmdhfcipurse.h"
26 #include "cipurse/cipursecore.h"
27 #include "cipurse/cipursecrypto.h"
28 #include "ui.h"
29 #include "cmdhf14a.h"
30 #include "cmdtrace.h"
31 #include "util.h"
32 #include "fileutils.h" // laodFileJSONroot
34 static int CmdHelp(const char *Cmd);
36 static int CmdHFCipurseInfo(const char *Cmd) {
37 CLIParserContext *ctx;
38 CLIParserInit(&ctx, "hf cipurse info",
39 "Get info from cipurse tags",
40 "hf cipurse info");
42 void *argtable[] = {
43 arg_param_begin,
44 arg_param_end
46 CLIExecWithReturn(ctx, Cmd, argtable, true);
47 CLIParserFree(ctx);
49 // info about 14a part
50 infoHF14A(false, false, false);
52 // CIPURSE info
53 PrintAndLogEx(INFO, "-----------" _CYAN_("CIPURSE Info") "---------------------------------");
54 SetAPDULogging(false);
56 uint8_t buf[APDU_RES_LEN] = {0};
57 size_t len = 0;
58 uint16_t sw = 0;
59 int res = CIPURSESelect(true, true, buf, sizeof(buf), &len, &sw);
61 if (res) {
62 DropField();
63 return res;
66 if (sw != 0x9000) {
67 if (sw)
68 PrintAndLogEx(INFO, "Not a CIPURSE card. APDU response: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
69 else
70 PrintAndLogEx(ERR, "APDU exchange error. Card returns 0x0000");
72 DropField();
73 return PM3_SUCCESS;
76 PrintAndLogEx(INFO, "Cipurse card ( " _GREEN_("ok") " )");
78 res = CIPURSESelectFile(0x2ff7, buf, sizeof(buf), &len, &sw);
79 if (res != 0 || sw != 0x9000) {
80 DropField();
81 return PM3_SUCCESS;
84 res = CIPURSEReadBinary(0, buf, sizeof(buf), &len, &sw);
85 if (res != 0 || sw != 0x9000) {
86 DropField();
87 return PM3_SUCCESS;
90 if (len > 0) {
91 PrintAndLogEx(INFO, "Info file ( " _GREEN_("ok") " )");
92 PrintAndLogEx(INFO, "[%zu]: %s", len, sprint_hex(buf, len));
93 CIPURSEPrintInfoFile(buf, len);
96 DropField();
97 return PM3_SUCCESS;
100 static int CmdHFCipurseAuth(const char *Cmd) {
101 CLIParserContext *ctx;
102 CLIParserInit(&ctx, "hf cipurse auth",
103 "Authenticate with key ID and key. If no key is supplied, default key of 737373...7373 will be used",
104 "hf cipurse auth -> Authenticate with keyID 1, default key\n"
105 "hf cipurse auth -n 2 -k 65656565656565656565656565656565 -> Authenticate keyID 2 with key\n");
107 void *argtable[] = {
108 arg_param_begin,
109 arg_lit0("a", "apdu", "show APDU requests and responses"),
110 arg_lit0("v", "verbose", "show technical data"),
111 arg_int0("n", NULL, "<dec>", "key ID"),
112 arg_str0("k", "key", "<hex>", "Auth key"),
113 arg_param_end
115 CLIExecWithReturn(ctx, Cmd, argtable, true);
117 bool APDULogging = arg_get_lit(ctx, 1);
118 bool verbose = arg_get_lit(ctx, 2);
119 uint8_t keyId = arg_get_int_def(ctx, 3, 1);
121 uint8_t hdata[250] = {0};
122 int hdatalen = sizeof(hdata);
123 CLIGetHexWithReturn(ctx, 4, hdata, &hdatalen);
124 if (hdatalen && hdatalen != 16) {
125 PrintAndLogEx(ERR, _RED_("ERROR:") " key length for AES128 must be 16 bytes only");
126 CLIParserFree(ctx);
127 return PM3_EINVARG;
130 uint8_t key[] = {0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73};
131 if (hdatalen)
132 memcpy(key, hdata, CIPURSE_AES_KEY_LENGTH);
134 SetAPDULogging(APDULogging);
136 CLIParserFree(ctx);
138 size_t len = 0;
139 uint16_t sw = 0;
140 uint8_t buf[APDU_RES_LEN] = {0};
142 int res = CIPURSESelect(true, true, buf, sizeof(buf), &len, &sw);
143 if (res != 0 || sw != 0x9000) {
144 PrintAndLogEx(ERR, "Cipurse select " _RED_("error") ". Card returns 0x%04x", sw);
145 DropField();
146 return PM3_ESOFT;
149 uint8_t kvv[CIPURSE_KVV_LENGTH] = {0};
150 CipurseCGetKVV(key, kvv);
151 if (verbose) {
152 PrintAndLogEx(INFO, "Key id" _YELLOW_("%d") " key " _YELLOW_("%s") " KVV " _YELLOW_("%s")
153 , keyId
154 , sprint_hex(key, CIPURSE_AES_KEY_LENGTH)
155 , sprint_hex_inrow(kvv, CIPURSE_KVV_LENGTH)
159 bool bres = CIPURSEChannelAuthenticate(keyId, key, verbose);
161 if (verbose == false) {
162 if (bres)
163 PrintAndLogEx(INFO, "Authentication ( " _GREEN_("ok") " )");
164 else
165 PrintAndLogEx(ERR, "Authentication ( " _RED_("fail") " )");
168 DropField();
169 return (bres) ? PM3_SUCCESS : PM3_ESOFT;
172 static int CLIParseKeyAndSecurityLevels(CLIParserContext *ctx, size_t keyid, size_t sreqid, size_t srespid, uint8_t *key, CipurseChannelSecurityLevel *sreq, CipurseChannelSecurityLevel *sresp) {
173 uint8_t hdata[250] = {0};
174 int hdatalen = sizeof(hdata);
175 CLIGetHexWithReturn(ctx, keyid, hdata, &hdatalen);
176 if (hdatalen && hdatalen != 16) {
177 PrintAndLogEx(ERR, _RED_("ERROR:") " key length for AES128 must be 16 bytes only");
178 return PM3_EINVARG;
180 if (hdatalen)
181 memcpy(key, hdata, CIPURSE_AES_KEY_LENGTH);
183 *sreq = CPSMACed;
184 *sresp = CPSMACed;
186 char cdata[250] = {0};
187 int cdatalen = sizeof(cdata);
188 cdatalen--; // for trailer 0x00
189 CLIGetStrWithReturn(ctx, sreqid, (uint8_t *)cdata, &cdatalen);
190 if (cdatalen) {
191 str_lower(cdata);
192 if (strcmp(cdata, "plain") == 0)
193 *sreq = CPSPlain;
194 else if (strcmp(cdata, "mac") == 0)
195 *sreq = CPSMACed;
196 else if (strcmp(cdata, "enc") == 0 || strcmp(cdata, "encode") == 0 || strcmp(cdata, "encrypted") == 0)
197 *sreq = CPSEncrypted;
198 else {
199 PrintAndLogEx(ERR, _RED_("ERROR:") " security level can be only: plain | mac | encode");
200 return PM3_EINVARG;
204 cdatalen = sizeof(cdata);
205 memset(cdata, 0, cdatalen);
206 cdatalen--; // for trailer 0x00
207 CLIGetStrWithReturn(ctx, srespid, (uint8_t *)cdata, &cdatalen);
208 if (cdatalen) {
209 str_lower(cdata);
210 if (strcmp(cdata, "plain") == 0)
211 *sresp = CPSPlain;
212 else if (strcmp(cdata, "mac") == 0)
213 *sresp = CPSMACed;
214 else if (strcmp(cdata, "enc") == 0 || strcmp(cdata, "encode") == 0 || strcmp(cdata, "encrypted") == 0)
215 *sresp = CPSEncrypted;
216 else {
217 PrintAndLogEx(ERR, _RED_("ERROR:") " security level can be only: plain | mac | encode");
218 return PM3_EINVARG;
222 return PM3_SUCCESS;
225 static int CmdHFCipurseReadFile(const char *Cmd) {
226 CLIParserContext *ctx;
227 CLIParserInit(&ctx, "hf cipurse read",
228 "Read file by file ID with key ID and key. If no key is supplied, default key of 737373...7373 will be used",
229 "hf cipurse read -f 2ff7 -> Authenticate with keyID 1, read file with id 2ff7\n"
230 "hf cipurse read -n 2 -k 65656565656565656565656565656565 --fid 2ff7 -> Authenticate keyID 2 and read file\n");
232 void *argtable[] = {
233 arg_param_begin,
234 arg_lit0("a", "apdu", "show APDU requests and responses"),
235 arg_lit0("v", "verbose", "show technical data"),
236 arg_int0("n", NULL, "<dec>", "key ID"),
237 arg_str0("k", "key", "<hex>", "Auth key"),
238 arg_str0(NULL, "fid", "<hex>", "file ID"),
239 arg_int0("o", "offset", "<dec>", "offset for reading data from file"),
240 arg_lit0(NULL, "noauth", "read file without authentication"),
241 arg_str0(NULL, "sreq", "<plain|mac(default)|encode>", "communication reader-PICC security level"),
242 arg_str0(NULL, "sresp", "<plain|mac(default)|encode>", "communication PICC-reader security level"),
243 arg_param_end
245 CLIExecWithReturn(ctx, Cmd, argtable, true);
248 bool APDULogging = arg_get_lit(ctx, 1);
249 bool verbose = arg_get_lit(ctx, 2);
250 uint8_t keyId = arg_get_int_def(ctx, 3, 1);
252 CipurseChannelSecurityLevel sreq = CPSMACed;
253 CipurseChannelSecurityLevel sresp = CPSMACed;
254 uint8_t key[] = CIPURSE_DEFAULT_KEY;
255 int res = CLIParseKeyAndSecurityLevels(ctx, 4, 8, 9, key, &sreq, &sresp);
256 if (res) {
257 CLIParserFree(ctx);
258 return PM3_EINVARG;
261 uint8_t hdata[250] = {0};
262 int hdatalen = sizeof(hdata);
263 CLIGetHexWithReturn(ctx, 5, hdata, &hdatalen);
264 if (hdatalen && hdatalen != 2) {
265 PrintAndLogEx(ERR, _RED_("ERROR:") " file id length must be 2 bytes only");
266 CLIParserFree(ctx);
267 return PM3_EINVARG;
270 uint16_t fileId = 0x2ff7;
271 if (hdatalen)
272 fileId = (hdata[0] << 8) + hdata[1];
274 size_t offset = arg_get_int_def(ctx, 6, 0);
276 bool noAuth = arg_get_lit(ctx, 7);
278 SetAPDULogging(APDULogging);
280 CLIParserFree(ctx);
282 size_t len = 0;
283 uint16_t sw = 0;
284 uint8_t buf[APDU_RES_LEN] = {0};
286 res = CIPURSESelect(true, true, buf, sizeof(buf), &len, &sw);
287 if (res != 0 || sw != 0x9000) {
288 PrintAndLogEx(ERR, "Cipurse select " _RED_("error") ". Card returns 0x%04x", sw);
289 DropField();
290 return PM3_ESOFT;
293 if (verbose)
294 PrintAndLogEx(INFO, "File id " _YELLOW_("%x") " offset " _YELLOW_("%zu") " key id " _YELLOW_("%d") " key " _YELLOW_("%s"), fileId, offset, keyId, sprint_hex(key, CIPURSE_AES_KEY_LENGTH));
296 if (noAuth == false) {
297 bool bres = CIPURSEChannelAuthenticate(keyId, key, verbose);
298 if (bres == false) {
299 if (verbose == false)
300 PrintAndLogEx(ERR, "Authentication ( " _RED_("fail") " )");
301 DropField();
302 return PM3_ESOFT;
305 // set channel security levels
306 CIPURSECSetActChannelSecurityLevels(sreq, sresp);
309 res = CIPURSESelectFile(fileId, buf, sizeof(buf), &len, &sw);
310 if (res != 0 || sw != 0x9000) {
311 if (verbose == false)
312 PrintAndLogEx(ERR, "File select " _RED_("ERROR") ". Card returns 0x%04x", sw);
313 DropField();
314 return PM3_ESOFT;
317 if (verbose)
318 PrintAndLogEx(INFO, "Select file 0x%x ( " _GREEN_("ok") " )", fileId);
320 res = CIPURSEReadBinary(offset, buf, sizeof(buf), &len, &sw);
321 if (res != 0 || sw != 0x9000) {
322 if (verbose == false)
323 PrintAndLogEx(ERR, "File read " _RED_("ERROR") ". Card returns 0x%04x", sw);
324 DropField();
325 return PM3_ESOFT;
328 if (len == 0)
329 PrintAndLogEx(INFO, "File id " _YELLOW_("%x") " is empty", fileId);
330 else
331 PrintAndLogEx(INFO, "File id " _YELLOW_("%x") " data[%zu]: %s", fileId, len, sprint_hex(buf, len));
333 DropField();
334 return PM3_SUCCESS;
337 static int CmdHFCipurseWriteFile(const char *Cmd) {
338 CLIParserContext *ctx;
339 CLIParserInit(&ctx, "hf cipurse write",
340 "Write file by file ID with key ID and key. If no key is supplied, default key of 737373...7373 will be used",
341 "hf cipurse write -f 2ff7 -> Authenticate with keyID 1, write file with id 2ff7\n"
342 "hf cipurse write -n 2 -k 65656565656565656565656565656565 --fid 2ff7 -> Authenticate keyID 2 and write file\n");
344 void *argtable[] = {
345 arg_param_begin,
346 arg_lit0("a", "apdu", "show APDU requests and responses"),
347 arg_lit0("v", "verbose", "show technical data"),
348 arg_int0("n", NULL, "<dec>", "key ID"),
349 arg_str0("k", "key", "<hex>", "Auth key"),
350 arg_str0(NULL, "fid", "<hex>", "file ID"),
351 arg_int0("o", "offset", "<dec>", "offset for reading data from file"),
352 arg_lit0(NULL, "noauth", "read file without authentication"),
353 arg_str0(NULL, "sreq", "<plain|mac(default)|encode>", "communication reader-PICC security level"),
354 arg_str0(NULL, "sresp", "<plain|mac(default)|encode>", "communication PICC-reader security level"),
355 arg_str0("d", "data", "<hex>", "hex data to write to new file"),
356 arg_param_end
358 CLIExecWithReturn(ctx, Cmd, argtable, true);
360 bool APDULogging = arg_get_lit(ctx, 1);
361 bool verbose = arg_get_lit(ctx, 2);
362 uint8_t keyId = arg_get_int_def(ctx, 3, 1);
364 CipurseChannelSecurityLevel sreq = CPSMACed;
365 CipurseChannelSecurityLevel sresp = CPSMACed;
367 uint8_t key[] = CIPURSE_DEFAULT_KEY;
368 int res = CLIParseKeyAndSecurityLevels(ctx, 4, 8, 9, key, &sreq, &sresp);
369 if (res) {
370 CLIParserFree(ctx);
371 return PM3_EINVARG;
374 uint16_t fileId = 0x2ff7;
376 uint8_t hdata[250] = {0};
377 int hdatalen = sizeof(hdata);
378 CLIGetHexWithReturn(ctx, 5, hdata, &hdatalen);
379 if (hdatalen && hdatalen != 2) {
380 PrintAndLogEx(ERR, _RED_("ERROR:") " file id length must be 2 bytes only");
381 CLIParserFree(ctx);
382 return PM3_EINVARG;
384 if (hdatalen)
385 fileId = (hdata[0] << 8) + hdata[1];
387 size_t offset = arg_get_int_def(ctx, 6, 0);
389 bool noAuth = arg_get_lit(ctx, 7);
391 hdatalen = sizeof(hdata);
392 CLIGetHexWithReturn(ctx, 10, hdata, &hdatalen);
393 if (hdatalen == 0) {
394 PrintAndLogEx(ERR, _RED_("ERROR:") " file content length must be more 0");
395 CLIParserFree(ctx);
396 return PM3_EINVARG;
399 SetAPDULogging(APDULogging);
401 CLIParserFree(ctx);
403 size_t len = 0;
404 uint16_t sw = 0;
405 uint8_t buf[APDU_RES_LEN] = {0};
407 res = CIPURSESelect(true, true, buf, sizeof(buf), &len, &sw);
408 if (res != 0 || sw != 0x9000) {
409 PrintAndLogEx(ERR, "Cipurse select " _RED_("error") ". Card returns 0x%04x", sw);
410 DropField();
411 return PM3_ESOFT;
414 if (verbose) {
415 PrintAndLogEx(INFO, "File id " _YELLOW_("%x") " offset " _YELLOW_("%zu") " key id " _YELLOW_("%d") " key " _YELLOW_("%s")
416 , fileId
417 , offset
418 , keyId
419 , sprint_hex(key, CIPURSE_AES_KEY_LENGTH)
421 PrintAndLogEx(INFO, "data[%d]: %s", hdatalen, sprint_hex(hdata, hdatalen));
424 if (noAuth == false) {
425 bool bres = CIPURSEChannelAuthenticate(keyId, key, verbose);
426 if (bres == false) {
427 if (verbose == false)
428 PrintAndLogEx(ERR, "Authentication ( " _RED_("fail") " )");
429 DropField();
430 return PM3_ESOFT;
433 // set channel security levels
434 CIPURSECSetActChannelSecurityLevels(sreq, sresp);
437 res = CIPURSESelectFile(fileId, buf, sizeof(buf), &len, &sw);
438 if (res != 0 || sw != 0x9000) {
439 if (verbose == false)
440 PrintAndLogEx(ERR, "File select " _RED_("ERROR") ". Card returns 0x%04x", sw);
441 DropField();
442 return PM3_ESOFT;
445 if (verbose)
446 PrintAndLogEx(INFO, "Select file 0x%x ( " _GREEN_("ok") " )", fileId);
448 res = CIPURSEUpdateBinary(offset, hdata, hdatalen, buf, sizeof(buf), &len, &sw);
449 if (res != 0 || sw != 0x9000) {
450 if (verbose == false)
451 PrintAndLogEx(ERR, "File write " _RED_("ERROR") ". Card returns 0x%04x", sw);
452 DropField();
453 return PM3_ESOFT;
456 PrintAndLogEx(INFO, "File id " _YELLOW_("%x") " successfully written", fileId);
458 DropField();
459 return PM3_SUCCESS;
462 static int CmdHFCipurseReadFileAttr(const char *Cmd) {
463 CLIParserContext *ctx;
464 CLIParserInit(&ctx, "hf cipurse aread",
465 "Read file attributes by file ID with key ID and key. If no key is supplied, default key of 737373...7373 will be used",
466 "hf cipurse aread -f 2ff7 -> Authenticate with keyID 1, read file attributes with id 2ff7\n"
467 "hf cipurse aread -n 2 -k 65656565656565656565656565656565 --fid 2ff7 -> Authenticate keyID 2, read file attributes\n");
469 void *argtable[] = {
470 arg_param_begin,
471 arg_lit0("a", "apdu", "show APDU requests and responses"),
472 arg_lit0("v", "verbose", "show technical data"),
473 arg_int0("n", NULL, "<dec>", "key ID"),
474 arg_str0("k", "key", "<hex>", "Auth key"),
475 arg_str0(NULL, "fid", "<hex>", "file ID"),
476 arg_lit0(NULL, "noauth", "read file attributes without authentication"),
477 arg_str0(NULL, "sreq", "<plain|mac(default)|encode>", "communication reader-PICC security level"),
478 arg_str0(NULL, "sresp", "<plain|mac(default)|encode>", "communication PICC-reader security level"),
479 arg_lit0(NULL, "sel-adf", "show info about ADF itself"),
480 arg_lit0(NULL, "sel-mf", "show info about master file"),
481 arg_param_end
483 CLIExecWithReturn(ctx, Cmd, argtable, true);
485 bool APDULogging = arg_get_lit(ctx, 1);
486 bool verbose = arg_get_lit(ctx, 2);
487 uint8_t keyId = arg_get_int_def(ctx, 3, 1);
489 CipurseChannelSecurityLevel sreq = CPSMACed;
490 CipurseChannelSecurityLevel sresp = CPSMACed;
491 uint8_t key[] = CIPURSE_DEFAULT_KEY;
492 int res = CLIParseKeyAndSecurityLevels(ctx, 4, 7, 8, key, &sreq, &sresp);
493 if (res) {
494 CLIParserFree(ctx);
495 return PM3_EINVARG;
498 uint8_t hdata[250] = {0};
499 int hdatalen = sizeof(hdata);
500 CLIGetHexWithReturn(ctx, 5, hdata, &hdatalen);
501 if (hdatalen && hdatalen != 2) {
502 PrintAndLogEx(ERR, _RED_("ERROR:") " file id length must be 2 bytes only");
503 CLIParserFree(ctx);
504 return PM3_EINVARG;
507 uint16_t fileId = 0x2ff7;
508 if (hdatalen)
509 fileId = (hdata[0] << 8) + hdata[1];
511 bool noAuth = arg_get_lit(ctx, 6);
512 bool seladf = arg_get_lit(ctx, 9);
513 bool selmf = arg_get_lit(ctx, 10);
515 SetAPDULogging(APDULogging);
517 CLIParserFree(ctx);
519 uint8_t buf[APDU_RES_LEN] = {0};
520 size_t len = 0;
521 uint16_t sw = 0;
523 res = CIPURSESelect(true, true, buf, sizeof(buf), &len, &sw);
524 if (res != 0 || sw != 0x9000) {
525 PrintAndLogEx(ERR, "Cipurse select " _RED_("error") ". Card returns 0x%04x", sw);
526 DropField();
527 return PM3_ESOFT;
530 if (verbose) {
531 PrintAndLogEx(INFO, "File id " _YELLOW_("%x") " key id " _YELLOW_("%d") " key " _YELLOW_("%s")
532 , fileId
533 , keyId
534 , sprint_hex(key, CIPURSE_AES_KEY_LENGTH)
538 if (noAuth == false) {
539 bool bres = CIPURSEChannelAuthenticate(keyId, key, verbose);
540 if (bres == false) {
541 if (verbose == false)
542 PrintAndLogEx(ERR, "Authentication ( " _RED_("fail") " )");
543 DropField();
544 return PM3_ESOFT;
547 // set channel security levels
548 CIPURSECSetActChannelSecurityLevels(sreq, sresp);
551 if (seladf == false) {
552 if (selmf)
553 res = CIPURSESelectMFFile(buf, sizeof(buf), &len, &sw);
554 else
555 res = CIPURSESelectFile(fileId, buf, sizeof(buf), &len, &sw);
557 if (res != 0 || sw != 0x9000) {
558 if (verbose == false)
559 PrintAndLogEx(ERR, "File select " _RED_("ERROR") ". Card returns 0x%04x", sw);
560 DropField();
561 return PM3_ESOFT;
565 if (verbose)
566 PrintAndLogEx(INFO, "Select file 0x%x ( " _GREEN_("ok") " )", fileId);
568 res = CIPURSEReadFileAttributes(buf, sizeof(buf), &len, &sw);
569 if (res != 0 || sw != 0x9000) {
570 if (verbose == false)
571 PrintAndLogEx(ERR, "File read " _RED_("ERROR") ". Card returns 0x%04x", sw);
572 DropField();
573 return PM3_ESOFT;
576 if (len == 0) {
577 PrintAndLogEx(WARNING, "File id " _YELLOW_("%x") " attributes is empty", fileId);
578 DropField();
579 return PM3_SUCCESS;
582 if (verbose)
583 PrintAndLogEx(INFO, "File id " _YELLOW_("%x") " attributes[%zu]: %s", fileId, len, sprint_hex(buf, len));
585 CIPURSEPrintFileAttr(buf, len);
587 DropField();
588 return PM3_SUCCESS;
591 static int CmdHFCipurseDeleteFile(const char *Cmd) {
592 CLIParserContext *ctx;
593 CLIParserInit(&ctx, "hf cipurse delete",
594 "Read file by file ID with key ID and key. If no key is supplied, default key of 737373...7373 will be used",
595 "hf cipurse delete -f 2ff7 -> Authenticate with keyID 1, delete file with id 2ff7\n"
596 "hf cipurse delete -n 2 -k 65656565656565656565656565656565 --fid 2ff7 -> Authenticate keyID 2 and delete file\n");
598 void *argtable[] = {
599 arg_param_begin,
600 arg_lit0("a", "apdu", "show APDU requests and responses"),
601 arg_lit0("v", "verbose", "show technical data"),
602 arg_int0("n", NULL, "<dec>", "key ID"),
603 arg_str0("k", "key", "<hex>", "Auth key"),
604 arg_str0(NULL, "fid", "<hex>", "file ID"),
605 arg_str0(NULL, "sreq", "<plain|mac(default)|encode>", "communication reader-PICC security level"),
606 arg_str0(NULL, "sresp", "<plain|mac(default)|encode>", "communication PICC-reader security level"),
607 arg_param_end
609 CLIExecWithReturn(ctx, Cmd, argtable, true);
611 bool APDULogging = arg_get_lit(ctx, 1);
612 bool verbose = arg_get_lit(ctx, 2);
613 uint8_t keyId = arg_get_int_def(ctx, 3, 1);
615 CipurseChannelSecurityLevel sreq = CPSMACed;
616 CipurseChannelSecurityLevel sresp = CPSMACed;
617 uint8_t key[] = CIPURSE_DEFAULT_KEY;
618 int res = CLIParseKeyAndSecurityLevels(ctx, 4, 6, 7, key, &sreq, &sresp);
619 if (res) {
620 CLIParserFree(ctx);
621 return PM3_EINVARG;
624 uint8_t hdata[250] = {0};
625 int hdatalen = sizeof(hdata);
626 CLIGetHexWithReturn(ctx, 5, hdata, &hdatalen);
627 if (hdatalen && hdatalen != 2) {
628 PrintAndLogEx(ERR, _RED_("ERROR:") " file id length must be 2 bytes only");
629 CLIParserFree(ctx);
630 return PM3_EINVARG;
633 uint16_t fileId = 0x2ff7;
634 if (hdatalen)
635 fileId = (hdata[0] << 8) + hdata[1];
637 SetAPDULogging(APDULogging);
639 CLIParserFree(ctx);
641 uint8_t buf[APDU_RES_LEN] = {0};
642 size_t len = 0;
643 uint16_t sw = 0;
645 res = CIPURSESelect(true, true, buf, sizeof(buf), &len, &sw);
646 if (res != 0 || sw != 0x9000) {
647 PrintAndLogEx(ERR, "Cipurse select " _RED_("error") ". Card returns 0x%04x", sw);
648 DropField();
649 return PM3_ESOFT;
652 if (verbose) {
653 PrintAndLogEx(INFO, "File id " _YELLOW_("%x") " key id " _YELLOW_("%d") " key " _YELLOW_("%s")
654 , fileId
655 , keyId
656 , sprint_hex(key, CIPURSE_AES_KEY_LENGTH)
660 bool bres = CIPURSEChannelAuthenticate(keyId, key, verbose);
661 if (bres == false) {
662 if (verbose == false)
663 PrintAndLogEx(ERR, "Authentication ( " _RED_("fail") " )");
664 DropField();
665 return PM3_ESOFT;
668 // set channel security levels
669 CIPURSECSetActChannelSecurityLevels(sreq, sresp);
671 res = CIPURSEDeleteFile(fileId, buf, sizeof(buf), &len, &sw);
672 if (res != 0 || sw != 0x9000) {
673 if (verbose == false)
674 PrintAndLogEx(ERR, "File select " _RED_("ERROR") ". Card returns 0x%04x", sw);
675 DropField();
676 return PM3_ESOFT;
679 PrintAndLogEx(INFO, "File id " _YELLOW_("%04x") " deleted " _GREEN_("succesfully"), fileId);
681 DropField();
682 return PM3_SUCCESS;
686 bool CheckCardCipurse(void) {
687 uint8_t buf[APDU_RES_LEN] = {0};
688 size_t len = 0;
689 uint16_t sw = 0;
690 int res = CIPURSESelect(true, false, buf, sizeof(buf), &len, &sw);
692 return (res == 0 && sw == 0x9000);
695 static command_t CommandTable[] = {
696 {"help", CmdHelp, AlwaysAvailable, "This help."},
697 {"info", CmdHFCipurseInfo, IfPm3Iso14443a, "Get info about CIPURSE tag"},
698 {"auth", CmdHFCipurseAuth, IfPm3Iso14443a, "Authenticate CIPURSE tag"},
699 {"read", CmdHFCipurseReadFile, IfPm3Iso14443a, "Read binary file"},
700 {"write", CmdHFCipurseWriteFile, IfPm3Iso14443a, "Write binary file"},
701 {"aread", CmdHFCipurseReadFileAttr, IfPm3Iso14443a, "Read file attributes"},
702 {"delete", CmdHFCipurseDeleteFile, IfPm3Iso14443a, "Delete file"},
703 {NULL, NULL, 0, NULL}
706 int CmdHFCipurse(const char *Cmd) {
707 clearCommandBuffer();
708 return CmdsParse(CommandTable, Cmd);
711 int CmdHelp(const char *Cmd) {
712 (void)Cmd; // Cmd is not used so far
713 CmdsHelp(CommandTable);
714 return PM3_SUCCESS;