1 //-----------------------------------------------------------------------------
2 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
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.
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"
26 #include "cmdparser.h" // command_t
27 #include "commonutil.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"
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
48 uint8_t aid
[PxSE_AID_LENGTH
];
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};
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
;
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
, "");
128 static int CmdHFCipurseInfo(const char *Cmd
) {
129 CLIParserContext
*ctx
;
130 CLIParserInit(&ctx
, "hf cipurse info",
131 "Get info from CIPURSE tags",
138 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
141 // info about 14a part
142 infoHF14A(false, false, false);
145 PrintAndLogEx(INFO
, "------------------- " _CYAN_("CIPURSE Info") " --------------------");
146 SetAPDULogging(false);
148 uint8_t buf
[APDU_RES_LEN
] = {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
) {
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
) {
167 PrintAndLogEx(INFO
, _CYAN_("PxSE") " exist: %s", PxSE_AID_LIST
[i
].name
);
169 PrintAndLogEx(INFO
, "PxSE data:");
170 TLVPrintFromBuffer(buf
, len
);
172 PrintAndLogEx(INFO
, "");
176 res
= CIPURSESelect(false, true, buf
, sizeof(buf
), &len
, &sw
);
181 PrintAndLogEx(INFO
, "Application `" _YELLOW_("AF F1") "` selected " _GREEN_("successfully"));
183 if (sw
!= ISO7816_OK
) {
185 PrintAndLogEx(ERR
, "APDU exchange error. Card returns 0x0000");
188 PrintAndLogEx(INFO
, "Not a CIPURSE card. APDU response: %04x - %s", sw
, GetAPDUCodeDescription(sw
>> 8, sw
& 0xff));
190 PrintAndLogEx(INFO
, "Unknown AID and MasterFile can be selected. Maybe CIPURSE card in the " _CYAN_("perso") " state");
197 PrintAndLogEx(INFO
, "Cipurse card ( " _GREEN_("ok") " )");
200 res
= SelectAndPrintInfoFile();
201 if (res
!= 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
);
217 if (CLIParamHexToBuf(arg_get_str(ctx
, keyid
), hdata
, hdatalen
, &hdatalen
)) {
221 if (hdatalen
&& hdatalen
!= 16) {
222 PrintAndLogEx(ERR
, _RED_("ERROR:") " key length for AES128 must be 16 bytes only");
227 memcpy(key
, hdata
, CIPURSE_AES_KEY_LENGTH
);
229 memcpy(key
, defaultKey
, sizeof(defaultKey
));
236 if (aidid
&& aid
&& aidlen
) {
237 hdatalen
= sizeof(hdata
);
238 if (CLIParamHexToBuf(arg_get_str(ctx
, aidid
), hdata
, hdatalen
, &hdatalen
)) {
242 if (hdatalen
&& (hdatalen
< 1 || hdatalen
> 16)) {
243 PrintAndLogEx(ERR
, _RED_("ERROR:") " application id length must be 1-16 bytes only");
249 memcpy(aid
, hdata
, hdatalen
);
255 memcpy(aid
, defaultAID
, defaultAIDLength
);
256 *aidlen
= defaultAIDLength
;
265 hdatalen
= sizeof(hdata
);
266 if (CLIParamHexToBuf(arg_get_str(ctx
, fidid
), hdata
, hdatalen
, &hdatalen
))
269 if (hdatalen
&& hdatalen
!= 2) {
270 PrintAndLogEx(ERR
, _RED_("ERROR:") " file id length must be 2 bytes only");
276 *fid
= (hdata
[0] << 8) + hdata
[1];
284 if (chfidid
&& chfid
) {
285 hdatalen
= sizeof(hdata
);
286 if (CLIParamHexToBuf(arg_get_str(ctx
, chfidid
), hdata
, hdatalen
, &hdatalen
))
288 if (hdatalen
&& hdatalen
!= 2) {
289 PrintAndLogEx(ERR
, _RED_("ERROR:") " child file id length must be 2 bytes only");
293 *chfid
= defaultFileId
;
295 *chfid
= (hdata
[0] << 8) + hdata
[1];
301 if (sreqid
&& srespid
&& sreq
&& sresp
) {
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
))
313 if (strcmp(cdata
, "plain") == 0)
315 else if (strcmp(cdata
, "mac") == 0)
317 else if (strcmp(cdata
, "enc") == 0 || strcmp(cdata
, "encode") == 0 || strcmp(cdata
, "encrypted") == 0)
318 *sreq
= CPSEncrypted
;
320 PrintAndLogEx(ERR
, _RED_("ERROR:") " security level can be only: plain | mac | encode");
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
))
333 if (strcmp(cdata
, "plain") == 0)
335 else if (strcmp(cdata
, "mac") == 0)
337 else if (strcmp(cdata
, "enc") == 0 || strcmp(cdata
, "encode") == 0 || strcmp(cdata
, "encrypted") == 0)
338 *sresp
= CPSEncrypted
;
340 PrintAndLogEx(ERR
, _RED_("ERROR:") " security level can be only: plain | mac | encode");
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
) {
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
) {
368 PrintAndLogEx(ERR
, "Cipurse select application " _GREEN_("%s ") _RED_("error") ". Card returns 0x%04x", sprint_hex_inrow(aid
, aidLen
), *sw
);
373 PrintAndLogEx(INFO
, "Cipurse select application " _YELLOW_("%s ") " ( %s )", sprint_hex_inrow(aid
, aidLen
), _GREEN_("ok"));
378 res
= CIPURSESelectFileEx(true, true, fileId
, buf
, bufSize
, len
, sw
);
379 if (res
!= 0 || *sw
!= ISO7816_OK
) {
381 PrintAndLogEx(ERR
, "Cipurse select file 0x%04x ( %s )", fileId
, _RED_("fail"));
382 PrintAndLogEx(ERR
, "Card returns 0x%04x", *sw
);
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
) {
395 PrintAndLogEx(ERR
, "Cipurse select default file " _RED_("error") ". Card returns 0x%04x", *sw
);
400 PrintAndLogEx(INFO
, "Cipurse select default file ( " _GREEN_("ok") " )");
405 res
= CIPURSESelect(true, true, buf
, bufSize
, len
, sw
);
406 if (res
!= 0 || *sw
!= ISO7816_OK
) {
408 PrintAndLogEx(ERR
, "Cipurse select default application " _RED_("error") ". Card returns 0x%04x", *sw
);
413 PrintAndLogEx(INFO
, "Cipurse select default application ( " _GREEN_("ok") " )");
419 PrintAndLogEx(INFO
, "Select child file");
422 res
= CIPURSESelectFileEx(false, true, childFileId
, buf
, bufSize
, len
, sw
);
423 if (res
!= 0 || *sw
!= ISO7816_OK
) {
425 PrintAndLogEx(ERR
, "Select child file 0x%04x " _RED_("error") ". Card returns 0x%04x", childFileId
, *sw
);
430 PrintAndLogEx(INFO
, "Select child file " _CYAN_("0x%04x ") " ( " _GREEN_("ok") " )", childFileId
);
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");
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"),
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};
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
)) {
481 bool selmfd
= arg_get_lit(ctx
, 6);
485 SetAPDULogging(APDULogging
);
487 uint8_t buf
[APDU_RES_LEN
] = {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
) {
498 PrintAndLogEx(INFO
, "File data:");
499 print_buffer(buf
, len
, 1);
503 TLVPrintFromBuffer(buf
, len
);
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");
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"),
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};
537 uint16_t fileId
= defaultFileId
;
539 int res
= CLIParseCommandParameters(ctx
, 7, 3, 4, 0, 0, key
, aid
, &aidLen
, &useAID
, &fileId
, &useFID
, NULL
, NULL
);
540 if (res
|| (useAID
&& useFID
)) {
545 bool selmfd
= arg_get_lit(ctx
, 5);
546 uint8_t keyId
= arg_get_int_def(ctx
, 6, defaultKeyId
);
550 SetAPDULogging(APDULogging
);
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
) {
562 uint8_t kvv
[CIPURSE_KVV_LENGTH
] = {0};
563 CipurseCGetKVV(key
, kvv
);
565 PrintAndLogEx(INFO
, "Key id " _YELLOW_("%d") " key " _YELLOW_("%s") " KVV " _YELLOW_("%s")
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"));
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");
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)"),
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};
618 uint16_t fileId
= defaultFileId
;
620 int res
= CLIParseCommandParameters(ctx
, 4, 5, 6, 9, 10, key
, aid
, &aidLen
, &useAID
, &fileId
, &useFID
, &sreq
, &sresp
);
621 if (res
|| useFID
== false) {
626 size_t offset
= arg_get_int_def(ctx
, 7, 0);
628 bool noAuth
= arg_get_lit(ctx
, 8);
630 SetAPDULogging(APDULogging
);
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
);
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
);
659 PrintAndLogEx(INFO
, "Select file 0x%x ( %s )", fileId
, _GREEN_("ok"));
661 if (noAuth
== false) {
662 bool bres
= CIPURSEChannelAuthenticate(keyId
, key
, verbose
);
664 if (verbose
== false)
665 PrintAndLogEx(ERR
, "Authentication ( " _RED_("fail") " )");
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
);
683 PrintAndLogEx(INFO
, "File id " _YELLOW_("%x") " is empty", fileId
);
685 PrintAndLogEx(INFO
, "File id " _YELLOW_("%x") " data[%zu]: %s", fileId
, len
, sprint_hex(buf
, len
));
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");
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"),
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};
730 uint16_t fileId
= defaultFileId
;
732 int res
= CLIParseCommandParameters(ctx
, 4, 5, 6, 9, 10, key
, aid
, &aidLen
, &useAID
, &fileId
, &useFID
, &sreq
, &sresp
);
733 if (res
|| useFID
== false) {
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
);
746 PrintAndLogEx(ERR
, _RED_("ERROR:") " file content length must be more 0");
751 bool needCommit
= arg_get_lit(ctx
, 12);
755 SetAPDULogging(APDULogging
);
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
);
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")
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
);
788 PrintAndLogEx(INFO
, "Select file 0x%x ( %s )", fileId
, _GREEN_("ok"));
790 if (noAuth
== false) {
791 bool bres
= CIPURSEChannelAuthenticate(keyId
, key
, verbose
);
793 if (verbose
== false)
794 PrintAndLogEx(ERR
, "Authentication ( " _RED_("fail") " )");
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
);
811 PrintAndLogEx(INFO
, "File id " _YELLOW_("%x") " successfully written", fileId
);
815 res
= CIPURSECommitTransaction(&sw
);
816 if (res
!= 0 || sw
!= ISO7816_OK
)
817 PrintAndLogEx(WARNING
, "Commit ( " _YELLOW_("fail") " ) Card returns 0x%04x", sw
);
820 PrintAndLogEx(INFO
, "Commit ( " _GREEN_("ok") " )");
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");
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)"),
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};
866 uint16_t fileId
= defaultFileId
;
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
);
876 bool noAuth
= arg_get_lit(ctx
, 9);
880 SetAPDULogging(APDULogging
);
882 uint8_t buf
[APDU_RES_LEN
] = {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") " )");
895 PrintAndLogEx(INFO
, "File " _CYAN_("Master File"));
897 PrintAndLogEx(INFO
, "File id " _CYAN_("%04x"), fileId
);
899 PrintAndLogEx(INFO
, "Application ID " _CYAN_("%s"), sprint_hex_inrow(aid
, aidLen
));
902 PrintAndLogEx(INFO
, "Child file id " _CYAN_("%04x"), childFileId
);
905 PrintAndLogEx(INFO
, "Key id " _YELLOW_("%d") " key " _YELLOW_("%s")
907 , sprint_hex(key
, CIPURSE_AES_KEY_LENGTH
)
911 if (noAuth
== false) {
912 bool bres
= CIPURSEChannelAuthenticate(keyId
, key
, verbose
);
914 if (verbose
== false)
915 PrintAndLogEx(ERR
, "Authentication ( " _RED_("fail") " )");
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
);
933 PrintAndLogEx(WARNING
, "File attributes is empty");
939 PrintAndLogEx(INFO
, "Attributes raw data [%zu]: %s", len
, sprint_hex(buf
, len
));
941 CIPURSEPrintFileAttr(buf
, len
);
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");
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"),
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};
987 uint16_t fileId
= defaultFileId
;
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
);
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");
1008 bool needCommit
= arg_get_lit(ctx
, 13);
1012 SetAPDULogging(APDULogging
);
1015 PrintAndLogEx(INFO
, "Attribtes data[%d]: %s", hdatalen
, sprint_hex(hdata
, hdatalen
));
1016 CIPURSEPrintFileUpdateAttr(hdata
, hdatalen
);
1019 uint8_t buf
[APDU_RES_LEN
] = {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") " )");
1032 PrintAndLogEx(INFO
, "File " _CYAN_("Master File"));
1034 PrintAndLogEx(INFO
, "File id " _CYAN_("%04x"), fileId
);
1036 PrintAndLogEx(INFO
, "Application ID " _CYAN_("%s"), sprint_hex_inrow(aid
, aidLen
));
1039 PrintAndLogEx(INFO
, "Child file id " _CYAN_("%04x"), childFileId
);
1042 PrintAndLogEx(INFO
, "Key id " _YELLOW_("%d") " key " _YELLOW_("%s")
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") " )");
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
);
1069 PrintAndLogEx(INFO
, "File attributes updated ( " _GREEN_("ok") " )");
1073 res
= CIPURSECommitTransaction(&sw
);
1074 if (res
!= 0 || sw
!= ISO7816_OK
)
1075 PrintAndLogEx(WARNING
, "Commit ( " _YELLOW_("fail") " ) Card returns 0x%04x", sw
);
1078 PrintAndLogEx(INFO
, "Commit ( " _GREEN_("ok") " )");
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
[] = {
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"),
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
);
1119 bool noauth
= arg_get_lit(ctx
, 7);
1122 SetAPDULogging(APDULogging
);
1124 uint8_t buf
[APDU_RES_LEN
] = {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
);
1136 PrintAndLogEx(WARNING
, _YELLOW_("FORMAT erases all the data at this card!!!"));
1138 PrintAndLogEx(INFO
, "key id " _YELLOW_("%d") " key " _YELLOW_("%s")
1140 , sprint_hex(key
, CIPURSE_AES_KEY_LENGTH
)
1145 bool bres
= CIPURSEChannelAuthenticate(keyId
, key
, verbose
);
1146 if (bres
== false) {
1148 PrintAndLogEx(ERR
, "Authentication ( " _RED_("fail") " )");
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
);
1163 PrintAndLogEx(INFO
, "Card formatted " _GREEN_("succesfully"));
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
[] = {
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"),
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};
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
);
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");
1228 bool noauth
= arg_get_lit(ctx
, 11);
1229 bool needCommit
= arg_get_lit(ctx
, 12);
1232 SetAPDULogging(APDULogging
);
1234 if (verbose
&& hdatalen
> 3)
1235 CIPURSEPrintDGIArray(hdata
, hdatalen
);
1237 uint8_t buf
[APDU_RES_LEN
] = {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") " )");
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
);
1256 PrintAndLogEx(INFO
, "Cipurse masterfile " _GREEN_("selected"));
1261 PrintAndLogEx(INFO
, "Key id " _YELLOW_("%d") " key " _YELLOW_("%s")
1263 , sprint_hex(key
, CIPURSE_AES_KEY_LENGTH
)
1268 bool bres
= CIPURSEChannelAuthenticate(keyId
, key
, verbose
);
1269 if (bres
== false) {
1271 PrintAndLogEx(ERR
, "Authentication ( " _RED_("fail") " )");
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
));
1288 PrintAndLogEx(INFO
, "File created " _GREEN_("succesfully"));
1292 res
= CIPURSECommitTransaction(&sw
);
1293 if (res
!= 0 || sw
!= ISO7816_OK
)
1294 PrintAndLogEx(WARNING
, "Commit ( " _YELLOW_("fail") " ) Card returns 0x%04x", sw
);
1297 PrintAndLogEx(INFO
, "Commit ( " _GREEN_("ok") " )");
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
[] = {
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"),
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};
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
)) {
1352 bool noauth
= arg_get_lit(ctx
, 10);
1353 bool needCommit
= arg_get_lit(ctx
, 11);
1356 SetAPDULogging(APDULogging
);
1360 PrintAndLogEx(INFO
, "File id " _CYAN_("%x"), fileId
);
1362 PrintAndLogEx(INFO
, "Application ID " _CYAN_("%s"), sprint_hex_inrow(aid
, aidLen
));
1365 PrintAndLogEx(INFO
, "Child file id " _CYAN_("%x"), childFileId
);
1368 PrintAndLogEx(INFO
, "Key id " _YELLOW_("%d") " key " _YELLOW_("%s")
1370 , sprint_hex(key
, CIPURSE_AES_KEY_LENGTH
)
1374 uint8_t buf
[APDU_RES_LEN
] = {0};
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
);
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
);
1395 bool bres
= CIPURSEChannelAuthenticate(keyId
, key
, verbose
);
1396 if (bres
== false) {
1398 PrintAndLogEx(ERR
, "Authentication ( " _RED_("fail") " )");
1403 // set channel security levels
1404 CIPURSECSetActChannelSecurityLevels(sreq
, sresp
);
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
)
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
)
1430 PrintAndLogEx(INFO
, "File id " _CYAN_("%04x") " deleted " _GREEN_("succesfully"), fileId
);
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
)
1442 PrintAndLogEx(INFO
, "Delete application " _CYAN_("%s") " ( %s )", sprint_hex_inrow(aid
, aidLen
), _GREEN_("ok"));
1447 res
= CIPURSECommitTransaction(&sw
);
1448 if (res
!= 0 || sw
!= ISO7816_OK
)
1449 PrintAndLogEx(WARNING
, "Commit ( " _YELLOW_("fail") " ) Card returns 0x%04x", sw
);
1452 PrintAndLogEx(INFO
, "Commit ( " _GREEN_("ok") " )");
1459 static int CmdHFCipurseUpdateKey(const char *Cmd
) {
1460 CLIParserContext
*ctx
;
1461 CLIParserInit(&ctx
, "hf cipurse updkey",
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
[] = {
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 "),
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};
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
);
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.");
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.");
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.");
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.");
1552 uint8_t encKey
[CIPURSE_AES_KEY_LENGTH
] = CIPURSE_DEFAULT_KEY
;
1554 memcpy(encKey
, hdata
, CIPURSE_AES_KEY_LENGTH
);
1556 bool noauth
= arg_get_lit(ctx
, 15);
1557 bool needCommit
= arg_get_lit(ctx
, 16);
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);
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
)));
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};
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") " )");
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
);
1605 PrintAndLogEx(INFO
, "Cipurse masterfile " _GREEN_("selected"));
1610 PrintAndLogEx(INFO
, "Key id " _YELLOW_("%d") " key " _YELLOW_("%s")
1612 , sprint_hex(key
, CIPURSE_AES_KEY_LENGTH
)
1617 bool bres
= CIPURSEChannelAuthenticate(keyId
, key
, verbose
);
1618 if (bres
== false) {
1620 PrintAndLogEx(ERR
, "Authentication ( " _RED_("fail") " )");
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
));
1637 PrintAndLogEx(INFO
, "Key updated " _GREEN_("succesfully"));
1641 res
= CIPURSECommitTransaction(&sw
);
1642 if (res
!= 0 || sw
!= ISO7816_OK
)
1643 PrintAndLogEx(WARNING
, "Commit ( " _YELLOW_("fail") " ) Card returns 0x%04x", sw
);
1646 PrintAndLogEx(INFO
, "Commit ( " _GREEN_("ok") " )");
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
[] = {
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 "),
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};
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
);
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.");
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.");
1722 bool noauth
= arg_get_lit(ctx
, 12);
1723 bool needCommit
= arg_get_lit(ctx
, 13);
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};
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") " )");
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
);
1753 PrintAndLogEx(INFO
, "Cipurse masterfile " _GREEN_("selected"));
1758 PrintAndLogEx(INFO
, "Key id " _YELLOW_("%d") " key " _YELLOW_("%s")
1760 , sprint_hex(key
, CIPURSE_AES_KEY_LENGTH
)
1765 bool bres
= CIPURSEChannelAuthenticate(keyId
, key
, verbose
);
1766 if (bres
== false) {
1768 PrintAndLogEx(ERR
, "Authentication ( " _RED_("fail") " )");
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
));
1785 PrintAndLogEx(INFO
, "Key attributes updated " _GREEN_("succesfully"));
1789 res
= CIPURSECommitTransaction(&sw
);
1790 if (res
!= 0 || sw
!= ISO7816_OK
)
1791 PrintAndLogEx(WARNING
, "Commit ( " _YELLOW_("fail") " ) Card returns 0x%04x", sw
);
1794 PrintAndLogEx(INFO
, "Commit ( " _GREEN_("ok") " )");
1801 bool CheckCardCipurse(void) {
1802 uint8_t buf
[APDU_RES_LEN
] = {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",
1816 void *argtable
[] = {
1820 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
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
[] = {
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 )"),
1843 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
1845 bool clearing
= arg_get_lit(ctx
, 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};
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
);
1870 defaultFileId
= fileId
;
1873 memcpy(defaultAID
, aid
, CIPURSE_MAX_AID_LENGTH
);
1874 defaultAIDLength
= aidLen
;
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
);
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
);