Mfp read plain (#704)
[proxmark3-svn] / client / cmdhfmfp.c
1 //-----------------------------------------------------------------------------
2 // Copyright (C) 2018 Merlok
3 //
4 // This code is licensed to you under the terms of the GNU GPL, version 2 or,
5 // at your option, any later version. See the LICENSE.txt file for the text of
6 // the license.
7 //-----------------------------------------------------------------------------
8 // High frequency MIFARE Plus commands
9 //-----------------------------------------------------------------------------
10
11 #include "cmdhfmfp.h"
12
13 #include <inttypes.h>
14 #include <string.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <ctype.h>
18 #include "comms.h"
19 #include "cmdmain.h"
20 #include "util.h"
21 #include "ui.h"
22 #include "cmdhf14a.h"
23 #include "mifare.h"
24 #include "mifare4.h"
25 #include "cliparser/cliparser.h"
26 #include "polarssl/libpcrypto.h"
27
28 static const uint8_t DefaultKey[16] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
29
30 typedef struct {
31 uint8_t Code;
32 const char *Description;
33 } PlusErrorsElm;
34
35 static const PlusErrorsElm PlusErrors[] = {
36 {0xFF, ""},
37 {0x00, "Unknown error"},
38 {0x06, "Block use error"},
39 {0x07, "Command use error"},
40 {0x08, "Invalid write command"},
41 {0x09, "Invalid block number"},
42 {0x0b, "Command code error"},
43 {0x0c, "Length error"},
44 {0x90, "OK"},
45 };
46 int PlusErrorsLen = sizeof(PlusErrors) / sizeof(PlusErrorsElm);
47
48 const char * GetErrorDescription(uint8_t errorCode) {
49 for(int i = 0; i < PlusErrorsLen; i++)
50 if (errorCode == PlusErrors[i].Code)
51 return PlusErrors[i].Description;
52
53 return PlusErrors[0].Description;
54 }
55
56 static int CmdHelp(const char *Cmd);
57
58 static bool VerboseMode = false;
59 void SetVerboseMode(bool verbose) {
60 VerboseMode = verbose;
61 }
62
63 int intExchangeRAW14aPlus(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
64 if(VerboseMode)
65 PrintAndLog(">>> %s", sprint_hex(datain, datainlen));
66
67 int res = ExchangeRAW14a(datain, datainlen, activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen);
68
69 if(VerboseMode)
70 PrintAndLog("<<< %s", sprint_hex(dataout, *dataoutlen));
71
72 return res;
73 }
74
75 int MFPWritePerso(uint8_t *keyNum, uint8_t *key, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
76 uint8_t rcmd[3 + 16] = {0xa8, keyNum[1], keyNum[0], 0x00};
77 memmove(&rcmd[3], key, 16);
78
79 return intExchangeRAW14aPlus(rcmd, sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen);
80 }
81
82 int MFPCommitPerso(bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
83 uint8_t rcmd[1] = {0xaa};
84
85 return intExchangeRAW14aPlus(rcmd, sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen);
86 }
87
88 int MFPReadBlock(mf4Session *session, bool plain, uint8_t blockNum, uint8_t blockCount, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac) {
89 uint8_t rcmd[4 + 8] = {(plain?(0x37):(0x33)), blockNum, 0x00, blockCount};
90 if (!plain && session)
91 CalculateMAC(session, rcmd, 4, &rcmd[4], VerboseMode);
92
93 int res = intExchangeRAW14aPlus(rcmd, plain?4:sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen);
94 if(res)
95 return res;
96
97 if(session && mac)
98 CalculateMAC(session, dataout, *dataoutlen, mac, VerboseMode);
99
100 return 0;
101 }
102
103 int MFPWriteBlock(mf4Session *session, uint8_t blockNum, uint8_t *data, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac) {
104 uint8_t rcmd[1 + 2 + 16 + 8] = {0xA3, blockNum, 0x00};
105 memmove(&rcmd[3], data, 16);
106 if (session)
107 CalculateMAC(session, rcmd, 19, &rcmd[19], VerboseMode);
108
109 int res = intExchangeRAW14aPlus(rcmd, sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen);
110 if(res)
111 return res;
112
113 if(session && mac)
114 CalculateMAC(session, dataout, *dataoutlen, mac, VerboseMode);
115
116 return 0;
117 }
118
119 int CmdHFMFPInfo(const char *cmd) {
120
121 if (cmd && strlen(cmd) > 0)
122 PrintAndLog("WARNING: command don't have any parameters.\n");
123
124 // info about 14a part
125 CmdHF14AInfo("");
126
127 // Mifare Plus info
128 UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0}};
129 SendCommand(&c);
130
131 UsbCommand resp;
132 WaitForResponse(CMD_ACK,&resp);
133
134 iso14a_card_select_t card;
135 memcpy(&card, (iso14a_card_select_t *)resp.d.asBytes, sizeof(iso14a_card_select_t));
136
137 uint64_t select_status = resp.arg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision
138
139 if (select_status == 1 || select_status == 2) {
140 PrintAndLog("----------------------------------------------");
141 PrintAndLog("Mifare Plus info:");
142
143 // MIFARE Type Identification Procedure
144 // https://www.nxp.com/docs/en/application-note/AN10833.pdf
145 uint16_t ATQA = card.atqa[0] + (card.atqa[1] << 8);
146 if (ATQA == 0x0004) PrintAndLog("ATQA: Mifare Plus 2k 4bUID");
147 if (ATQA == 0x0002) PrintAndLog("ATQA: Mifare Plus 4k 4bUID");
148 if (ATQA == 0x0044) PrintAndLog("ATQA: Mifare Plus 2k 7bUID");
149 if (ATQA == 0x0042) PrintAndLog("ATQA: Mifare Plus 4k 7bUID");
150
151 uint8_t SLmode = 0xff;
152 if (card.sak == 0x08) {
153 PrintAndLog("SAK: Mifare Plus 2k 7bUID");
154 if (select_status == 2) SLmode = 1;
155 }
156 if (card.sak == 0x18) {
157 PrintAndLog("SAK: Mifare Plus 4k 7bUID");
158 if (select_status == 2) SLmode = 1;
159 }
160 if (card.sak == 0x10) {
161 PrintAndLog("SAK: Mifare Plus 2k");
162 if (select_status == 2) SLmode = 2;
163 }
164 if (card.sak == 0x11) {
165 PrintAndLog("SAK: Mifare Plus 4k");
166 if (select_status == 2) SLmode = 2;
167 }
168 if (card.sak == 0x20) {
169 PrintAndLog("SAK: Mifare Plus SL0/SL3 or Mifare desfire");
170 if (card.ats_len > 0) {
171 SLmode = 3;
172
173 // check SL0
174 uint8_t data[250] = {0};
175 int datalen = 0;
176 // https://github.com/Proxmark/proxmark3/blob/master/client/scripts/mifarePlus.lua#L161
177 uint8_t cmd[3 + 16] = {0xa8, 0x90, 0x90, 0x00};
178 int res = ExchangeRAW14a(cmd, sizeof(cmd), false, false, data, sizeof(data), &datalen);
179 if (!res && datalen > 1 && data[0] == 0x09) {
180 SLmode = 0;
181 }
182 }
183 }
184
185 if (SLmode != 0xff)
186 PrintAndLog("Mifare Plus SL mode: SL%d", SLmode);
187 else
188 PrintAndLog("Mifare Plus SL mode: unknown(");
189 } else {
190 PrintAndLog("Mifare Plus info not available.");
191 }
192
193 DropField();
194
195 return 0;
196 }
197
198 int CmdHFMFPWritePerso(const char *cmd) {
199 uint8_t keyNum[64] = {0};
200 int keyNumLen = 0;
201 uint8_t key[64] = {0};
202 int keyLen = 0;
203
204 CLIParserInit("hf mfp wrp",
205 "Executes Write Perso command. Can be used in SL0 mode only.",
206 "Usage:\n\thf mfp wrp 4000 000102030405060708090a0b0c0d0e0f -> write key (00..0f) to key number 4000 \n"
207 "\thf mfp wrp 4000 -> write default key(0xff..0xff) to key number 4000");
208
209 void* argtable[] = {
210 arg_param_begin,
211 arg_lit0("vV", "verbose", "show internal data."),
212 arg_str1(NULL, NULL, "<HEX key number (2b)>", NULL),
213 arg_strx0(NULL, NULL, "<HEX key (16b)>", NULL),
214 arg_param_end
215 };
216 CLIExecWithReturn(cmd, argtable, true);
217
218 bool verbose = arg_get_lit(1);
219 CLIGetHexWithReturn(2, keyNum, &keyNumLen);
220 CLIGetHexWithReturn(3, key, &keyLen);
221 CLIParserFree();
222
223 SetVerboseMode(verbose);
224
225 if (!keyLen) {
226 memmove(key, DefaultKey, 16);
227 keyLen = 16;
228 }
229
230 if (keyNumLen != 2) {
231 PrintAndLog("Key number length must be 2 bytes instead of: %d", keyNumLen);
232 return 1;
233 }
234 if (keyLen != 16) {
235 PrintAndLog("Key length must be 16 bytes instead of: %d", keyLen);
236 return 1;
237 }
238
239 uint8_t data[250] = {0};
240 int datalen = 0;
241
242 int res = MFPWritePerso(keyNum, key, true, false, data, sizeof(data), &datalen);
243 if (res) {
244 PrintAndLog("Exchange error: %d", res);
245 return res;
246 }
247
248 if (datalen != 3) {
249 PrintAndLog("Command must return 3 bytes instead of: %d", datalen);
250 return 1;
251 }
252
253 if (data[0] != 0x90) {
254 PrintAndLog("Command error: %02x %s", data[0], GetErrorDescription(data[0]));
255 return 1;
256 }
257 PrintAndLog("Write OK.");
258
259 return 0;
260 }
261
262 uint16_t CardAddresses[] = {0x9000, 0x9001, 0x9002, 0x9003, 0x9004, 0xA000, 0xA001, 0xA080, 0xA081, 0xC000, 0xC001};
263
264 int CmdHFMFPInitPerso(const char *cmd) {
265 int res;
266 uint8_t key[256] = {0};
267 int keyLen = 0;
268 uint8_t keyNum[2] = {0};
269 uint8_t data[250] = {0};
270 int datalen = 0;
271
272 CLIParserInit("hf mfp initp",
273 "Executes Write Perso command for all card's keys. Can be used in SL0 mode only.",
274 "Usage:\n\thf mfp initp 000102030405060708090a0b0c0d0e0f -> fill all the keys with key (00..0f)\n"
275 "\thf mfp initp -vv -> fill all the keys with default key(0xff..0xff) and show all the data exchange");
276
277 void* argtable[] = {
278 arg_param_begin,
279 arg_litn("vV", "verbose", 0, 2, "show internal data."),
280 arg_strx0(NULL, NULL, "<HEX key (16b)>", NULL),
281 arg_param_end
282 };
283 CLIExecWithReturn(cmd, argtable, true);
284
285 bool verbose = arg_get_lit(1);
286 bool verbose2 = arg_get_lit(1) > 1;
287 CLIGetHexWithReturn(2, key, &keyLen);
288 CLIParserFree();
289
290 if (keyLen && keyLen != 16) {
291 PrintAndLog("Key length must be 16 bytes instead of: %d", keyLen);
292 return 1;
293 }
294
295 if (!keyLen)
296 memmove(key, DefaultKey, 16);
297
298 SetVerboseMode(verbose2);
299 for (uint16_t sn = 0x4000; sn < 0x4050; sn++) {
300 keyNum[0] = sn >> 8;
301 keyNum[1] = sn & 0xff;
302 res = MFPWritePerso(keyNum, key, (sn == 0x4000), true, data, sizeof(data), &datalen);
303 if (!res && (datalen == 3) && data[0] == 0x09) {
304 PrintAndLog("2k card detected.");
305 break;
306 }
307 if (res || (datalen != 3) || data[0] != 0x90) {
308 PrintAndLog("Write error on address %04x", sn);
309 break;
310 }
311 }
312
313 SetVerboseMode(verbose);
314 for (int i = 0; i < sizeof(CardAddresses) / 2; i++) {
315 keyNum[0] = CardAddresses[i] >> 8;
316 keyNum[1] = CardAddresses[i] & 0xff;
317 res = MFPWritePerso(keyNum, key, false, true, data, sizeof(data), &datalen);
318 if (!res && (datalen == 3) && data[0] == 0x09) {
319 PrintAndLog("Skipped[%04x]...", CardAddresses[i]);
320 } else {
321 if (res || (datalen != 3) || data[0] != 0x90) {
322 PrintAndLog("Write error on address %04x", CardAddresses[i]);
323 break;
324 }
325 }
326 }
327
328 DropField();
329
330 if (res)
331 return res;
332
333 PrintAndLog("Done.");
334
335 return 0;
336 }
337
338 int CmdHFMFPCommitPerso(const char *cmd) {
339 CLIParserInit("hf mfp commitp",
340 "Executes Commit Perso command. Can be used in SL0 mode only.",
341 "Usage:\n\thf mfp commitp -> \n");
342
343 void* argtable[] = {
344 arg_param_begin,
345 arg_lit0("vV", "verbose", "show internal data."),
346 arg_int0(NULL, NULL, "SL mode", NULL),
347 arg_param_end
348 };
349 CLIExecWithReturn(cmd, argtable, true);
350
351 bool verbose = arg_get_lit(1);
352 CLIParserFree();
353
354 SetVerboseMode(verbose);
355
356 uint8_t data[250] = {0};
357 int datalen = 0;
358
359 int res = MFPCommitPerso(true, false, data, sizeof(data), &datalen);
360 if (res) {
361 PrintAndLog("Exchange error: %d", res);
362 return res;
363 }
364
365 if (datalen != 3) {
366 PrintAndLog("Command must return 3 bytes instead of: %d", datalen);
367 return 1;
368 }
369
370 if (data[0] != 0x90) {
371 PrintAndLog("Command error: %02x %s", data[0], GetErrorDescription(data[0]));
372 return 1;
373 }
374 PrintAndLog("Switch level OK.");
375
376 return 0;
377 }
378
379 int CmdHFMFPAuth(const char *cmd) {
380 uint8_t keyn[250] = {0};
381 int keynlen = 0;
382 uint8_t key[250] = {0};
383 int keylen = 0;
384
385 CLIParserInit("hf mfp auth",
386 "Executes AES authentication command for Mifare Plus card",
387 "Usage:\n\thf mfp auth 4000 000102030405060708090a0b0c0d0e0f -> executes authentication\n"
388 "\thf mfp auth 9003 FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -v -> executes authentication and shows all the system data\n");
389
390 void* argtable[] = {
391 arg_param_begin,
392 arg_lit0("vV", "verbose", "show internal data."),
393 arg_str1(NULL, NULL, "<Key Num (HEX 2 bytes)>", NULL),
394 arg_str1(NULL, NULL, "<Key Value (HEX 16 bytes)>", NULL),
395 arg_param_end
396 };
397 CLIExecWithReturn(cmd, argtable, true);
398
399 bool verbose = arg_get_lit(1);
400 CLIGetHexWithReturn(2, keyn, &keynlen);
401 CLIGetHexWithReturn(3, key, &keylen);
402 CLIParserFree();
403
404 if (keynlen != 2) {
405 PrintAndLog("ERROR: <Key Num> must be 2 bytes long instead of: %d", keynlen);
406 return 1;
407 }
408
409 if (keylen != 16) {
410 PrintAndLog("ERROR: <Key Value> must be 16 bytes long instead of: %d", keylen);
411 return 1;
412 }
413
414 return MifareAuth4(NULL, keyn, key, true, false, verbose);
415 }
416
417 int CmdHFMFPRdbl(const char *cmd) {
418 uint8_t keyn[2] = {0};
419 uint8_t key[250] = {0};
420 int keylen = 0;
421
422 CLIParserInit("hf mfp rdbl",
423 "Reads several blocks from Mifare Plus card in plain mode.",
424 "Usage:\n\thf mfp rdbl 0 000102030405060708090a0b0c0d0e0f -> executes authentication and read block 0 data\n"
425 "\thf mfp rdbl 1 -v -> executes authentication and shows sector 1 data with default key 0xFF..0xFF and some additional data\n");
426
427 void* argtable[] = {
428 arg_param_begin,
429 arg_lit0("vV", "verbose", "show internal data."),
430 arg_int0("nN", "count", "blocks count (by default 1).", NULL),
431 arg_lit0("bB", "keyb", "use key B (by default keyA)."),
432 arg_lit0("pP", "plain", "plain communication between reader and card."),
433 arg_int1(NULL, NULL, "<Block Num (0..255)>", NULL),
434 arg_str0(NULL, NULL, "<Key Value (HEX 16 bytes)>", NULL),
435 arg_param_end
436 };
437 CLIExecWithReturn(cmd, argtable, false);
438
439 bool verbose = arg_get_lit(1);
440 int blocksCount = arg_get_int_def(2, 1);
441 bool keyB = arg_get_lit(3);
442 int plain = arg_get_lit(4) | true;
443 uint32_t blockn = arg_get_int(5);
444 CLIGetHexWithReturn(6, key, &keylen);
445 CLIParserFree();
446
447 SetVerboseMode(verbose);
448
449 if (!keylen) {
450 memmove(key, DefaultKey, 16);
451 keylen = 16;
452 }
453
454 if (blockn > 255) {
455 PrintAndLog("ERROR: <Block Num> must be in range [0..255] instead of: %d", blockn);
456 return 1;
457 }
458
459 if (keylen != 16) {
460 PrintAndLog("ERROR: <Key Value> must be 16 bytes long instead of: %d", keylen);
461 return 1;
462 }
463
464 // 3 blocks - wo iso14443-4 chaining
465 if (blocksCount > 3) {
466 PrintAndLog("ERROR: blocks count must be less than 3 instead of: %d", blocksCount);
467 return 1;
468 }
469
470 uint8_t sectorNum = mfSectorNum(blockn & 0xff);
471 uint16_t uKeyNum = 0x4000 + sectorNum * 2 + (keyB ? 1 : 0);
472 keyn[0] = uKeyNum >> 8;
473 keyn[1] = uKeyNum & 0xff;
474 if (verbose)
475 PrintAndLog("--block:%d sector[%d]:%02x key:%04x", blockn, mfNumBlocksPerSector(sectorNum), sectorNum, uKeyNum);
476
477 mf4Session session;
478 int res = MifareAuth4(&session, keyn, key, true, true, verbose);
479 if (res) {
480 PrintAndLog("Authentication error: %d", res);
481 return res;
482 }
483
484 uint8_t data[250] = {0};
485 int datalen = 0;
486 uint8_t mac[8] = {0};
487 res = MFPReadBlock(&session, plain, blockn & 0xff, blocksCount, false, false, data, sizeof(data), &datalen, mac);
488 if (res) {
489 PrintAndLog("Read error: %d", res);
490 return res;
491 }
492
493 if (datalen && data[0] != 0x90) {
494 PrintAndLog("Card read error: %02x %s", data[0], GetErrorDescription(data[0]));
495 return 6;
496 }
497
498 if (datalen != 1 + blocksCount * 16 + 8 + 2) {
499 PrintAndLog("Error return length:%d", datalen);
500 return 5;
501 }
502
503 int indx = blockn;
504 for(int i = 0; i < blocksCount; i++) {
505 PrintAndLog("data[%03d]: %s", indx, sprint_hex(&data[1 + i * 16], 16));
506 indx++;
507 if (mfIsSectorTrailer(indx)){
508 PrintAndLog("data[%03d]: ------------------- trailer -------------------", indx);
509 indx++;
510 }
511 }
512
513 if (!memcmp(&data[blocksCount * 16 + 1], mac, 8)) {
514 PrintAndLog("WARNING: mac not equal...");
515 PrintAndLog("MAC card: %s", sprint_hex(&data[blocksCount * 16 + 1], 8));
516 PrintAndLog("MAC reader: %s", sprint_hex(mac, 8));
517 } else {
518 if(verbose)
519 PrintAndLog("MAC: %s", sprint_hex(&data[blocksCount * 16 + 1], 8));
520 }
521
522 return 0;
523 }
524
525 int CmdHFMFPRdsc(const char *cmd) {
526 uint8_t keyn[2] = {0};
527 uint8_t key[250] = {0};
528 int keylen = 0;
529
530 CLIParserInit("hf mfp rdsc",
531 "Reads one sector from Mifare Plus card in plain mode.",
532 "Usage:\n\thf mfp rdsc 0 000102030405060708090a0b0c0d0e0f -> executes authentication and read sector 0 data\n"
533 "\thf mfp rdsc 1 -v -> executes authentication and shows sector 1 data with default key 0xFF..0xFF and some additional data\n");
534
535 void* argtable[] = {
536 arg_param_begin,
537 arg_lit0("vV", "verbose", "show internal data."),
538 arg_lit0("bB", "keyb", "use key B (by default keyA)."),
539 arg_lit0("pP", "plain", "plain communication between reader and card."),
540 arg_int1(NULL, NULL, "<Sector Num (0..255)>", NULL),
541 arg_str0(NULL, NULL, "<Key Value (HEX 16 bytes)>", NULL),
542 arg_param_end
543 };
544 CLIExecWithReturn(cmd, argtable, false);
545
546 bool verbose = arg_get_lit(1);
547 bool keyB = arg_get_lit(2);
548 bool plain = arg_get_lit(3) | true;
549 uint32_t sectorNum = arg_get_int(4);
550 CLIGetHexWithReturn(5, key, &keylen);
551 CLIParserFree();
552
553 SetVerboseMode(verbose);
554
555 if (!keylen) {
556 memmove(key, DefaultKey, 16);
557 keylen = 16;
558 }
559
560 if (sectorNum > 39) {
561 PrintAndLog("ERROR: <Sector Num> must be in range [0..39] instead of: %d", sectorNum);
562 return 1;
563 }
564
565 if (keylen != 16) {
566 PrintAndLog("ERROR: <Key Value> must be 16 bytes long instead of: %d", keylen);
567 return 1;
568 }
569
570 uint16_t uKeyNum = 0x4000 + sectorNum * 2 + (keyB ? 1 : 0);
571 keyn[0] = uKeyNum >> 8;
572 keyn[1] = uKeyNum & 0xff;
573 if (verbose)
574 PrintAndLog("--sector[%d]:%02x key:%04x", mfNumBlocksPerSector(sectorNum), sectorNum, uKeyNum);
575
576 mf4Session session;
577 int res = MifareAuth4(&session, keyn, key, true, true, verbose);
578 if (res) {
579 PrintAndLog("Authentication error: %d", res);
580 return res;
581 }
582
583 uint8_t data[250] = {0};
584 int datalen = 0;
585 uint8_t mac[8] = {0};
586 for(int n = mfFirstBlockOfSector(sectorNum); n < mfFirstBlockOfSector(sectorNum) + mfNumBlocksPerSector(sectorNum); n++) {
587 res = MFPReadBlock(&session, plain, n & 0xff, 1, false, true, data, sizeof(data), &datalen, mac);
588 if (res) {
589 PrintAndLog("Read error: %d", res);
590 DropField();
591 return res;
592 }
593
594 if (datalen && data[0] != 0x90) {
595 PrintAndLog("Card read error: %02x %s", data[0], GetErrorDescription(data[0]));
596 DropField();
597 return 6;
598 }
599 if (datalen != 1 + 16 + 8 + 2) {
600 PrintAndLog("Error return length:%d", datalen);
601 DropField();
602 return 5;
603 }
604
605 PrintAndLog("data[%03d]: %s", n, sprint_hex(&data[1], 16));
606
607 if (!memcmp(&data[1 + 16], mac, 8)) {
608 PrintAndLog("WARNING: mac on block %d not equal...", n);
609 PrintAndLog("MAC card: %s", sprint_hex(&data[1 + 16], 8));
610 PrintAndLog("MAC reader: %s", sprint_hex(mac, 8));
611 } else {
612 if(verbose)
613 PrintAndLog("MAC: %s", sprint_hex(&data[1 + 16], 8));
614 }
615 }
616 DropField();
617
618 return 0;
619 }
620
621 int CmdHFMFPWrbl(const char *cmd) {
622 uint8_t keyn[2] = {0};
623 uint8_t key[250] = {0};
624 int keylen = 0;
625 uint8_t datain[250] = {0};
626 int datainlen = 0;
627
628 CLIParserInit("hf mfp wrbl",
629 "Writes one block to Mifare Plus card.",
630 "Usage:\n\thf mfp wrbl 1 ff0000000000000000000000000000ff 000102030405060708090a0b0c0d0e0f -> writes block 1 data\n"
631 "\thf mfp wrbl 2 ff0000000000000000000000000000ff -v -> writes block 2 data with default key 0xFF..0xFF and some additional data\n");
632
633 void* argtable[] = {
634 arg_param_begin,
635 arg_lit0("vV", "verbose", "show internal data."),
636 arg_lit0("bB", "keyb", "use key B (by default keyA)."),
637 arg_int1(NULL, NULL, "<Block Num (0..255)>", NULL),
638 arg_str1(NULL, NULL, "<Data (HEX 16 bytes)>", NULL),
639 arg_str0(NULL, NULL, "<Key (HEX 16 bytes)>", NULL),
640 arg_param_end
641 };
642 CLIExecWithReturn(cmd, argtable, false);
643
644 bool verbose = arg_get_lit(1);
645 bool keyB = arg_get_lit(2);
646 uint32_t blockNum = arg_get_int(3);
647 CLIGetHexWithReturn(4, datain, &datainlen);
648 CLIGetHexWithReturn(5, key, &keylen);
649 CLIParserFree();
650
651 SetVerboseMode(verbose);
652
653 if (!keylen) {
654 memmove(key, DefaultKey, 16);
655 keylen = 16;
656 }
657
658 if (blockNum > 39) {
659 PrintAndLog("ERROR: <Block Num> must be in range [0..255] instead of: %d", blockNum);
660 return 1;
661 }
662
663 if (keylen != 16) {
664 PrintAndLog("ERROR: <Key> must be 16 bytes long instead of: %d", keylen);
665 return 1;
666 }
667
668 if (datainlen != 16) {
669 PrintAndLog("ERROR: <Data> must be 16 bytes long instead of: %d", datainlen);
670 return 1;
671 }
672
673 uint8_t sectorNum = mfSectorNum(blockNum & 0xff);
674 uint16_t uKeyNum = 0x4000 + sectorNum * 2 + (keyB ? 1 : 0);
675 keyn[0] = uKeyNum >> 8;
676 keyn[1] = uKeyNum & 0xff;
677 if (verbose)
678 PrintAndLog("--block:%d sector[%d]:%02x key:%04x", blockNum & 0xff, mfNumBlocksPerSector(sectorNum), sectorNum, uKeyNum);
679
680 mf4Session session;
681 int res = MifareAuth4(&session, keyn, key, true, true, verbose);
682 if (res) {
683 PrintAndLog("Authentication error: %d", res);
684 return res;
685 }
686
687 uint8_t data[250] = {0};
688 int datalen = 0;
689 uint8_t mac[8] = {0};
690 res = MFPWriteBlock(&session, blockNum & 0xff, datain, false, false, data, sizeof(data), &datalen, mac);
691 if (res) {
692 PrintAndLog("Write error: %d", res);
693 DropField();
694 return res;
695 }
696
697 if (datalen != 3 && (datalen != 3 + 8)) {
698 PrintAndLog("Error return length:%d", datalen);
699 DropField();
700 return 5;
701 }
702
703 if (datalen && data[0] != 0x90) {
704 PrintAndLog("Card write error: %02x %s", data[0], GetErrorDescription(data[0]));
705 DropField();
706 return 6;
707 }
708
709 if (!memcmp(&data[1], mac, 8)) {
710 PrintAndLog("WARNING: mac not equal...");
711 PrintAndLog("MAC card: %s", sprint_hex(&data[1], 8));
712 PrintAndLog("MAC reader: %s", sprint_hex(mac, 8));
713 } else {
714 if(verbose)
715 PrintAndLog("MAC: %s", sprint_hex(&data[1], 8));
716 }
717
718 DropField();
719 return 0;
720 }
721
722 static command_t CommandTable[] =
723 {
724 {"help", CmdHelp, 1, "This help"},
725 {"info", CmdHFMFPInfo, 0, "Info about Mifare Plus tag"},
726 {"wrp", CmdHFMFPWritePerso, 0, "Write Perso command"},
727 {"initp", CmdHFMFPInitPerso, 0, "Fills all the card's keys"},
728 {"commitp", CmdHFMFPCommitPerso, 0, "Move card to SL1 or SL3 mode"},
729 {"auth", CmdHFMFPAuth, 0, "Authentication"},
730 {"rdbl", CmdHFMFPRdbl, 0, "Read blocks"},
731 {"rdsc", CmdHFMFPRdsc, 0, "Read sectors"},
732 // {"wrbl", CmdHFMFPWrbl, 0, "Write blocks"},
733 {NULL, NULL, 0, NULL}
734 };
735
736 int CmdHFMFP(const char *Cmd) {
737 (void)WaitForResponseTimeout(CMD_ACK,NULL,100);
738 CmdsParse(CommandTable, Cmd);
739 return 0;
740 }
741
742 int CmdHelp(const char *Cmd) {
743 CmdsHelp(CommandTable);
744 return 0;
745 }
Impressum, Datenschutz