recover_pk.py: replace secp192r1 by prime192v1
[RRG-proxmark3.git] / client / src / cmdhfcipurse.c
blob3f6e76ec24ce5a3a4316da3a0a59e36b990619c5
1 //-----------------------------------------------------------------------------
2 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // See LICENSE.txt for the text of the license.
15 //-----------------------------------------------------------------------------
16 // High frequency FIDO U2F and FIDO2 contactless authenticators
17 //-----------------------------------------------------------------------------
19 // JAVA implementation here:
21 // https://github.com/duychuongvn/cipurse-card-core
22 //-----------------------------------------------------------------------------
24 #include "cmdhffido.h"
25 #include <unistd.h>
26 #include "cmdparser.h" // command_t
27 #include "commonutil.h"
28 #include "comms.h"
29 #include "proxmark3.h"
30 #include "emv/emvcore.h"
31 #include "emv/emvjson.h"
32 #include "cliparser.h"
33 #include "cmdhfcipurse.h"
34 #include "cipurse/cipursecore.h"
35 #include "cipurse/cipursecrypto.h"
36 #include "cipurse/cipursetest.h"
37 #include "ui.h"
38 #include "cmdhf14a.h"
39 #include "cmdtrace.h"
40 #include "util.h"
41 #include "fileutils.h" // laodFileJSONroot
42 #include "crypto/libpcrypto.h"
43 #include "protocols.h" // ISO7816 APDU return codes
45 const uint8_t PxSE_AID[] = {0xA0, 0x00, 0x00, 0x05, 0x07, 0x01, 0x00};
46 #define PxSE_AID_LENGTH 7
47 typedef struct {
48 uint8_t aid[PxSE_AID_LENGTH];
49 const char *name;
50 } PxSE_AID_t;
52 static const PxSE_AID_t PxSE_AID_LIST[] = {
53 {{0xA0, 0x00, 0x00, 0x05, 0x07, 0x01, 0x00}, "Proximity Transport System Environment (PTSE)" },
54 {{0xA0, 0x00, 0x00, 0x05, 0x07, 0x02, 0x00}, "Proximity Facility Access System Environment (PASE)" },
55 {{0xA0, 0x00, 0x00, 0x05, 0x07, 0x03, 0x00}, "Proximity Digital Identity System Environment (PDSE)" },
56 {{0xA0, 0x00, 0x00, 0x05, 0x07, 0x04, 0x00}, "Proximity Event Ticketing System Environment (PESE)" },
57 {{0xA0, 0x00, 0x00, 0x05, 0x07, 0x05, 0x00}, "Proximity Couponing System Environment (PCSE)" },
58 {{0xA0, 0x00, 0x00, 0x05, 0x07, 0x06, 0x00}, "Proximity Micro-Payment System Environment (PMSE)" }
61 static const APDUSpcCodeDescription_t SelectAPDUCodeDescriptions[] = {
62 {0x6984, "Key is blocked for use as key encryption key" },
63 {0x6985, "Command not allowed on deactivated ADF or maximum files count already reached" },
64 {0x6A80, "Incorrect creation parameters in the command data field for the EF/ADF creation" },
65 {0x6A81, "Command for creation of ADF is not permitted on ADF level" },
66 {0x6A84, "Not enough memory space" },
67 {0x6A88, "Invalid key number (outside the range supported by the currend DF)" },
68 {0x6A89, "FileID / SFID already exists" },
69 {0x6A89, "AID already exists" }
72 static const APDUSpcCodeDescription_t DeleteAPDUCodeDescriptions[] = {
73 {0x6985, "Referenced PxSE application cannot be deleted due to reference to CIPURSE application" },
74 {0x6986, "Deletion of MF or predefined EFs is not allowed" },
75 {0x6A82, "File not found" }
78 static const APDUSpcCodeDescription_t UAPDpdateKeyAttrCodeDescriptions[] = {
79 {0x6581, "Transaction mechanism capabilities exceeded" },
80 {0x6982, "Key is frozen or only the key itself has the rights to update" },
81 {0x6985, "Deactivated file" },
82 {0x6A88, "Invalid key number (outside the range supported by the current DF)" }
85 static const APDUSpcCodeDescription_t UAPDpdateKeyCodeDescriptions[] = {
86 {0x6982, "Key is frozen or only the key itself has the rights to update" },
87 {0x6984, "Enc key is blocked or invalid" },
88 {0x6985, "Deactivated file" },
89 {0x6A80, "Invalid algo, key length or kvv" },
90 {0x6A88, "Invalid key number (outside the range supported by the current DF)" }
93 static uint8_t defaultKeyId = 1;
94 static uint8_t defaultKey[CIPURSE_AES_KEY_LENGTH] = CIPURSE_DEFAULT_KEY;
95 #define CIPURSE_MAX_AID_LENGTH 16
96 static uint8_t defaultAID[CIPURSE_MAX_AID_LENGTH] = CIPURSE_DEFAULT_AID;
97 static size_t defaultAIDLength = 5;
98 static uint16_t defaultFileId = 0x2ff7;
100 static int CmdHelp(const char *Cmd);
102 static int SelectAndPrintInfoFile(void) {
103 uint8_t buf[APDU_RES_LEN] = {0};
104 size_t len = 0;
105 uint16_t sw = 0;
107 int res = CIPURSESelectFile(0x2ff7, buf, sizeof(buf), &len, &sw);
108 if (res != 0 || sw != ISO7816_OK)
109 return PM3_EAPDU_FAIL;
111 res = CIPURSEReadBinary(0, buf, sizeof(buf), &len, &sw);
112 if (res != 0 || sw != ISO7816_OK)
113 return PM3_EAPDU_FAIL;
115 if (len > 0) {
116 PrintAndLogEx(INFO, "Info file ( " _GREEN_("ok") " )");
118 PrintAndLogEx(INFO, " # | bytes | ascii");
119 PrintAndLogEx(INFO, "---+-------------------------------------------------+-----------------");
120 print_hex_break(buf, len, 16);
121 PrintAndLogEx(NORMAL, "");
122 CIPURSEPrintInfoFile(buf, len);
123 PrintAndLogEx(INFO, "");
125 return PM3_SUCCESS;
128 static int CmdHFCipurseInfo(const char *Cmd) {
129 CLIParserContext *ctx;
130 CLIParserInit(&ctx, "hf cipurse info",
131 "Get info from CIPURSE tags",
132 "hf cipurse info");
134 void *argtable[] = {
135 arg_param_begin,
136 arg_param_end
138 CLIExecWithReturn(ctx, Cmd, argtable, true);
139 CLIParserFree(ctx);
141 // info about 14a part
142 infoHF14A(false, false, false);
144 // CIPURSE info
145 PrintAndLogEx(INFO, "------------------- " _CYAN_("CIPURSE Info") " --------------------");
146 SetAPDULogging(false);
148 uint8_t buf[APDU_RES_LEN] = {0};
149 size_t len = 0;
150 uint16_t sw = 0;
152 bool mfExist = false;
153 bool infoPrinted = false;
154 int res = CIPURSESelectMFEx(true, true, buf, sizeof(buf), &len, &sw);
155 if (res == PM3_SUCCESS && sw == ISO7816_OK) {
156 mfExist = true;
157 PrintAndLogEx(INFO, _YELLOW_("MasterFile") " exist and can be selected.");
159 res = SelectAndPrintInfoFile();
160 infoPrinted = (res == PM3_SUCCESS);
163 for (int i = 0; i < ARRAYLEN(PxSE_AID_LIST); i++) {
164 res = CIPURSESelectAID(false, true, (uint8_t *)PxSE_AID_LIST[i].aid, PxSE_AID_LENGTH, buf, sizeof(buf), &len, &sw);
165 if (res == PM3_SUCCESS && sw == ISO7816_OK) {
166 mfExist = true;
167 PrintAndLogEx(INFO, _CYAN_("PxSE") " exist: %s", PxSE_AID_LIST[i].name);
168 if (len > 0) {
169 PrintAndLogEx(INFO, "PxSE data:");
170 TLVPrintFromBuffer(buf, len);
172 PrintAndLogEx(INFO, "");
176 res = CIPURSESelect(false, true, buf, sizeof(buf), &len, &sw);
177 if (res) {
178 DropField();
179 return res;
181 PrintAndLogEx(INFO, "Application `" _YELLOW_("AF F1") "` selected " _GREEN_("successfully"));
183 if (sw != ISO7816_OK) {
184 if (sw == 0x0000) {
185 PrintAndLogEx(ERR, "APDU exchange error. Card returns 0x0000");
186 } else {
187 if (!mfExist)
188 PrintAndLogEx(INFO, "Not a CIPURSE card. APDU response: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
189 else
190 PrintAndLogEx(INFO, "Unknown AID and MasterFile can be selected. Maybe CIPURSE card in the " _CYAN_("perso") " state");
193 DropField();
194 return PM3_SUCCESS;
197 PrintAndLogEx(INFO, "Cipurse card ( " _GREEN_("ok") " )");
199 if (!infoPrinted) {
200 res = SelectAndPrintInfoFile();
201 if (res != PM3_SUCCESS) {
202 DropField();
203 return PM3_SUCCESS;
207 DropField();
208 return PM3_SUCCESS;
211 static int CLIParseCommandParametersEx(CLIParserContext *ctx, size_t keyid, size_t aidid, size_t fidid, size_t chfidid, size_t sreqid, size_t srespid,
212 uint8_t *key, uint8_t *aid, size_t *aidlen, bool *useaid, uint16_t *fid, bool *usefid, uint16_t *chfid, bool *usechfid,
213 CipurseChannelSecurityLevel *sreq, CipurseChannelSecurityLevel *sresp) {
214 uint8_t hdata[250] = {0};
215 int hdatalen = sizeof(hdata);
216 if (keyid) {
217 if (CLIParamHexToBuf(arg_get_str(ctx, keyid), hdata, hdatalen, &hdatalen)) {
218 return PM3_ESOFT;
221 if (hdatalen && hdatalen != 16) {
222 PrintAndLogEx(ERR, _RED_("ERROR:") " key length for AES128 must be 16 bytes only");
223 return PM3_EINVARG;
226 if (hdatalen)
227 memcpy(key, hdata, CIPURSE_AES_KEY_LENGTH);
228 else
229 memcpy(key, defaultKey, sizeof(defaultKey));
232 if (useaid) {
233 *useaid = false;
236 if (aidid && aid && aidlen) {
237 hdatalen = sizeof(hdata);
238 if (CLIParamHexToBuf(arg_get_str(ctx, aidid), hdata, hdatalen, &hdatalen)) {
239 return PM3_ESOFT;
242 if (hdatalen && (hdatalen < 1 || hdatalen > 16)) {
243 PrintAndLogEx(ERR, _RED_("ERROR:") " application id length must be 1-16 bytes only");
244 return PM3_EINVARG;
247 *aidlen = 0;
248 if (hdatalen) {
249 memcpy(aid, hdata, hdatalen);
250 *aidlen = hdatalen;
251 if (useaid) {
252 *useaid = true;
254 } else {
255 memcpy(aid, defaultAID, defaultAIDLength);
256 *aidlen = defaultAIDLength;
260 if (usefid) {
261 *usefid = false;
264 if (fidid && fid) {
265 hdatalen = sizeof(hdata);
266 if (CLIParamHexToBuf(arg_get_str(ctx, fidid), hdata, hdatalen, &hdatalen))
267 return PM3_ESOFT;
269 if (hdatalen && hdatalen != 2) {
270 PrintAndLogEx(ERR, _RED_("ERROR:") " file id length must be 2 bytes only");
271 return PM3_EINVARG;
274 *fid = 0;
275 if (hdatalen) {
276 *fid = (hdata[0] << 8) + hdata[1];
277 if (usefid)
278 *usefid = true;
282 if (usechfid)
283 *usechfid = false;
284 if (chfidid && chfid) {
285 hdatalen = sizeof(hdata);
286 if (CLIParamHexToBuf(arg_get_str(ctx, chfidid), hdata, hdatalen, &hdatalen))
287 return PM3_ESOFT;
288 if (hdatalen && hdatalen != 2) {
289 PrintAndLogEx(ERR, _RED_("ERROR:") " child file id length must be 2 bytes only");
290 return PM3_EINVARG;
293 *chfid = defaultFileId;
294 if (hdatalen) {
295 *chfid = (hdata[0] << 8) + hdata[1];
296 if (usechfid)
297 *usechfid = true;
301 if (sreqid && srespid && sreq && sresp) {
302 *sreq = CPSMACed;
303 *sresp = CPSMACed;
305 char cdata[250] = {0};
306 int cdatalen = sizeof(cdata);
307 cdatalen--; // for trailer 0x00
308 if (CLIParamStrToBuf(arg_get_str(ctx, sreqid), (uint8_t *)cdata, cdatalen, &cdatalen))
309 return PM3_ESOFT;
311 if (cdatalen) {
312 str_lower(cdata);
313 if (strcmp(cdata, "plain") == 0)
314 *sreq = CPSPlain;
315 else if (strcmp(cdata, "mac") == 0)
316 *sreq = CPSMACed;
317 else if (strcmp(cdata, "enc") == 0 || strcmp(cdata, "encode") == 0 || strcmp(cdata, "encrypted") == 0)
318 *sreq = CPSEncrypted;
319 else {
320 PrintAndLogEx(ERR, _RED_("ERROR:") " security level can be only: plain | mac | encode");
321 return PM3_EINVARG;
325 cdatalen = sizeof(cdata);
326 memset(cdata, 0, cdatalen);
327 cdatalen--; // for trailer 0x00
328 if (CLIParamStrToBuf(arg_get_str(ctx, srespid), (uint8_t *)cdata, cdatalen, &cdatalen))
329 return PM3_ESOFT;
331 if (cdatalen) {
332 str_lower(cdata);
333 if (strcmp(cdata, "plain") == 0)
334 *sresp = CPSPlain;
335 else if (strcmp(cdata, "mac") == 0)
336 *sresp = CPSMACed;
337 else if (strcmp(cdata, "enc") == 0 || strcmp(cdata, "encode") == 0 || strcmp(cdata, "encrypted") == 0)
338 *sresp = CPSEncrypted;
339 else {
340 PrintAndLogEx(ERR, _RED_("ERROR:") " security level can be only: plain | mac | encode");
341 return PM3_EINVARG;
346 return PM3_SUCCESS;
349 static int CLIParseCommandParameters(CLIParserContext *ctx, size_t keyid, size_t aidid, size_t fidid, size_t sreqid, size_t srespid,
350 uint8_t *key, uint8_t *aid, size_t *aidlen, bool *useaid, uint16_t *fid, bool *usefid,
351 CipurseChannelSecurityLevel *sreq, CipurseChannelSecurityLevel *sresp) {
352 return CLIParseCommandParametersEx(ctx, keyid, aidid, fidid, 0, sreqid, srespid,
353 key, aid, aidlen, useaid, fid, usefid, NULL, NULL, sreq, sresp);
356 static int SelectCommandEx(bool selectDefaultFile, bool useAID, uint8_t *aid, size_t aidLen, bool useFID, uint16_t fileId,
357 bool selChildFile, uint16_t childFileId, bool verbose,
358 uint8_t *buf, size_t bufSize, size_t *len, uint16_t *sw) {
359 int res = 0;
360 if (verbose && selChildFile)
361 PrintAndLogEx(INFO, "Select top level application/file");
363 if (useAID && aidLen > 0) {
365 res = CIPURSESelectAID(true, true, aid, aidLen, buf, bufSize, len, sw);
366 if (res != 0 || *sw != ISO7816_OK) {
367 if (verbose) {
368 PrintAndLogEx(ERR, "Cipurse select application " _GREEN_("%s ") _RED_("error") ". Card returns 0x%04x", sprint_hex_inrow(aid, aidLen), *sw);
370 return PM3_ESOFT;
372 if (verbose) {
373 PrintAndLogEx(INFO, "Cipurse select application " _YELLOW_("%s ") " ( %s )", sprint_hex_inrow(aid, aidLen), _GREEN_("ok"));
376 } else if (useFID) {
378 res = CIPURSESelectFileEx(true, true, fileId, buf, bufSize, len, sw);
379 if (res != 0 || *sw != ISO7816_OK) {
380 if (verbose) {
381 PrintAndLogEx(ERR, "Cipurse select file 0x%04x ( %s )", fileId, _RED_("fail"));
382 PrintAndLogEx(ERR, "Card returns 0x%04x", *sw);
384 return PM3_ESOFT;
386 if (verbose) {
387 PrintAndLogEx(INFO, "Cipurse select file " _YELLOW_("0x%04X ") " ( " _GREEN_("ok") " )", fileId);
390 } else if (selectDefaultFile) {
392 res = CIPURSESelectMFDefaultFileEx(true, true, buf, bufSize, len, sw);
393 if (res != 0 || *sw != ISO7816_OK) {
394 if (verbose) {
395 PrintAndLogEx(ERR, "Cipurse select default file " _RED_("error") ". Card returns 0x%04x", *sw);
397 return PM3_ESOFT;
399 if (verbose) {
400 PrintAndLogEx(INFO, "Cipurse select default file ( " _GREEN_("ok") " )");
403 } else {
405 res = CIPURSESelect(true, true, buf, bufSize, len, sw);
406 if (res != 0 || *sw != ISO7816_OK) {
407 if (verbose) {
408 PrintAndLogEx(ERR, "Cipurse select default application " _RED_("error") ". Card returns 0x%04x", *sw);
410 return PM3_ESOFT;
412 if (verbose) {
413 PrintAndLogEx(INFO, "Cipurse select default application ( " _GREEN_("ok") " )");
417 if (selChildFile) {
418 if (verbose) {
419 PrintAndLogEx(INFO, "Select child file");
422 res = CIPURSESelectFileEx(false, true, childFileId, buf, bufSize, len, sw);
423 if (res != 0 || *sw != ISO7816_OK) {
424 if (verbose) {
425 PrintAndLogEx(ERR, "Select child file 0x%04x " _RED_("error") ". Card returns 0x%04x", childFileId, *sw);
427 return PM3_ESOFT;
429 if (verbose) {
430 PrintAndLogEx(INFO, "Select child file " _CYAN_("0x%04x ") " ( " _GREEN_("ok") " )", childFileId);
434 return PM3_SUCCESS;
437 static int SelectCommand(bool selectDefaultFile, bool useAID, uint8_t *aid, size_t aidLen, bool useFID, uint16_t fileId, bool verbose,
438 uint8_t *buf, size_t bufSize, size_t *len, uint16_t *sw) {
439 return SelectCommandEx(selectDefaultFile, useAID, aid, aidLen, useFID, fileId, false, 0, verbose, buf, bufSize, len, sw);
442 static int CmdHFCipurseSelect(const char *Cmd) {
443 CLIParserContext *ctx;
444 CLIParserInit(&ctx, "hf cipurse select",
445 "Select application or file",
446 "hf cipurse select --aid A0000005070100 -> Select PTSE application by AID\n"
447 "hf cipurse select --fid 3f00 -> Select master file by FID 3f00\n"
448 "hf cipurse select --fid 2ff7 -> Select attribute file by FID 2ff7\n"
449 "hf cipurse select --mfd -vt -> Select default file by empty FID and show response data in plain and TLV decoded format\n");
451 void *argtable[] = {
452 arg_param_begin,
453 arg_lit0("a", "apdu", "Show APDU requests and responses"),
454 arg_lit0("v", "verbose", "Verbose mode"),
455 arg_lit0("t", "tlv", "TLV decode returned data"),
456 arg_str0(NULL, "aid", "<hex>", "Application ID (AID) 1..16 bytes"),
457 arg_str0(NULL, "fid", "<hex>", "Top level file (or application) ID (FID) 2 bytes"),
458 arg_lit0(NULL, "mfd", "Select masterfile by empty id"),
459 arg_str0(NULL, "chfid", "<hex>", "Child file ID (EF under application/master file) 2 bytes"),
460 arg_param_end
462 CLIExecWithReturn(ctx, Cmd, argtable, true);
464 bool APDULogging = arg_get_lit(ctx, 1);
465 bool verbose = arg_get_lit(ctx, 2);
466 bool showTLV = arg_get_lit(ctx, 3);
468 uint8_t aid[16] = {0};
469 size_t aidLen = 0;
470 bool useAID = false;
471 uint16_t fileId = 0;
472 bool useFID = false;
473 uint16_t childFileId = defaultFileId;
474 bool useChildFID = false;
475 int res = CLIParseCommandParametersEx(ctx, 0, 4, 5, 7, 0, 0, NULL, aid, &aidLen, &useAID, &fileId, &useFID, &childFileId, &useChildFID, NULL, NULL);
476 if (res || (useAID && useFID)) {
477 CLIParserFree(ctx);
478 return PM3_EINVARG;
481 bool selmfd = arg_get_lit(ctx, 6);
483 CLIParserFree(ctx);
485 SetAPDULogging(APDULogging);
487 uint8_t buf[APDU_RES_LEN] = {0};
488 size_t len = 0;
489 uint16_t sw = 0;
490 res = SelectCommandEx(selmfd, useAID, aid, aidLen, useFID, fileId, useChildFID, childFileId, true, buf, sizeof(buf), &len, &sw);
491 if (res != 0 || sw != ISO7816_OK) {
492 DropField();
493 return PM3_ESOFT;
496 if (len > 0) {
497 if (verbose) {
498 PrintAndLogEx(INFO, "File data:");
499 print_buffer(buf, len, 1);
502 if (showTLV)
503 TLVPrintFromBuffer(buf, len);
506 DropField();
507 return PM3_SUCCESS;
510 static int CmdHFCipurseAuth(const char *Cmd) {
511 CLIParserContext *ctx;
512 CLIParserInit(&ctx, "hf cipurse auth",
513 "Authenticate with key ID and key. If no key is supplied, default key of 737373...7373 will be used",
514 "hf cipurse auth -> Authenticate with keyID 1, default key\n"
515 "hf cipurse auth -n 2 -k 65656565656565656565656565656565 -> Authenticate keyID 2 with key\n");
517 void *argtable[] = {
518 arg_param_begin,
519 arg_lit0("a", "apdu", "Show APDU requests and responses"),
520 arg_lit0("v", "verbose", "Verbose mode"),
521 arg_str0(NULL, "aid", "<hex>", "Application ID (AID) ( 1..16 bytes )"),
522 arg_str0(NULL, "fid", "<hex>", "Top file/application ID (FID) ( 2 bytes )"),
523 arg_lit0(NULL, "mfd", "Select masterfile by empty id"),
524 arg_int0("n", NULL, "<dec>", "Key ID"),
525 arg_str0("k", "key", "<hex>", "Auth key"),
526 arg_param_end
528 CLIExecWithReturn(ctx, Cmd, argtable, true);
530 bool APDULogging = arg_get_lit(ctx, 1);
531 bool verbose = arg_get_lit(ctx, 2);
533 uint8_t key[CIPURSE_AES_KEY_LENGTH] = {0};
534 uint8_t aid[16] = {0};
535 size_t aidLen = 0;
536 bool useAID = false;
537 uint16_t fileId = defaultFileId;
538 bool useFID = false;
539 int res = CLIParseCommandParameters(ctx, 7, 3, 4, 0, 0, key, aid, &aidLen, &useAID, &fileId, &useFID, NULL, NULL);
540 if (res || (useAID && useFID)) {
541 CLIParserFree(ctx);
542 return PM3_EINVARG;
545 bool selmfd = arg_get_lit(ctx, 5);
546 uint8_t keyId = arg_get_int_def(ctx, 6, defaultKeyId);
548 CLIParserFree(ctx);
550 SetAPDULogging(APDULogging);
552 size_t len = 0;
553 uint16_t sw = 0;
554 uint8_t buf[APDU_RES_LEN] = {0};
556 res = SelectCommand(selmfd, useAID, aid, aidLen, useFID, fileId, true, buf, sizeof(buf), &len, &sw);
557 if (res != 0 || sw != ISO7816_OK) {
558 DropField();
559 return PM3_ESOFT;
562 uint8_t kvv[CIPURSE_KVV_LENGTH] = {0};
563 CipurseCGetKVV(key, kvv);
564 if (verbose) {
565 PrintAndLogEx(INFO, "Key id " _YELLOW_("%d") " key " _YELLOW_("%s") " KVV " _YELLOW_("%s")
566 , keyId
567 , sprint_hex(key, CIPURSE_AES_KEY_LENGTH)
568 , sprint_hex_inrow(kvv, CIPURSE_KVV_LENGTH)
572 bool bres = CIPURSEChannelAuthenticate(keyId, key, verbose);
574 if (verbose == false) {
575 PrintAndLogEx(INFO, "Authentication ( %s ) ", (bres) ? _GREEN_("ok") : _RED_("fail"));
578 DropField();
579 return (bres) ? PM3_SUCCESS : PM3_ESOFT;
582 static int CmdHFCipurseReadFile(const char *Cmd) {
583 CLIParserContext *ctx;
584 CLIParserInit(&ctx, "hf cipurse read",
585 "Read file in the application by file ID with key ID and key. If no key is supplied, default key of 737373...7373 will be used",
586 "hf cipurse read --fid 2ff7 -> Authenticate with keyID 1, read file with id 2ff7\n"
587 "hf cipurse read -n 2 -k 65656565656565656565656565656565 --fid 2ff7 -> Authenticate keyID 2 and read file\n"
588 "hf cipurse read --aid 4144204631 --fid 0102 -> read file with id 0102 from application 4144204631\n");
590 void *argtable[] = {
591 arg_param_begin,
592 arg_lit0("a", "apdu", "Show APDU requests and responses"),
593 arg_lit0("v", "verbose", "Verbose mode"),
594 arg_int0("n", NULL, "<dec>", "Key ID"),
595 arg_str0("k", "key", "<hex>", "Auth key"),
596 arg_str0(NULL, "aid", "<hex>", "Application ID (AID) ( 1..16 bytes )"),
597 arg_str0(NULL, "fid", "<hex>", "File ID"),
598 arg_int0("o", "offset", "<dec>", "Offset for reading data from file"),
599 arg_lit0(NULL, "noauth", "Read file without authentication"),
600 arg_str0(NULL, "sreq", "<plain|mac|encode>", "Communication reader-PICC security level (def: mac)"),
601 arg_str0(NULL, "sresp", "<plain|mac|encode>", "Communication PICC-reader security level (def: mac)"),
602 arg_param_end
604 CLIExecWithReturn(ctx, Cmd, argtable, true);
607 bool APDULogging = arg_get_lit(ctx, 1);
608 bool verbose = arg_get_lit(ctx, 2);
609 uint8_t keyId = arg_get_int_def(ctx, 3, defaultKeyId);
611 CipurseChannelSecurityLevel sreq = CPSMACed;
612 CipurseChannelSecurityLevel sresp = CPSMACed;
613 uint8_t key[CIPURSE_AES_KEY_LENGTH] = {0};
615 uint8_t aid[16] = {0};
616 size_t aidLen = 0;
617 bool useAID = false;
618 uint16_t fileId = defaultFileId;
619 bool useFID = false;
620 int res = CLIParseCommandParameters(ctx, 4, 5, 6, 9, 10, key, aid, &aidLen, &useAID, &fileId, &useFID, &sreq, &sresp);
621 if (res || useFID == false) {
622 CLIParserFree(ctx);
623 return PM3_EINVARG;
626 size_t offset = arg_get_int_def(ctx, 7, 0);
628 bool noAuth = arg_get_lit(ctx, 8);
630 SetAPDULogging(APDULogging);
632 CLIParserFree(ctx);
634 size_t len = 0;
635 uint16_t sw = 0;
636 uint8_t buf[APDU_RES_LEN] = {0};
638 res = CIPURSESelectAID(true, true, aid, aidLen, buf, sizeof(buf), &len, &sw);
639 if (res != 0 || sw != ISO7816_OK) {
640 PrintAndLogEx(ERR, "Cipurse select application " _CYAN_("%s") " ( " _RED_("error") " ). Card returns 0x%04x", sprint_hex_inrow(aid, aidLen), sw);
641 DropField();
642 return PM3_ESOFT;
645 if (verbose) {
646 PrintAndLogEx(INFO, "Cipurse select application " _CYAN_("%s") " ( %s )", sprint_hex_inrow(aid, aidLen), _GREEN_("ok"));
647 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));
650 res = CIPURSESelectFile(fileId, buf, sizeof(buf), &len, &sw);
651 if (res != 0 || sw != ISO7816_OK) {
652 if (verbose == false)
653 PrintAndLogEx(ERR, "File select ( " _RED_("error") " ). Card returns 0x%04x", sw);
654 DropField();
655 return PM3_ESOFT;
658 if (verbose)
659 PrintAndLogEx(INFO, "Select file 0x%x ( %s )", fileId, _GREEN_("ok"));
661 if (noAuth == false) {
662 bool bres = CIPURSEChannelAuthenticate(keyId, key, verbose);
663 if (bres == false) {
664 if (verbose == false)
665 PrintAndLogEx(ERR, "Authentication ( " _RED_("fail") " )");
666 DropField();
667 return PM3_ESOFT;
670 // set channel security levels
671 CIPURSECSetActChannelSecurityLevels(sreq, sresp);
674 res = CIPURSEReadBinary(offset, buf, sizeof(buf), &len, &sw);
675 if (res != 0 || sw != ISO7816_OK) {
676 if (verbose == false)
677 PrintAndLogEx(ERR, "File read " _RED_("ERROR") ". Card returns 0x%04x", sw);
678 DropField();
679 return PM3_ESOFT;
682 if (len == 0)
683 PrintAndLogEx(INFO, "File id " _YELLOW_("%x") " is empty", fileId);
684 else
685 PrintAndLogEx(INFO, "File id " _YELLOW_("%x") " data[%zu]: %s", fileId, len, sprint_hex(buf, len));
687 DropField();
688 return PM3_SUCCESS;
691 static int CmdHFCipurseWriteFile(const char *Cmd) {
692 CLIParserContext *ctx;
693 CLIParserInit(&ctx, "hf cipurse write",
694 "Write file in the application by file ID with key ID and key. If no key is supplied, default key of 737373...7373 will be used",
695 "hf cipurse write --fid 2ff7 -d aabb -> Authenticate with keyID 1, write file with id 2ff7\n"
696 "hf cipurse write -n 2 -k 65656565656565656565656565656565 --fid 2ff7 -d aabb -> Authenticate keyID 2 and write file\n"
697 "hf cipurse write --aid 4144204631 --fid 0102 -d aabb -> write file with id 0102 in the 4144204631 application\n"
698 "hf cipurse write --fid 0102 -d aabb --commit -> write file with id 0102 and perform commit after write\n");
700 void *argtable[] = {
701 arg_param_begin,
702 arg_lit0("a", "apdu", "Show APDU requests and responses"),
703 arg_lit0("v", "verbose", "Verbose mode"),
704 arg_int0("n", NULL, "<dec>", "Key ID"),
705 arg_str0("k", "key", "<hex>", "Auth key"),
706 arg_str0(NULL, "aid", "<hex>", "Application ID (AID) ( 1..16 bytes )"),
707 arg_str0(NULL, "fid", "<hex>", "File ID"),
708 arg_int0("o", "offset", "<dec>", "Offset for reading data from file"),
709 arg_lit0(NULL, "noauth", "Read file without authentication"),
710 arg_str0(NULL, "sreq", "<plain|mac|encode>", "Communication reader-PICC security level (def: mac)"),
711 arg_str0(NULL, "sresp", "<plain|mac|encode>", "Communication PICC-reader security level (def: mac)"),
712 arg_str0("d", "data", "<hex>", "Data to write to new file"),
713 arg_lit0(NULL, "commit", "Commit after write"),
714 arg_param_end
716 CLIExecWithReturn(ctx, Cmd, argtable, true);
718 bool APDULogging = arg_get_lit(ctx, 1);
719 bool verbose = arg_get_lit(ctx, 2);
720 uint8_t keyId = arg_get_int_def(ctx, 3, defaultKeyId);
722 CipurseChannelSecurityLevel sreq = CPSMACed;
723 CipurseChannelSecurityLevel sresp = CPSMACed;
725 uint8_t key[CIPURSE_AES_KEY_LENGTH] = {0};
727 uint8_t aid[16] = {0};
728 size_t aidLen = 0;
729 bool useAID = false;
730 uint16_t fileId = defaultFileId;
731 bool useFID = false;
732 int res = CLIParseCommandParameters(ctx, 4, 5, 6, 9, 10, key, aid, &aidLen, &useAID, &fileId, &useFID, &sreq, &sresp);
733 if (res || useFID == false) {
734 CLIParserFree(ctx);
735 return PM3_EINVARG;
738 size_t offset = arg_get_int_def(ctx, 7, 0);
740 bool noAuth = arg_get_lit(ctx, 8);
742 uint8_t hdata[250] = {0};
743 int hdatalen = sizeof(hdata);
744 CLIGetHexWithReturn(ctx, 11, hdata, &hdatalen);
745 if (hdatalen == 0) {
746 PrintAndLogEx(ERR, _RED_("ERROR:") " file content length must be more 0");
747 CLIParserFree(ctx);
748 return PM3_EINVARG;
751 bool needCommit = arg_get_lit(ctx, 12);
753 CLIParserFree(ctx);
755 SetAPDULogging(APDULogging);
757 size_t len = 0;
758 uint16_t sw = 0;
759 uint8_t buf[APDU_RES_LEN] = {0};
761 res = CIPURSESelectAID(true, true, aid, aidLen, buf, sizeof(buf), &len, &sw);
762 if (res != 0 || sw != ISO7816_OK) {
763 PrintAndLogEx(ERR, "Cipurse select application " _CYAN_("%s") " ( " _RED_("error") " ). Card returns 0x%04x", sprint_hex_inrow(aid, aidLen), sw);
764 DropField();
765 return PM3_ESOFT;
768 if (verbose) {
769 PrintAndLogEx(INFO, "Cipurse select application " _CYAN_("%s") " ( %s )", sprint_hex_inrow(aid, aidLen), _GREEN_("ok"));
770 PrintAndLogEx(INFO, "File id " _YELLOW_("%x") " offset " _YELLOW_("%zu") " key id " _YELLOW_("%d") " key " _YELLOW_("%s")
771 , fileId
772 , offset
773 , keyId
774 , sprint_hex(key, CIPURSE_AES_KEY_LENGTH)
776 PrintAndLogEx(INFO, "Data [%d]: %s", hdatalen, sprint_hex(hdata, hdatalen));
779 res = CIPURSESelectFile(fileId, buf, sizeof(buf), &len, &sw);
780 if (res != 0 || sw != ISO7816_OK) {
781 if (verbose == false)
782 PrintAndLogEx(ERR, "File select " _RED_("ERROR") ". Card returns 0x%04x", sw);
783 DropField();
784 return PM3_ESOFT;
787 if (verbose)
788 PrintAndLogEx(INFO, "Select file 0x%x ( %s )", fileId, _GREEN_("ok"));
790 if (noAuth == false) {
791 bool bres = CIPURSEChannelAuthenticate(keyId, key, verbose);
792 if (bres == false) {
793 if (verbose == false)
794 PrintAndLogEx(ERR, "Authentication ( " _RED_("fail") " )");
795 DropField();
796 return PM3_ESOFT;
799 // set channel security levels
800 CIPURSECSetActChannelSecurityLevels(sreq, sresp);
803 res = CIPURSEUpdateBinary(offset, hdata, hdatalen, buf, sizeof(buf), &len, &sw);
804 if (res != 0 || sw != ISO7816_OK) {
805 if (verbose == false)
806 PrintAndLogEx(ERR, "File write " _RED_("ERROR") ". Card returns 0x%04x", sw);
807 DropField();
808 return PM3_ESOFT;
811 PrintAndLogEx(INFO, "File id " _YELLOW_("%x") " successfully written", fileId);
813 if (needCommit) {
814 sw = 0;
815 res = CIPURSECommitTransaction(&sw);
816 if (res != 0 || sw != ISO7816_OK)
817 PrintAndLogEx(WARNING, "Commit ( " _YELLOW_("fail") " ) Card returns 0x%04x", sw);
819 if (verbose)
820 PrintAndLogEx(INFO, "Commit ( " _GREEN_("ok") " )");
823 DropField();
824 return PM3_SUCCESS;
827 static int CmdHFCipurseReadFileAttr(const char *Cmd) {
828 CLIParserContext *ctx;
829 CLIParserInit(&ctx, "hf cipurse aread",
830 "Read file attributes by file ID with key ID and key. If no key is supplied, default key of 737373...7373 will be used",
831 "hf cipurse aread --fid 2ff7 -> Select MF, Authenticate with keyID 1, read file attributes with id 2ff7\n"
832 "hf cipurse aread --mfd -> read file attributes for master file (MF)\n"
833 "hf cipurse aread --chfid 0102 -> read file 0102 attributes in the default application\n"
834 "hf cipurse aread --aid 4144204632 --chfid 0102 -> read file 0102 attributes in the 4144204632 application\n"
835 "hf cipurse aread -n 2 -k 65656565656565656565656565656565 --fid 2ff7 -> Authenticate keyID 2, read file attributes\n");
837 void *argtable[] = {
838 arg_param_begin,
839 arg_lit0("a", "apdu", "Show APDU requests and responses"),
840 arg_lit0("v", "verbose", "Verbose mode"),
841 arg_int0("n", NULL, "<dec>", "Key ID"),
842 arg_str0("k", "key", "<hex>", "Auth key"),
843 arg_lit0(NULL, "mfd", "Show info about master file"),
844 arg_str0(NULL, "aid", "<hex>", "Select application ID (AID) ( 1..16 bytes )"),
845 arg_str0(NULL, "fid", "<hex>", "File ID"),
846 arg_str0(NULL, "chfid", "<hex>", "Child file ID (EF under application/master file) ( 2 bytes )"),
847 arg_lit0(NULL, "noauth", "Read file attributes without authentication"),
848 arg_str0(NULL, "sreq", "<plain|mac|encode>", "Communication reader-PICC security level (def: mac)"),
849 arg_str0(NULL, "sresp", "<plain|mac|encode>", "Communication PICC-reader security level (def: mac)"),
850 arg_param_end
852 CLIExecWithReturn(ctx, Cmd, argtable, true);
854 bool APDULogging = arg_get_lit(ctx, 1);
855 bool verbose = arg_get_lit(ctx, 2);
856 uint8_t keyId = arg_get_int_def(ctx, 3, defaultKeyId);
857 bool selmfd = arg_get_lit(ctx, 5);
859 CipurseChannelSecurityLevel sreq = CPSMACed;
860 CipurseChannelSecurityLevel sresp = CPSMACed;
861 uint8_t key[CIPURSE_AES_KEY_LENGTH] = {0};
863 uint8_t aid[16] = {0};
864 size_t aidLen = 0;
865 bool useAID = false;
866 uint16_t fileId = defaultFileId;
867 bool useFID = false;
868 uint16_t childFileId = defaultFileId;
869 bool useChildFID = false;
870 int res = CLIParseCommandParametersEx(ctx, 4, 6, 7, 8, 10, 11, key, aid, &aidLen, &useAID, &fileId, &useFID, &childFileId, &useChildFID, &sreq, &sresp);
871 if (res) {
872 CLIParserFree(ctx);
873 return PM3_EINVARG;
876 bool noAuth = arg_get_lit(ctx, 9);
878 CLIParserFree(ctx);
880 SetAPDULogging(APDULogging);
882 uint8_t buf[APDU_RES_LEN] = {0};
883 size_t len = 0;
884 uint16_t sw = 0;
886 res = SelectCommandEx(selmfd, useAID, aid, aidLen, useFID, fileId, useChildFID, childFileId, verbose, buf, sizeof(buf), &len, &sw);
887 if (res != 0 || sw != ISO7816_OK) {
888 PrintAndLogEx(ERR, "Select command ( " _RED_("error") " )");
889 DropField();
890 return PM3_ESOFT;
893 if (verbose) {
894 if (selmfd)
895 PrintAndLogEx(INFO, "File " _CYAN_("Master File"));
896 else if (useFID)
897 PrintAndLogEx(INFO, "File id " _CYAN_("%04x"), fileId);
898 else
899 PrintAndLogEx(INFO, "Application ID " _CYAN_("%s"), sprint_hex_inrow(aid, aidLen));
901 if (useChildFID)
902 PrintAndLogEx(INFO, "Child file id " _CYAN_("%04x"), childFileId);
904 if (!noAuth)
905 PrintAndLogEx(INFO, "Key id " _YELLOW_("%d") " key " _YELLOW_("%s")
906 , keyId
907 , sprint_hex(key, CIPURSE_AES_KEY_LENGTH)
911 if (noAuth == false) {
912 bool bres = CIPURSEChannelAuthenticate(keyId, key, verbose);
913 if (bres == false) {
914 if (verbose == false)
915 PrintAndLogEx(ERR, "Authentication ( " _RED_("fail") " )");
916 DropField();
917 return PM3_ESOFT;
920 // set channel security levels
921 CIPURSECSetActChannelSecurityLevels(sreq, sresp);
924 res = CIPURSEReadFileAttributes(buf, sizeof(buf), &len, &sw);
925 if (res != 0 || sw != ISO7816_OK) {
926 if (verbose == false)
927 PrintAndLogEx(ERR, "File read " _RED_("ERROR") ". Card returns 0x%04x", sw);
928 DropField();
929 return PM3_ESOFT;
932 if (len == 0) {
933 PrintAndLogEx(WARNING, "File attributes is empty");
934 DropField();
935 return PM3_SUCCESS;
938 if (verbose)
939 PrintAndLogEx(INFO, "Attributes raw data [%zu]: %s", len, sprint_hex(buf, len));
941 CIPURSEPrintFileAttr(buf, len);
943 DropField();
944 return PM3_SUCCESS;
947 static int CmdHFCipurseWriteFileAttr(const char *Cmd) {
948 CLIParserContext *ctx;
949 CLIParserInit(&ctx, "hf cipurse awrite",
950 "Write file attributes by file ID with key ID and key. If no key is supplied, default key of 737373...7373 will be used",
951 "hf cipurse awrite --fid 2ff7 -d 080000C1C1C1C1C1C1C1C1C1 -> write default file attributes with id 2ff7\n"
952 "hf cipurse awrite --mfd -d 080000FFFFFFFFFFFFFFFFFF86023232 --commit -> write file attributes for master file (MF)\n"
953 "hf cipurse awrite --chfid 0102 -d 020000ffffff -> write file 0102 attributes in the default application to full access\n"
954 "hf cipurse awrite --chfid 0102 -d 02000040ffff -> write file 0102 attributes in the default application to full access with keys 1 and 2\n");
956 void *argtable[] = {
957 arg_param_begin,
958 arg_lit0("a", "apdu", "Show APDU requests and responses"),
959 arg_lit0("v", "verbose", "Verbose mode"),
960 arg_int0("n", NULL, "<dec>", "Key ID"),
961 arg_str0("k", "key", "<hex>", "Auth key"),
962 arg_lit0(NULL, "mfd", "Show info about master file"),
963 arg_str0(NULL, "aid", "<hex>", "Select application ID (AID) ( 1..16 bytes )"),
964 arg_str0(NULL, "fid", "<hex>", "File ID"),
965 arg_str0(NULL, "chfid", "<hex>", "Child file ID (EF under application/master file) ( 2 bytes )"),
966 arg_lit0(NULL, "noauth", "Read file attributes without authentication"),
967 arg_str0(NULL, "sreq", "<plain|mac|encode>", "Communication reader-PICC security level (def: mac)"),
968 arg_str0(NULL, "sresp", "<plain|mac|encode>", "Communication PICC-reader security level (def: mac)"),
969 arg_str0("d", "data", "<hex>", "File attributes"),
970 arg_lit0(NULL, "commit", "Commit after write"),
971 arg_param_end
973 CLIExecWithReturn(ctx, Cmd, argtable, false);
975 bool APDULogging = arg_get_lit(ctx, 1);
976 bool verbose = arg_get_lit(ctx, 2);
977 uint8_t keyId = arg_get_int_def(ctx, 3, defaultKeyId);
978 bool selmfd = arg_get_lit(ctx, 5);
980 CipurseChannelSecurityLevel sreq = CPSMACed;
981 CipurseChannelSecurityLevel sresp = CPSMACed;
982 uint8_t key[CIPURSE_AES_KEY_LENGTH] = {0};
984 uint8_t aid[16] = {0};
985 size_t aidLen = 0;
986 bool useAID = false;
987 uint16_t fileId = defaultFileId;
988 bool useFID = false;
989 uint16_t childFileId = defaultFileId;
990 bool useChildFID = false;
991 int res = CLIParseCommandParametersEx(ctx, 4, 6, 7, 8, 10, 11, key, aid, &aidLen, &useAID, &fileId, &useFID, &childFileId, &useChildFID, &sreq, &sresp);
992 if (res) {
993 CLIParserFree(ctx);
994 return PM3_EINVARG;
997 bool noAuth = arg_get_lit(ctx, 9);
999 uint8_t hdata[250] = {0};
1000 int hdatalen = sizeof(hdata);
1001 CLIGetHexWithReturn(ctx, 12, hdata, &hdatalen);
1002 if (hdatalen == 0) {
1003 PrintAndLogEx(ERR, _RED_("ERROR:") " file attributes length must be more 0");
1004 CLIParserFree(ctx);
1005 return PM3_EINVARG;
1008 bool needCommit = arg_get_lit(ctx, 13);
1010 CLIParserFree(ctx);
1012 SetAPDULogging(APDULogging);
1014 if (verbose) {
1015 PrintAndLogEx(INFO, "Attribtes data[%d]: %s", hdatalen, sprint_hex(hdata, hdatalen));
1016 CIPURSEPrintFileUpdateAttr(hdata, hdatalen);
1019 uint8_t buf[APDU_RES_LEN] = {0};
1020 size_t len = 0;
1021 uint16_t sw = 0;
1023 res = SelectCommandEx(selmfd, useAID, aid, aidLen, useFID, fileId, useChildFID, childFileId, verbose, buf, sizeof(buf), &len, &sw);
1024 if (res != 0 || sw != ISO7816_OK) {
1025 PrintAndLogEx(ERR, "Select command ( " _RED_("error") " )");
1026 DropField();
1027 return PM3_ESOFT;
1030 if (verbose) {
1031 if (selmfd)
1032 PrintAndLogEx(INFO, "File " _CYAN_("Master File"));
1033 else if (useFID)
1034 PrintAndLogEx(INFO, "File id " _CYAN_("%04x"), fileId);
1035 else
1036 PrintAndLogEx(INFO, "Application ID " _CYAN_("%s"), sprint_hex_inrow(aid, aidLen));
1038 if (useChildFID)
1039 PrintAndLogEx(INFO, "Child file id " _CYAN_("%04x"), childFileId);
1041 if (!noAuth)
1042 PrintAndLogEx(INFO, "Key id " _YELLOW_("%d") " key " _YELLOW_("%s")
1043 , keyId
1044 , sprint_hex(key, CIPURSE_AES_KEY_LENGTH)
1048 if (noAuth == false) {
1049 bool bres = CIPURSEChannelAuthenticate(keyId, key, verbose);
1050 if (bres == false) {
1051 if (verbose == false)
1052 PrintAndLogEx(ERR, "Authentication ( " _RED_("fail") " )");
1053 DropField();
1054 return PM3_ESOFT;
1057 // set channel security levels
1058 CIPURSECSetActChannelSecurityLevels(sreq, sresp);
1061 res = CIPURSEUpdateFileAttributes(hdata, hdatalen, buf, sizeof(buf), &len, &sw);
1062 if (res != 0 || sw != ISO7816_OK) {
1063 if (verbose == false)
1064 PrintAndLogEx(ERR, "File attributes update " _RED_("ERROR") ". Card returns 0x%04x", sw);
1065 DropField();
1066 return PM3_ESOFT;
1069 PrintAndLogEx(INFO, "File attributes updated ( " _GREEN_("ok") " )");
1071 if (needCommit) {
1072 sw = 0;
1073 res = CIPURSECommitTransaction(&sw);
1074 if (res != 0 || sw != ISO7816_OK)
1075 PrintAndLogEx(WARNING, "Commit ( " _YELLOW_("fail") " ) Card returns 0x%04x", sw);
1077 if (verbose)
1078 PrintAndLogEx(INFO, "Commit ( " _GREEN_("ok") " )");
1081 DropField();
1082 return PM3_SUCCESS;
1085 static int CmdHFCipurseFormatAll(const char *Cmd) {
1086 CLIParserContext *ctx;
1087 CLIParserInit(&ctx, "hf cipurse formatall",
1088 "Format card. Erases all the data at the card level!",
1089 "hf cipurse formatall -> Format card with default key\n"
1090 "hf cipurse formatall -n 2 -k 65656565656565656565656565656565 -> Format card with keyID 2\n"
1091 "hf cipurse formatall --no-auth -> Format card without authentication. Works for card in perso state\n");
1093 void *argtable[] = {
1094 arg_param_begin,
1095 arg_lit0("a", "apdu", "Show APDU requests and responses"),
1096 arg_lit0("v", "verbose", "Verbose mode"),
1097 arg_int0("n", NULL, "<dec>", "Key ID"),
1098 arg_str0("k", "key", "<hex>", "Auth key"),
1099 arg_str0(NULL, "sreq", "<plain|mac|encode>", "Communication reader-PICC security level (def: mac)"),
1100 arg_str0(NULL, "sresp", "<plain|mac|encode>", "Communication PICC-reader security level (def: mac)"),
1101 arg_lit0(NULL, "no-auth", "Execute without authentication"),
1102 arg_param_end
1104 CLIExecWithReturn(ctx, Cmd, argtable, true);
1106 bool APDULogging = arg_get_lit(ctx, 1);
1107 bool verbose = arg_get_lit(ctx, 2);
1108 uint8_t keyId = arg_get_int_def(ctx, 3, defaultKeyId);
1110 CipurseChannelSecurityLevel sreq = CPSMACed;
1111 CipurseChannelSecurityLevel sresp = CPSMACed;
1112 uint8_t key[CIPURSE_AES_KEY_LENGTH] = {0};
1113 int res = CLIParseCommandParameters(ctx, 4, 0, 0, 5, 6, key, NULL, NULL, NULL, NULL, NULL, &sreq, &sresp);
1114 if (res) {
1115 CLIParserFree(ctx);
1116 return PM3_EINVARG;
1119 bool noauth = arg_get_lit(ctx, 7);
1121 CLIParserFree(ctx);
1122 SetAPDULogging(APDULogging);
1124 uint8_t buf[APDU_RES_LEN] = {0};
1125 size_t len = 0;
1126 uint16_t sw = 0;
1128 res = CIPURSESelectMFEx(true, true, buf, sizeof(buf), &len, &sw);
1129 if (res != 0 || sw != ISO7816_OK) {
1130 PrintAndLogEx(ERR, "Cipurse masterfile select " _RED_("error") ". Card returns 0x%04x", sw);
1131 DropField();
1132 return PM3_ESOFT;
1135 if (verbose) {
1136 PrintAndLogEx(WARNING, _YELLOW_("FORMAT erases all the data at this card!!!"));
1137 if (!noauth)
1138 PrintAndLogEx(INFO, "key id " _YELLOW_("%d") " key " _YELLOW_("%s")
1139 , keyId
1140 , sprint_hex(key, CIPURSE_AES_KEY_LENGTH)
1144 if (!noauth) {
1145 bool bres = CIPURSEChannelAuthenticate(keyId, key, verbose);
1146 if (bres == false) {
1147 if (verbose)
1148 PrintAndLogEx(ERR, "Authentication ( " _RED_("fail") " )");
1149 DropField();
1150 return PM3_ESOFT;
1153 // set channel security levels
1154 CIPURSECSetActChannelSecurityLevels(sreq, sresp);
1157 res = CIPURSEFormatAll(&sw);
1158 if (res != 0 || sw != ISO7816_OK) {
1159 PrintAndLogEx(ERR, "Format " _RED_("ERROR") ". Card returns 0x%04x", sw);
1160 DropField();
1161 return PM3_ESOFT;
1163 PrintAndLogEx(INFO, "Card formatted " _GREEN_("succesfully"));
1165 DropField();
1166 return PM3_SUCCESS;
1169 static int CmdHFCipurseCreateDGI(const char *Cmd) {
1170 CLIParserContext *ctx;
1171 CLIParserInit(&ctx, "hf cipurse create",
1172 "Create application/file/key by provide appropriate DGI. If no key is supplied, default key of 737373...7373 will be used",
1173 "hf cipurse create -d 9200123F00200008000062098407A0000005070100 -> create PTSE file with FID 0x2000 and space for 8 AIDs\n"
1174 "hf cipurse create -d 92002438613F010A050200004040FF021009021009621084054144204631D407A0000005070100A00F28"
1175 "73737373737373737373737373737373015FD67B000102030405060708090A0B0C0D0E0F01C6A13B -> create default file with FID 3F01 and 2 keys\n"
1176 "hf cipurse create --aid 4144204631 -d 92010C010001020030020000FFFFFF -> create 0x0102 binary data EF under application 4144204631\n");
1178 void *argtable[] = {
1179 arg_param_begin,
1180 arg_lit0("a", "apdu", "Show APDU requests and responses"),
1181 arg_lit0("v", "verbose", "Verbose mode"),
1182 arg_int0("n", NULL, "<dec>", "Key ID"),
1183 arg_str0("k", "key", "<hex>", "Auth key"),
1185 arg_str0(NULL, "aid", "<hex>", "Application ID (AID) ( 1..16 bytes )"),
1186 arg_str0(NULL, "fid", "<hex>", "File ID (FID) ( 2 bytes )"),
1187 arg_lit0(NULL, "mfd", "Select masterfile by empty id"),
1189 arg_str0("d", "data", "<hex>", "Data with DGI for create"),
1190 arg_str0(NULL, "sreq", "<plain|mac|encode>", "Communication reader-PICC security level (def: mac)"),
1191 arg_str0(NULL, "sresp", "<plain|mac|encode>", "Communication PICC-reader security level (def: mac)"),
1192 arg_lit0(NULL, "no-auth", "Execute without authentication"),
1193 arg_lit0(NULL, "commit", "Commit after create"),
1194 arg_param_end
1196 CLIExecWithReturn(ctx, Cmd, argtable, false);
1198 bool APDULogging = arg_get_lit(ctx, 1);
1199 bool verbose = arg_get_lit(ctx, 2);
1200 uint8_t keyId = arg_get_int_def(ctx, 3, defaultKeyId);
1202 CipurseChannelSecurityLevel sreq = CPSMACed;
1203 CipurseChannelSecurityLevel sresp = CPSMACed;
1204 uint8_t key[CIPURSE_AES_KEY_LENGTH] = {0};
1206 uint8_t aid[16] = {0};
1207 size_t aidLen = 0;
1208 bool useAID = false;
1209 uint16_t fileId = defaultFileId;
1210 bool useFID = false;
1211 int res = CLIParseCommandParameters(ctx, 4, 5, 6, 9, 10, key, aid, &aidLen, &useAID, &fileId, &useFID, &sreq, &sresp);
1212 if (res) {
1213 CLIParserFree(ctx);
1214 return PM3_EINVARG;
1217 bool selmfd = arg_get_lit(ctx, 7);
1219 uint8_t hdata[250] = {0};
1220 int hdatalen = sizeof(hdata);
1221 CLIGetHexWithReturn(ctx, 8, hdata, &hdatalen);
1222 if (hdatalen < 4 || hdatalen > 200) {
1223 PrintAndLogEx(ERR, _RED_("ERROR:") " data length must be 4-200 bytes only");
1224 CLIParserFree(ctx);
1225 return PM3_EINVARG;
1228 bool noauth = arg_get_lit(ctx, 11);
1229 bool needCommit = arg_get_lit(ctx, 12);
1231 CLIParserFree(ctx);
1232 SetAPDULogging(APDULogging);
1234 if (verbose && hdatalen > 3)
1235 CIPURSEPrintDGIArray(hdata, hdatalen);
1237 uint8_t buf[APDU_RES_LEN] = {0};
1238 size_t len = 0;
1239 uint16_t sw = 0;
1241 if (useAID || useFID || selmfd) {
1242 res = SelectCommand(selmfd, useAID, aid, aidLen, useFID, fileId, verbose, buf, sizeof(buf), &len, &sw);
1243 if (res != 0 || sw != ISO7816_OK) {
1244 PrintAndLogEx(ERR, "Select command ( " _RED_("error") " )");
1245 DropField();
1246 return PM3_ESOFT;
1248 } else {
1249 res = CIPURSESelectMFEx(true, true, buf, sizeof(buf), &len, &sw);
1250 if (res != 0 || sw != ISO7816_OK) {
1251 PrintAndLogEx(ERR, "Cipurse masterfile select " _RED_("error") ". Card returns 0x%04x", sw);
1252 DropField();
1253 return PM3_ESOFT;
1255 if (verbose)
1256 PrintAndLogEx(INFO, "Cipurse masterfile " _GREEN_("selected"));
1259 if (verbose) {
1260 if (!noauth)
1261 PrintAndLogEx(INFO, "Key id " _YELLOW_("%d") " key " _YELLOW_("%s")
1262 , keyId
1263 , sprint_hex(key, CIPURSE_AES_KEY_LENGTH)
1267 if (!noauth) {
1268 bool bres = CIPURSEChannelAuthenticate(keyId, key, verbose);
1269 if (bres == false) {
1270 if (verbose)
1271 PrintAndLogEx(ERR, "Authentication ( " _RED_("fail") " )");
1272 DropField();
1273 return PM3_ESOFT;
1276 // set channel security levels
1277 CIPURSECSetActChannelSecurityLevels(sreq, sresp);
1280 res = CIPURSECreateFile(hdata, hdatalen, buf, sizeof(buf), &len, &sw);
1281 if (res != 0 || sw != ISO7816_OK) {
1282 PrintAndLogEx(ERR, "Create file command " _RED_("ERROR"));
1283 PrintAndLogEx(ERR, "0x%04x - %s", sw,
1284 GetSpecificAPDUCodeDesc(SelectAPDUCodeDescriptions, ARRAYLEN(SelectAPDUCodeDescriptions), sw));
1285 DropField();
1286 return PM3_ESOFT;
1288 PrintAndLogEx(INFO, "File created " _GREEN_("succesfully"));
1290 if (needCommit) {
1291 sw = 0;
1292 res = CIPURSECommitTransaction(&sw);
1293 if (res != 0 || sw != ISO7816_OK)
1294 PrintAndLogEx(WARNING, "Commit ( " _YELLOW_("fail") " ) Card returns 0x%04x", sw);
1296 if (verbose)
1297 PrintAndLogEx(INFO, "Commit ( " _GREEN_("ok") " )");
1300 DropField();
1301 return PM3_SUCCESS;
1304 static int CmdHFCipurseDeleteFile(const char *Cmd) {
1305 CLIParserContext *ctx;
1306 CLIParserInit(&ctx, "hf cipurse delete",
1307 "Delete file by file ID with key ID and key. If no key is supplied, default key of 737373...7373 will be used",
1308 "hf cipurse delete --fid 2ff7 -> Authenticate with keyID 1, delete file with id 2ff7 at top level\n"
1309 "hf cipurse delete -n 2 -k 65656565656565656565656565656565 --fid 2ff7 -> Authenticate keyID 2 and delete file\n"
1310 "hf cipurse delete --aid A0000005070100 --no-auth -> delete PTSE file with AID A0000005070100 without authentication\n"
1311 "hf cipurse delete --aid 4144204631 --chfid 0102 -> delete EF with FID 0x0102 under default application\n");
1313 void *argtable[] = {
1314 arg_param_begin,
1315 arg_lit0("a", "apdu", "Show APDU requests and responses"),
1316 arg_lit0("v", "verbose", "Verbose mode"),
1317 arg_int0("n", NULL, "<dec>", "Key ID"),
1318 arg_str0("k", "key", "<hex>", "Auth key"),
1319 arg_str0(NULL, "fid", "<hex>", "File/application ID under MF for delete"),
1320 arg_str0(NULL, "aid", "<hex>", "Application ID (AID) for delete ( 1..16 bytes )"),
1321 arg_str0(NULL, "chfid", "<hex>", "Child file ID (EF under application/master file) ( 2 bytes )"),
1322 arg_str0(NULL, "sreq", "<plain|mac|encode>", "Communication reader-PICC security level (def: mac)"),
1323 arg_str0(NULL, "sresp", "<plain|mac|encode>", "Communication PICC-reader security level (def: mac)"),
1324 arg_lit0(NULL, "no-auth", "Execute without authentication"),
1325 arg_lit0(NULL, "commit", "commit after delete"),
1326 arg_param_end
1328 CLIExecWithReturn(ctx, Cmd, argtable, false);
1330 bool APDULogging = arg_get_lit(ctx, 1);
1331 bool verbose = arg_get_lit(ctx, 2);
1332 uint8_t keyId = arg_get_int_def(ctx, 3, defaultKeyId);
1334 CipurseChannelSecurityLevel sreq = CPSMACed;
1335 CipurseChannelSecurityLevel sresp = CPSMACed;
1336 uint8_t key[CIPURSE_AES_KEY_LENGTH] = {0};
1338 uint8_t aid[16] = {0};
1339 size_t aidLen = 0;
1340 bool useAID = false;
1341 uint16_t fileId = defaultFileId;
1342 bool useFID = false;
1343 uint16_t childFileId = defaultFileId;
1344 bool useChildFID = false;
1345 int res = CLIParseCommandParametersEx(ctx, 4, 6, 5, 7, 8, 9, key, aid, &aidLen, &useAID, &fileId, &useFID, &childFileId, &useChildFID, &sreq, &sresp);
1346 // useAID and useFID in the same state
1347 if (res || !(useAID ^ useFID)) {
1348 CLIParserFree(ctx);
1349 return PM3_EINVARG;
1352 bool noauth = arg_get_lit(ctx, 10);
1353 bool needCommit = arg_get_lit(ctx, 11);
1355 CLIParserFree(ctx);
1356 SetAPDULogging(APDULogging);
1358 if (verbose) {
1359 if (useFID)
1360 PrintAndLogEx(INFO, "File id " _CYAN_("%x"), fileId);
1361 else
1362 PrintAndLogEx(INFO, "Application ID " _CYAN_("%s"), sprint_hex_inrow(aid, aidLen));
1364 if (useChildFID)
1365 PrintAndLogEx(INFO, "Child file id " _CYAN_("%x"), childFileId);
1367 if (!noauth)
1368 PrintAndLogEx(INFO, "Key id " _YELLOW_("%d") " key " _YELLOW_("%s")
1369 , keyId
1370 , sprint_hex(key, CIPURSE_AES_KEY_LENGTH)
1374 uint8_t buf[APDU_RES_LEN] = {0};
1375 size_t len = 0;
1376 uint16_t sw = 0;
1378 if (useChildFID) {
1379 res = SelectCommand(false, useAID, aid, aidLen, useFID, fileId, verbose, buf, sizeof(buf), &len, &sw);
1380 if (res != 0 || sw != ISO7816_OK) {
1381 PrintAndLogEx(ERR, "Top level select " _RED_("error") ". Card returns 0x%04x", sw);
1382 DropField();
1383 return PM3_ESOFT;
1385 } else {
1386 res = CIPURSESelectMFEx(true, true, buf, sizeof(buf), &len, &sw);
1387 if (res != 0 || sw != ISO7816_OK) {
1388 PrintAndLogEx(ERR, "Cipurse masterfile select " _RED_("error") ". Card returns 0x%04x", sw);
1389 DropField();
1390 return PM3_ESOFT;
1394 if (!noauth) {
1395 bool bres = CIPURSEChannelAuthenticate(keyId, key, verbose);
1396 if (bres == false) {
1397 if (verbose)
1398 PrintAndLogEx(ERR, "Authentication ( " _RED_("fail") " )");
1399 DropField();
1400 return PM3_ESOFT;
1403 // set channel security levels
1404 CIPURSECSetActChannelSecurityLevels(sreq, sresp);
1407 if (useChildFID) {
1408 res = CIPURSEDeleteFile(childFileId, buf, sizeof(buf), &len, &sw);
1409 if (res != 0 || sw != ISO7816_OK) {
1410 PrintAndLogEx(ERR, "Delete child file " _CYAN_("%04x ") " %s", childFileId, _RED_("ERROR"));
1411 PrintAndLogEx(ERR, "0x%04x - %s",
1413 GetSpecificAPDUCodeDesc(DeleteAPDUCodeDescriptions, ARRAYLEN(DeleteAPDUCodeDescriptions), sw)
1415 DropField();
1416 return PM3_ESOFT;
1418 PrintAndLogEx(INFO, "Child file id " _CYAN_("%04x") " deleted " _GREEN_("succesfully"), childFileId);
1419 } else if (useFID) {
1420 res = CIPURSEDeleteFile(fileId, buf, sizeof(buf), &len, &sw);
1421 if (res != 0 || sw != ISO7816_OK) {
1422 PrintAndLogEx(ERR, "Delete file " _CYAN_("%04x ") " %s", fileId, _RED_("ERROR"));
1423 PrintAndLogEx(ERR, "0x%04x - %s",
1425 GetSpecificAPDUCodeDesc(DeleteAPDUCodeDescriptions, ARRAYLEN(DeleteAPDUCodeDescriptions), sw)
1427 DropField();
1428 return PM3_ESOFT;
1430 PrintAndLogEx(INFO, "File id " _CYAN_("%04x") " deleted " _GREEN_("succesfully"), fileId);
1431 } else {
1432 res = CIPURSEDeleteFileAID(aid, aidLen, buf, sizeof(buf), &len, &sw);
1433 if (res != 0 || sw != ISO7816_OK) {
1434 PrintAndLogEx(ERR, "Delete application " _CYAN_("%s ") " %s", sprint_hex_inrow(aid, aidLen), _RED_("ERROR"));
1435 PrintAndLogEx(ERR, "0x%04x - %s",
1437 GetSpecificAPDUCodeDesc(DeleteAPDUCodeDescriptions, ARRAYLEN(DeleteAPDUCodeDescriptions), sw)
1439 DropField();
1440 return PM3_ESOFT;
1442 PrintAndLogEx(INFO, "Delete application " _CYAN_("%s") " ( %s )", sprint_hex_inrow(aid, aidLen), _GREEN_("ok"));
1445 if (needCommit) {
1446 sw = 0;
1447 res = CIPURSECommitTransaction(&sw);
1448 if (res != 0 || sw != ISO7816_OK)
1449 PrintAndLogEx(WARNING, "Commit ( " _YELLOW_("fail") " ) Card returns 0x%04x", sw);
1451 if (verbose)
1452 PrintAndLogEx(INFO, "Commit ( " _GREEN_("ok") " )");
1455 DropField();
1456 return PM3_SUCCESS;
1459 static int CmdHFCipurseUpdateKey(const char *Cmd) {
1460 CLIParserContext *ctx;
1461 CLIParserInit(&ctx, "hf cipurse updkey",
1462 "Update key",
1463 "hf cipurse updkey --aid 4144204631 --newkeyn 2 --newkeya 00 --newkey 73737373737373737373737373737373 -> update default application key 2 with default value 73..73\n"
1464 "hf cipurse updkey --newkeyn 1 --newkeya 00 --newkey 0102030405060708090a0b0c0d0e0f10 --commit -> for key 1");
1466 void *argtable[] = {
1467 arg_param_begin,
1468 arg_lit0("a", "apdu", "Show APDU requests and responses"),
1469 arg_lit0("v", "verbose", "Show technical data"),
1470 arg_int0("n", NULL, "<dec>", "Key ID for authentication"),
1471 arg_str0("k", "key", "<hex>", "Auth key"),
1473 arg_str0(NULL, "aid", "<hex 1..16 bytes>", "Application ID (AID)"),
1474 arg_str0(NULL, "fid", "<hex 2 bytes>", "File ID (FID)"),
1475 arg_lit0(NULL, "mfd", "Select masterfile by empty id"),
1477 arg_int0(NULL, "newkeyn", "<dec>", "Target key ID"),
1478 arg_str0(NULL, "newkey", "<hex 16 byte>", "New key"),
1479 arg_str0(NULL, "newkeya", "<hex 1 byte>", "New key additional info (def: 0x00)"),
1481 arg_int0(NULL, "enckeyn", "<dec>", "Encrypt key ID (must be equal to the key on the card)"),
1482 arg_str0(NULL, "enckey", "<hex 16 byte>", "Encrypt key (must be equal to the key on the card)"),
1484 arg_str0(NULL, "sreq", "<plain|mac(default)|encode>", "Communication reader-PICC security level"),
1485 arg_str0(NULL, "sresp", "<plain|mac(default)|encode>", "Communication PICC-reader security level"),
1486 arg_lit0(NULL, "no-auth", "Execute without authentication"),
1487 arg_lit0(NULL, "commit", "Commit "),
1488 arg_param_end
1490 CLIExecWithReturn(ctx, Cmd, argtable, false);
1492 bool APDULogging = arg_get_lit(ctx, 1);
1493 bool verbose = arg_get_lit(ctx, 2);
1494 uint8_t keyId = arg_get_int_def(ctx, 3, defaultKeyId);
1496 CipurseChannelSecurityLevel sreq = CPSMACed;
1497 CipurseChannelSecurityLevel sresp = CPSMACed;
1498 uint8_t key[CIPURSE_AES_KEY_LENGTH] = {0};
1500 uint8_t aid[16] = {0};
1501 size_t aidLen = 0;
1502 bool useAID = false;
1503 uint16_t fileId = defaultFileId;
1504 bool useFID = false;
1505 int res = CLIParseCommandParameters(ctx, 4, 5, 6, 13, 14, key, aid, &aidLen, &useAID, &fileId, &useFID, &sreq, &sresp);
1506 if (res) {
1507 CLIParserFree(ctx);
1508 return PM3_EINVARG;
1511 bool selmfd = arg_get_lit(ctx, 7);
1513 uint8_t newKeyId = arg_get_int_def(ctx, 8, 0);
1514 if (newKeyId == 0) {
1515 PrintAndLogEx(ERR, _RED_("ERROR:") " new key id must be specified.");
1516 CLIParserFree(ctx);
1517 return PM3_EINVARG;
1520 uint8_t hdata[250] = {0};
1521 int hdatalen = sizeof(hdata);
1522 CLIGetHexWithReturn(ctx, 9, hdata, &hdatalen);
1523 if (hdatalen != 16) {
1524 PrintAndLogEx(ERR, _RED_("ERROR:") " new key must be 16 bytes only and must be specified.");
1525 CLIParserFree(ctx);
1526 return PM3_EINVARG;
1529 uint8_t newKey[CIPURSE_AES_KEY_LENGTH] = {0};
1530 memcpy(newKey, hdata, CIPURSE_AES_KEY_LENGTH);
1532 hdatalen = sizeof(hdata);
1533 CLIGetHexWithReturn(ctx, 10, hdata, &hdatalen);
1534 if (hdatalen && hdatalen != 1) {
1535 PrintAndLogEx(ERR, _RED_("ERROR:") " new key additional info must be 1 byte only.");
1536 CLIParserFree(ctx);
1537 return PM3_EINVARG;
1540 uint8_t newKeyAInfo = (hdatalen) ? hdata[0] : 0x00;
1542 uint8_t encKeyId = arg_get_int_def(ctx, 11, 0);
1544 hdatalen = sizeof(hdata);
1545 CLIGetHexWithReturn(ctx, 12, hdata, &hdatalen);
1546 if (hdatalen && hdatalen != 16) {
1547 PrintAndLogEx(ERR, _RED_("ERROR:") " encode key must be 16 bytes only and must be specified.");
1548 CLIParserFree(ctx);
1549 return PM3_EINVARG;
1552 uint8_t encKey[CIPURSE_AES_KEY_LENGTH] = CIPURSE_DEFAULT_KEY;
1553 if (hdatalen)
1554 memcpy(encKey, hdata, CIPURSE_AES_KEY_LENGTH);
1556 bool noauth = arg_get_lit(ctx, 15);
1557 bool needCommit = arg_get_lit(ctx, 16);
1559 CLIParserFree(ctx);
1560 SetAPDULogging(APDULogging);
1562 uint8_t kvv[CIPURSE_KVV_LENGTH] = {0};
1563 CipurseCGetKVV(newKey, kvv);
1565 uint8_t keydata[3 + 16 + 3] = {newKeyAInfo, 0x10, 0x09, 0x00};
1566 memcpy(&keydata[3], newKey, 16);
1567 memcpy(&keydata[3 + 16], kvv, 3);
1569 if (verbose) {
1570 PrintAndLogEx(INFO, "New key number: %d", newKeyId);
1571 PrintAndLogEx(INFO, "New key additional info: 0x%02x", newKeyAInfo);
1572 PrintAndLogEx(INFO, "New key: %s", sprint_hex_inrow(newKey, 16));
1573 PrintAndLogEx(INFO, "New key kvv: %s", sprint_hex_inrow(kvv, 3));
1574 PrintAndLogEx(INFO, "New key data: %s", sprint_hex_inrow(keydata, sizeof(keydata)));
1575 if (encKeyId) {
1576 PrintAndLogEx(INFO, "Encode key number: %d", encKeyId);
1577 PrintAndLogEx(INFO, "Encode key: %s", sprint_hex_inrow(encKey, 16));
1579 aes_encode(NULL, encKey, newKey, &keydata[3], CIPURSE_AES_KEY_LENGTH);
1581 PrintAndLogEx(INFO, "Encoded new key data: %s", sprint_hex_inrow(keydata, sizeof(keydata)));
1583 PrintAndLogEx(NORMAL, "");
1586 uint8_t buf[APDU_RES_LEN] = {0};
1587 size_t len = 0;
1588 uint16_t sw = 0;
1590 if (useAID || useFID || selmfd) {
1591 res = SelectCommand(selmfd, useAID, aid, aidLen, useFID, fileId, verbose, buf, sizeof(buf), &len, &sw);
1592 if (res != 0 || sw != ISO7816_OK) {
1593 PrintAndLogEx(ERR, "Select command ( " _RED_("error") " )");
1594 DropField();
1595 return PM3_ESOFT;
1597 } else {
1598 res = CIPURSESelectMFEx(true, true, buf, sizeof(buf), &len, &sw);
1599 if (res != 0 || sw != ISO7816_OK) {
1600 PrintAndLogEx(ERR, "Cipurse masterfile select " _RED_("error") ". Card returns 0x%04x", sw);
1601 DropField();
1602 return PM3_ESOFT;
1604 if (verbose)
1605 PrintAndLogEx(INFO, "Cipurse masterfile " _GREEN_("selected"));
1608 if (verbose) {
1609 if (!noauth)
1610 PrintAndLogEx(INFO, "Key id " _YELLOW_("%d") " key " _YELLOW_("%s")
1611 , keyId
1612 , sprint_hex(key, CIPURSE_AES_KEY_LENGTH)
1616 if (!noauth) {
1617 bool bres = CIPURSEChannelAuthenticate(keyId, key, verbose);
1618 if (bres == false) {
1619 if (verbose)
1620 PrintAndLogEx(ERR, "Authentication ( " _RED_("fail") " )");
1621 DropField();
1622 return PM3_ESOFT;
1625 // set channel security levels
1626 CIPURSECSetActChannelSecurityLevels(sreq, sresp);
1629 res = CIPURSEUpdateKey(encKeyId, newKeyId, keydata, sizeof(keydata), buf, sizeof(buf), &len, &sw);
1630 if (res != 0 || sw != ISO7816_OK) {
1631 PrintAndLogEx(ERR, "Update key command " _RED_("ERROR"));
1632 PrintAndLogEx(ERR, "0x%04x - %s", sw,
1633 GetSpecificAPDUCodeDesc(UAPDpdateKeyCodeDescriptions, ARRAYLEN(UAPDpdateKeyCodeDescriptions), sw));
1634 DropField();
1635 return PM3_ESOFT;
1637 PrintAndLogEx(INFO, "Key updated " _GREEN_("succesfully"));
1639 if (needCommit) {
1640 sw = 0;
1641 res = CIPURSECommitTransaction(&sw);
1642 if (res != 0 || sw != ISO7816_OK)
1643 PrintAndLogEx(WARNING, "Commit ( " _YELLOW_("fail") " ) Card returns 0x%04x", sw);
1645 if (verbose)
1646 PrintAndLogEx(INFO, "Commit ( " _GREEN_("ok") " )");
1649 DropField();
1650 return PM3_SUCCESS;
1653 static int CmdHFCipurseUpdateKeyAttr(const char *Cmd) {
1654 CLIParserContext *ctx;
1655 CLIParserInit(&ctx, "hf cipurse updakey",
1656 "Update key attributes. Factory default - 0x02.\n"
1657 "b0 - Update right - 1 self\n"
1658 "b1 - Change key and rights - 0 frozen\n"
1659 "b2 - Use as key encryption key - 1 blocked\n"
1660 "b8 - Key validity - 0 valid",
1661 "hf cipurse updakey --trgkeyn 2 --attr 80 -> block key 2 for lifetime (WARNING!)\n"
1662 "hf cipurse updakey --trgkeyn 1 --attr 02 --commit -> for key 1");
1664 void *argtable[] = {
1665 arg_param_begin,
1666 arg_lit0("a", "apdu", "Show APDU requests and responses"),
1667 arg_lit0("v", "verbose", "Show technical data"),
1668 arg_int0("n", NULL, "<dec>", "Key ID for authentication"),
1669 arg_str0("k", "key", "<hex>", "Auth key"),
1671 arg_str0(NULL, "aid", "<hex 1..16 bytes>", "Application ID (AID)"),
1672 arg_str0(NULL, "fid", "<hex 2 bytes>", "File ID (FID)"),
1673 arg_lit0(NULL, "mfd", "Select masterfile by empty id"),
1675 arg_int0(NULL, "trgkeyn", "<dec>", "Target key ID"),
1676 arg_str0(NULL, "attr", "<hex 1 byte>", "Key attributes 1 byte"),
1677 arg_str0(NULL, "sreq", "<plain|mac(default)|encode>", "Communication reader-PICC security level"),
1678 arg_str0(NULL, "sresp", "<plain|mac(default)|encode>", "Communication PICC-reader security level"),
1679 arg_lit0(NULL, "no-auth", "Execute without authentication"),
1680 arg_lit0(NULL, "commit", "Commit "),
1681 arg_param_end
1683 CLIExecWithReturn(ctx, Cmd, argtable, false);
1685 bool APDULogging = arg_get_lit(ctx, 1);
1686 bool verbose = arg_get_lit(ctx, 2);
1687 uint8_t keyId = arg_get_int_def(ctx, 3, defaultKeyId);
1689 CipurseChannelSecurityLevel sreq = CPSMACed;
1690 CipurseChannelSecurityLevel sresp = CPSMACed;
1691 uint8_t key[CIPURSE_AES_KEY_LENGTH] = {0};
1693 uint8_t aid[16] = {0};
1694 size_t aidLen = 0;
1695 bool useAID = false;
1696 uint16_t fileId = defaultFileId;
1697 bool useFID = false;
1698 int res = CLIParseCommandParameters(ctx, 4, 5, 6, 10, 11, key, aid, &aidLen, &useAID, &fileId, &useFID, &sreq, &sresp);
1699 if (res) {
1700 CLIParserFree(ctx);
1701 return PM3_EINVARG;
1704 bool selmfd = arg_get_lit(ctx, 7);
1706 uint8_t trgKeyId = arg_get_int_def(ctx, 8, 0);
1707 if (trgKeyId == 0) {
1708 PrintAndLogEx(ERR, _RED_("ERROR:") " target key id must be specified.");
1709 CLIParserFree(ctx);
1710 return PM3_EINVARG;
1713 uint8_t hdata[250] = {0};
1714 int hdatalen = sizeof(hdata);
1715 CLIGetHexWithReturn(ctx, 9, hdata, &hdatalen);
1716 if (hdatalen != 1) {
1717 PrintAndLogEx(ERR, _RED_("ERROR:") " key attributes must be 1 bytes only and must be specified.");
1718 CLIParserFree(ctx);
1719 return PM3_EINVARG;
1722 bool noauth = arg_get_lit(ctx, 12);
1723 bool needCommit = arg_get_lit(ctx, 13);
1725 CLIParserFree(ctx);
1726 SetAPDULogging(APDULogging);
1728 if (verbose && hdatalen == 1) {
1729 PrintAndLogEx(INFO, "Decoded attributes:");
1730 CIPURSEPrintKeySecurityAttributes(hdata[0]);
1731 PrintAndLogEx(NORMAL, "");
1734 uint8_t buf[APDU_RES_LEN] = {0};
1735 size_t len = 0;
1736 uint16_t sw = 0;
1738 if (useAID || useFID || selmfd) {
1739 res = SelectCommand(selmfd, useAID, aid, aidLen, useFID, fileId, verbose, buf, sizeof(buf), &len, &sw);
1740 if (res != 0 || sw != ISO7816_OK) {
1741 PrintAndLogEx(ERR, "Select command ( " _RED_("error") " )");
1742 DropField();
1743 return PM3_ESOFT;
1745 } else {
1746 res = CIPURSESelectMFEx(true, true, buf, sizeof(buf), &len, &sw);
1747 if (res != 0 || sw != ISO7816_OK) {
1748 PrintAndLogEx(ERR, "Cipurse masterfile select " _RED_("error") ". Card returns 0x%04x", sw);
1749 DropField();
1750 return PM3_ESOFT;
1752 if (verbose)
1753 PrintAndLogEx(INFO, "Cipurse masterfile " _GREEN_("selected"));
1756 if (verbose) {
1757 if (!noauth)
1758 PrintAndLogEx(INFO, "Key id " _YELLOW_("%d") " key " _YELLOW_("%s")
1759 , keyId
1760 , sprint_hex(key, CIPURSE_AES_KEY_LENGTH)
1764 if (!noauth) {
1765 bool bres = CIPURSEChannelAuthenticate(keyId, key, verbose);
1766 if (bres == false) {
1767 if (verbose)
1768 PrintAndLogEx(ERR, "Authentication ( " _RED_("fail") " )");
1769 DropField();
1770 return PM3_ESOFT;
1773 // set channel security levels
1774 CIPURSECSetActChannelSecurityLevels(sreq, sresp);
1777 res = CIPURSEUpdateKeyAttrib(trgKeyId, hdata[0], buf, sizeof(buf), &len, &sw);
1778 if (res != 0 || sw != ISO7816_OK) {
1779 PrintAndLogEx(ERR, "Update key attributes command " _RED_("ERROR"));
1780 PrintAndLogEx(ERR, "0x%04x - %s", sw,
1781 GetSpecificAPDUCodeDesc(UAPDpdateKeyAttrCodeDescriptions, ARRAYLEN(UAPDpdateKeyAttrCodeDescriptions), sw));
1782 DropField();
1783 return PM3_ESOFT;
1785 PrintAndLogEx(INFO, "Key attributes updated " _GREEN_("succesfully"));
1787 if (needCommit) {
1788 sw = 0;
1789 res = CIPURSECommitTransaction(&sw);
1790 if (res != 0 || sw != ISO7816_OK)
1791 PrintAndLogEx(WARNING, "Commit ( " _YELLOW_("fail") " ) Card returns 0x%04x", sw);
1793 if (verbose)
1794 PrintAndLogEx(INFO, "Commit ( " _GREEN_("ok") " )");
1797 DropField();
1798 return PM3_SUCCESS;
1801 bool CheckCardCipurse(void) {
1802 uint8_t buf[APDU_RES_LEN] = {0};
1803 size_t len = 0;
1804 uint16_t sw = 0;
1805 int res = CIPURSESelect(true, false, buf, sizeof(buf), &len, &sw);
1807 return (res == 0 && sw == ISO7816_OK);
1810 static int CmdHFCipurseTest(const char *Cmd) {
1811 CLIParserContext *ctx;
1812 CLIParserInit(&ctx, "hf cipurse test",
1813 "Regression tests",
1814 "hf cipurse test");
1816 void *argtable[] = {
1817 arg_param_begin,
1818 arg_param_end
1820 CLIExecWithReturn(ctx, Cmd, argtable, true);
1821 CLIParserFree(ctx);
1822 CIPURSETest(true);
1823 return PM3_SUCCESS;
1826 static int CmdHFCipurseDefault(const char *Cmd) {
1827 CLIParserContext *ctx;
1828 CLIParserInit(&ctx, "hf cipurse default",
1829 "Set default parameters for access to cipurse card",
1830 "hf cipurse default --reset -> reset parameters to default\n"
1831 "hf cipurse default -n 1 -k 65656565656565656565656565656565 --fid 2ff7 -> Set key, key id and file id\n"
1832 "hf cipurse default --aid 4144204632 -> set default application id\n");
1834 void *argtable[] = {
1835 arg_param_begin,
1836 arg_lit0(NULL, "clear", "Resets to defaults"),
1837 arg_int0("n", NULL, "<dec>", "Key ID"),
1838 arg_str0("k", "key", "<hex>", "Authentication key"),
1839 arg_str0(NULL, "aid", "<hex>", "Application ID (AID) ( 1..16 bytes )"),
1840 arg_str0(NULL, "fid", "<hex>", "File ID ( 2 bytes )"),
1841 arg_param_end
1843 CLIExecWithReturn(ctx, Cmd, argtable, true);
1845 bool clearing = arg_get_lit(ctx, 1);
1846 if (clearing) {
1847 defaultKeyId = 1;
1848 defaultFileId = 0x2ff7;
1849 uint8_t ckey[CIPURSE_AES_KEY_LENGTH] = CIPURSE_DEFAULT_KEY;
1850 memcpy(defaultKey, ckey, CIPURSE_AES_KEY_LENGTH);
1851 uint8_t aid[CIPURSE_MAX_AID_LENGTH] = CIPURSE_DEFAULT_AID;
1852 memcpy(defaultAID, aid, CIPURSE_MAX_AID_LENGTH);
1853 defaultAIDLength = 5;
1856 defaultKeyId = arg_get_int_def(ctx, 2, defaultKeyId);
1858 uint8_t aid[CIPURSE_MAX_AID_LENGTH] = {0};
1859 size_t aidLen = 0;
1860 bool useAID = false;
1861 uint16_t fileId = defaultFileId;
1862 bool useFID = false;
1863 int res = CLIParseCommandParameters(ctx, 3, 4, 5, 0, 0, defaultKey, aid, &aidLen, &useAID, &fileId, &useFID, NULL, NULL);
1864 if (res) {
1865 CLIParserFree(ctx);
1866 return PM3_EINVARG;
1869 if (useFID)
1870 defaultFileId = fileId;
1872 if (useAID) {
1873 memcpy(defaultAID, aid, CIPURSE_MAX_AID_LENGTH);
1874 defaultAIDLength = aidLen;
1877 CLIParserFree(ctx);
1879 PrintAndLogEx(INFO, "------------------- " _CYAN_("Default parameters") " -------------------");
1881 PrintAndLogEx(INFO, "Key ID : %d", defaultKeyId);
1882 PrintAndLogEx(INFO, "Key : %s", sprint_hex(defaultKey, sizeof(defaultKey)));
1883 PrintAndLogEx(INFO, "AID : %s", sprint_hex(defaultAID, defaultAIDLength));
1884 PrintAndLogEx(INFO, "File ID: 0x%04x", defaultFileId);
1886 return PM3_SUCCESS;
1889 static command_t CommandTable[] = {
1890 {"help", CmdHelp, AlwaysAvailable, "This help."},
1891 {"info", CmdHFCipurseInfo, IfPm3Iso14443a, "Get info about CIPURSE tag"},
1892 {"select", CmdHFCipurseSelect, IfPm3Iso14443a, "Select CIPURSE application or file"},
1893 {"auth", CmdHFCipurseAuth, IfPm3Iso14443a, "Authenticate CIPURSE tag"},
1894 {"read", CmdHFCipurseReadFile, IfPm3Iso14443a, "Read binary file"},
1895 {"write", CmdHFCipurseWriteFile, IfPm3Iso14443a, "Write binary file"},
1896 {"aread", CmdHFCipurseReadFileAttr, IfPm3Iso14443a, "Read file attributes"},
1897 {"awrite", CmdHFCipurseWriteFileAttr, IfPm3Iso14443a, "Write file attributes"},
1898 {"formatall", CmdHFCipurseFormatAll, IfPm3Iso14443a, "Erase all the data from chip"},
1899 {"create", CmdHFCipurseCreateDGI, IfPm3Iso14443a, "Create file, application, key via DGI record"},
1900 {"delete", CmdHFCipurseDeleteFile, IfPm3Iso14443a, "Delete file"},
1901 {"updkey", CmdHFCipurseUpdateKey, IfPm3Iso14443a, "Update key"},
1902 {"updakey", CmdHFCipurseUpdateKeyAttr, IfPm3Iso14443a, "Update key attributes"},
1903 {"default", CmdHFCipurseDefault, IfPm3Iso14443a, "Set default key and file id for all the other commands"},
1904 {"test", CmdHFCipurseTest, AlwaysAvailable, "Regression tests"},
1905 {NULL, NULL, 0, NULL}
1908 int CmdHFCipurse(const char *Cmd) {
1909 clearCommandBuffer();
1910 return CmdsParse(CommandTable, Cmd);
1913 int CmdHelp(const char *Cmd) {
1914 (void)Cmd; // Cmd is not used so far
1915 CmdsHelp(CommandTable);
1916 return PM3_SUCCESS;