1 //-----------------------------------------------------------------------------
2 // Copyright (C) 2018 Merlok
3 // Copyright (C) 2018 drHatson
5 // This code is licensed to you under the terms of the GNU GPL, version 2 or,
6 // at your option, any later version. See the LICENSE.txt file for the text of
8 //-----------------------------------------------------------------------------
9 // High frequency MIFARE Plus commands
10 //-----------------------------------------------------------------------------
25 #include "mifare/mifare4.h"
26 #include "mifare/mad.h"
27 #include "mifare/ndef.h"
28 #include "cliparser/cliparser.h"
29 #include "crypto/libpcrypto.h"
32 static const uint8_t DefaultKey
[16] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
34 static int CmdHelp(const char *Cmd
);
36 int CmdHFMFPInfo(const char *cmd
) {
38 if (cmd
&& strlen(cmd
) > 0)
39 PrintAndLog("WARNING: command don't have any parameters.\n");
41 // info about 14a part
45 UsbCommand c
= {CMD_READER_ISO_14443a
, {ISO14A_CONNECT
| ISO14A_NO_DISCONNECT
, 0, 0}};
49 WaitForResponse(CMD_ACK
,&resp
);
51 iso14a_card_select_t card
;
52 memcpy(&card
, (iso14a_card_select_t
*)resp
.d
.asBytes
, sizeof(iso14a_card_select_t
));
54 uint64_t select_status
= resp
.arg
[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision
56 if (select_status
== 1 || select_status
== 2) {
57 PrintAndLog("----------------------------------------------");
58 PrintAndLog("Mifare Plus info:");
60 // MIFARE Type Identification Procedure
61 // https://www.nxp.com/docs/en/application-note/AN10833.pdf
62 uint16_t ATQA
= card
.atqa
[0] + (card
.atqa
[1] << 8);
63 if (ATQA
== 0x0004) PrintAndLog("ATQA: Mifare Plus 2k 4bUID");
64 if (ATQA
== 0x0002) PrintAndLog("ATQA: Mifare Plus 4k 4bUID");
65 if (ATQA
== 0x0044) PrintAndLog("ATQA: Mifare Plus 2k 7bUID");
66 if (ATQA
== 0x0042) PrintAndLog("ATQA: Mifare Plus 4k 7bUID");
68 uint8_t SLmode
= 0xff;
69 if (card
.sak
== 0x08) {
70 PrintAndLog("SAK: Mifare Plus 2k 7bUID");
71 if (select_status
== 2) SLmode
= 1;
73 if (card
.sak
== 0x18) {
74 PrintAndLog("SAK: Mifare Plus 4k 7bUID");
75 if (select_status
== 2) SLmode
= 1;
77 if (card
.sak
== 0x10) {
78 PrintAndLog("SAK: Mifare Plus 2k");
79 if (select_status
== 2) SLmode
= 2;
81 if (card
.sak
== 0x11) {
82 PrintAndLog("SAK: Mifare Plus 4k");
83 if (select_status
== 2) SLmode
= 2;
85 if (card
.sak
== 0x20) {
86 PrintAndLog("SAK: Mifare Plus SL0/SL3 or Mifare desfire");
87 if (card
.ats_len
> 0) {
91 uint8_t data
[250] = {0};
93 // https://github.com/Proxmark/proxmark3/blob/master/client/scripts/mifarePlus.lua#L161
94 uint8_t cmd
[3 + 16] = {0xa8, 0x90, 0x90, 0x00};
95 int res
= ExchangeRAW14a(cmd
, sizeof(cmd
), false, false, data
, sizeof(data
), &datalen
);
96 if (!res
&& datalen
> 1 && data
[0] == 0x09) {
103 PrintAndLog("Mifare Plus SL mode: SL%d", SLmode
);
105 PrintAndLog("Mifare Plus SL mode: unknown(");
107 PrintAndLog("Mifare Plus info not available.");
115 int CmdHFMFPWritePerso(const char *cmd
) {
116 uint8_t keyNum
[64] = {0};
118 uint8_t key
[64] = {0};
121 CLIParserInit("hf mfp wrp",
122 "Executes Write Perso command. Can be used in SL0 mode only.",
123 "Usage:\n\thf mfp wrp 4000 000102030405060708090a0b0c0d0e0f -> write key (00..0f) to key number 4000 \n"
124 "\thf mfp wrp 4000 -> write default key(0xff..0xff) to key number 4000");
128 arg_lit0("vV", "verbose", "show internal data."),
129 arg_str1(NULL
, NULL
, "<HEX key number (2b)>", NULL
),
130 arg_strx0(NULL
, NULL
, "<HEX key (16b)>", NULL
),
133 CLIExecWithReturn(cmd
, argtable
, true);
135 bool verbose
= arg_get_lit(1);
136 CLIGetHexWithReturn(2, keyNum
, &keyNumLen
);
137 CLIGetHexWithReturn(3, key
, &keyLen
);
140 mfpSetVerboseMode(verbose
);
143 memmove(key
, DefaultKey
, 16);
147 if (keyNumLen
!= 2) {
148 PrintAndLog("Key number length must be 2 bytes instead of: %d", keyNumLen
);
152 PrintAndLog("Key length must be 16 bytes instead of: %d", keyLen
);
156 uint8_t data
[250] = {0};
159 int res
= MFPWritePerso(keyNum
, key
, true, false, data
, sizeof(data
), &datalen
);
161 PrintAndLog("Exchange error: %d", res
);
166 PrintAndLog("Command must return 3 bytes instead of: %d", datalen
);
170 if (data
[0] != 0x90) {
171 PrintAndLog("Command error: %02x %s", data
[0], mfpGetErrorDescription(data
[0]));
174 PrintAndLog("Write OK.");
179 uint16_t CardAddresses
[] = {0x9000, 0x9001, 0x9002, 0x9003, 0x9004, 0xA000, 0xA001, 0xA080, 0xA081, 0xC000, 0xC001};
181 int CmdHFMFPInitPerso(const char *cmd
) {
183 uint8_t key
[256] = {0};
185 uint8_t keyNum
[2] = {0};
186 uint8_t data
[250] = {0};
189 CLIParserInit("hf mfp initp",
190 "Executes Write Perso command for all card's keys. Can be used in SL0 mode only.",
191 "Usage:\n\thf mfp initp 000102030405060708090a0b0c0d0e0f -> fill all the keys with key (00..0f)\n"
192 "\thf mfp initp -vv -> fill all the keys with default key(0xff..0xff) and show all the data exchange");
196 arg_litn("vV", "verbose", 0, 2, "show internal data."),
197 arg_strx0(NULL
, NULL
, "<HEX key (16b)>", NULL
),
200 CLIExecWithReturn(cmd
, argtable
, true);
202 bool verbose
= arg_get_lit(1);
203 bool verbose2
= arg_get_lit(1) > 1;
204 CLIGetHexWithReturn(2, key
, &keyLen
);
207 if (keyLen
&& keyLen
!= 16) {
208 PrintAndLog("Key length must be 16 bytes instead of: %d", keyLen
);
213 memmove(key
, DefaultKey
, 16);
215 mfpSetVerboseMode(verbose2
);
216 for (uint16_t sn
= 0x4000; sn
< 0x4050; sn
++) {
218 keyNum
[1] = sn
& 0xff;
219 res
= MFPWritePerso(keyNum
, key
, (sn
== 0x4000), true, data
, sizeof(data
), &datalen
);
220 if (!res
&& (datalen
== 3) && data
[0] == 0x09) {
221 PrintAndLog("2k card detected.");
224 if (res
|| (datalen
!= 3) || data
[0] != 0x90) {
225 PrintAndLog("Write error on address %04x", sn
);
230 mfpSetVerboseMode(verbose
);
231 for (int i
= 0; i
< sizeof(CardAddresses
) / 2; i
++) {
232 keyNum
[0] = CardAddresses
[i
] >> 8;
233 keyNum
[1] = CardAddresses
[i
] & 0xff;
234 res
= MFPWritePerso(keyNum
, key
, false, true, data
, sizeof(data
), &datalen
);
235 if (!res
&& (datalen
== 3) && data
[0] == 0x09) {
236 PrintAndLog("Skipped[%04x]...", CardAddresses
[i
]);
238 if (res
|| (datalen
!= 3) || data
[0] != 0x90) {
239 PrintAndLog("Write error on address %04x", CardAddresses
[i
]);
250 PrintAndLog("Done.");
255 int CmdHFMFPCommitPerso(const char *cmd
) {
256 CLIParserInit("hf mfp commitp",
257 "Executes Commit Perso command. Can be used in SL0 mode only.",
258 "Usage:\n\thf mfp commitp -> \n");
262 arg_lit0("vV", "verbose", "show internal data."),
263 arg_int0(NULL
, NULL
, "SL mode", NULL
),
266 CLIExecWithReturn(cmd
, argtable
, true);
268 bool verbose
= arg_get_lit(1);
271 mfpSetVerboseMode(verbose
);
273 uint8_t data
[250] = {0};
276 int res
= MFPCommitPerso(true, false, data
, sizeof(data
), &datalen
);
278 PrintAndLog("Exchange error: %d", res
);
283 PrintAndLog("Command must return 3 bytes instead of: %d", datalen
);
287 if (data
[0] != 0x90) {
288 PrintAndLog("Command error: %02x %s", data
[0], mfpGetErrorDescription(data
[0]));
291 PrintAndLog("Switch level OK.");
296 int CmdHFMFPAuth(const char *cmd
) {
297 uint8_t keyn
[250] = {0};
299 uint8_t key
[250] = {0};
302 CLIParserInit("hf mfp auth",
303 "Executes AES authentication command for Mifare Plus card",
304 "Usage:\n\thf mfp auth 4000 000102030405060708090a0b0c0d0e0f -> executes authentication\n"
305 "\thf mfp auth 9003 FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -v -> executes authentication and shows all the system data\n");
309 arg_lit0("vV", "verbose", "show internal data."),
310 arg_str1(NULL
, NULL
, "<Key Num (HEX 2 bytes)>", NULL
),
311 arg_str1(NULL
, NULL
, "<Key Value (HEX 16 bytes)>", NULL
),
314 CLIExecWithReturn(cmd
, argtable
, true);
316 bool verbose
= arg_get_lit(1);
317 CLIGetHexWithReturn(2, keyn
, &keynlen
);
318 CLIGetHexWithReturn(3, key
, &keylen
);
322 PrintAndLog("ERROR: <Key Num> must be 2 bytes long instead of: %d", keynlen
);
327 PrintAndLog("ERROR: <Key Value> must be 16 bytes long instead of: %d", keylen
);
331 return MifareAuth4(NULL
, keyn
, key
, true, false, verbose
);
334 int CmdHFMFPRdbl(const char *cmd
) {
335 uint8_t keyn
[2] = {0};
336 uint8_t key
[250] = {0};
339 CLIParserInit("hf mfp rdbl",
340 "Reads several blocks from Mifare Plus card.",
341 "Usage:\n\thf mfp rdbl 0 000102030405060708090a0b0c0d0e0f -> executes authentication and read block 0 data\n"
342 "\thf mfp rdbl 1 -v -> executes authentication and shows sector 1 data with default key 0xFF..0xFF and some additional data\n");
346 arg_lit0("vV", "verbose", "show internal data."),
347 arg_int0("nN", "count", "blocks count (by default 1).", NULL
),
348 arg_lit0("bB", "keyb", "use key B (by default keyA)."),
349 arg_lit0("pP", "plain", "plain communication mode between reader and card."),
350 arg_int1(NULL
, NULL
, "<Block Num (0..255)>", NULL
),
351 arg_str0(NULL
, NULL
, "<Key Value (HEX 16 bytes)>", NULL
),
354 CLIExecWithReturn(cmd
, argtable
, false);
356 bool verbose
= arg_get_lit(1);
357 int blocksCount
= arg_get_int_def(2, 1);
358 bool keyB
= arg_get_lit(3);
359 int plain
= arg_get_lit(4);
360 uint32_t blockn
= arg_get_int(5);
361 CLIGetHexWithReturn(6, key
, &keylen
);
364 mfpSetVerboseMode(verbose
);
367 memmove(key
, DefaultKey
, 16);
372 PrintAndLog("ERROR: <Block Num> must be in range [0..255] instead of: %d", blockn
);
377 PrintAndLog("ERROR: <Key Value> must be 16 bytes long instead of: %d", keylen
);
381 // 3 blocks - wo iso14443-4 chaining
382 if (blocksCount
> 3) {
383 PrintAndLog("ERROR: blocks count must be less than 3 instead of: %d", blocksCount
);
387 if (blocksCount
> 1 && mfIsSectorTrailer(blockn
)) {
388 PrintAndLog("WARNING: trailer!");
391 uint8_t sectorNum
= mfSectorNum(blockn
& 0xff);
392 uint16_t uKeyNum
= 0x4000 + sectorNum
* 2 + (keyB
? 1 : 0);
393 keyn
[0] = uKeyNum
>> 8;
394 keyn
[1] = uKeyNum
& 0xff;
396 PrintAndLog("--block:%d sector[%d]:%02x key:%04x", blockn
, mfNumBlocksPerSector(sectorNum
), sectorNum
, uKeyNum
);
399 int res
= MifareAuth4(&session
, keyn
, key
, true, true, verbose
);
401 PrintAndLog("Authentication error: %d", res
);
405 uint8_t data
[250] = {0};
407 uint8_t mac
[8] = {0};
408 res
= MFPReadBlock(&session
, plain
, blockn
& 0xff, blocksCount
, false, false, data
, sizeof(data
), &datalen
, mac
);
410 PrintAndLog("Read error: %d", res
);
414 if (datalen
&& data
[0] != 0x90) {
415 PrintAndLog("Card read error: %02x %s", data
[0], mfpGetErrorDescription(data
[0]));
419 if (datalen
!= 1 + blocksCount
* 16 + 8 + 2) {
420 PrintAndLog("Error return length:%d", datalen
);
425 for(int i
= 0; i
< blocksCount
; i
++) {
426 PrintAndLog("data[%03d]: %s", indx
, sprint_hex(&data
[1 + i
* 16], 16));
428 if (mfIsSectorTrailer(indx
) && i
!= blocksCount
- 1){
429 PrintAndLog("data[%03d]: ------------------- trailer -------------------", indx
);
434 if (memcmp(&data
[blocksCount
* 16 + 1], mac
, 8)) {
435 PrintAndLog("WARNING: mac not equal...");
436 PrintAndLog("MAC card: %s", sprint_hex(&data
[blocksCount
* 16 + 1], 8));
437 PrintAndLog("MAC reader: %s", sprint_hex(mac
, 8));
440 PrintAndLog("MAC: %s", sprint_hex(&data
[blocksCount
* 16 + 1], 8));
446 int CmdHFMFPRdsc(const char *cmd
) {
447 uint8_t keyn
[2] = {0};
448 uint8_t key
[250] = {0};
451 CLIParserInit("hf mfp rdsc",
452 "Reads one sector from Mifare Plus card.",
453 "Usage:\n\thf mfp rdsc 0 000102030405060708090a0b0c0d0e0f -> executes authentication and read sector 0 data\n"
454 "\thf mfp rdsc 1 -v -> executes authentication and shows sector 1 data with default key 0xFF..0xFF and some additional data\n");
458 arg_lit0("vV", "verbose", "show internal data."),
459 arg_lit0("bB", "keyb", "use key B (by default keyA)."),
460 arg_lit0("pP", "plain", "plain communication mode between reader and card."),
461 arg_int1(NULL
, NULL
, "<Sector Num (0..255)>", NULL
),
462 arg_str0(NULL
, NULL
, "<Key Value (HEX 16 bytes)>", NULL
),
465 CLIExecWithReturn(cmd
, argtable
, false);
467 bool verbose
= arg_get_lit(1);
468 bool keyB
= arg_get_lit(2);
469 bool plain
= arg_get_lit(3);
470 uint32_t sectorNum
= arg_get_int(4);
471 CLIGetHexWithReturn(5, key
, &keylen
);
474 mfpSetVerboseMode(verbose
);
477 memmove(key
, DefaultKey
, 16);
481 if (sectorNum
> 39) {
482 PrintAndLog("ERROR: <Sector Num> must be in range [0..39] instead of: %d", sectorNum
);
487 PrintAndLog("ERROR: <Key Value> must be 16 bytes long instead of: %d", keylen
);
491 uint16_t uKeyNum
= 0x4000 + sectorNum
* 2 + (keyB
? 1 : 0);
492 keyn
[0] = uKeyNum
>> 8;
493 keyn
[1] = uKeyNum
& 0xff;
495 PrintAndLog("--sector[%d]:%02x key:%04x", mfNumBlocksPerSector(sectorNum
), sectorNum
, uKeyNum
);
498 int res
= MifareAuth4(&session
, keyn
, key
, true, true, verbose
);
500 PrintAndLog("Authentication error: %d", res
);
504 uint8_t data
[250] = {0};
506 uint8_t mac
[8] = {0};
507 for(int n
= mfFirstBlockOfSector(sectorNum
); n
< mfFirstBlockOfSector(sectorNum
) + mfNumBlocksPerSector(sectorNum
); n
++) {
508 res
= MFPReadBlock(&session
, plain
, n
& 0xff, 1, false, true, data
, sizeof(data
), &datalen
, mac
);
510 PrintAndLog("Read error: %d", res
);
515 if (datalen
&& data
[0] != 0x90) {
516 PrintAndLog("Card read error: %02x %s", data
[0], mfpGetErrorDescription(data
[0]));
520 if (datalen
!= 1 + 16 + 8 + 2) {
521 PrintAndLog("Error return length:%d", datalen
);
526 PrintAndLog("data[%03d]: %s", n
, sprint_hex(&data
[1], 16));
528 if (memcmp(&data
[1 + 16], mac
, 8)) {
529 PrintAndLog("WARNING: mac on block %d not equal...", n
);
530 PrintAndLog("MAC card: %s", sprint_hex(&data
[1 + 16], 8));
531 PrintAndLog("MAC reader: %s", sprint_hex(mac
, 8));
534 PrintAndLog("MAC: %s", sprint_hex(&data
[1 + 16], 8));
542 int CmdHFMFPWrbl(const char *cmd
) {
543 uint8_t keyn
[2] = {0};
544 uint8_t key
[250] = {0};
546 uint8_t datain
[250] = {0};
549 CLIParserInit("hf mfp wrbl",
550 "Writes one block to Mifare Plus card.",
551 "Usage:\n\thf mfp wrbl 1 ff0000000000000000000000000000ff 000102030405060708090a0b0c0d0e0f -> writes block 1 data\n"
552 "\thf mfp wrbl 2 ff0000000000000000000000000000ff -v -> writes block 2 data with default key 0xFF..0xFF and some additional data\n");
556 arg_lit0("vV", "verbose", "show internal data."),
557 arg_lit0("bB", "keyb", "use key B (by default keyA)."),
558 arg_int1(NULL
, NULL
, "<Block Num (0..255)>", NULL
),
559 arg_str1(NULL
, NULL
, "<Data (HEX 16 bytes)>", NULL
),
560 arg_str0(NULL
, NULL
, "<Key (HEX 16 bytes)>", NULL
),
563 CLIExecWithReturn(cmd
, argtable
, false);
565 bool verbose
= arg_get_lit(1);
566 bool keyB
= arg_get_lit(2);
567 uint32_t blockNum
= arg_get_int(3);
568 CLIGetHexWithReturn(4, datain
, &datainlen
);
569 CLIGetHexWithReturn(5, key
, &keylen
);
572 mfpSetVerboseMode(verbose
);
575 memmove(key
, DefaultKey
, 16);
580 PrintAndLog("ERROR: <Block Num> must be in range [0..255] instead of: %d", blockNum
);
585 PrintAndLog("ERROR: <Key> must be 16 bytes long instead of: %d", keylen
);
589 if (datainlen
!= 16) {
590 PrintAndLog("ERROR: <Data> must be 16 bytes long instead of: %d", datainlen
);
594 uint8_t sectorNum
= mfSectorNum(blockNum
& 0xff);
595 uint16_t uKeyNum
= 0x4000 + sectorNum
* 2 + (keyB
? 1 : 0);
596 keyn
[0] = uKeyNum
>> 8;
597 keyn
[1] = uKeyNum
& 0xff;
599 PrintAndLog("--block:%d sector[%d]:%02x key:%04x", blockNum
& 0xff, mfNumBlocksPerSector(sectorNum
), sectorNum
, uKeyNum
);
602 int res
= MifareAuth4(&session
, keyn
, key
, true, true, verbose
);
604 PrintAndLog("Authentication error: %d", res
);
608 uint8_t data
[250] = {0};
610 uint8_t mac
[8] = {0};
611 res
= MFPWriteBlock(&session
, blockNum
& 0xff, datain
, false, false, data
, sizeof(data
), &datalen
, mac
);
613 PrintAndLog("Write error: %d", res
);
618 if (datalen
!= 3 && (datalen
!= 3 + 8)) {
619 PrintAndLog("Error return length:%d", datalen
);
624 if (datalen
&& data
[0] != 0x90) {
625 PrintAndLog("Card write error: %02x %s", data
[0], mfpGetErrorDescription(data
[0]));
630 if (memcmp(&data
[1], mac
, 8)) {
631 PrintAndLog("WARNING: mac not equal...");
632 PrintAndLog("MAC card: %s", sprint_hex(&data
[1], 8));
633 PrintAndLog("MAC reader: %s", sprint_hex(mac
, 8));
636 PrintAndLog("MAC: %s", sprint_hex(&data
[1], 8));
640 PrintAndLog("Write OK.");
644 int CmdHFMFPMAD(const char *cmd
) {
646 CLIParserInit("hf mfp mad",
647 "Checks and prints Mifare Application Directory (MAD)",
648 "Usage:\n\thf mfp mad -> shows MAD if exists\n"
649 "\thf mfp mad -a 03e1 -k d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7 -> shows NDEF data if exists\n");
653 arg_lit0("vV", "verbose", "show technical data"),
654 arg_str0("aA", "aid", "print all sectors with aid", NULL
),
655 arg_str0("kK", "key", "key for printing sectors", NULL
),
656 arg_lit0("bB", "keyb", "use key B for access printing sectors (by default: key A)"),
659 CLIExecWithReturn(cmd
, argtable
, true);
661 bool verbose
= arg_get_lit(1);
662 uint8_t aid
[2] = {0};
664 CLIGetHexWithReturn(2, aid
, &aidlen
);
665 uint8_t key
[16] = {0};
667 CLIGetHexWithReturn(3, key
, &keylen
);
668 bool keyB
= arg_get_lit(4);
672 if (aidlen
!= 2 && keylen
> 0) {
673 PrintAndLogEx(WARNING
, "do not need a key without aid.");
676 uint8_t sector0
[16 * 4] = {0};
677 uint8_t sector10
[16 * 4] = {0};
679 if (mfpReadSector(MF_MAD1_SECTOR
, MF_KEY_A
, (uint8_t *)g_mifarep_mad_key
, sector0
, verbose
)) {
680 PrintAndLogEx(NORMAL
, "");
681 PrintAndLogEx(ERR
, "read sector 0 error. card don't have MAD or don't have MAD on default keys.");
686 for (int i
= 0; i
< 4; i
++)
687 PrintAndLogEx(NORMAL
, "[%d] %s", i
, sprint_hex(§or0
[i
* 16], 16));
690 bool haveMAD2
= false;
691 MAD1DecodeAndPrint(sector0
, verbose
, &haveMAD2
);
694 if (mfpReadSector(MF_MAD2_SECTOR
, MF_KEY_A
, (uint8_t *)g_mifarep_mad_key
, sector10
, verbose
)) {
695 PrintAndLogEx(NORMAL
, "");
696 PrintAndLogEx(ERR
, "read sector 0x10 error. card don't have MAD or don't have MAD on default keys.");
700 MAD2DecodeAndPrint(sector10
, verbose
);
704 uint16_t aaid
= (aid
[0] << 8) + aid
[1];
705 PrintAndLogEx(NORMAL
, "\n-------------- AID 0x%04x ---------------", aaid
);
707 uint16_t mad
[7 + 8 + 8 + 8 + 8] = {0};
709 if (MADDecode(sector0
, sector10
, mad
, &madlen
)) {
710 PrintAndLogEx(ERR
, "can't decode mad.");
714 uint8_t akey
[16] = {0};
715 memcpy(akey
, g_mifarep_ndef_key
, 16);
717 memcpy(akey
, key
, 16);
720 for (int i
= 0; i
< madlen
; i
++) {
721 if (aaid
== mad
[i
]) {
722 uint8_t vsector
[16 * 4] = {0};
723 if (mfpReadSector(i
+ 1, keyB
? MF_KEY_B
: MF_KEY_A
, akey
, vsector
, false)) {
724 PrintAndLogEx(NORMAL
, "");
725 PrintAndLogEx(ERR
, "read sector %d error.", i
+ 1);
729 for (int j
= 0; j
< (verbose
? 4 : 3); j
++)
730 PrintAndLogEx(NORMAL
, " [%03d] %s", (i
+ 1) * 4 + j
, sprint_hex(&vsector
[j
* 16], 16));
738 int CmdHFMFPNDEF(const char *cmd
) {
740 CLIParserInit("hf mfp ndef",
741 "Prints NFC Data Exchange Format (NDEF)",
742 "Usage:\n\thf mfp ndef -> shows NDEF data\n"
743 "\thf mfp ndef -a 03e1 -k d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7 -> shows NDEF data with custom AID and key\n");
747 arg_litn("vV", "verbose", 0, 2, "show technical data"),
748 arg_str0("aA", "aid", "replace default aid for NDEF", NULL
),
749 arg_str0("kK", "key", "replace default key for NDEF", NULL
),
750 arg_lit0("bB", "keyb", "use key B for access sectors (by default: key A)"),
753 CLIExecWithReturn(cmd
, argtable
, true);
755 bool verbose
= arg_get_lit(1);
756 bool verbose2
= arg_get_lit(1) > 1;
757 uint8_t aid
[2] = {0};
759 CLIGetHexWithReturn(2, aid
, &aidlen
);
760 uint8_t key
[16] = {0};
762 CLIGetHexWithReturn(3, key
, &keylen
);
763 bool keyB
= arg_get_lit(4);
767 uint16_t ndefAID
= 0x03e1;
769 ndefAID
= (aid
[0] << 8) + aid
[1];
771 uint8_t ndefkey
[16] = {0};
772 memcpy(ndefkey
, g_mifarep_ndef_key
, 16);
774 memcpy(ndefkey
, key
, 16);
777 uint8_t sector0
[16 * 4] = {0};
778 uint8_t sector10
[16 * 4] = {0};
779 uint8_t data
[4096] = {0};
782 PrintAndLogEx(NORMAL
, "");
784 if (mfpReadSector(MF_MAD1_SECTOR
, MF_KEY_A
, (uint8_t *)g_mifarep_mad_key
, sector0
, verbose
)) {
785 PrintAndLogEx(ERR
, "read sector 0 error. card don't have MAD or don't have MAD on default keys.");
789 bool haveMAD2
= false;
790 int res
= MADCheck(sector0
, NULL
, verbose
, &haveMAD2
);
792 PrintAndLogEx(ERR
, "MAD error %d.", res
);
797 if (mfpReadSector(MF_MAD2_SECTOR
, MF_KEY_A
, (uint8_t *)g_mifarep_mad_key
, sector10
, verbose
)) {
798 PrintAndLogEx(ERR
, "read sector 0x10 error. card don't have MAD or don't have MAD on default keys.");
803 uint16_t mad
[7 + 8 + 8 + 8 + 8] = {0};
805 if (MADDecode(sector0
, (haveMAD2
? sector10
: NULL
), mad
, &madlen
)) {
806 PrintAndLogEx(ERR
, "can't decode mad.");
810 printf("data reading:");
811 for (int i
= 0; i
< madlen
; i
++) {
812 if (ndefAID
== mad
[i
]) {
813 uint8_t vsector
[16 * 4] = {0};
814 if (mfpReadSector(i
+ 1, keyB
? MF_KEY_B
: MF_KEY_A
, ndefkey
, vsector
, false)) {
815 PrintAndLogEx(ERR
, "read sector %d error.", i
+ 1);
819 memcpy(&data
[datalen
], vsector
, 16 * 3);
828 PrintAndLogEx(ERR
, "no NDEF data.");
833 PrintAndLogEx(NORMAL
, "NDEF data:");
834 dump_buffer(data
, datalen
, stdout
, 1);
837 NDEFDecodeAndPrint(data
, datalen
, verbose
);
842 static command_t CommandTable
[] =
844 {"help", CmdHelp
, 1, "This help"},
845 {"info", CmdHFMFPInfo
, 0, "Info about Mifare Plus tag"},
846 {"wrp", CmdHFMFPWritePerso
, 0, "Write Perso command"},
847 {"initp", CmdHFMFPInitPerso
, 0, "Fills all the card's keys"},
848 {"commitp", CmdHFMFPCommitPerso
, 0, "Move card to SL1 or SL3 mode"},
849 {"auth", CmdHFMFPAuth
, 0, "Authentication"},
850 {"rdbl", CmdHFMFPRdbl
, 0, "Read blocks"},
851 {"rdsc", CmdHFMFPRdsc
, 0, "Read sectors"},
852 {"wrbl", CmdHFMFPWrbl
, 0, "Write blocks"},
853 {"mad", CmdHFMFPMAD
, 0, "Checks and prints MAD"},
854 {"ndef", CmdHFMFPNDEF
, 0, "Prints NDEF records from card"},
855 {NULL
, NULL
, 0, NULL
}
858 int CmdHFMFP(const char *Cmd
) {
859 (void)WaitForResponseTimeout(CMD_ACK
,NULL
,100);
860 CmdsParse(CommandTable
, Cmd
);
864 int CmdHelp(const char *Cmd
) {
865 CmdsHelp(CommandTable
);