]> git.zerfleddert.de Git - proxmark3-svn/blame - client/cmdhfmfp.c
Merge pull request #969 from pwpiwi/gcc10_fixes
[proxmark3-svn] / client / cmdhfmfp.c
CommitLineData
dc3e2acf
OM
1//-----------------------------------------------------------------------------
2// Copyright (C) 2018 Merlok
4b5d696c 3// Copyright (C) 2018 drHatson
dc3e2acf
OM
4//
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
7// the license.
8//-----------------------------------------------------------------------------
9// High frequency MIFARE Plus commands
10//-----------------------------------------------------------------------------
11
12#include "cmdhfmfp.h"
13
14#include <inttypes.h>
15#include <string.h>
16#include <stdio.h>
17#include <stdlib.h>
18#include <ctype.h>
19#include "comms.h"
20#include "cmdmain.h"
21#include "util.h"
22#include "ui.h"
23#include "cmdhf14a.h"
24#include "mifare.h"
fdd9395d
OM
25#include "mifare/mifare4.h"
26#include "mifare/mad.h"
27#include "mifare/ndef.h"
ae3340a0 28#include "cliparser/cliparser.h"
700d8687 29#include "crypto/libpcrypto.h"
fdd9395d 30#include "emv/dump.h"
ae3340a0
OM
31
32static const uint8_t DefaultKey[16] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
33
dc3e2acf
OM
34static int CmdHelp(const char *Cmd);
35
36int CmdHFMFPInfo(const char *cmd) {
37
38 if (cmd && strlen(cmd) > 0)
39 PrintAndLog("WARNING: command don't have any parameters.\n");
40
41 // info about 14a part
42 CmdHF14AInfo("");
43
44 // Mifare Plus info
45 UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0}};
46 SendCommand(&c);
47
48 UsbCommand resp;
49 WaitForResponse(CMD_ACK,&resp);
50
51 iso14a_card_select_t card;
52 memcpy(&card, (iso14a_card_select_t *)resp.d.asBytes, sizeof(iso14a_card_select_t));
53
54 uint64_t select_status = resp.arg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision
55
56 if (select_status == 1 || select_status == 2) {
57 PrintAndLog("----------------------------------------------");
58 PrintAndLog("Mifare Plus info:");
59
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");
67
68 uint8_t SLmode = 0xff;
69 if (card.sak == 0x08) {
70 PrintAndLog("SAK: Mifare Plus 2k 7bUID");
71 if (select_status == 2) SLmode = 1;
72 }
73 if (card.sak == 0x18) {
74 PrintAndLog("SAK: Mifare Plus 4k 7bUID");
75 if (select_status == 2) SLmode = 1;
76 }
77 if (card.sak == 0x10) {
78 PrintAndLog("SAK: Mifare Plus 2k");
79 if (select_status == 2) SLmode = 2;
80 }
81 if (card.sak == 0x11) {
82 PrintAndLog("SAK: Mifare Plus 4k");
83 if (select_status == 2) SLmode = 2;
84 }
85 if (card.sak == 0x20) {
86 PrintAndLog("SAK: Mifare Plus SL0/SL3 or Mifare desfire");
87 if (card.ats_len > 0) {
88 SLmode = 3;
89
90 // check SL0
91 uint8_t data[250] = {0};
92 int datalen = 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) {
97 SLmode = 0;
98 }
99 }
100 }
101
102 if (SLmode != 0xff)
103 PrintAndLog("Mifare Plus SL mode: SL%d", SLmode);
104 else
105 PrintAndLog("Mifare Plus SL mode: unknown(");
106 } else {
107 PrintAndLog("Mifare Plus info not available.");
108 }
109
110 DropField();
111
112 return 0;
113}
114
ae3340a0
OM
115int CmdHFMFPWritePerso(const char *cmd) {
116 uint8_t keyNum[64] = {0};
117 int keyNumLen = 0;
118 uint8_t key[64] = {0};
119 int keyLen = 0;
120
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");
125
126 void* argtable[] = {
127 arg_param_begin,
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),
131 arg_param_end
132 };
133 CLIExecWithReturn(cmd, argtable, true);
134
135 bool verbose = arg_get_lit(1);
136 CLIGetHexWithReturn(2, keyNum, &keyNumLen);
137 CLIGetHexWithReturn(3, key, &keyLen);
138 CLIParserFree();
139
fdd9395d 140 mfpSetVerboseMode(verbose);
ae3340a0
OM
141
142 if (!keyLen) {
143 memmove(key, DefaultKey, 16);
144 keyLen = 16;
145 }
146
147 if (keyNumLen != 2) {
148 PrintAndLog("Key number length must be 2 bytes instead of: %d", keyNumLen);
149 return 1;
150 }
151 if (keyLen != 16) {
152 PrintAndLog("Key length must be 16 bytes instead of: %d", keyLen);
153 return 1;
154 }
155
156 uint8_t data[250] = {0};
157 int datalen = 0;
158
159 int res = MFPWritePerso(keyNum, key, true, false, data, sizeof(data), &datalen);
160 if (res) {
161 PrintAndLog("Exchange error: %d", res);
162 return res;
163 }
164
165 if (datalen != 3) {
166 PrintAndLog("Command must return 3 bytes instead of: %d", datalen);
167 return 1;
168 }
169
170 if (data[0] != 0x90) {
fdd9395d 171 PrintAndLog("Command error: %02x %s", data[0], mfpGetErrorDescription(data[0]));
ae3340a0
OM
172 return 1;
173 }
174 PrintAndLog("Write OK.");
175
176 return 0;
177}
178
179uint16_t CardAddresses[] = {0x9000, 0x9001, 0x9002, 0x9003, 0x9004, 0xA000, 0xA001, 0xA080, 0xA081, 0xC000, 0xC001};
180
181int CmdHFMFPInitPerso(const char *cmd) {
182 int res;
183 uint8_t key[256] = {0};
184 int keyLen = 0;
185 uint8_t keyNum[2] = {0};
186 uint8_t data[250] = {0};
187 int datalen = 0;
188
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");
193
194 void* argtable[] = {
195 arg_param_begin,
196 arg_litn("vV", "verbose", 0, 2, "show internal data."),
197 arg_strx0(NULL, NULL, "<HEX key (16b)>", NULL),
198 arg_param_end
199 };
200 CLIExecWithReturn(cmd, argtable, true);
201
202 bool verbose = arg_get_lit(1);
203 bool verbose2 = arg_get_lit(1) > 1;
204 CLIGetHexWithReturn(2, key, &keyLen);
205 CLIParserFree();
206
207 if (keyLen && keyLen != 16) {
208 PrintAndLog("Key length must be 16 bytes instead of: %d", keyLen);
209 return 1;
210 }
211
212 if (!keyLen)
213 memmove(key, DefaultKey, 16);
214
fdd9395d 215 mfpSetVerboseMode(verbose2);
ae3340a0
OM
216 for (uint16_t sn = 0x4000; sn < 0x4050; sn++) {
217 keyNum[0] = sn >> 8;
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.");
222 break;
223 }
224 if (res || (datalen != 3) || data[0] != 0x90) {
225 PrintAndLog("Write error on address %04x", sn);
226 break;
227 }
228 }
229
fdd9395d 230 mfpSetVerboseMode(verbose);
ae3340a0
OM
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]);
237 } else {
238 if (res || (datalen != 3) || data[0] != 0x90) {
239 PrintAndLog("Write error on address %04x", CardAddresses[i]);
240 break;
241 }
242 }
243 }
244
245 DropField();
246
247 if (res)
248 return res;
249
250 PrintAndLog("Done.");
251
252 return 0;
253}
254
255int 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");
259
260 void* argtable[] = {
261 arg_param_begin,
262 arg_lit0("vV", "verbose", "show internal data."),
263 arg_int0(NULL, NULL, "SL mode", NULL),
264 arg_param_end
265 };
266 CLIExecWithReturn(cmd, argtable, true);
267
268 bool verbose = arg_get_lit(1);
269 CLIParserFree();
270
fdd9395d 271 mfpSetVerboseMode(verbose);
ae3340a0
OM
272
273 uint8_t data[250] = {0};
274 int datalen = 0;
275
276 int res = MFPCommitPerso(true, false, data, sizeof(data), &datalen);
277 if (res) {
278 PrintAndLog("Exchange error: %d", res);
279 return res;
280 }
281
282 if (datalen != 3) {
283 PrintAndLog("Command must return 3 bytes instead of: %d", datalen);
284 return 1;
285 }
286
287 if (data[0] != 0x90) {
fdd9395d 288 PrintAndLog("Command error: %02x %s", data[0], mfpGetErrorDescription(data[0]));
ae3340a0
OM
289 return 1;
290 }
291 PrintAndLog("Switch level OK.");
292
293 return 0;
294}
295
296int CmdHFMFPAuth(const char *cmd) {
297 uint8_t keyn[250] = {0};
298 int keynlen = 0;
299 uint8_t key[250] = {0};
300 int keylen = 0;
301
302 CLIParserInit("hf mfp auth",
c8a0f550 303 "Executes AES authentication command for Mifare Plus card",
ae3340a0
OM
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");
306
307 void* argtable[] = {
308 arg_param_begin,
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),
312 arg_param_end
313 };
314 CLIExecWithReturn(cmd, argtable, true);
315
316 bool verbose = arg_get_lit(1);
317 CLIGetHexWithReturn(2, keyn, &keynlen);
318 CLIGetHexWithReturn(3, key, &keylen);
319 CLIParserFree();
320
321 if (keynlen != 2) {
322 PrintAndLog("ERROR: <Key Num> must be 2 bytes long instead of: %d", keynlen);
323 return 1;
324 }
325
326 if (keylen != 16) {
327 PrintAndLog("ERROR: <Key Value> must be 16 bytes long instead of: %d", keylen);
328 return 1;
329 }
330
331 return MifareAuth4(NULL, keyn, key, true, false, verbose);
332}
333
334int CmdHFMFPRdbl(const char *cmd) {
c8a0f550
OM
335 uint8_t keyn[2] = {0};
336 uint8_t key[250] = {0};
337 int keylen = 0;
338
339 CLIParserInit("hf mfp rdbl",
4b5d696c 340 "Reads several blocks from Mifare Plus card.",
c8a0f550
OM
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");
343
344 void* argtable[] = {
345 arg_param_begin,
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)."),
4b5d696c 349 arg_lit0("pP", "plain", "plain communication mode between reader and card."),
c8a0f550
OM
350 arg_int1(NULL, NULL, "<Block Num (0..255)>", NULL),
351 arg_str0(NULL, NULL, "<Key Value (HEX 16 bytes)>", NULL),
352 arg_param_end
353 };
354 CLIExecWithReturn(cmd, argtable, false);
355
356 bool verbose = arg_get_lit(1);
357 int blocksCount = arg_get_int_def(2, 1);
358 bool keyB = arg_get_lit(3);
4b5d696c 359 int plain = arg_get_lit(4);
c8a0f550
OM
360 uint32_t blockn = arg_get_int(5);
361 CLIGetHexWithReturn(6, key, &keylen);
362 CLIParserFree();
363
fdd9395d 364 mfpSetVerboseMode(verbose);
c8a0f550
OM
365
366 if (!keylen) {
367 memmove(key, DefaultKey, 16);
368 keylen = 16;
369 }
370
371 if (blockn > 255) {
372 PrintAndLog("ERROR: <Block Num> must be in range [0..255] instead of: %d", blockn);
373 return 1;
374 }
375
376 if (keylen != 16) {
377 PrintAndLog("ERROR: <Key Value> must be 16 bytes long instead of: %d", keylen);
378 return 1;
379 }
380
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);
384 return 1;
385 }
386
4b5d696c 387 if (blocksCount > 1 && mfIsSectorTrailer(blockn)) {
388 PrintAndLog("WARNING: trailer!");
389 }
390
c8a0f550
OM
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;
395 if (verbose)
396 PrintAndLog("--block:%d sector[%d]:%02x key:%04x", blockn, mfNumBlocksPerSector(sectorNum), sectorNum, uKeyNum);
397
398 mf4Session session;
399 int res = MifareAuth4(&session, keyn, key, true, true, verbose);
400 if (res) {
401 PrintAndLog("Authentication error: %d", res);
402 return res;
403 }
404
405 uint8_t data[250] = {0};
406 int datalen = 0;
407 uint8_t mac[8] = {0};
408 res = MFPReadBlock(&session, plain, blockn & 0xff, blocksCount, false, false, data, sizeof(data), &datalen, mac);
409 if (res) {
410 PrintAndLog("Read error: %d", res);
411 return res;
412 }
413
414 if (datalen && data[0] != 0x90) {
fdd9395d 415 PrintAndLog("Card read error: %02x %s", data[0], mfpGetErrorDescription(data[0]));
c8a0f550
OM
416 return 6;
417 }
418
419 if (datalen != 1 + blocksCount * 16 + 8 + 2) {
420 PrintAndLog("Error return length:%d", datalen);
421 return 5;
422 }
423
424 int indx = blockn;
425 for(int i = 0; i < blocksCount; i++) {
426 PrintAndLog("data[%03d]: %s", indx, sprint_hex(&data[1 + i * 16], 16));
427 indx++;
4b5d696c 428 if (mfIsSectorTrailer(indx) && i != blocksCount - 1){
c8a0f550
OM
429 PrintAndLog("data[%03d]: ------------------- trailer -------------------", indx);
430 indx++;
431 }
432 }
433
4b5d696c 434 if (memcmp(&data[blocksCount * 16 + 1], mac, 8)) {
c8a0f550
OM
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));
438 } else {
439 if(verbose)
440 PrintAndLog("MAC: %s", sprint_hex(&data[blocksCount * 16 + 1], 8));
441 }
ae3340a0
OM
442
443 return 0;
444}
445
446int CmdHFMFPRdsc(const char *cmd) {
c8a0f550
OM
447 uint8_t keyn[2] = {0};
448 uint8_t key[250] = {0};
449 int keylen = 0;
450
451 CLIParserInit("hf mfp rdsc",
4b5d696c 452 "Reads one sector from Mifare Plus card.",
c8a0f550
OM
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");
455
456 void* argtable[] = {
457 arg_param_begin,
458 arg_lit0("vV", "verbose", "show internal data."),
459 arg_lit0("bB", "keyb", "use key B (by default keyA)."),
4b5d696c 460 arg_lit0("pP", "plain", "plain communication mode between reader and card."),
c8a0f550
OM
461 arg_int1(NULL, NULL, "<Sector Num (0..255)>", NULL),
462 arg_str0(NULL, NULL, "<Key Value (HEX 16 bytes)>", NULL),
463 arg_param_end
464 };
465 CLIExecWithReturn(cmd, argtable, false);
466
467 bool verbose = arg_get_lit(1);
468 bool keyB = arg_get_lit(2);
4b5d696c 469 bool plain = arg_get_lit(3);
c8a0f550
OM
470 uint32_t sectorNum = arg_get_int(4);
471 CLIGetHexWithReturn(5, key, &keylen);
472 CLIParserFree();
473
fdd9395d 474 mfpSetVerboseMode(verbose);
c8a0f550
OM
475
476 if (!keylen) {
477 memmove(key, DefaultKey, 16);
478 keylen = 16;
479 }
480
481 if (sectorNum > 39) {
482 PrintAndLog("ERROR: <Sector Num> must be in range [0..39] instead of: %d", sectorNum);
483 return 1;
484 }
485
486 if (keylen != 16) {
487 PrintAndLog("ERROR: <Key Value> must be 16 bytes long instead of: %d", keylen);
488 return 1;
489 }
490
491 uint16_t uKeyNum = 0x4000 + sectorNum * 2 + (keyB ? 1 : 0);
492 keyn[0] = uKeyNum >> 8;
493 keyn[1] = uKeyNum & 0xff;
494 if (verbose)
495 PrintAndLog("--sector[%d]:%02x key:%04x", mfNumBlocksPerSector(sectorNum), sectorNum, uKeyNum);
496
497 mf4Session session;
498 int res = MifareAuth4(&session, keyn, key, true, true, verbose);
499 if (res) {
500 PrintAndLog("Authentication error: %d", res);
501 return res;
502 }
503
504 uint8_t data[250] = {0};
505 int datalen = 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);
509 if (res) {
510 PrintAndLog("Read error: %d", res);
511 DropField();
512 return res;
513 }
514
515 if (datalen && data[0] != 0x90) {
fdd9395d 516 PrintAndLog("Card read error: %02x %s", data[0], mfpGetErrorDescription(data[0]));
c8a0f550
OM
517 DropField();
518 return 6;
519 }
520 if (datalen != 1 + 16 + 8 + 2) {
521 PrintAndLog("Error return length:%d", datalen);
522 DropField();
523 return 5;
524 }
525
526 PrintAndLog("data[%03d]: %s", n, sprint_hex(&data[1], 16));
527
4b5d696c 528 if (memcmp(&data[1 + 16], mac, 8)) {
c8a0f550
OM
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));
532 } else {
533 if(verbose)
534 PrintAndLog("MAC: %s", sprint_hex(&data[1 + 16], 8));
535 }
536 }
537 DropField();
ae3340a0
OM
538
539 return 0;
540}
541
542int CmdHFMFPWrbl(const char *cmd) {
c8a0f550
OM
543 uint8_t keyn[2] = {0};
544 uint8_t key[250] = {0};
545 int keylen = 0;
546 uint8_t datain[250] = {0};
547 int datainlen = 0;
548
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");
553
554 void* argtable[] = {
555 arg_param_begin,
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),
561 arg_param_end
562 };
563 CLIExecWithReturn(cmd, argtable, false);
564
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);
570 CLIParserFree();
571
fdd9395d 572 mfpSetVerboseMode(verbose);
c8a0f550
OM
573
574 if (!keylen) {
575 memmove(key, DefaultKey, 16);
576 keylen = 16;
577 }
578
579 if (blockNum > 39) {
580 PrintAndLog("ERROR: <Block Num> must be in range [0..255] instead of: %d", blockNum);
581 return 1;
582 }
583
584 if (keylen != 16) {
585 PrintAndLog("ERROR: <Key> must be 16 bytes long instead of: %d", keylen);
586 return 1;
587 }
588
589 if (datainlen != 16) {
590 PrintAndLog("ERROR: <Data> must be 16 bytes long instead of: %d", datainlen);
591 return 1;
592 }
ae3340a0 593
c8a0f550
OM
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;
598 if (verbose)
599 PrintAndLog("--block:%d sector[%d]:%02x key:%04x", blockNum & 0xff, mfNumBlocksPerSector(sectorNum), sectorNum, uKeyNum);
600
601 mf4Session session;
602 int res = MifareAuth4(&session, keyn, key, true, true, verbose);
603 if (res) {
604 PrintAndLog("Authentication error: %d", res);
605 return res;
606 }
607
608 uint8_t data[250] = {0};
609 int datalen = 0;
610 uint8_t mac[8] = {0};
611 res = MFPWriteBlock(&session, blockNum & 0xff, datain, false, false, data, sizeof(data), &datalen, mac);
612 if (res) {
613 PrintAndLog("Write error: %d", res);
614 DropField();
615 return res;
616 }
617
618 if (datalen != 3 && (datalen != 3 + 8)) {
619 PrintAndLog("Error return length:%d", datalen);
620 DropField();
621 return 5;
622 }
623
624 if (datalen && data[0] != 0x90) {
fdd9395d 625 PrintAndLog("Card write error: %02x %s", data[0], mfpGetErrorDescription(data[0]));
c8a0f550
OM
626 DropField();
627 return 6;
628 }
629
4b5d696c 630 if (memcmp(&data[1], mac, 8)) {
c8a0f550
OM
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));
634 } else {
635 if(verbose)
636 PrintAndLog("MAC: %s", sprint_hex(&data[1], 8));
637 }
638
639 DropField();
4b5d696c 640 PrintAndLog("Write OK.");
ae3340a0
OM
641 return 0;
642}
643
fdd9395d
OM
644int CmdHFMFPMAD(const char *cmd) {
645
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");
650
651 void *argtable[] = {
652 arg_param_begin,
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)"),
657 arg_param_end
658 };
659 CLIExecWithReturn(cmd, argtable, true);
660
661 bool verbose = arg_get_lit(1);
662 uint8_t aid[2] = {0};
663 int aidlen;
664 CLIGetHexWithReturn(2, aid, &aidlen);
665 uint8_t key[16] = {0};
666 int keylen;
667 CLIGetHexWithReturn(3, key, &keylen);
668 bool keyB = arg_get_lit(4);
669
670 CLIParserFree();
671
672 if (aidlen != 2 && keylen > 0) {
673 PrintAndLogEx(WARNING, "do not need a key without aid.");
674 }
675
676 uint8_t sector0[16 * 4] = {0};
677 uint8_t sector10[16 * 4] = {0};
678
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.");
682 return 2;
683 }
684
685 if (verbose) {
686 for (int i = 0; i < 4; i ++)
687 PrintAndLogEx(NORMAL, "[%d] %s", i, sprint_hex(&sector0[i * 16], 16));
688 }
689
690 bool haveMAD2 = false;
691 MAD1DecodeAndPrint(sector0, verbose, &haveMAD2);
692
693 if (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.");
697 return 2;
698 }
699
700 MAD2DecodeAndPrint(sector10, verbose);
701 }
702
703 if (aidlen == 2) {
704 uint16_t aaid = (aid[0] << 8) + aid[1];
705 PrintAndLogEx(NORMAL, "\n-------------- AID 0x%04x ---------------", aaid);
706
707 uint16_t mad[7 + 8 + 8 + 8 + 8] = {0};
708 size_t madlen = 0;
709 if (MADDecode(sector0, sector10, mad, &madlen)) {
710 PrintAndLogEx(ERR, "can't decode mad.");
711 return 10;
712 }
713
714 uint8_t akey[16] = {0};
715 memcpy(akey, g_mifarep_ndef_key, 16);
716 if (keylen == 16) {
717 memcpy(akey, key, 16);
718 }
719
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);
726 return 2;
727 }
728
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));
731 }
732 }
733 }
734
735 return 0;
736}
737
738int CmdHFMFPNDEF(const char *cmd) {
739
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");
744
745 void *argtable[] = {
746 arg_param_begin,
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)"),
751 arg_param_end
752 };
753 CLIExecWithReturn(cmd, argtable, true);
754
755 bool verbose = arg_get_lit(1);
756 bool verbose2 = arg_get_lit(1) > 1;
757 uint8_t aid[2] = {0};
758 int aidlen;
759 CLIGetHexWithReturn(2, aid, &aidlen);
760 uint8_t key[16] = {0};
761 int keylen;
762 CLIGetHexWithReturn(3, key, &keylen);
763 bool keyB = arg_get_lit(4);
764
765 CLIParserFree();
766
767 uint16_t ndefAID = 0x03e1;
768 if (aidlen == 2)
769 ndefAID = (aid[0] << 8) + aid[1];
770
771 uint8_t ndefkey[16] = {0};
772 memcpy(ndefkey, g_mifarep_ndef_key, 16);
773 if (keylen == 16) {
774 memcpy(ndefkey, key, 16);
775 }
776
777 uint8_t sector0[16 * 4] = {0};
778 uint8_t sector10[16 * 4] = {0};
779 uint8_t data[4096] = {0};
780 int datalen = 0;
781
782 PrintAndLogEx(NORMAL, "");
783
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.");
786 return 2;
787 }
788
789 bool haveMAD2 = false;
790 int res = MADCheck(sector0, NULL, verbose, &haveMAD2);
791 if (res) {
792 PrintAndLogEx(ERR, "MAD error %d.", res);
793 return res;
794 }
795
796 if (haveMAD2) {
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.");
799 return 2;
800 }
801 }
802
803 uint16_t mad[7 + 8 + 8 + 8 + 8] = {0};
804 size_t madlen = 0;
805 if (MADDecode(sector0, (haveMAD2 ? sector10 : NULL), mad, &madlen)) {
806 PrintAndLogEx(ERR, "can't decode mad.");
807 return 10;
808 }
809
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);
816 return 2;
817 }
818
819 memcpy(&data[datalen], vsector, 16 * 3);
820 datalen += 16 * 3;
821
822 printf(".");
823 }
824 }
825 printf(" OK\n");
826
827 if (!datalen) {
828 PrintAndLogEx(ERR, "no NDEF data.");
829 return 11;
830 }
831
832 if (verbose2) {
833 PrintAndLogEx(NORMAL, "NDEF data:");
834 dump_buffer(data, datalen, stdout, 1);
835 }
836
837 NDEFDecodeAndPrint(data, datalen, verbose);
838
839 return 0;
840}
841
dc3e2acf
OM
842static command_t CommandTable[] =
843{
844 {"help", CmdHelp, 1, "This help"},
845 {"info", CmdHFMFPInfo, 0, "Info about Mifare Plus tag"},
ae3340a0
OM
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"},
c8a0f550
OM
849 {"auth", CmdHFMFPAuth, 0, "Authentication"},
850 {"rdbl", CmdHFMFPRdbl, 0, "Read blocks"},
851 {"rdsc", CmdHFMFPRdsc, 0, "Read sectors"},
4b5d696c 852 {"wrbl", CmdHFMFPWrbl, 0, "Write blocks"},
fdd9395d
OM
853 {"mad", CmdHFMFPMAD, 0, "Checks and prints MAD"},
854 {"ndef", CmdHFMFPNDEF, 0, "Prints NDEF records from card"},
dc3e2acf
OM
855 {NULL, NULL, 0, NULL}
856};
857
858int CmdHFMFP(const char *Cmd) {
859 (void)WaitForResponseTimeout(CMD_ACK,NULL,100);
860 CmdsParse(CommandTable, Cmd);
861 return 0;
862}
863
864int CmdHelp(const char *Cmd) {
865 CmdsHelp(CommandTable);
866 return 0;
867}
Impressum, Datenschutz