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 MIFARE Plus commands
17 //-----------------------------------------------------------------------------
21 #include "cmdparser.h" // command_t
22 #include "commonutil.h" // ARRAYLEN
27 #include "mifare/mifare4.h"
28 #include "mifare/mad.h"
30 #include "cliparser.h"
31 #include "mifare/mifaredefault.h"
32 #include "util_posix.h"
33 #include "fileutils.h"
34 #include "protocols.h"
35 #include "crypto/libpcrypto.h"
36 #include "cmdhfmf.h" // printblock, header
39 static const uint8_t mfp_default_key
[16] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
40 static uint16_t mfp_card_adresses
[] = {0x9000, 0x9001, 0x9002, 0x9003, 0x9004, 0x9006, 0x9007, 0xA000, 0xA001, 0xA080, 0xA081, 0xC000, 0xC001};
42 #define MFP_KEY_FILE_SIZE 14 + (2 * 64 * (AES_KEY_LEN + 1))
44 static int CmdHelp(const char *Cmd
);
47 The 7 MSBits (= n) code the storage size itself based on 2^n,
48 the LSBit is set to '0' if the size is exactly 2^n
49 and set to '1' if the storage size is between 2^n and 2^(n+1).
50 For this version of DESFire the 7 MSBits are set to 0x0C (2^12 = 4096) and the LSBit is '0'.
52 static char *getCardSizeStr(uint8_t fsize
) {
54 static char buf
[40] = {0x00};
57 uint16_t usize
= 1 << ((fsize
>> 1) + 1);
58 uint16_t lsize
= 1 << (fsize
>> 1);
62 snprintf(retStr
, sizeof(buf
), "0x%02X ( " _GREEN_("%d - %d bytes") " )", fsize
, usize
, lsize
);
64 snprintf(retStr
, sizeof(buf
), "0x%02X ( " _GREEN_("%d bytes") " )", fsize
, lsize
);
68 static char *getProtocolStr(uint8_t id
, bool hw
) {
70 static char buf
[50] = {0x00};
74 snprintf(retStr
, sizeof(buf
), "0x%02X ( " _YELLOW_("ISO 14443-3 MIFARE, 14443-4") " )", id
);
75 } else if (id
== 0x05) {
77 snprintf(retStr
, sizeof(buf
), "0x%02X ( " _YELLOW_("ISO 14443-2, 14443-3") " )", id
);
79 snprintf(retStr
, sizeof(buf
), "0x%02X ( " _YELLOW_("ISO 14443-3, 14443-4") " )", id
);
81 snprintf(retStr
, sizeof(buf
), "0x%02X ( " _YELLOW_("Unknown") " )", id
);
86 static char *getVersionStr(uint8_t type
, uint8_t major
, uint8_t minor
) {
88 static char buf
[40] = {0x00};
91 if (type
== 0x01 && major
== 0x00)
92 snprintf(retStr
, sizeof(buf
), "%x.%x ( " _GREEN_("DESFire MF3ICD40") " )", major
, minor
);
93 else if (major
== 0x10 && minor
== 0x00)
94 snprintf(retStr
, sizeof(buf
), "%x.%x ( " _GREEN_("NTAG413DNA") " )", major
, minor
);
95 else if (type
== 0x01 && major
== 0x01 && minor
== 0x00)
96 snprintf(retStr
, sizeof(buf
), "%x.%x ( " _GREEN_("DESFire EV1") " )", major
, minor
);
97 else if (type
== 0x01 && major
== 0x12 && minor
== 0x00)
98 snprintf(retStr
, sizeof(buf
), "%x.%x ( " _GREEN_("DESFire EV2") " )", major
, minor
);
99 else if (type
== 0x01 && major
== 0x22 && minor
== 0x00)
100 snprintf(retStr
, sizeof(buf
), "%x.%x ( " _GREEN_("DESFire EV2 XL") " )", major
, minor
);
101 else if (type
== 0x01 && major
== 0x42 && minor
== 0x00)
102 snprintf(retStr
, sizeof(buf
), "%x.%x ( " _GREEN_("DESFire EV2") " )", major
, minor
);
103 else if (type
== 0x01 && major
== 0x33 && minor
== 0x00)
104 snprintf(retStr
, sizeof(buf
), "%x.%x ( " _GREEN_("DESFire EV3") " )", major
, minor
);
105 else if (type
== 0x01 && major
== 0x30 && minor
== 0x00)
106 snprintf(retStr
, sizeof(buf
), "%x.%x ( " _GREEN_("DESFire Light") " )", major
, minor
);
107 else if (type
== 0x02 && major
== 0x11 && minor
== 0x00)
108 snprintf(retStr
, sizeof(buf
), "%x.%x ( " _GREEN_("Plus EV1") " )", major
, minor
);
109 else if (type
== 0x02 && major
== 0x22 && minor
== 0x00)
110 snprintf(retStr
, sizeof(buf
), "%x.%x ( " _GREEN_("Plus EV2") " )", major
, minor
);
112 snprintf(retStr
, sizeof(buf
), "%x.%x ( " _YELLOW_("Unknown") " )", major
, minor
);
116 static char *getTypeStr(uint8_t type
) {
118 static char buf
[40] = {0x00};
123 snprintf(retStr
, sizeof(buf
), "0x%02X ( " _YELLOW_("DESFire") " )", type
);
126 snprintf(retStr
, sizeof(buf
), "0x%02X ( " _YELLOW_("Plus") " )", type
);
129 snprintf(retStr
, sizeof(buf
), "0x%02X ( " _YELLOW_("Ultralight") " )", type
);
132 snprintf(retStr
, sizeof(buf
), "0x%02X ( " _YELLOW_("NTAG") " )", type
);
135 snprintf(retStr
, sizeof(buf
), "0x%02X ( " _YELLOW_("Smartcard") " )", type
);
143 static nxp_cardtype_t
getCardType(uint8_t type
, uint8_t major
, uint8_t minor
) {
146 if (type
== 0x01 && major
== 0x00 && minor
== 0x02)
147 return DESFIRE_MF3ICD40
;
150 if (type
== 0x01 && major
== 0x01 && minor
== 0x00)
154 if (type
== 0x01 && major
== 0x12 && minor
== 0x00)
157 if (type
== 0x01 && major
== 0x22 && minor
== 0x00)
158 return DESFIRE_EV2_XL
;
161 if (type
== 0x01 && major
== 0x33 && minor
== 0x00)
165 if (type
== 0x08 && major
== 0x30 && minor
== 0x00)
166 return DESFIRE_LIGHT
;
168 // combo card DESFire / EMV
169 if (type
== 0x81 && major
== 0x42 && minor
== 0x00)
173 if (type
== 0x02 && major
== 0x11 && minor
== 0x00)
177 if (type
== 0x02 && major
== 0x22 && minor
== 0x00)
181 if (type
== 0x04 && major
== 0x10 && minor
== 0x00)
185 if (type
== 0x04 && major
== 0x30 && minor
== 0x00)
192 static int plus_print_signature(uint8_t *uid
, uint8_t uidlen
, uint8_t *signature
, int signature_len
) {
194 // ref: MIFARE Plus EV1 Originality Signature Validation
195 #define PUBLIC_PLUS_ECDA_KEYLEN 57
196 const ecdsa_publickey_t nxp_plus_public_keys
[] = {
197 {"MIFARE Plus EV1", "044409ADC42F91A8394066BA83D872FB1D16803734E911170412DDF8BAD1A4DADFD0416291AFE1C748253925DA39A5F39A1C557FFACD34C62E"},
198 {"MIFARE Plus Ev2", "04BB49AE4447E6B1B6D21C098C1538B594A11A4A1DBF3D5E673DEACDEB3CC512D1C08AFA1A2768CE20A200BACD2DC7804CD7523A0131ABF607"},
199 {"MIFARE Plus Troika", "040F732E0EA7DF2B38F791BF89425BF7DCDF3EE4D976669E3831F324FF15751BD52AFF1782F72FF2731EEAD5F63ABE7D126E03C856FFB942AF"}
203 bool is_valid
= false;
205 for (i
= 0; i
< ARRAYLEN(nxp_plus_public_keys
); i
++) {
208 uint8_t key
[PUBLIC_PLUS_ECDA_KEYLEN
];
209 param_gethex_to_eol(nxp_plus_public_keys
[i
].value
, 0, key
, PUBLIC_PLUS_ECDA_KEYLEN
, &dl
);
211 int res
= ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP224R1
, key
, uid
, uidlen
, signature
, signature_len
, false);
212 is_valid
= (res
== 0);
217 PrintAndLogEx(NORMAL
, "");
218 PrintAndLogEx(INFO
, "--- " _CYAN_("Tag Signature"));
220 if (is_valid
== false || i
== ARRAYLEN(nxp_plus_public_keys
)) {
221 PrintAndLogEx(INFO
, " Elliptic curve parameters: NID_secp224r1");
222 PrintAndLogEx(INFO
, " TAG IC Signature: %s", sprint_hex_inrow(signature
, 16));
223 PrintAndLogEx(INFO
, " : %s", sprint_hex_inrow(signature
+ 16, 16));
224 PrintAndLogEx(INFO
, " : %s", sprint_hex_inrow(signature
+ 32, 16));
225 PrintAndLogEx(INFO
, " : %s", sprint_hex_inrow(signature
+ 48, signature_len
- 48));
226 PrintAndLogEx(SUCCESS
, " Signature verification: " _RED_("failed"));
230 PrintAndLogEx(INFO
, " IC signature public key name: " _GREEN_("%s"), nxp_plus_public_keys
[i
].desc
);
231 PrintAndLogEx(INFO
, "IC signature public key value: %.32s", nxp_plus_public_keys
[i
].value
);
232 PrintAndLogEx(INFO
, " : %.32s", nxp_plus_public_keys
[i
].value
+ 32);
233 PrintAndLogEx(INFO
, " : %.32s", nxp_plus_public_keys
[i
].value
+ 64);
234 PrintAndLogEx(INFO
, " : %.32s", nxp_plus_public_keys
[i
].value
+ 96);
235 PrintAndLogEx(INFO
, " Elliptic curve parameters: NID_secp224r1");
236 PrintAndLogEx(INFO
, " TAG IC Signature: %s", sprint_hex_inrow(signature
, 16));
237 PrintAndLogEx(INFO
, " : %s", sprint_hex_inrow(signature
+ 16, 16));
238 PrintAndLogEx(INFO
, " : %s", sprint_hex_inrow(signature
+ 32, 16));
239 PrintAndLogEx(INFO
, " : %s", sprint_hex_inrow(signature
+ 48, signature_len
- 48));
240 PrintAndLogEx(SUCCESS
, " Signature verification: " _GREEN_("successful"));
244 static int get_plus_signature(uint8_t *signature
, int *signature_len
) {
246 mfpSetVerboseMode(false);
248 uint8_t data
[59] = {0};
249 int resplen
= 0, retval
= PM3_SUCCESS
;
250 MFPGetSignature(true, false, data
, sizeof(data
), &resplen
);
253 memcpy(signature
, data
+ 1, 56);
264 static int plus_print_version(uint8_t *version
) {
265 PrintAndLogEx(SUCCESS
, "UID: " _GREEN_("%s"), sprint_hex(version
+ 14, 7));
266 PrintAndLogEx(SUCCESS
, "Batch number: " _GREEN_("%s"), sprint_hex(version
+ 21, 5));
267 PrintAndLogEx(SUCCESS
, "Production date: week " _GREEN_("%02x") " / " _GREEN_("20%02x"), version
[7 + 7 + 7 + 5], version
[7 + 7 + 7 + 5 + 1]);
268 PrintAndLogEx(NORMAL
, "");
269 PrintAndLogEx(INFO
, "--- " _CYAN_("Hardware Information"));
270 PrintAndLogEx(INFO
, " Raw : %s", sprint_hex(version
, 7));
271 PrintAndLogEx(INFO
, " Vendor Id: " _YELLOW_("%s"), getTagInfo(version
[0]));
272 PrintAndLogEx(INFO
, " Type: %s", getTypeStr(version
[1]));
273 PrintAndLogEx(INFO
, " Subtype: " _YELLOW_("0x%02X"), version
[2]);
274 PrintAndLogEx(INFO
, " Version: %s", getVersionStr(version
[1], version
[3], version
[4]));
275 PrintAndLogEx(INFO
, " Storage size: %s", getCardSizeStr(version
[5]));
276 PrintAndLogEx(INFO
, " Protocol: %s", getProtocolStr(version
[6], true));
277 PrintAndLogEx(NORMAL
, "");
278 PrintAndLogEx(INFO
, "--- " _CYAN_("Software Information"));
279 PrintAndLogEx(INFO
, " Raw : %s", sprint_hex(version
+ 7, 6));
280 PrintAndLogEx(INFO
, " Vendor Id: " _YELLOW_("%s"), getTagInfo(version
[7]));
281 PrintAndLogEx(INFO
, " Type: %s", getTypeStr(version
[8]));
282 PrintAndLogEx(INFO
, " Subtype: " _YELLOW_("0x%02X"), version
[9]);
283 PrintAndLogEx(INFO
, " Version: " _YELLOW_("%d.%d"), version
[10], version
[11]);
284 PrintAndLogEx(INFO
, " Storage size: %s", getCardSizeStr(version
[12]));
285 PrintAndLogEx(INFO
, " Protocol: %s", getProtocolStr(version
[13], false));
289 static int get_plus_version(uint8_t *version
, int *version_len
) {
291 int resplen
= 0, retval
= PM3_SUCCESS
;
292 mfpSetVerboseMode(false);
293 MFPGetVersion(true, false, version
, *version_len
, &resplen
);
295 *version_len
= resplen
;
302 static int CmdHFMFPInfo(const char *Cmd
) {
303 CLIParserContext
*ctx
;
304 CLIParserInit(&ctx
, "hf mfp info",
305 "Get info from MIFARE Plus tags",
312 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
314 PrintAndLogEx(NORMAL
, "");
315 PrintAndLogEx(INFO
, "--- " _CYAN_("Tag Information") " ---------------------------");
318 SendCommandMIX(CMD_HF_ISO14443A_READER
, ISO14A_CONNECT
, 0, 0, NULL
, 0);
319 PacketResponseNG resp
;
320 WaitForResponse(CMD_ACK
, &resp
);
322 iso14a_card_select_t card
;
323 memcpy(&card
, (iso14a_card_select_t
*)resp
.data
.asBytes
, sizeof(iso14a_card_select_t
));
325 uint64_t select_status
= resp
.oldarg
[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision
327 bool supportVersion
= false;
328 bool supportSignature
= false;
331 uint8_t version
[30] = {0};
332 int version_len
= sizeof(version
);
333 if (get_plus_version(version
, &version_len
) == PM3_SUCCESS
) {
334 plus_print_version(version
);
335 supportVersion
= true;
337 // info about 14a part, historical bytes.
338 infoHF14A(false, false, false);
341 // Signature originality check
342 uint8_t signature
[56] = {0};
343 int signature_len
= sizeof(signature
);
344 if (get_plus_signature(signature
, &signature_len
) == PM3_SUCCESS
) {
345 plus_print_signature(card
.uid
, card
.uidlen
, signature
, signature_len
);
346 supportSignature
= true;
349 if (select_status
== 1 || select_status
== 2) {
351 PrintAndLogEx(INFO
, "--- " _CYAN_("Fingerprint"));
355 if (supportVersion
) {
357 int cardtype
= getCardType(version
[1], version
[3], version
[4]);
360 if (supportSignature
) {
361 PrintAndLogEx(INFO
, "Tech..... " _GREEN_("MIFARE Plus EV1"));
363 PrintAndLogEx(INFO
, "Tech..... " _YELLOW_("MIFARE Plus SE/X"));
369 if (supportSignature
) {
370 PrintAndLogEx(INFO
, "Tech..... " _GREEN_("MIFARE Plus EV2"));
372 PrintAndLogEx(INFO
, "Tech..... " _YELLOW_("MIFARE Plus EV2 ???"));
377 case DESFIRE_MF3ICD40
:
382 case DESFIRE_LIGHT
: {
383 PrintAndLogEx(HINT
, "Card seems to be MIFARE DESFire. Try " _YELLOW_("`hf mfdes info`"));
384 PrintAndLogEx(NORMAL
, "");
389 PrintAndLogEx(INFO
, "Tech..... Unknown ( " _YELLOW_("%u") " )", cardtype
);
395 // MIFARE Type Identification Procedure
396 // https://www.nxp.com/docs/en/application-note/AN10833.pdf
397 uint16_t ATQA
= card
.atqa
[0] + (card
.atqa
[1] << 8);
400 PrintAndLogEx(INFO
, "Size..... " _GREEN_("2K") " (%s UID)", (ATQA
& 0x0040) ? "7" : "4");
404 PrintAndLogEx(INFO
, "Size..... " _GREEN_("4K") " (%s UID)", (ATQA
& 0x0040) ? "7" : "4");
408 uint8_t SLmode
= 0xFF;
410 if (card
.sak
== 0x08) {
411 PrintAndLogEx(INFO
, "SAK...... " _GREEN_("2K 7b UID"));
412 if (select_status
== 2) SLmode
= 1;
414 if (card
.sak
== 0x18) {
415 PrintAndLogEx(INFO
, "SAK...... " _GREEN_("4K 7b UID"));
416 if (select_status
== 2) SLmode
= 1;
418 if (card
.sak
== 0x10) {
419 PrintAndLogEx(INFO
, "SAK...... " _GREEN_("2K"));
420 if (select_status
== 2) SLmode
= 2;
422 if (card
.sak
== 0x11) {
423 PrintAndLogEx(INFO
, "SAK...... " _GREEN_("4K"));
424 if (select_status
== 2) SLmode
= 2;
428 if (card
.sak
== 0x20) {
429 if (card
.ats_len
> 0) {
430 PrintAndLogEx(INFO
, "SAK...... " _GREEN_("MIFARE Plus SL0/SL3") " or " _GREEN_("MIFARE DESFire"));
433 uint8_t data
[128] = {0};
435 // https://github.com/Proxmark/proxmark3/blob/master/client/luascripts/mifarePlus.lua#L161
436 uint8_t cmd
[3 + 16] = {0xa8, 0x90, 0x90, 0x00};
437 int res
= ExchangeRAW14a(cmd
, sizeof(cmd
), true, false, data
, sizeof(data
), &datalen
, false);
438 if (res
!= PM3_SUCCESS
) {
439 PrintAndLogEx(INFO
, "Identification failed");
440 PrintAndLogEx(NORMAL
, "");
444 // DESFire answers 0x1C or 67 00
445 // Plus answers 0x0B, 0x09, 0x06
446 // 6D00 is "INS code not supported" in APDU
455 PrintAndLogEx(INFO
, _RED_("Send copy to iceman of this command output!"));
456 PrintAndLogEx(INFO
, "Data... %s", sprint_hex(data
, datalen
));
459 if ((memcmp(data
, "\x67\x00", 2) == 0) || // wrong length
460 (memcmp(data
, "\x1C\x83\x0C", 3) == 0) // desfire answers
462 PrintAndLogEx(INFO
, "Result... " _RED_("MIFARE DESFire"));
463 PrintAndLogEx(NORMAL
, "");
467 // } else if (memcmp(data, "\x68\x82", 2) == 0) { // Secure message not supported
468 } else if (memcmp(data
, "\x6D\x00", 2) == 0) {
469 // } else if (memcmp(data, "\x6E\x00", 2) == 0) { // Class not supported
472 PrintAndLogEx(INFO
, "Result... " _GREEN_("MIFARE Plus SL0/SL3"));
475 if ((datalen
> 1) && (data
[0] == 0x09)) {
483 // How do we detect SL0 / SL1 / SL2 / SL3 modes?!?
484 PrintAndLogEx(INFO
, "--- " _CYAN_("Security Level (SL)"));
487 PrintAndLogEx(SUCCESS
, "SL mode... " _YELLOW_("SL%d"), SLmode
);
489 PrintAndLogEx(WARNING
, "SL mode... " _YELLOW_("unknown"));
493 PrintAndLogEx(INFO
, "SL 0: initial delivery configuration, used for card personalization");
496 PrintAndLogEx(INFO
, "SL 1: backwards functional compatibility mode (with MIFARE Classic 1K / 4K) with an optional AES authentication");
499 PrintAndLogEx(INFO
, "SL 2: 3-Pass Authentication based on AES followed by MIFARE CRYPTO1 authentication, communication secured by MIFARE CRYPTO1");
502 PrintAndLogEx(INFO
, "SL 3: 3-Pass authentication based on AES, data manipulation commands secured by AES encryption and an AES based MACing method.");
509 PrintAndLogEx(INFO
, "MIFARE Plus info not available");
511 PrintAndLogEx(NORMAL
, "");
516 static int CmdHFMFPWritePerso(const char *Cmd
) {
517 CLIParserContext
*ctx
;
518 CLIParserInit(&ctx
, "hf mfp wrp",
519 "Executes Write Perso command. Can be used in SL0 mode only.",
520 "Use this command to program AES keys, as well as personalize other data on the tag.\n"
522 "* Address 00 [00-FF]: Memory blocks (as well as ACLs and Crypto1 keys)\n"
523 "* Address 40 [00-40]: AES sector keys\n"
524 "* Address 90 [00-04]: AES administrative keys\n"
525 "* Address A0 [00, 01, 80, 81]: Virtual Card keys\n"
526 "* Address B0 [00-03]: Configuration data (DO NOT TOUCH B003)\n"
528 "hf mfp wrp --adr 4000 --data 000102030405060708090a0b0c0d0e0f -> write key (00..0f) to key number 4000 \n"
529 "hf mfp wrp --adr 4000 -> write default key(0xff..0xff) to key number 4000\n"
530 "hf mfp wrp --adr b000 -d FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -> allow 255 commands without MAC in configuration block (B000)\n"
531 "hf mfp wrp --adr 0003 -d 1234561234567F078869B0B1B2B3B4B5 -> write crypto1 keys A: 123456123456 and B: B0B1B2B3B4B5 to block 3\n");
535 arg_lit0("v", "verbose", "Verbose output"),
536 arg_str1("a", "adr", "<hex>", "Address, 2 hex bytes"),
537 arg_str0("d", "data", "<hex>", "Data, 16 hex bytes"),
540 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
542 bool verbose
= arg_get_lit(ctx
, 1);
544 uint8_t addr
[64] = {0};
546 CLIGetHexWithReturn(ctx
, 2, addr
, &addrLen
);
548 uint8_t datain
[64] = {0};
550 CLIGetHexWithReturn(ctx
, 3, datain
, &datainLen
);
553 mfpSetVerboseMode(verbose
);
556 memmove(datain
, mfp_default_key
, 16);
561 PrintAndLogEx(ERR
, "Address length must be 2 bytes. Got %d", addrLen
);
564 if (datainLen
!= 16) {
565 PrintAndLogEx(ERR
, "Data length must be 16 bytes. Got %d", datainLen
);
569 uint8_t data
[250] = {0};
572 int res
= MFPWritePerso(addr
, datain
, true, false, data
, sizeof(data
), &datalen
);
574 PrintAndLogEx(ERR
, "Exchange error: %d", res
);
579 PrintAndLogEx(ERR
, "Command must return 3 bytes. Got %d", datalen
);
583 if (data
[0] != 0x90) {
584 PrintAndLogEx(ERR
, "Command error: %02x %s", data
[0], mfpGetErrorDescription(data
[0]));
588 PrintAndLogEx(INFO
, "Write ( " _GREEN_("ok") " )");
592 static int CmdHFMFPInitPerso(const char *Cmd
) {
593 CLIParserContext
*ctx
;
594 CLIParserInit(&ctx
, "hf mfp initp",
595 "Executes Write Perso command for all card's keys. Can be used in SL0 mode only.",
596 "hf mfp initp --key 000102030405060708090a0b0c0d0e0f -> fill all the keys with key (00..0f)\n"
597 "hf mfp initp -vv -> fill all the keys with default key(0xff..0xff) and show all the data exchange");
601 arg_litn("v", "verbose", 0, 2, "Verbose output"),
602 arg_str0("k", "key", "<hex>", "Key, 16 hex bytes"),
605 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
607 bool verbose
= arg_get_lit(ctx
, 1);
608 bool verbose2
= arg_get_lit(ctx
, 1) > 1;
610 uint8_t key
[256] = {0};
612 CLIGetHexWithReturn(ctx
, 2, key
, &keylen
);
615 if (keylen
&& keylen
!= 16) {
616 PrintAndLogEx(FAILED
, "Key length must be 16 bytes. Got %d", keylen
);
621 memmove(key
, mfp_default_key
, sizeof(mfp_default_key
));
624 uint8_t keyNum
[2] = {0};
625 uint8_t data
[250] = {0};
629 mfpSetVerboseMode(verbose2
);
630 for (uint16_t sn
= 0x4000; sn
< 0x4050; sn
++) {
632 keyNum
[1] = sn
& 0xff;
633 res
= MFPWritePerso(keyNum
, key
, (sn
== 0x4000), true, data
, sizeof(data
), &datalen
);
634 if (!res
&& (datalen
== 3) && data
[0] == 0x09) {
635 PrintAndLogEx(INFO
, "2K card detected.");
638 if (res
|| (datalen
!= 3) || data
[0] != 0x90) {
639 PrintAndLogEx(ERR
, "Write error on address %04x", sn
);
644 mfpSetVerboseMode(verbose
);
645 for (int i
= 0; i
< ARRAYLEN(mfp_card_adresses
); i
++) {
646 keyNum
[0] = mfp_card_adresses
[i
] >> 8;
647 keyNum
[1] = mfp_card_adresses
[i
] & 0xff;
648 res
= MFPWritePerso(keyNum
, key
, false, true, data
, sizeof(data
), &datalen
);
649 if (!res
&& (datalen
== 3) && data
[0] == 0x09) {
650 PrintAndLogEx(WARNING
, "Skipped[%04x]...", mfp_card_adresses
[i
]);
652 if (res
|| (datalen
!= 3) || data
[0] != 0x90) {
653 PrintAndLogEx(ERR
, "Write error on address %04x", mfp_card_adresses
[i
]);
663 PrintAndLogEx(INFO
, "Done!");
667 static int CmdHFMFPCommitPerso(const char *Cmd
) {
668 CLIParserContext
*ctx
;
669 CLIParserInit(&ctx
, "hf mfp commitp",
670 "Executes Commit Perso command. Can be used in SL0 mode only.\n"
671 "OBS! This command will not be executed if \n"
672 "CardConfigKey, CardMasterKey and L3SwitchKey AES keys are not written.",
674 // "hf mfp commitp --sl 1"
679 arg_lit0("v", "verbose", "Verbose output"),
680 // arg_int0(NULL, "sl", "<dec>", "SL mode"),
683 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
684 bool verbose
= arg_get_lit(ctx
, 1);
685 // int slmode = arg_get_int(ctx, 2);
688 mfpSetVerboseMode(verbose
);
690 uint8_t data
[250] = {0};
693 int res
= MFPCommitPerso(true, false, data
, sizeof(data
), &datalen
);
695 PrintAndLogEx(ERR
, "Exchange error: %d", res
);
700 PrintAndLogEx(ERR
, "Command must return 3 bytes. Got %d", datalen
);
704 if (data
[0] != 0x90) {
705 PrintAndLogEx(ERR
, "Command error: %02x %s", data
[0], mfpGetErrorDescription(data
[0]));
708 PrintAndLogEx(INFO
, "Switched security level ( " _GREEN_("ok") " )");
712 static int CmdHFMFPAuth(const char *Cmd
) {
713 uint8_t keyn
[250] = {0};
715 uint8_t key
[250] = {0};
718 CLIParserContext
*ctx
;
719 CLIParserInit(&ctx
, "hf mfp auth",
720 "Executes AES authentication command for MIFARE Plus card",
721 "hf mfp auth --ki 4000 --key 000102030405060708090a0b0c0d0e0f -> executes authentication\n"
722 "hf mfp auth --ki 9003 --key FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -v -> executes authentication and shows all the system data");
726 arg_lit0("v", "verbose", "Verbose output"),
727 arg_str1(NULL
, "ki", "<hex>", "Key number, 2 hex bytes"),
728 arg_str1(NULL
, "key", "<hex>", "Key, 16 hex bytes"),
731 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
733 bool verbose
= arg_get_lit(ctx
, 1);
734 CLIGetHexWithReturn(ctx
, 2, keyn
, &keynlen
);
735 CLIGetHexWithReturn(ctx
, 3, key
, &keylen
);
739 PrintAndLogEx(ERR
, "ERROR: <key number> must be 2 bytes. Got %d", keynlen
);
744 PrintAndLogEx(ERR
, "ERROR: <key> must be 16 bytes. Got %d", keylen
);
748 return MifareAuth4(NULL
, keyn
, key
, true, false, true, verbose
, false);
750 static int data_crypt(mf4Session_t
*mf4session
, uint8_t *dati
, uint8_t *dato
, bool rev
) {
752 memcpy(kenc
, mf4session
->Kenc
, 16);
754 memcpy(ti
, mf4session
->TI
, 4);
756 uint8_t IV
[16] = {0, 0, 0x00, 0x00, 0x00, 0, 0x00, 0x00, 0x00, 0};
758 ctr
[0] = (uint8_t)(mf4session
->R_Ctr
& 0xff);
759 for (int i
= 0; i
< 9; i
+= 4) {memcpy(&IV
[i
], ctr
, 1);}
760 memcpy(&IV
[12], ti
, 4); // For reads TI is LS
762 ctr
[0] = (uint8_t)(mf4session
->W_Ctr
& 0xff);
763 for (int i
= 3; i
< 16; i
+= 4) {memcpy(&IV
[i
], ctr
, 1);}
764 memcpy(&IV
[0], ti
, 4); // For writes TI is MS
767 aes_decode(IV
, kenc
, dati
, dato
, 16);
769 aes_encode(IV
, kenc
, dati
, dato
, 16);
773 static int CmdHFMFPRdbl(const char *Cmd
) {
774 CLIParserContext
*ctx
;
775 CLIParserInit(&ctx
, "hf mfp rdbl",
776 "Reads blocks from MIFARE Plus card",
777 "hf mfp rdbl --blk 0 --key 000102030405060708090a0b0c0d0e0f -> executes authentication and read block 0 data\n"
778 "hf mfp rdbl --blk 1 -v -> executes authentication and shows sector 1 data with default key 0xFF..0xFF");
782 arg_lit0("v", "verbose", "Verbose output"),
783 arg_int0("n", "count", "<dec>", "Blocks count (def: 1)"),
784 arg_lit0("b", "keyb", "Use key B (def: keyA)"),
785 arg_lit0("p", "plain", "Do not use encrypted communication mode between reader and card"),
786 arg_lit0(NULL
, "nmc", "Do not append MAC to command"),
787 arg_lit0(NULL
, "nmr", "Do not expect MAC in reply"),
788 arg_int1(NULL
, "blk", "<0..255>", "Block number"),
789 arg_str0("k", "key", "<hex>", "Key, 16 hex bytes"),
792 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
794 bool verbose
= arg_get_lit(ctx
, 1);
795 int blocksCount
= arg_get_int_def(ctx
, 2, 1);
796 bool keyB
= arg_get_lit(ctx
, 3);
797 bool plain
= arg_get_lit(ctx
, 4);
798 bool nomaccmd
= arg_get_lit(ctx
, 5);
799 bool nomacres
= arg_get_lit(ctx
, 6);
800 uint32_t blockn
= arg_get_int(ctx
, 7);
802 uint8_t keyn
[2] = {0};
803 uint8_t key
[250] = {0};
805 CLIGetHexWithReturn(ctx
, 8, key
, &keylen
);
808 mfpSetVerboseMode(verbose
);
811 memmove(key
, mfp_default_key
, 16);
816 PrintAndLogEx(ERR
, "<block number> must be in range [0..255]. got %d", blockn
);
821 PrintAndLogEx(ERR
, "<key> must be 16 bytes. Got %d", keylen
);
825 // 3 blocks - wo iso14443-4 chaining
826 if (blocksCount
> 3) {
827 PrintAndLogEx(ERR
, "blocks count must be less than 3. Got %d", blocksCount
);
831 if (blocksCount
> 1 && mfIsSectorTrailer(blockn
)) {
832 PrintAndLogEx(WARNING
, "WARNING: trailer!");
835 uint8_t sectorNum
= mfSectorNum(blockn
& 0xff);
836 uint16_t uKeyNum
= 0x4000 + sectorNum
* 2 + (keyB
? 1 : 0);
837 keyn
[0] = uKeyNum
>> 8;
838 keyn
[1] = uKeyNum
& 0xff;
840 PrintAndLogEx(INFO
, "--block:%d sector[%u]:%02x key:%04x", blockn
, mfNumBlocksPerSector(sectorNum
), sectorNum
, uKeyNum
);
842 mf4Session_t mf4session
;
843 int res
= MifareAuth4(&mf4session
, keyn
, key
, true, true, true, verbose
, false);
845 PrintAndLogEx(ERR
, "Authentication error: %d", res
);
849 uint8_t data
[250] = {0};
851 uint8_t mac
[8] = {0};
852 res
= MFPReadBlock(&mf4session
, plain
, nomaccmd
, nomacres
, blockn
& 0xff, blocksCount
, false, false, data
, sizeof(data
), &datalen
, mac
);
854 PrintAndLogEx(ERR
, "Read error: %d", res
);
858 if (datalen
&& data
[0] != 0x90) {
859 PrintAndLogEx(ERR
, "Card read error: %02x %s", data
[0], mfpGetErrorDescription(data
[0]));
862 //PrintAndLogEx(INFO, "%i", 8 && (!macres || 0xff));
863 if (datalen
!= 1 + blocksCount
* 16 + (nomacres
? 0 : 8) + 2) {
864 PrintAndLogEx(ERR
, "Error return length: %d", datalen
);
868 if (!plain
) data_crypt(&mf4session
, &data
[1], &data
[1], true);
869 uint8_t sector
= mfSectorNum(blockn
);
870 mf_print_sector_hdr(sector
);
873 for (int i
= 0; i
< blocksCount
; i
++) {
874 mf_print_block_one(indx
, data
+ 1 + (i
* MFBLOCK_SIZE
), verbose
);
878 if (memcmp(&data
[(blocksCount
* 16) + 1], mac
, 8) && !nomacres
) {
879 PrintAndLogEx(WARNING
, "WARNING: mac not equal...");
880 PrintAndLogEx(WARNING
, "MAC card... " _YELLOW_("%s"), sprint_hex_inrow(&data
[1 + (blocksCount
* MFBLOCK_SIZE
)], 8));
881 PrintAndLogEx(WARNING
, "MAC reader... " _YELLOW_("%s"), sprint_hex_inrow(mac
, sizeof(mac
)));
882 } else if (!nomacres
) {
884 PrintAndLogEx(INFO
, "MAC... " _YELLOW_("%s"), sprint_hex_inrow(&data
[1 + (blocksCount
* MFBLOCK_SIZE
)], 8));
887 PrintAndLogEx(NORMAL
, "");
891 static int CmdHFMFPRdsc(const char *Cmd
) {
892 CLIParserContext
*ctx
;
893 CLIParserInit(&ctx
, "hf mfp rdsc",
894 "Reads one sector from MIFARE Plus card",
895 "hf mfp rdsc -s 0 --key 000102030405060708090a0b0c0d0e0f -> executes authentication and read sector 0 data\n"
896 "hf mfp rdsc -s 1 -v -> executes authentication and shows sector 1 data with default key");
900 arg_lit0("v", "verbose", "Verbose output"),
901 arg_lit0("b", "keyb", "Use key B (def: keyA)"),
902 arg_lit0("p", "plain", "Do not use encrypted communication mode between reader and card"),
903 arg_lit0(NULL
, "nmc", "Do not append MAC to command"),
904 arg_lit0(NULL
, "nmr", "Do not expect MAC in reply"),
905 arg_int1("s", "sn", "<0..255>", "Sector number"),
906 arg_str0("k", "key", "<hex>", "Key, 16 hex bytes"),
909 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
911 bool verbose
= arg_get_lit(ctx
, 1);
912 bool keyB
= arg_get_lit(ctx
, 2);
913 bool plain
= arg_get_lit(ctx
, 3);
914 bool nomaccmd
= arg_get_lit(ctx
, 4);
915 bool nomacres
= arg_get_lit(ctx
, 5);
916 uint32_t sectorNum
= arg_get_int(ctx
, 6);
917 uint8_t keyn
[2] = {0};
918 uint8_t key
[250] = {0};
920 CLIGetHexWithReturn(ctx
, 7, key
, &keylen
);
923 mfpSetVerboseMode(verbose
);
926 memmove(key
, mfp_default_key
, 16);
930 if (sectorNum
> 39) {
931 PrintAndLogEx(ERR
, "<sector number> must be in range [0..39]. Got %d", sectorNum
);
936 PrintAndLogEx(ERR
, "<key> must be 16 bytes. Got %d", keylen
);
940 uint16_t uKeyNum
= 0x4000 + sectorNum
* 2 + (keyB
? 1 : 0);
941 keyn
[0] = uKeyNum
>> 8;
942 keyn
[1] = uKeyNum
& 0xff;
944 PrintAndLogEx(INFO
, "--sector[%u]:%02x key:%04x", mfNumBlocksPerSector(sectorNum
), sectorNum
, uKeyNum
);
946 mf4Session_t mf4session
;
947 int res
= MifareAuth4(&mf4session
, keyn
, key
, true, true, true, verbose
, false);
949 PrintAndLogEx(ERR
, "Authentication error: %d", res
);
953 uint8_t data
[250] = {0};
955 uint8_t mac
[8] = {0};
957 mf_print_sector_hdr(sectorNum
);
959 for (int blockno
= mfFirstBlockOfSector(sectorNum
); blockno
< mfFirstBlockOfSector(sectorNum
) + mfNumBlocksPerSector(sectorNum
); blockno
++) {
961 res
= MFPReadBlock(&mf4session
, plain
, nomaccmd
, nomacres
, blockno
& 0xff, 1, false, true, data
, sizeof(data
), &datalen
, mac
);
963 PrintAndLogEx(ERR
, "Read error: %d", res
);
968 if (datalen
&& data
[0] != 0x90) {
969 PrintAndLogEx(ERR
, "Card read error: %02x %s", data
[0], mfpGetErrorDescription(data
[0]));
974 if (datalen
!= 1 + MFBLOCK_SIZE
+ (nomacres
? 0 : 8) + 2) {
975 PrintAndLogEx(ERR
, "Error return length:%d", datalen
);
979 if (!plain
) data_crypt(&mf4session
, &data
[1], &data
[1], true);
980 mf_print_block_one(blockno
, data
+ 1, verbose
);
982 if (memcmp(&data
[1 + 16], mac
, 8) && !nomacres
) {
983 PrintAndLogEx(WARNING
, "WARNING: mac on block %d not equal...", blockno
);
984 PrintAndLogEx(WARNING
, "MAC card... " _YELLOW_("%s"), sprint_hex_inrow(&data
[1 + MFBLOCK_SIZE
], 8));
985 PrintAndLogEx(WARNING
, "MAC reader... " _YELLOW_("%s"), sprint_hex_inrow(mac
, sizeof(mac
)));
986 } else if (!nomacres
) {
988 PrintAndLogEx(INFO
, "MAC... " _YELLOW_("%s"), sprint_hex_inrow(&data
[1 + MFBLOCK_SIZE
], 8));
992 PrintAndLogEx(NORMAL
, "");
997 static int CmdHFMFPWrbl(const char *Cmd
) {
998 CLIParserContext
*ctx
;
999 CLIParserInit(&ctx
, "hf mfp wrbl",
1000 "Writes one block to MIFARE Plus card",
1001 "hf mfp wrbl --blk 1 -d ff0000000000000000000000000000ff --key 000102030405060708090a0b0c0d0e0f -> write block 1 data\n"
1002 "hf mfp wrbl --blk 2 -d ff0000000000000000000000000000ff -v -> write block 2 data with default key 0xFF..0xFF"
1005 void *argtable
[] = {
1007 arg_lit0("v", "verbose", "Verbose output"),
1008 arg_lit0("b", "keyb", "Use key B (def: keyA)"),
1009 arg_int1(NULL
, "blk", "<0..255>", "Block number"),
1010 arg_lit0("p", "plain", "Do not use encrypted transmission"),
1011 arg_lit0(NULL
, "nmr", "Do not expect MAC in response"),
1012 arg_str1("d", "data", "<hex>", "Data, 16 hex bytes"),
1013 arg_str0("k", "key", "<hex>", "Key, 16 hex bytes"),
1016 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
1018 bool verbose
= arg_get_lit(ctx
, 1);
1019 bool keyB
= arg_get_lit(ctx
, 2);
1020 uint32_t blockNum
= arg_get_int(ctx
, 3);
1021 bool plain
= arg_get_lit(ctx
, 4);
1022 bool nomacres
= arg_get_lit(ctx
, 5);
1024 uint8_t datain
[250] = {0};
1026 CLIGetHexWithReturn(ctx
, 6, datain
, &datainlen
);
1028 uint8_t key
[250] = {0};
1030 CLIGetHexWithReturn(ctx
, 7, key
, &keylen
);
1033 uint8_t keyn
[2] = {0};
1035 mfpSetVerboseMode(verbose
);
1038 memmove(key
, mfp_default_key
, 16);
1042 if (blockNum
> 255) {
1043 PrintAndLogEx(ERR
, "<block number> must be in range [0..255]. Got %d", blockNum
);
1048 PrintAndLogEx(ERR
, "<key> must be 16 bytes. Got %d", keylen
);
1052 if (datainlen
!= 16) {
1053 PrintAndLogEx(ERR
, "<data> must be 16 bytes. Got %d", datainlen
);
1057 uint8_t sectorNum
= mfSectorNum(blockNum
& 0xff);
1058 uint16_t uKeyNum
= 0x4000 + sectorNum
* 2 + (keyB
? 1 : 0);
1059 keyn
[0] = uKeyNum
>> 8;
1060 keyn
[1] = uKeyNum
& 0xff;
1062 PrintAndLogEx(INFO
, "--block:%d sector[%u]:%02x key:%04x", blockNum
& 0xff, mfNumBlocksPerSector(sectorNum
), sectorNum
, uKeyNum
);
1064 mf4Session_t mf4session
;
1065 int res
= MifareAuth4(&mf4session
, keyn
, key
, true, true, true, verbose
, false);
1067 PrintAndLogEx(ERR
, "Authentication error: %d", res
);
1070 if (!plain
) data_crypt(&mf4session
, &datain
[0], &datain
[0], false);
1071 uint8_t data
[250] = {0};
1073 uint8_t mac
[8] = {0};
1074 res
= MFPWriteBlock(&mf4session
, plain
, nomacres
, blockNum
& 0xff, 0x00, datain
, false, false, data
, sizeof(data
), &datalen
, mac
);
1076 PrintAndLogEx(ERR
, "Write error: %d", res
);
1081 if (datalen
!= 3 && (datalen
!= 3 + (nomacres
? 0 : 8))) {
1082 PrintAndLogEx(ERR
, "Error return length:%d", datalen
);
1087 if (datalen
&& data
[0] != 0x90) {
1088 PrintAndLogEx(ERR
, "Card write error: %02x %s", data
[0], mfpGetErrorDescription(data
[0]));
1093 if (memcmp(&data
[1], mac
, 8) && !nomacres
) {
1094 PrintAndLogEx(WARNING
, "WARNING: mac not equal...");
1095 PrintAndLogEx(WARNING
, "MAC card: %s", sprint_hex(&data
[1], 8));
1096 PrintAndLogEx(WARNING
, "MAC reader: %s", sprint_hex(mac
, 8));
1097 } else if (!nomacres
) {
1099 PrintAndLogEx(INFO
, "MAC: %s", sprint_hex(&data
[1], 8));
1103 PrintAndLogEx(INFO
, "Write ( " _GREEN_("ok") " )");
1107 static int CmdHFMFPChKey(const char *Cmd
) {
1108 CLIParserContext
*ctx
;
1109 CLIParserInit(&ctx
, "hf mfp chkey",
1110 "Change the keys on a Mifare Plus tag",
1111 "This requires the key that can update the key that you are trying to update.\n"
1112 "hf mfp chkey --ki 401f -d FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF --key A0A1A2A3A4A5A6A7A0A1A2A3A4A5A6A7 -> Change key B for Sector 15 from MAD to default\n"
1113 "hf mfp chkey --ki 9000 -d 32F9351A1C02B35FF97E0CA943F814F6 --key FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -> Change card master key to custom from default"
1116 void *argtable
[] = {
1118 arg_lit0("v", "verbose", "Verbose output"),
1119 arg_lit0(NULL
, "nmr", "Do not expect MAC in response"),
1120 arg_str1(NULL
, "ki", "<hex>", "Key Index, 2 hex bytes"),
1121 arg_str0("k", "key", "<hex>", "Current sector key, 16 hex bytes"),
1122 arg_lit0("b", "typeb", "Sector key is key B"),
1123 arg_str1("d", "data", "<hex>", "New key, 16 hex bytes"),
1126 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
1128 bool verbose
= arg_get_lit(ctx
, 1);
1129 bool nomacres
= arg_get_lit(ctx
, 2);
1131 uint8_t keyn
[250] = {0};
1133 uint8_t ki
[250] = {0};
1135 CLIGetHexWithReturn(ctx
, 3, ki
, &kilen
);
1137 uint8_t key
[250] = {0};
1139 CLIGetHexWithReturn(ctx
, 4, key
, &keylen
);
1141 bool usekeyb
= arg_get_lit(ctx
, 5);
1142 uint8_t datain
[250] = {0};
1144 CLIGetHexWithReturn(ctx
, 6, datain
, &datainlen
);
1148 mfpSetVerboseMode(verbose
);
1151 memmove(key
, mfp_default_key
, 16);
1156 PrintAndLogEx(ERR
, "<key> must be 16 bytes. Got %d", keylen
);
1160 if (datainlen
!= 16) {
1161 PrintAndLogEx(ERR
, "<data> must be 16 bytes. Got %d", datainlen
);
1164 mf4Session_t mf4session
;
1166 if (ki
[0] == 0x40) { // Only if we are working with sector keys
1168 keyn
[1] = (ki
[1] % 2 == 0) ? ki
[1] + 1 : ki
[1]; // If we change using key B, check if KI is key A
1170 keyn
[1] = (ki
[1] % 2 == 0) ? ki
[1] : ki
[1] - 1; // If we change using key A, check if KI is key A
1172 } else {keyn
[1] = ki
[1];}
1174 PrintAndLogEx(INFO
, "--key index:", sprint_hex(keyn
, 2));
1176 int res
= MifareAuth4(&mf4session
, keyn
, key
, true, true, true, verbose
, false);
1178 PrintAndLogEx(ERR
, "Authentication error: %d", res
);
1181 data_crypt(&mf4session
, &datain
[0], &datain
[0], false);
1182 uint8_t data
[250] = {0};
1184 uint8_t mac
[8] = {0};
1185 res
= MFPWriteBlock(&mf4session
, false, nomacres
, ki
[1], ki
[0], datain
, false, false, data
, sizeof(data
), &datalen
, mac
);
1187 PrintAndLogEx(ERR
, "Write error: %d", res
);
1192 if (datalen
!= 3 && (datalen
!= 3 + (nomacres
? 0 : 8))) {
1193 PrintAndLogEx(ERR
, "Error return length:%d", datalen
);
1198 if (datalen
&& data
[0] != 0x90) {
1199 PrintAndLogEx(ERR
, "Card write error: %02x %s", data
[0], mfpGetErrorDescription(data
[0]));
1204 if (memcmp(&data
[1], mac
, 8) && !nomacres
) {
1205 PrintAndLogEx(WARNING
, "WARNING: mac not equal...");
1206 PrintAndLogEx(WARNING
, "MAC card: %s", sprint_hex(&data
[1], 8));
1207 PrintAndLogEx(WARNING
, "MAC reader: %s", sprint_hex(mac
, 8));
1208 } else if (!nomacres
) {
1210 PrintAndLogEx(INFO
, "MAC: %s", sprint_hex(&data
[1], 8));
1214 PrintAndLogEx(INFO
, "Key update ( " _GREEN_("ok") " )");
1218 static int CmdHFMFPChConf(const char *Cmd
) {
1219 CLIParserContext
*ctx
;
1220 CLIParserInit(&ctx
, "hf mfp chconf",
1221 "Change the configuration on a Mifare Plus tag. DANGER!",
1222 "This requires Card Master Key (9000) or Card Configuration Key (9001).\n"
1223 "Configuration block info can be found below.\n"
1224 "* Block B000 (00; CMK): Max amount of commands without MAC (byte 0), as well as plain mode access (unknown).\n"
1225 "* Block B001 (01; CCK): Installation identifier for Virtual Card. Please consult NXP for data.\n"
1226 "* Block B002 (02; CCK): ATS data.\n"
1227 "* Block B003 (03; CCK): Use Random ID in SL3, decide whether proximity check is mandatory.\n * DO NOT WRITE THIS BLOCK UNDER ANY CIRCUMSTANCES! Risk of bricking.\n"
1228 "More configuration tips to follow. Check JMY600 Series IC Card Module.\n"
1229 "hf mfp chconf -c 00 -d 10ffffffffffffffffffffffffffffff --key A0A1A2A3A4A5A6A7A0A1A2A3A4A5A6A7 -> Allow 16 commands without MAC in a single transaction."
1232 void *argtable
[] = {
1234 arg_lit0("v", "verbose", "Verbose output"),
1235 arg_lit0(NULL
, "nmr", "Do not expect MAC in response"),
1236 arg_int1("c", "conf", "<hex>", "Config block number, 0-3"),
1237 arg_str0("k", "key", "<hex>", "Card key, 16 hex bytes"),
1238 arg_lit0(NULL
, "cck", "Auth as Card Configuration key instead of Card Master Key"),
1239 arg_str1("d", "data", "<hex>", "New configuration data, 16 hex bytes"),
1242 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
1244 bool verbose
= arg_get_lit(ctx
, 1);
1245 bool nomacres
= arg_get_lit(ctx
, 2);
1247 uint8_t keyn
[250] = {0};
1248 uint32_t blockNum
= arg_get_int(ctx
, 3);
1250 uint8_t key
[250] = {0};
1252 CLIGetHexWithReturn(ctx
, 4, key
, &keylen
);
1253 bool usecck
= arg_get_lit(ctx
, 5);
1255 uint8_t datain
[250] = {0};
1257 CLIGetHexWithReturn(ctx
, 6, datain
, &datainlen
);
1261 mfpSetVerboseMode(verbose
);
1264 memmove(key
, mfp_default_key
, 16);
1269 PrintAndLogEx(ERR
, "<key> must be 16 bytes. Got %d", keylen
);
1273 if (datainlen
!= 16) {
1274 PrintAndLogEx(ERR
, "<data> must be 16 bytes. Got %d", datainlen
);
1279 PrintAndLogEx(ERR
, "<config number> must be in range [0..3]. Got %d", blockNum
);
1282 mf4Session_t mf4session
;
1284 keyn
[1] = usecck
? 0x01 : 0x00;
1286 PrintAndLogEx(INFO
, "--key index:", sprint_hex(keyn
, 2));
1288 int res
= MifareAuth4(&mf4session
, keyn
, key
, true, true, true, verbose
, false);
1290 PrintAndLogEx(ERR
, "Authentication error: %d", res
);
1293 data_crypt(&mf4session
, &datain
[0], &datain
[0], false);
1294 uint8_t data
[250] = {0};
1296 uint8_t mac
[8] = {0};
1297 res
= MFPWriteBlock(&mf4session
, false, nomacres
, blockNum
& 0xff, 0xb0, datain
, false, false, data
, sizeof(data
), &datalen
, mac
);
1299 PrintAndLogEx(ERR
, "Write error: %d", res
);
1304 if (datalen
!= 3 && (datalen
!= 3 + (nomacres
? 0 : 8))) {
1305 PrintAndLogEx(ERR
, "Error return length:%d", datalen
);
1310 if (datalen
&& data
[0] != 0x90) {
1311 PrintAndLogEx(ERR
, "Card write error: %02x %s", data
[0], mfpGetErrorDescription(data
[0]));
1316 if (memcmp(&data
[1], mac
, 8) && !nomacres
) {
1317 PrintAndLogEx(WARNING
, "WARNING: mac not equal...");
1318 PrintAndLogEx(WARNING
, "MAC card: %s", sprint_hex(&data
[1], 8));
1319 PrintAndLogEx(WARNING
, "MAC reader: %s", sprint_hex(mac
, 8));
1320 } else if (!nomacres
) {
1322 PrintAndLogEx(INFO
, "MAC: %s", sprint_hex(&data
[1], 8));
1326 PrintAndLogEx(INFO
, "Write config ( " _GREEN_("ok") " )");
1330 static int plus_key_check(uint8_t startSector
, uint8_t endSector
, uint8_t startKeyAB
, uint8_t endKeyAB
,
1331 uint8_t keyList
[MAX_AES_KEYS_LIST_LEN
][AES_KEY_LEN
], size_t keyListLen
, uint8_t foundKeys
[2][64][AES_KEY_LEN
+ 1],
1334 bool selectCard
= true;
1335 uint8_t keyn
[2] = {0};
1337 // sector number from 0
1338 for (uint8_t sector
= startSector
; sector
<= endSector
; sector
++) {
1340 for (uint8_t keyAB
= startKeyAB
; keyAB
<= endKeyAB
; keyAB
++) {
1341 // main cycle with key check
1342 for (int i
= 0; i
< keyListLen
; i
++) {
1344 // allow client abort every iteration
1345 if (kbd_enter_pressed()) {
1346 PrintAndLogEx(WARNING
, "\naborted via keyboard!\n");
1348 return PM3_EOPABORTED
;
1352 if (verbose
== false) {
1353 PrintAndLogEx(NORMAL
, "." NOLF
);
1357 uint16_t uKeyNum
= 0x4000 + sector
* 2 + keyAB
;
1358 keyn
[0] = uKeyNum
>> 8;
1359 keyn
[1] = uKeyNum
& 0xff;
1361 for (int retry
= 0; retry
< 4; retry
++) {
1362 res
= MifareAuth4(NULL
, keyn
, keyList
[i
], selectCard
, true, false, false, true);
1363 if (res
== PM3_SUCCESS
|| res
== PM3_EWRONGANSWER
)
1367 PrintAndLogEx(WARNING
, "\nretried[%d]...", retry
);
1369 PrintAndLogEx(NORMAL
, "R" NOLF
);
1376 // key for [sector,keyAB] found
1377 if (res
== PM3_SUCCESS
) {
1379 PrintAndLogEx(INFO
, "\nFound key for sector %d key %s [%s]", sector
, keyAB
== 0 ? "A" : "B", sprint_hex_inrow(keyList
[i
], 16));
1381 PrintAndLogEx(NORMAL
, "+" NOLF
);
1383 foundKeys
[keyAB
][sector
][0] = 0x01;
1384 memcpy(&foundKeys
[keyAB
][sector
][1], keyList
[i
], AES_KEY_LEN
);
1389 // break out from keylist check loop,
1394 PrintAndLogEx(WARNING
, "\nsector %02d key %d [%s] res: %d", sector
, keyAB
, sprint_hex_inrow(keyList
[i
], 16), res
);
1398 // PM3_EWRONGANSWER -16
1399 if (res
== PM3_ERFTRANS
) {
1401 PrintAndLogEx(ERR
, "\nExchange error. Aborted.");
1403 PrintAndLogEx(NORMAL
, "E" NOLF
);
1406 return PM3_ECARDEXCHANGE
;
1418 static void Fill2bPattern(uint8_t keyList
[MAX_AES_KEYS_LIST_LEN
][AES_KEY_LEN
], uint32_t *keyListLen
, uint32_t *startPattern
) {
1419 for (uint32_t pt
= *startPattern
; pt
< 0x10000; pt
++) {
1420 keyList
[*keyListLen
][0] = (pt
>> 8) & 0xff;
1421 keyList
[*keyListLen
][1] = pt
& 0xff;
1422 memcpy(&keyList
[*keyListLen
][2], &keyList
[*keyListLen
][0], 2);
1423 memcpy(&keyList
[*keyListLen
][4], &keyList
[*keyListLen
][0], 4);
1424 memcpy(&keyList
[*keyListLen
][8], &keyList
[*keyListLen
][0], 8);
1427 if (*keyListLen
== MAX_AES_KEYS_LIST_LEN
)
1433 static int CmdHFMFPChk(const char *Cmd
) {
1435 CLIParserContext
*ctx
;
1436 CLIParserInit(&ctx
, "hf mfp chk",
1437 "Checks keys on MIFARE Plus card",
1438 "hf mfp chk -k 000102030405060708090a0b0c0d0e0f -> check key on sector 0 as key A and B\n"
1439 "hf mfp chk -s 2 -a -> check default key list on sector 2, only key A\n"
1440 "hf mfp chk -d mfp_default_keys -s0 -e6 -> check keys from dictionary against sectors 0-6\n"
1441 "hf mfp chk --pattern1b --dump -> check all 1-byte keys pattern and save found keys to file\n"
1442 "hf mfp chk --pattern2b --startp2b FA00 -> check all 2-byte keys pattern. Start from key FA00FA00...FA00");
1444 void *argtable
[] = {
1446 arg_lit0("a", "keya", "Check only key A (def: check all keys)"),
1447 arg_lit0("b", "keyb", "Check only key B (def: check all keys)"),
1448 arg_int0("s", "startsec", "<0..255>", "Start sector number"),
1449 arg_int0("e", "endsec", "<0..255>", "End sector number"),
1450 arg_str0("k", "key", "<hex>", "Key for checking (HEX 16 bytes)"),
1451 arg_str0("d", "dict", "<fn>", "Dictionary file with keys"),
1452 arg_lit0(NULL
, "pattern1b", "Check all 1-byte combinations of key (0000...0000, 0101...0101, 0202...0202, ...)"),
1453 arg_lit0(NULL
, "pattern2b", "Check all 2-byte combinations of key (0000...0000, 0001...0001, 0002...0002, ...)"),
1454 arg_str0(NULL
, "startp2b", "<pattern>", "Start key (2-byte HEX) for 2-byte search (use with `--pattern2b`)"),
1455 arg_lit0(NULL
, "dump", "Dump found keys to JSON file"),
1456 arg_lit0("v", "verbose", "Verbose output"),
1459 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
1461 bool keyA
= arg_get_lit(ctx
, 1);
1462 bool keyB
= arg_get_lit(ctx
, 2);
1463 uint8_t startSector
= arg_get_int_def(ctx
, 3, 0);
1464 uint8_t endSector
= arg_get_int_def(ctx
, 4, 0);
1466 uint8_t keyList
[MAX_AES_KEYS_LIST_LEN
][AES_KEY_LEN
] = {{0}};
1467 uint32_t keyListLen
= 0;
1468 uint8_t foundKeys
[2][64][AES_KEY_LEN
+ 1] = {{{0}}};
1470 uint8_t vkey
[16] = {0};
1472 CLIGetHexWithReturn(ctx
, 5, vkey
, &vkeylen
);
1474 if (vkeylen
== 16) {
1475 memcpy(&keyList
[keyListLen
], vkey
, 16);
1478 PrintAndLogEx(ERR
, "Specified key must have 16 bytes. Got %d", vkeylen
);
1484 uint8_t dict_filename
[FILE_PATH_SIZE
+ 2] = {0};
1485 int dict_filenamelen
= 0;
1486 if (CLIParamStrToBuf(arg_get_str(ctx
, 6), dict_filename
, FILE_PATH_SIZE
, &dict_filenamelen
)) {
1487 PrintAndLogEx(FAILED
, "File name too long or invalid.");
1492 bool pattern1b
= arg_get_lit(ctx
, 7);
1493 bool pattern2b
= arg_get_lit(ctx
, 8);
1495 if (pattern1b
&& pattern2b
) {
1496 PrintAndLogEx(ERR
, "Pattern search mode must be 2-byte or 1-byte only.");
1501 if (dict_filenamelen
&& (pattern1b
|| pattern2b
)) {
1502 PrintAndLogEx(ERR
, "Pattern search mode and dictionary mode can't be used in one command.");
1507 uint32_t startPattern
= 0x0000;
1508 uint8_t vpattern
[2];
1509 int vpatternlen
= 0;
1510 CLIGetHexWithReturn(ctx
, 9, vpattern
, &vpatternlen
);
1511 if (vpatternlen
> 0) {
1512 if (vpatternlen
<= 2) {
1513 startPattern
= (vpattern
[0] << 8) + vpattern
[1];
1515 PrintAndLogEx(ERR
, "Pattern must be 2-bytes. Got %d", vpatternlen
);
1520 PrintAndLogEx(WARNING
, "Pattern entered, but search mode not is 2-byte search.");
1523 bool create_dumpfile
= arg_get_lit(ctx
, 10);
1524 bool verbose
= arg_get_lit(ctx
, 11);
1527 uint8_t startKeyAB
= 0;
1528 uint8_t endKeyAB
= 1;
1529 if (keyA
&& (keyB
== false))
1532 if ((keyA
== false) && keyB
)
1535 if (endSector
< startSector
)
1536 endSector
= startSector
;
1538 // 1-byte pattern search mode
1540 for (int i
= 0; i
< 0x100; i
++) {
1541 memset(keyList
[i
], i
, 16);
1547 // 2-byte pattern search mode
1549 Fill2bPattern(keyList
, &keyListLen
, &startPattern
);
1552 int res
= PM3_SUCCESS
;
1555 size_t endFilePosition
= 0;
1556 if (dict_filenamelen
) {
1557 uint32_t keycnt
= 0;
1558 res
= loadFileDICTIONARYEx((char *)dict_filename
, keyList
, sizeof(keyList
), NULL
, 16, &keycnt
, 0, &endFilePosition
, true);
1560 if (res
== PM3_SUCCESS
&& endFilePosition
) {
1561 keyListLen
= keycnt
;
1562 PrintAndLogEx(SUCCESS
, "First part of dictionary successfully loaded.");
1566 if (keyListLen
== 0) {
1567 for (int i
= 0; i
< g_mifare_plus_default_keys_len
; i
++) {
1568 if (hex_to_bytes(g_mifare_plus_default_keys
[i
], keyList
[keyListLen
], 16) != 16) {
1576 if (keyListLen
== 0) {
1577 PrintAndLogEx(ERR
, "Key list is empty. Nothing to check.");
1580 PrintAndLogEx(INFO
, "Loaded " _YELLOW_("%"PRIu32
) " keys", keyListLen
);
1583 if (verbose
== false) {
1584 PrintAndLogEx(INFO
, "Search keys");
1588 res
= plus_key_check(startSector
, endSector
, startKeyAB
, endKeyAB
, keyList
, keyListLen
, foundKeys
, verbose
);
1589 if (res
== PM3_EOPABORTED
) {
1593 if (pattern2b
&& startPattern
< 0x10000) {
1594 if (verbose
== false) {
1595 PrintAndLogEx(NORMAL
, "p" NOLF
);
1599 Fill2bPattern(keyList
, &keyListLen
, &startPattern
);
1603 if (dict_filenamelen
&& endFilePosition
) {
1604 if (verbose
== false)
1605 PrintAndLogEx(NORMAL
, "d" NOLF
);
1607 uint32_t keycnt
= 0;
1608 res
= loadFileDICTIONARYEx((char *)dict_filename
, keyList
, sizeof(keyList
), NULL
, 16, &keycnt
, endFilePosition
, &endFilePosition
, false);
1609 if (res
== PM3_SUCCESS
&& endFilePosition
) {
1610 keyListLen
= keycnt
;
1618 if (verbose
== false) {
1619 PrintAndLogEx(NORMAL
, "");
1623 char strA
[46 + 1] = {0};
1624 char strB
[46 + 1] = {0};
1626 uint8_t ndef_key
[] = {0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7};
1627 bool has_ndef_key
= false;
1628 bool printedHeader
= false;
1629 for (uint8_t s
= startSector
; s
<= endSector
; s
++) {
1631 if ((memcmp(&foundKeys
[0][s
][1], ndef_key
, AES_KEY_LEN
) == 0) ||
1632 (memcmp(&foundKeys
[1][s
][1], ndef_key
, AES_KEY_LEN
) == 0)) {
1633 has_ndef_key
= true;
1636 if (printedHeader
== false) {
1637 PrintAndLogEx(NORMAL
, "");
1638 PrintAndLogEx(INFO
, "-----+----------------------------------+----------------------------------");
1639 PrintAndLogEx(INFO
, " Sec | key A | key B");
1640 PrintAndLogEx(INFO
, "-----+----------------------------------+----------------------------------");
1641 printedHeader
= true;
1644 if (foundKeys
[0][s
][0]) {
1645 snprintf(strA
, sizeof(strA
), _GREEN_("%s"), sprint_hex_inrow(&foundKeys
[0][s
][1], AES_KEY_LEN
));
1647 snprintf(strA
, sizeof(strA
), _RED_("%s"), "--------------------------------");
1650 if (foundKeys
[1][s
][0]) {
1651 snprintf(strB
, sizeof(strB
), _GREEN_("%s"), sprint_hex_inrow(&foundKeys
[1][s
][1], AES_KEY_LEN
));
1653 snprintf(strB
, sizeof(strB
), _RED_("%s"), "--------------------------------");
1656 PrintAndLogEx(INFO
, " " _YELLOW_("%03d") " | %s | %s", s
, strA
, strB
);
1659 if (printedHeader
== false)
1660 PrintAndLogEx(INFO
, "No keys found(");
1662 PrintAndLogEx(INFO
, "-----+----------------------------------+----------------------------------\n");
1664 // save keys to json
1665 if (create_dumpfile
&& printedHeader
) {
1667 size_t keys_len
= (2 * 64 * (AES_KEY_LEN
+ 1));
1669 uint8_t data
[10 + 1 + 2 + 1 + 256 + keys_len
];
1670 memset(data
, 0, sizeof(data
));
1673 SendCommandMIX(CMD_HF_ISO14443A_READER
, ISO14A_CONNECT
, 0, 0, NULL
, 0);
1675 PacketResponseNG resp
;
1676 WaitForResponse(CMD_ACK
, &resp
);
1678 iso14a_card_select_t card
;
1679 memcpy(&card
, (iso14a_card_select_t
*)resp
.data
.asBytes
, sizeof(iso14a_card_select_t
));
1681 uint64_t select_status
= resp
.oldarg
[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision
1683 if (select_status
== 1 || select_status
== 2) {
1684 memcpy(data
, card
.uid
, card
.uidlen
);
1685 data
[10] = card
.sak
;
1686 data
[11] = card
.atqa
[1];
1687 data
[12] = card
.atqa
[0];
1688 atslen
= card
.ats_len
;
1690 memcpy(&data
[14], card
.ats
, atslen
);
1693 char *fptr
= calloc(sizeof(char) * (strlen("hf-mfp-") + strlen("-key")) + card
.uidlen
* 2 + 1, sizeof(uint8_t));
1694 strcpy(fptr
, "hf-mfp-");
1696 FillFileNameByUID(fptr
, card
.uid
, "-key", card
.uidlen
);
1698 // length: UID(10b)+SAK(1b)+ATQA(2b)+ATSlen(1b)+ATS(atslen)+foundKeys[2][64][AES_KEY_LEN + 1]
1699 memcpy(&data
[14 + atslen
], foundKeys
, keys_len
);
1700 // 64 here is for how many "rows" there is in the data array. A bit confusing
1701 saveFileJSON(fptr
, jsfMfPlusKeys
, data
, 64, NULL
);
1706 if ((memcmp(&foundKeys
[0][0][1], "\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7", AES_KEY_LEN
) == 0)) {
1707 PrintAndLogEx(HINT
, "MAD key detected. Try " _YELLOW_("`hf mfp mad`") " for more details");
1712 PrintAndLogEx(HINT
, "NDEF key detected. Try " _YELLOW_("`hf mfp ndefread -h`") " for more details");
1714 PrintAndLogEx(NORMAL
, "");
1718 static int CmdHFMFPDump(const char *Cmd
) {
1719 CLIParserContext
*ctx
;
1720 CLIParserInit(&ctx
, "hf mfp dump",
1721 "Dump MIFARE Plus tag to file (bin/json)\n"
1722 "If no <name> given, UID will be used as filename",
1724 "hf mfp dump --keys hf-mf-066C8B78-key.bin --> MIFARE Plus with keys from specified file\n");
1726 void *argtable
[] = {
1728 arg_str0("f", "file", "<fn>", "Specify a filename for dump file"),
1729 arg_str0("k", "keys", "<fn>", "Specify a filename for keys file"),
1730 // arg_lit0(NULL, "ns", "no save to file"),
1731 // arg_lit0("v", "verbose", "Verbose output"),
1734 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
1737 char data_fn
[FILE_PATH_SIZE
] = {0};
1738 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)data_fn
, FILE_PATH_SIZE
, &datafnlen
);
1741 char key_fn
[FILE_PATH_SIZE
] = {0};
1742 CLIParamStrToBuf(arg_get_str(ctx
, 2), (uint8_t *)key_fn
, FILE_PATH_SIZE
, &keyfnlen
);
1744 // bool nosave = arg_get_lit(ctx, 3);
1745 // bool verbose = arg_get_lit(ctx, 4);
1748 PrintAndLogEx(INFO
, " To be implemented, feel free to contribute!");
1749 return PM3_ENOTIMPL
;
1752 mfpSetVerboseMode(verbose);
1755 uint8_t *mem = calloc(MIFARE_4K_MAXBLOCK * MFBLOCK_SIZE, sizeof(uint8_t));
1757 PrintAndLogEx(ERR, "failed to allocate memory");
1762 // iso14a_card_select_t card ;
1763 // int res = mfp_read_tag(&card, mem, key_fn);
1764 // if (res != PM3_SUCCESS) {
1770 // Skip saving card data to file
1772 PrintAndLogEx(INFO, "Called with no save option");
1778 // if (strlen(data_fn) < 1) {
1779 // char *fptr = calloc(sizeof(char) * (strlen("hf-mfp-") + strlen("-dump")) + card.uidlen * 2 + 1, sizeof(uint8_t));
1780 // strcpy(fptr, "hf-mfp-");
1781 // FillFileNameByUID(fptr, card.uid, "-dump", card.uidlen);
1782 // strcpy(data_fn, fptr);
1786 // pm3_save_mf_dump(filename, dump, MIFARE_4K_MAX_BYTES, jsfCardMemory);
1793 static int CmdHFMFPMAD(const char *Cmd
) {
1795 CLIParserContext
*ctx
;
1796 CLIParserInit(&ctx
, "hf mfp mad",
1797 "Checks and prints MIFARE Application Directory (MAD)",
1799 "hf mfp mad --aid e103 -k d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7 -> read and print NDEF data from MAD aid");
1801 void *argtable
[] = {
1803 arg_lit0("v", "verbose", "Verbose output"),
1804 arg_str0(NULL
, "aid", "<hex>", "Print all sectors with aid"),
1805 arg_str0("k", "key", "<hex>", "Key for printing sectors"),
1806 arg_lit0("b", "keyb", "Use key B for access printing sectors (def: key A)"),
1807 arg_lit0(NULL
, "be", "(optional: BigEndian)"),
1808 arg_lit0(NULL
, "dch", "Decode Card Holder information"),
1811 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
1813 bool verbose
= arg_get_lit(ctx
, 1);
1814 uint8_t aid
[2] = {0};
1816 CLIGetHexWithReturn(ctx
, 2, aid
, &aidlen
);
1817 uint8_t key
[16] = {0};
1819 CLIGetHexWithReturn(ctx
, 3, key
, &keylen
);
1820 bool keyB
= arg_get_lit(ctx
, 4);
1821 bool swapmad
= arg_get_lit(ctx
, 5);
1822 bool decodeholder
= arg_get_lit(ctx
, 6);
1826 if (aidlen
!= 2 && !decodeholder
&& keylen
> 0) {
1827 PrintAndLogEx(WARNING
, "Using default MAD keys instead");
1830 uint8_t sector0
[16 * 4] = {0};
1831 uint8_t sector10
[16 * 4] = {0};
1833 if (mfpReadSector(MF_MAD1_SECTOR
, MF_KEY_A
, (uint8_t *)g_mifarep_mad_key
, sector0
, verbose
)) {
1834 PrintAndLogEx(NORMAL
, "");
1835 PrintAndLogEx(ERR
, "error, read sector 0. card doesn't have MAD or doesn't have MAD on default keys");
1842 PrintAndLogEx(SUCCESS
, "Raw:");
1843 for (int i
= 0; i
< 4; i
++)
1844 PrintAndLogEx(INFO
, "[%d] %s", i
, sprint_hex(§or0
[i
* 16], 16));
1847 bool haveMAD2
= false;
1848 MAD1DecodeAndPrint(sector0
, swapmad
, verbose
, &haveMAD2
);
1851 if (mfpReadSector(MF_MAD2_SECTOR
, MF_KEY_A
, (uint8_t *)g_mifarep_mad_key
, sector10
, verbose
)) {
1852 PrintAndLogEx(NORMAL
, "");
1853 PrintAndLogEx(ERR
, "error, read sector " _YELLOW_("0x10") ". Card doesn't have MAD or doesn't have MAD on default keys");
1857 MAD2DecodeAndPrint(sector10
, swapmad
, verbose
);
1860 if (aidlen
== 2 || decodeholder
) {
1861 uint16_t mad
[7 + 8 + 8 + 8 + 8] = {0};
1863 if (MADDecode(sector0
, sector10
, mad
, &madlen
, swapmad
)) {
1864 PrintAndLogEx(ERR
, "can't decode MAD");
1865 return PM3_EWRONGANSWER
;
1868 // copy default NDEF key
1869 uint8_t akey
[16] = {0};
1870 memcpy(akey
, g_mifarep_ndef_key
, 16);
1872 // user specified key
1874 memcpy(akey
, key
, 16);
1877 uint16_t aaid
= 0x0004;
1879 aaid
= (aid
[0] << 8) + aid
[1];
1880 PrintAndLogEx(NORMAL
, "");
1881 PrintAndLogEx(INFO
, "-------------- " _CYAN_("AID 0x%04x") " ---------------", aaid
);
1883 for (int i
= 0; i
< madlen
; i
++) {
1884 if (aaid
== mad
[i
]) {
1885 uint8_t vsector
[16 * 4] = {0};
1886 if (mfpReadSector(i
+ 1, keyB
? MF_KEY_B
: MF_KEY_A
, akey
, vsector
, false)) {
1887 PrintAndLogEx(NORMAL
, "");
1888 PrintAndLogEx(ERR
, "error, read sector %d error", i
+ 1);
1892 for (int j
= 0; j
< (verbose
? 4 : 3); j
++)
1893 PrintAndLogEx(NORMAL
, " [%03d] %s", (i
+ 1) * 4 + j
, sprint_hex(&vsector
[j
* 16], 16));
1900 PrintAndLogEx(NORMAL
, "");
1901 PrintAndLogEx(INFO
, "-------- " _CYAN_("Card Holder Info 0x%04x") " --------", aaid
);
1903 uint8_t data
[4096] = {0};
1906 for (int i
= 0; i
< madlen
; i
++) {
1907 if (aaid
== mad
[i
]) {
1909 uint8_t vsector
[16 * 4] = {0};
1910 if (mfReadSector(i
+ 1, keyB
? MF_KEY_B
: MF_KEY_A
, akey
, vsector
)) {
1911 PrintAndLogEx(NORMAL
, "");
1912 PrintAndLogEx(ERR
, "error, read sector %d", i
+ 1);
1916 memcpy(&data
[datalen
], vsector
, 16 * 3);
1922 PrintAndLogEx(WARNING
, "no Card Holder Info data");
1925 MADCardHolderInfoDecode(data
, datalen
, verbose
);
1931 static int CmdHFMFPNDEFFormat(const char *Cmd
) {
1932 CLIParserContext
*ctx
;
1933 CLIParserInit(&ctx
, "hf mfp ndefformat",
1934 "format MIFARE Plus Tag as a NFC tag with Data Exchange Format (NDEF)\n"
1935 "If no <name> given, UID will be used as filename. \n"
1936 "It will try default keys and MAD keys to detect if tag is already formatted in order to write.\n"
1938 "If not, it will try finding a key file based on your UID. ie, if you ran autopwn before",
1939 "hf mfp ndefformat\n"
1940 "hf mfp ndefformat --keys hf-mf-01020304-key.bin --> with keys from specified file\n"
1943 void *argtable
[] = {
1945 arg_str0("k", "keys", "<fn>", "filename of keys"),
1948 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
1951 char keyFilename
[FILE_PATH_SIZE
] = {0};
1952 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)keyFilename
, FILE_PATH_SIZE
, &keyfnlen
);
1956 PrintAndLogEx(SUCCESS
, "Not implemented yet. Feel free to contribute!");
1957 PrintAndLogEx(NORMAL
, "");
1961 int CmdHFMFPNDEFRead(const char *Cmd
) {
1963 CLIParserContext
*ctx
;
1964 CLIParserInit(&ctx
, "hf mfp ndefread",
1965 "Prints NFC Data Exchange Format (NDEF)",
1966 "hf mfp ndefread \n"
1967 "hf mfp ndefread -vv -> shows NDEF parsed and raw data\n"
1968 "hf mfp ndefread --aid e103 -k d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7 -> shows NDEF data with custom AID and key\n"
1969 "hf mfp ndefread -f myfilename -> save raw NDEF to file"
1972 void *argtable
[] = {
1974 arg_litn("v", "verbose", 0, 2, "verbose output"),
1975 arg_str0(NULL
, "aid", "<aid>", "replace default aid for NDEF"),
1976 arg_str0("k", "key", "<key>", "replace default key for NDEF"),
1977 arg_lit0("b", "keyb", "use key B for access sectors (by default: key A)"),
1978 arg_str0("f", "file", "<fn>", "save raw NDEF to file"),
1981 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
1983 bool verbose
= arg_get_lit(ctx
, 1);
1984 bool verbose2
= arg_get_lit(ctx
, 1) > 1;
1985 uint8_t aid
[2] = {0};
1987 CLIGetHexWithReturn(ctx
, 2, aid
, &aidlen
);
1988 uint8_t key
[16] = {0};
1990 CLIGetHexWithReturn(ctx
, 3, key
, &keylen
);
1991 bool keyB
= arg_get_lit(ctx
, 4);
1994 char filename
[FILE_PATH_SIZE
] = {0};
1995 CLIParamStrToBuf(arg_get_str(ctx
, 5), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
1998 uint16_t ndefAID
= 0xe103;
2000 ndefAID
= (aid
[0] << 8) + aid
[1];
2002 uint8_t ndefkey
[16] = {0};
2003 memcpy(ndefkey
, g_mifarep_ndef_key
, 16);
2005 memcpy(ndefkey
, key
, 16);
2008 uint8_t sector0
[16 * 4] = {0};
2009 uint8_t sector10
[16 * 4] = {0};
2010 uint8_t data
[4096] = {0};
2014 PrintAndLogEx(INFO
, "reading MAD v1 sector");
2016 if (mfpReadSector(MF_MAD1_SECTOR
, MF_KEY_A
, (uint8_t *)g_mifarep_mad_key
, sector0
, verbose
)) {
2017 PrintAndLogEx(ERR
, "error, read sector 0. card doesn't have MAD or doesn't have MAD on default keys");
2018 PrintAndLogEx(HINT
, "Try " _YELLOW_("`hf mfp ndefread -k `") " with your custom key");
2022 bool haveMAD2
= false;
2023 int res
= MADCheck(sector0
, NULL
, verbose
, &haveMAD2
);
2024 if (res
!= PM3_SUCCESS
) {
2025 PrintAndLogEx(ERR
, "MAD error %d", res
);
2032 PrintAndLogEx(INFO
, "reading MAD v2 sector");
2034 if (mfpReadSector(MF_MAD2_SECTOR
, MF_KEY_A
, (uint8_t *)g_mifarep_mad_key
, sector10
, verbose
)) {
2035 PrintAndLogEx(ERR
, "error, read sector 0x10. card doesn't have MAD or doesn't have MAD on default keys");
2036 PrintAndLogEx(HINT
, "Try " _YELLOW_("`hf mfp ndefread -k `") " with your custom key");
2041 uint16_t mad
[7 + 8 + 8 + 8 + 8] = {0};
2043 res
= MADDecode(sector0
, (haveMAD2
? sector10
: NULL
), mad
, &madlen
, false);
2044 if (res
!= PM3_SUCCESS
) {
2045 PrintAndLogEx(ERR
, "can't decode MAD");
2049 PrintAndLogEx(INFO
, "reading data from tag");
2050 for (int i
= 0; i
< madlen
; i
++) {
2051 if (ndefAID
== mad
[i
]) {
2052 uint8_t vsector
[16 * 4] = {0};
2053 if (mfpReadSector(i
+ 1, keyB
? MF_KEY_B
: MF_KEY_A
, ndefkey
, vsector
, false)) {
2054 PrintAndLogEx(ERR
, "error, reading sector %d", i
+ 1);
2058 memcpy(&data
[datalen
], vsector
, 16 * 3);
2061 PrintAndLogEx(INPLACE
, "%d", i
);
2064 PrintAndLogEx(NORMAL
, "");
2067 PrintAndLogEx(ERR
, "no NDEF data");
2072 PrintAndLogEx(NORMAL
, "");
2073 PrintAndLogEx(INFO
, "--- " _CYAN_("MF Plus NDEF raw") " ----------------");
2074 print_buffer(data
, datalen
, 1);
2077 res
= NDEFDecodeAndPrint(data
, datalen
, verbose
);
2078 if (res
!= PM3_SUCCESS
) {
2079 PrintAndLogEx(INFO
, "Trying to parse NDEF records w/o NDEF header");
2080 res
= NDEFRecordsDecodeAndPrint(data
, datalen
, verbose
);
2083 // get total NDEF length before save. If fails, we save it all
2085 if (NDEFGetTotalLength(data
, datalen
, &n
) != PM3_SUCCESS
)
2088 pm3_save_dump(filename
, data
, n
, jsfNDEF
);
2090 if (verbose
== false) {
2091 PrintAndLogEx(HINT
, "Try " _YELLOW_("`hf mfp ndefread -v`") " for more details");
2093 if (verbose2
== false) {
2094 PrintAndLogEx(HINT
, "Try " _YELLOW_("`hf mfp ndefread -vv`") " for more details");
2100 static int CmdHFMFPNDEFWrite(const char *Cmd
) {
2101 CLIParserContext
*ctx
;
2102 CLIParserInit(&ctx
, "hf mfp ndefwrite",
2103 "Write raw NDEF hex bytes to tag. This commands assumes tag already been NFC/NDEF formatted.\n",
2104 "hf mfp ndefwrite -d 0300FE -> write empty record to tag\n"
2105 "hf mfp ndefwrite -f myfilename\n"
2106 "hf mfp ndefwrite -d 033fd1023a53709101195405656e2d55534963656d616e2054776974746572206c696e6b5101195502747769747465722e636f6d2f686572726d616e6e31303031\n"
2109 void *argtable
[] = {
2111 arg_str0("d", NULL
, "<hex>", "raw NDEF hex bytes"),
2112 arg_str0("f", "file", "<fn>", "write raw NDEF file to tag"),
2113 arg_lit0("p", NULL
, "fix NDEF record headers / terminator block if missing"),
2114 arg_lit0("v", "verbose", "verbose output"),
2117 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
2119 uint8_t raw
[4096] = {0};
2121 CLIGetHexWithReturn(ctx
, 1, raw
, &rawlen
);
2124 char filename
[FILE_PATH_SIZE
] = {0};
2125 CLIParamStrToBuf(arg_get_str(ctx
, 2), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
2127 bool fix_msg
= arg_get_lit(ctx
, 3);
2128 bool verbose
= arg_get_lit(ctx
, 4);
2132 PrintAndLogEx(NORMAL
, "called with fix NDEF message param");
2136 PrintAndLogEx(NORMAL
, "");
2138 PrintAndLogEx(SUCCESS
, "Not implemented yet. Feel free to contribute!");
2139 PrintAndLogEx(NORMAL
, "");
2143 static int CmdHFMFPList(const char *Cmd
) {
2144 return CmdTraceListAlias(Cmd
, "hf mfp", "mfp -c");
2147 static command_t CommandTable
[] = {
2148 {"help", CmdHelp
, AlwaysAvailable
, "This help"},
2149 {"list", CmdHFMFPList
, AlwaysAvailable
, "List MIFARE Plus history"},
2150 {"-----------", CmdHelp
, IfPm3Iso14443a
, "------------------- " _CYAN_("operations") " ---------------------"},
2151 {"auth", CmdHFMFPAuth
, IfPm3Iso14443a
, "Authentication"},
2152 {"chk", CmdHFMFPChk
, IfPm3Iso14443a
, "Check keys"},
2153 {"dump", CmdHFMFPDump
, IfPm3Iso14443a
, "Dump MIFARE Plus tag to binary file"},
2154 {"info", CmdHFMFPInfo
, IfPm3Iso14443a
, "Info about MIFARE Plus tag"},
2155 {"mad", CmdHFMFPMAD
, IfPm3Iso14443a
, "Check and print MAD"},
2156 {"rdbl", CmdHFMFPRdbl
, IfPm3Iso14443a
, "Read blocks from card"},
2157 {"rdsc", CmdHFMFPRdsc
, IfPm3Iso14443a
, "Read sectors from card"},
2158 {"wrbl", CmdHFMFPWrbl
, IfPm3Iso14443a
, "Write block to card"},
2159 {"chkey", CmdHFMFPChKey
, IfPm3Iso14443a
, "Change key on card"},
2160 {"chconf", CmdHFMFPChConf
, IfPm3Iso14443a
, "Change config on card"},
2161 {"-----------", CmdHelp
, IfPm3Iso14443a
, "---------------- " _CYAN_("personalization") " -------------------"},
2162 {"commitp", CmdHFMFPCommitPerso
, IfPm3Iso14443a
, "Configure security layer (SL1/SL3 mode)"},
2163 {"initp", CmdHFMFPInitPerso
, IfPm3Iso14443a
, "Fill all the card's keys in SL0 mode"},
2164 {"wrp", CmdHFMFPWritePerso
, IfPm3Iso14443a
, "Write Perso command"},
2165 {"-----------", CmdHelp
, IfPm3Iso14443a
, "---------------------- " _CYAN_("ndef") " ------------------------"},
2166 {"ndefformat", CmdHFMFPNDEFFormat
, IfPm3Iso14443a
, "Format MIFARE Plus Tag as NFC Tag"},
2167 {"ndefread", CmdHFMFPNDEFRead
, IfPm3Iso14443a
, "Read and print NDEF records from card"},
2168 {"ndefwrite", CmdHFMFPNDEFWrite
, IfPm3Iso14443a
, "Write NDEF records to card"},
2169 {NULL
, NULL
, 0, NULL
}
2172 static int CmdHelp(const char *Cmd
) {
2173 (void)Cmd
; // Cmd is not used so far
2174 CmdsHelp(CommandTable
);
2178 int CmdHFMFP(const char *Cmd
) {
2179 clearCommandBuffer();
2180 return CmdsParse(CommandTable
, Cmd
);