renamed 'hf mfdes readdata, writedata' to 'read/write'
[RRG-proxmark3.git] / client / src / cmdhfmfdes.c
blob4a59c780aaf03364075be8be008107194a3b43d5
1 //-----------------------------------------------------------------------------
2 // Copyright (C) 2014 Iceman
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 Desfire commands
9 //-----------------------------------------------------------------------------
10 // Code heavily modified by B.Kerler :)
12 #include "cmdhfmfdes.h"
14 #include <stdio.h>
15 #include <string.h>
17 #include "commonutil.h" // ARRAYLEN
18 #include "cmdparser.h" // command_t
19 #include "comms.h"
20 #include "ui.h"
21 #include "cmdhf14a.h"
22 #include "aes.h"
23 #include "crypto/libpcrypto.h"
24 #include "protocols.h"
25 #include "cmdtrace.h"
26 #include "cliparser.h"
27 #include "iso7816/apduinfo.h" // APDU manipulation / errorcodes
28 #include "iso7816/iso7816core.h" // APDU logging
29 #include "util_posix.h" // msleep
30 #include "mifare/desfire_crypto.h"
31 #include "crapto1/crapto1.h"
32 #include "fileutils.h"
33 #include "mifare/mifaredefault.h" // default keys
34 #include "nfc/ndef.h" // NDEF
35 #include "mifare/mad.h"
36 #include "generator.h"
37 #include "aiddesfire.h"
38 #include "util.h"
40 #define MAX_KEY_LEN 24
41 #define MAX_KEYS_LIST_LEN 1024
43 #define status(x) ( ((uint16_t)(0x91<<8)) + (uint16_t)x )
45 #ifndef DropFieldDesfire
46 #define DropFieldDesfire() { \
47 clearCommandBuffer(); \
48 SendCommandNG(CMD_HF_DROPFIELD, NULL, 0); \
49 tag->rf_field_on = false; \
50 PrintAndLogEx(DEBUG, "field dropped"); \
52 #endif
54 struct desfire_key default_key = {0};
56 uint8_t desdefaultkeys[3][8] = {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //Official
57 {0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47},
58 {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}
61 uint8_t aesdefaultkeys[5][16] = {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //Official, TRF7970A
62 {0x79, 0x70, 0x25, 0x53, 0x79, 0x70, 0x25, 0x53, 0x79, 0x70, 0x25, 0x53, 0x79, 0x70, 0x25, 0x53}, // TRF7970A
63 {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}, // TRF7970A
64 {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f},
65 {0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f}
68 uint8_t k3kdefaultkeys[1][24] = {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
70 struct desfire_tag mf_state = {.session_key = NULL, .authentication_scheme = AS_LEGACY, .authenticated_key_no = NOT_YET_AUTHENTICATED, .crypto_buffer = NULL, .crypto_buffer_size = 0, .selected_application = 0};
71 static desfiretag_t tag = &mf_state;
73 typedef struct mfdes_authinput {
74 uint8_t mode;
75 uint8_t algo;
76 uint8_t keyno;
77 uint8_t keylen;
78 uint8_t key[24];
79 uint8_t kdfAlgo;
80 uint8_t kdfInputLen;
81 uint8_t kdfInput[31];
82 } PACKED mfdes_authinput_t;
84 static mfdes_authinput_t currentauth[0xF] = {{.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}};
86 typedef struct mfdes_auth_res {
87 uint8_t sessionkeylen;
88 uint8_t sessionkey[24];
89 } PACKED mfdes_auth_res_t;
91 typedef struct mfdes_data {
92 uint8_t fileno; //01
93 uint8_t offset[3];
94 uint8_t length[3];
95 uint8_t *data;
96 } PACKED mfdes_data_t;
98 typedef struct mfdes_info_res {
99 uint8_t isOK;
100 uint8_t uid[7];
101 uint8_t uidlen;
102 uint8_t versionHW[7];
103 uint8_t versionSW[7];
104 uint8_t details[14];
105 } PACKED mfdes_info_res_t;
107 typedef struct mfdes_value {
108 uint8_t fileno; //01
109 uint8_t value[16];
110 } PACKED mfdes_value_t;
112 typedef struct mfdes_file {
113 uint8_t fileno; //01
114 uint8_t fid[2]; //03E1
115 uint8_t comset; //00
116 uint8_t access_rights[2]; ///EEEE
117 uint8_t filesize[3]; //0F0000
118 } PACKED mfdes_file_t;
120 typedef struct mfdes_linear {
121 uint8_t fileno; //01
122 uint8_t fid[2]; //03E1
123 uint8_t comset; //00
124 uint8_t access_rights[2]; ///EEEE
125 uint8_t recordsize[3];
126 uint8_t maxnumrecords[3];
127 } PACKED mfdes_linear_t;
129 typedef struct mfdes_value_file {
130 uint8_t fileno; //01
131 uint8_t comset; //00
132 uint8_t access_rights[2]; ///EEEE
133 uint8_t lowerlimit[4];
134 uint8_t upperlimit[4];
135 uint8_t value[4];
136 uint8_t limitedcreditenabled;
137 } PACKED mfdes_value_file_t;
139 typedef enum {
140 MFDES_DATA_FILE = 0,
141 MFDES_RECORD_FILE,
142 MFDES_VALUE_FILE
143 } MFDES_FILE_TYPE_T;
145 // NXP Appnote AN10787 - Application Directory (MAD)
146 typedef enum {
147 CL_ADMIN = 0,
148 CL_MISC1,
149 CL_MISC2,
150 CL_MISC3,
151 CL_MISC4,
152 CL_MISC5,
153 CL_MISC6,
154 CL_MISC7,
155 CL_AIRLINES = 8,
156 CL_FERRY,
157 CL_RAIL,
158 CL_MISC,
159 CL_TRANSPORT,
160 CL_SECURITY = 0x14,
161 CL_CITYTRAFFIC = 0x18,
162 CL_CZECH_RAIL,
163 CL_BUS,
164 CL_MMT,
165 CL_TAXI = 0x28,
166 CL_TOLL = 0x30,
167 CL_GENERIC_TRANS,
168 CL_COMPANY_SERVICES = 0x38,
169 CL_CITYCARD = 0x40,
170 CL_ACCESS_CONTROL_1 = 0x47,
171 CL_ACCESS_CONTROL_2,
172 CL_VIGIK = 0x49,
173 CL_NED_DEFENCE = 0x4A,
174 CL_BOSCH_TELECOM = 0x4B,
175 CL_EU = 0x4C,
176 CL_SKI_TICKET = 0x50,
177 CL_SOAA = 0x55,
178 CL_ACCESS2 = 0x56,
179 CL_FOOD = 0x60,
180 CL_NONFOOD = 0x68,
181 CL_HOTEL = 0x70,
182 CL_LOYALTY = 0x71,
183 CL_AIRPORT = 0x75,
184 CL_CAR_RENTAL = 0x78,
185 CL_NED_GOV = 0x79,
186 CL_ADMIN2 = 0x80,
187 CL_PURSE = 0x88,
188 CL_TV = 0x90,
189 CL_CRUISESHIP = 0x91,
190 CL_IOPTA = 0x95,
191 CL_METERING = 0x97,
192 CL_TELEPHONE = 0x98,
193 CL_HEALTH = 0xA0,
194 CL_WAREHOUSE = 0xA8,
195 CL_BANKING = 0xB8,
196 CL_ENTERTAIN = 0xC0,
197 CL_PARKING = 0xC8,
198 CL_FLEET = 0xC9,
199 CL_FUEL = 0xD0,
200 CL_INFO = 0xD8,
201 CL_PRESS = 0xE0,
202 CL_NFC = 0xE1,
203 CL_COMPUTER = 0xE8,
204 CL_MAIL = 0xF0,
205 CL_AMISC = 0xF8,
206 CL_AMISC1 = 0xF9,
207 CL_AMISC2 = 0xFA,
208 CL_AMISC3 = 0xFB,
209 CL_AMISC4 = 0xFC,
210 CL_AMISC5 = 0xFD,
211 CL_AMISC6 = 0xFE,
212 CL_AMISC7 = 0xFF,
213 } aidcluster_h;
215 static const char *cluster_to_text(uint8_t cluster) {
216 switch (cluster) {
217 case CL_ADMIN:
218 return "card administration";
219 case CL_MISC1:
220 case CL_MISC2:
221 case CL_MISC3:
222 case CL_MISC4:
223 case CL_MISC5:
224 case CL_MISC6:
225 case CL_MISC7:
226 return "miscellaneous applications";
227 case CL_AIRLINES:
228 return "airlines";
229 case CL_FERRY:
230 return "ferry traffic";
231 case CL_RAIL:
232 return "railway services";
233 case CL_MISC:
234 return "miscellaneous applications";
235 case CL_TRANSPORT:
236 return "transport";
237 case CL_SECURITY:
238 return "security solutions";
239 case CL_CITYTRAFFIC:
240 return "city traffic";
241 case CL_CZECH_RAIL:
242 return "Czech Railways";
243 case CL_BUS:
244 return "bus services";
245 case CL_MMT:
246 return "multi modal transit";
247 case CL_TAXI:
248 return "taxi";
249 case CL_TOLL:
250 return "road toll";
251 case CL_GENERIC_TRANS:
252 return "generic transport";
253 case CL_COMPANY_SERVICES:
254 return "company services";
255 case CL_CITYCARD:
256 return "city card services";
257 case CL_ACCESS_CONTROL_1:
258 case CL_ACCESS_CONTROL_2:
259 return "access control & security";
260 case CL_VIGIK:
261 return "VIGIK";
262 case CL_NED_DEFENCE:
263 return "Ministry of Defence, Netherlands";
264 case CL_BOSCH_TELECOM:
265 return "Bosch Telecom, Germany";
266 case CL_EU:
267 return "European Union Institutions";
268 case CL_SKI_TICKET:
269 return "ski ticketing";
270 case CL_SOAA:
271 return "SOAA standard for offline access standard";
272 case CL_ACCESS2:
273 return "access control & security";
274 case CL_FOOD:
275 return "food";
276 case CL_NONFOOD:
277 return "non-food trade";
278 case CL_HOTEL:
279 return "hotel";
280 case CL_LOYALTY:
281 return "loyalty";
282 case CL_AIRPORT:
283 return "airport services";
284 case CL_CAR_RENTAL:
285 return "car rental";
286 case CL_NED_GOV:
287 return "Dutch government";
288 case CL_ADMIN2:
289 return "administration services";
290 case CL_PURSE:
291 return "electronic purse";
292 case CL_TV:
293 return "television";
294 case CL_CRUISESHIP:
295 return "cruise ship";
296 case CL_IOPTA:
297 return "IOPTA";
298 case CL_METERING:
299 return "metering";
300 case CL_TELEPHONE:
301 return "telephone";
302 case CL_HEALTH:
303 return "health services";
304 case CL_WAREHOUSE:
305 return "warehouse";
306 case CL_BANKING:
307 return "banking";
308 case CL_ENTERTAIN:
309 return "entertainment & sports";
310 case CL_PARKING:
311 return "car parking";
312 case CL_FLEET:
313 return "fleet management";
314 case CL_FUEL:
315 return "fuel, gasoline";
316 case CL_INFO:
317 return "info services";
318 case CL_PRESS:
319 return "press";
320 case CL_NFC:
321 return "NFC Forum";
322 case CL_COMPUTER:
323 return "computer";
324 case CL_MAIL:
325 return "mail";
326 case CL_AMISC:
327 case CL_AMISC1:
328 case CL_AMISC2:
329 case CL_AMISC3:
330 case CL_AMISC4:
331 case CL_AMISC5:
332 case CL_AMISC6:
333 case CL_AMISC7:
334 return "miscellaneous applications";
335 default:
336 break;
338 return "reserved";
341 typedef enum {
342 DESFIRE_UNKNOWN = 0,
343 DESFIRE_MF3ICD40,
344 DESFIRE_EV1,
345 DESFIRE_EV2,
346 DESFIRE_EV3,
347 DESFIRE_LIGHT,
348 PLUS_EV1,
349 NTAG413DNA,
350 } nxp_cardtype_t;
352 typedef struct dfname {
353 uint8_t aid[3];
354 uint8_t fid[2];
355 uint8_t name[16];
356 } PACKED dfname_t;
358 typedef struct aidhdr {
359 uint8_t aid[3];
360 uint8_t keysetting1;
361 uint8_t keysetting2;
362 uint8_t fid[2];
363 uint8_t name[16];
364 } PACKED aidhdr_t;
366 static int CmdHelp(const char *Cmd);
368 static const char *getEncryptionAlgoStr(uint8_t algo) {
369 switch (algo) {
370 case MFDES_ALGO_AES :
371 return "AES";
372 case MFDES_ALGO_3DES :
373 return "3DES";
374 case MFDES_ALGO_DES :
375 return "DES";
376 case MFDES_ALGO_3K3DES :
377 return "3K3DES";
378 default :
379 return "";
383 The 7 MSBits (= n) code the storage size itself based on 2^n,
384 the LSBit is set to '0' if the size is exactly 2^n
385 and set to '1' if the storage size is between 2^n and 2^(n+1).
386 For this version of DESFire the 7 MSBits are set to 0x0C (2^12 = 4096) and the LSBit is '0'.
388 static char *getCardSizeStr(uint8_t fsize) {
390 static char buf[40] = {0x00};
391 char *retStr = buf;
393 uint16_t usize = 1 << (((uint16_t)fsize >> 1) + 1);
394 uint16_t lsize = 1 << ((uint16_t)fsize >> 1);
396 // is LSB set?
397 if (fsize & 1)
398 snprintf(retStr, sizeof(buf), "0x%02X ( " _GREEN_("%d - %d bytes") " )", fsize, usize, lsize);
399 else
400 snprintf(retStr, sizeof(buf), "0x%02X ( " _GREEN_("%d bytes") " )", fsize, lsize);
401 return buf;
404 static char *getProtocolStr(uint8_t id, bool hw) {
406 static char buf[50] = {0x00};
407 char *retStr = buf;
409 if (id == 0x04) {
410 snprintf(retStr, sizeof(buf), "0x%02X ( " _YELLOW_("ISO 14443-3 MIFARE, 14443-4") " )", id);
411 } else if (id == 0x05) {
412 if (hw)
413 snprintf(retStr, sizeof(buf), "0x%02X ( " _YELLOW_("ISO 14443-2, 14443-3") " )", id);
414 else
415 snprintf(retStr, sizeof(buf), "0x%02X ( " _YELLOW_("ISO 14443-3, 14443-4") " )", id);
416 } else {
417 snprintf(retStr, sizeof(buf), "0x%02X ( " _YELLOW_("Unknown") " )", id);
419 return buf;
422 static char *getVersionStr(uint8_t major, uint8_t minor) {
424 static char buf[40] = {0x00};
425 char *retStr = buf;
427 if (major == 0x00)
428 snprintf(retStr, sizeof(buf), "%x.%x ( " _GREEN_("DESFire MF3ICD40") " )", major, minor);
429 else if (major == 0x01 && minor == 0x00)
430 snprintf(retStr, sizeof(buf), "%x.%x ( " _GREEN_("DESFire EV1") " )", major, minor);
431 else if (major == 0x12 && minor == 0x00)
432 snprintf(retStr, sizeof(buf), "%x.%x ( " _GREEN_("DESFire EV2") " )", major, minor);
433 else if (major == 0x42 && minor == 0x00)
434 snprintf(retStr, sizeof(buf), "%x.%x ( " _GREEN_("DESFire EV2") " )", major, minor);
435 else if (major == 0x33 && minor == 0x00)
436 snprintf(retStr, sizeof(buf), "%x.%x ( " _GREEN_("DESFire EV3") " )", major, minor);
437 else if (major == 0x30 && minor == 0x00)
438 snprintf(retStr, sizeof(buf), "%x.%x ( " _GREEN_("DESFire Light") " )", major, minor);
439 else if (major == 0x10 && minor == 0x00)
440 snprintf(retStr, sizeof(buf), "%x.%x ( " _GREEN_("NTAG413DNA") " )", major, minor);
441 else
442 snprintf(retStr, sizeof(buf), "%x.%x ( " _YELLOW_("Unknown") " )", major, minor);
443 return buf;
445 //04 01 01 01 00 1A 05
448 static int DESFIRESendApdu(bool activate_field, bool leavefield_on, sAPDU apdu, uint8_t *result, uint32_t max_result_len, uint32_t *result_len, uint16_t *sw) {
450 *result_len = 0;
451 if (sw) *sw = 0;
453 uint16_t isw = 0;
454 int res = 0;
456 if (activate_field) {
457 DropFieldDesfire();
458 msleep(50);
461 // select?
462 uint8_t data[APDU_RES_LEN] = {0};
464 // COMPUTE APDU
465 int datalen = 0;
466 //if (APDUEncodeS(&apdu, false, IncludeLe ? 0x100 : 0x00, data, &datalen)) {
467 if (APDUEncodeS(&apdu, false, 0x100, data, &datalen)) {
468 PrintAndLogEx(ERR, "APDU encoding error.");
469 return PM3_EAPDU_ENCODEFAIL;
472 if (GetAPDULogging() || (g_debugMode > 1))
473 PrintAndLogEx(SUCCESS, ">>>> %s", sprint_hex(data, datalen));
475 res = ExchangeAPDU14a(data, datalen, activate_field, leavefield_on, result, max_result_len, (int *)result_len);
476 if (res != PM3_SUCCESS) {
477 return res;
480 if (activate_field) {
481 PrintAndLogEx(DEBUG, "field up");
482 tag->rf_field_on = true;
485 if (GetAPDULogging() || (g_debugMode > 1))
486 PrintAndLogEx(SUCCESS, "<<<< %s", sprint_hex(result, *result_len));
488 if (*result_len < 2) {
489 return PM3_SUCCESS;
492 *result_len -= 2;
493 isw = (result[*result_len] << 8) + result[*result_len + 1];
494 if (sw)
495 *sw = isw;
497 if (isw != 0x9000 && isw != status(MFDES_S_OPERATION_OK) && isw != status(MFDES_S_SIGNATURE) && isw != status(MFDES_S_ADDITIONAL_FRAME) && isw != status(MFDES_S_NO_CHANGES)) {
498 if (GetAPDULogging()) {
499 if (isw >> 8 == 0x61) {
500 PrintAndLogEx(ERR, "APDU chaining len: 0x%02x -->", isw & 0xff);
501 } else {
502 PrintAndLogEx(ERR, "APDU(%02x%02x) ERROR: [0x%4X] %s", apdu.CLA, apdu.INS, isw, GetAPDUCodeDescription(isw >> 8, isw & 0xff));
503 return PM3_EAPDU_FAIL;
506 return PM3_EAPDU_FAIL;
508 return PM3_SUCCESS;
511 static const char *getstatus(uint16_t *sw) {
512 if (sw == NULL) return "--> sw argument error. This should never happen !";
513 if (((*sw >> 8) & 0xFF) == 0x91) {
514 switch (*sw & 0xFF) {
515 case MFDES_E_OUT_OF_EEPROM:
516 return "Out of Eeprom, insufficient NV-Memory to complete command";
517 case MFDES_E_ILLEGAL_COMMAND_CODE:
518 return "Command code not supported";
520 case MFDES_E_INTEGRITY_ERROR:
521 return "CRC or MAC does not match data / Padding bytes invalid";
523 case MFDES_E_NO_SUCH_KEY:
524 return "Invalid key number specified";
526 case MFDES_E_LENGTH:
527 return "Length of command string invalid";
529 case MFDES_E_PERMISSION_DENIED:
530 return "Current configuration/status does not allow the requested command";
532 case MFDES_E_PARAMETER_ERROR:
533 return "Value of the parameter(s) invalid";
535 case MFDES_E_APPLICATION_NOT_FOUND:
536 return "Requested AID not present on PICC";
538 case MFDES_E_APPL_INTEGRITY:
539 return "Application integrity error, application will be disabled";
541 case MFDES_E_AUTHENTIFICATION_ERROR:
542 return "Current authentication status does not allow the requested command";
544 case MFDES_E_BOUNDARY:
545 return "Attempted to read/write data from/to beyond the file's/record's limit";
547 case MFDES_E_PICC_INTEGRITY:
548 return "PICC integrity error, PICC will be disabled";
550 case MFDES_E_COMMAND_ABORTED:
551 return "Previous command was not fully completed / Not all Frames were requested or provided by the PCD";
553 case MFDES_E_PICC_DISABLED:
554 return "PICC was disabled by an unrecoverable error";
556 case MFDES_E_COUNT:
557 return "Application count is limited to 28, not addition CreateApplication possible";
559 case MFDES_E_DUPLICATE:
560 return "Duplicate entry: File/Application/ISO Text does already exist";
562 case MFDES_E_EEPROM:
563 return "Eeprom error due to loss of power, internal backup/rollback mechanism activated";
565 case MFDES_E_FILE_NOT_FOUND:
566 return "Specified file number does not exist";
568 case MFDES_E_FILE_INTEGRITY:
569 return "File integrity error, file will be disabled";
571 default:
572 return "Unknown error";
575 return "Unknown error";
578 static const char *GetErrorString(int res, uint16_t *sw) {
579 switch (res) {
580 case PM3_EAPDU_FAIL:
581 return getstatus(sw);
582 case PM3_EUNDEF:
583 return "Undefined error";
584 case PM3_EINVARG:
585 return "Invalid argument(s)";
586 case PM3_EDEVNOTSUPP:
587 return "Operation not supported by device";
588 case PM3_ETIMEOUT:
589 return "Operation timed out";
590 case PM3_EOPABORTED:
591 return "Operation aborted (by user)";
592 case PM3_ENOTIMPL:
593 return "Not (yet) implemented";
594 case PM3_ERFTRANS:
595 return "Error while RF transmission";
596 case PM3_EIO:
597 return "Input / output error";
598 case PM3_EOVFLOW:
599 return "Buffer overflow";
600 case PM3_ESOFT:
601 return "Software error";
602 case PM3_EFLASH:
603 return "Flash error";
604 case PM3_EMALLOC:
605 return "Memory allocation error";
606 case PM3_EFILE:
607 return "File error";
608 case PM3_ENOTTY:
609 return "Generic TTY error";
610 case PM3_EINIT:
611 return "Initialization error";
612 case PM3_EWRONGANSWER:
613 return "Expected a different answer error";
614 case PM3_EOUTOFBOUND:
615 return "Memory out-of-bounds error";
616 case PM3_ECARDEXCHANGE:
617 return "Exchange with card error";
618 case PM3_EAPDU_ENCODEFAIL:
619 return "Failed to create APDU";
620 case PM3_ENODATA:
621 return "No data";
622 case PM3_EFATAL:
623 return "Fatal error";
624 default:
625 break;
627 return "";
630 static int send_desfire_cmd(sAPDU *apdu, bool select, uint8_t *dest, uint32_t *recv_len, uint16_t *sw, uint32_t splitbysize, bool readalldata) {
631 if (apdu == NULL) {
632 PrintAndLogEx(DEBUG, "APDU=NULL");
633 return PM3_EINVARG;
635 if (sw == NULL) {
636 PrintAndLogEx(DEBUG, "SW=NULL");
637 return PM3_EINVARG;
639 if (recv_len == NULL) {
640 PrintAndLogEx(DEBUG, "RECV_LEN=NULL");
641 return PM3_EINVARG;
644 *sw = 0;
645 uint8_t data[255 * 5] = {0x00};
646 uint32_t resplen = 0;
647 uint32_t pos = 0;
648 uint32_t i = 1;
649 int res = DESFIRESendApdu(select, true, *apdu, data, sizeof(data), &resplen, sw);
650 if (res != PM3_SUCCESS) {
651 PrintAndLogEx(DEBUG, "%s", GetErrorString(res, sw));
652 DropFieldDesfire();
653 return res;
655 if (dest != NULL) {
656 memcpy(dest, data, resplen);
659 pos += resplen;
660 if (!readalldata) {
661 if (*sw == status(MFDES_ADDITIONAL_FRAME)) {
662 *recv_len = pos;
663 return PM3_SUCCESS;
665 return res;
668 while (*sw == status(MFDES_ADDITIONAL_FRAME)) {
669 apdu->INS = MFDES_ADDITIONAL_FRAME; //0xAF
670 apdu->Lc = 0;
671 apdu->P1 = 0;
672 apdu->P2 = 0;
674 res = DESFIRESendApdu(false, true, *apdu, data, sizeof(data), &resplen, sw);
675 if (res != PM3_SUCCESS) {
676 PrintAndLogEx(DEBUG, "%s", GetErrorString(res, sw));
677 DropFieldDesfire();
678 return res;
681 if (dest != NULL) {
682 if (splitbysize) {
683 memcpy(&dest[i * splitbysize], data, resplen);
684 i += 1;
685 } else {
686 memcpy(&dest[pos], data, resplen);
689 pos += resplen;
691 if (*sw != status(MFDES_ADDITIONAL_FRAME)) break;
694 *recv_len = (splitbysize) ? i : pos;
695 return PM3_SUCCESS;
698 static nxp_cardtype_t getCardType(uint8_t major, uint8_t minor) {
700 if (major == 0x00)
701 return DESFIRE_MF3ICD40;
702 if (major == 0x01 && minor == 0x00)
703 return DESFIRE_EV1;
704 if (major == 0x12 && minor == 0x00)
705 return DESFIRE_EV2;
706 if (major == 0x33 && minor == 0x00)
707 return DESFIRE_EV3;
708 if (major == 0x30 && minor == 0x00)
709 return DESFIRE_LIGHT;
710 if (major == 0x11 && minor == 0x00)
711 return PLUS_EV1;
712 if (major == 0x10 && minor == 0x00)
713 return NTAG413DNA;
714 return DESFIRE_UNKNOWN;
717 static int mfdes_get_info(mfdes_info_res_t *info) {
718 SendCommandNG(CMD_HF_DESFIRE_INFO, NULL, 0);
719 PacketResponseNG resp;
721 if (WaitForResponseTimeout(CMD_HF_DESFIRE_INFO, &resp, 1500) == false) {
722 PrintAndLogEx(WARNING, "Command execute timeout");
723 DropFieldDesfire();
724 return PM3_ETIMEOUT;
727 memcpy(info, resp.data.asBytes, sizeof(mfdes_info_res_t));
729 if (resp.status != PM3_SUCCESS) {
730 switch (info->isOK) {
731 case 1:
732 PrintAndLogEx(WARNING, "Can't select card");
733 break;
734 case 2:
735 PrintAndLogEx(WARNING, "Card is most likely not DESFire. Wrong size UID");
736 break;
737 case 3:
738 default:
739 PrintAndLogEx(WARNING, _RED_("Command unsuccessful"));
740 break;
742 return PM3_ESOFT;
745 return PM3_SUCCESS;
748 static int handler_desfire_auth(mfdes_authinput_t *payload, mfdes_auth_res_t *rpayload) {
749 // 3 different way to authenticate AUTH (CRC16) , AUTH_ISO (CRC32) , AUTH_AES (CRC32)
750 // 4 different crypto arg1 DES, 3DES, 3K3DES, AES
751 // 3 different communication modes, PLAIN,MAC,CRYPTO
752 tag->authenticated_key_no = NOT_YET_AUTHENTICATED;
753 tag->session_key = NULL;
755 mbedtls_aes_context ctx;
757 uint8_t keybytes[24];
758 // Crypt constants
759 uint8_t IV[16] = {0x00};
760 uint8_t RndA[16] = {0x00};
761 uint8_t RndB[16] = {0x00};
762 uint8_t encRndB[16] = {0x00};
763 uint8_t rotRndB[16] = {0x00}; //RndB'
764 uint8_t both[32 + 1] = {0x00}; // ek/dk_keyNo(RndA+RndB')
766 // Generate Random Value
767 uint32_t ng = msclock();
768 uint32_t value = prng_successor(ng, 32);
769 num_to_bytes(value, 4, &RndA[0]);
770 value = prng_successor(ng, 32);
771 num_to_bytes(value, 4, &RndA[4]);
772 value = prng_successor(ng, 32);
773 num_to_bytes(value, 4, &RndA[8]);
774 value = prng_successor(ng, 32);
775 num_to_bytes(value, 4, &RndA[12]);
777 // Part 1
778 memcpy(keybytes, payload->key, payload->keylen);
780 struct desfire_key dkey = {0};
781 desfirekey_t key = &dkey;
783 if (payload->algo == MFDES_ALGO_AES) {
784 mbedtls_aes_init(&ctx);
785 Desfire_aes_key_new(keybytes, key);
786 } else if (payload->algo == MFDES_ALGO_3DES) {
787 Desfire_3des_key_new_with_version(keybytes, key);
788 } else if (payload->algo == MFDES_ALGO_DES) {
789 Desfire_des_key_new(keybytes, key);
790 } else if (payload->algo == MFDES_ALGO_3K3DES) {
791 Desfire_3k3des_key_new_with_version(keybytes, key);
794 if (payload->kdfAlgo == MFDES_KDF_ALGO_AN10922) {
795 mifare_kdf_an10922(key, payload->kdfInput, payload->kdfInputLen);
796 PrintAndLogEx(DEBUG, " Derrived key: " _GREEN_("%s"), sprint_hex(key->data, key_block_size(key)));
797 } else if (payload->kdfAlgo == MFDES_KDF_ALGO_GALLAGHER) {
798 // We will overrite any provided KDF input since a gallagher specific KDF was requested.
799 payload->kdfInputLen = 11;
801 if (mfdes_kdf_input_gallagher(tag->info.uid, tag->info.uidlen, payload->keyno, tag->selected_application, payload->kdfInput, &payload->kdfInputLen) != PM3_SUCCESS) {
802 PrintAndLogEx(FAILED, "Could not generate Gallagher KDF input");
805 mifare_kdf_an10922(key, payload->kdfInput, payload->kdfInputLen);
806 PrintAndLogEx(DEBUG, " KDF Input: " _YELLOW_("%s"), sprint_hex(payload->kdfInput, payload->kdfInputLen));
807 PrintAndLogEx(DEBUG, " Derrived key: " _GREEN_("%s"), sprint_hex(key->data, key_block_size(key)));
811 uint8_t subcommand = MFDES_AUTHENTICATE;
812 tag->authentication_scheme = AS_LEGACY;
814 if (payload->mode == MFDES_AUTH_AES) {
815 subcommand = MFDES_AUTHENTICATE_AES;
816 tag->authentication_scheme = AS_NEW;
817 } else if (payload->mode == MFDES_AUTH_ISO) {
818 subcommand = MFDES_AUTHENTICATE_ISO;
819 tag->authentication_scheme = AS_NEW;
822 uint32_t recv_len = 0;
823 uint16_t sw = 0;
824 uint8_t recv_data[256] = {0};
826 if (payload->mode != MFDES_AUTH_PICC) {
827 // Let's send our auth command
828 uint8_t data[] = {payload->keyno};
829 sAPDU apdu = {0x90, subcommand, 0x00, 0x00, 0x01, data};
830 int res = send_desfire_cmd(&apdu, false, recv_data, &recv_len, &sw, 0, false);
831 if (res != PM3_SUCCESS) {
832 return 1;
835 // else {
837 cmd[0] = AUTHENTICATE;
838 cmd[1] = payload->keyno;
839 len = DesfireAPDU(cmd, 2, resp);
843 if (!recv_len) {
844 return 2;
847 if (sw != status(MFDES_ADDITIONAL_FRAME)) {
848 return 3;
851 uint32_t expectedlen = 8;
852 if (payload->algo == MFDES_ALGO_AES || payload->algo == MFDES_ALGO_3K3DES) {
853 expectedlen = 16;
856 if (recv_len != expectedlen) {
857 return 4;
859 uint32_t rndlen = recv_len;
861 // Part 2
862 if (payload->mode != MFDES_AUTH_PICC) {
863 memcpy(encRndB, recv_data, rndlen);
864 } else {
865 memcpy(encRndB, recv_data + 2, rndlen);
868 // Part 3
869 if (payload->algo == MFDES_ALGO_AES) {
870 if (mbedtls_aes_setkey_dec(&ctx, key->data, 128) != 0) {
871 return 5;
873 mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_DECRYPT, rndlen, IV, encRndB, RndB);
874 } else if (payload->algo == MFDES_ALGO_DES)
875 des_decrypt(RndB, encRndB, key->data);
876 else if (payload->algo == MFDES_ALGO_3DES)
877 tdes_nxp_receive(encRndB, RndB, rndlen, key->data, IV, 2);
878 else if (payload->algo == MFDES_ALGO_3K3DES) {
879 tdes_nxp_receive(encRndB, RndB, rndlen, key->data, IV, 3);
882 if (g_debugMode > 1) {
883 PrintAndLogEx(DEBUG, "encRndB: %s", sprint_hex(encRndB, 8));
884 PrintAndLogEx(DEBUG, "RndB: %s", sprint_hex(RndB, 8));
887 // - Rotate RndB by 8 bits
888 memcpy(rotRndB, RndB, rndlen);
889 rol(rotRndB, rndlen);
891 uint8_t encRndA[16] = {0x00};
893 // - Encrypt our response
894 if (payload->mode == MFDES_AUTH_DES || payload->mode == MFDES_AUTH_PICC) {
895 des_decrypt(encRndA, RndA, key->data);
896 memcpy(both, encRndA, rndlen);
898 for (uint32_t x = 0; x < rndlen; x++) {
899 rotRndB[x] = rotRndB[x] ^ encRndA[x];
902 des_decrypt(encRndB, rotRndB, key->data);
903 memcpy(both + rndlen, encRndB, rndlen);
904 } else if (payload->mode == MFDES_AUTH_ISO) {
905 if (payload->algo == MFDES_ALGO_3DES) {
906 uint8_t tmp[16] = {0x00};
907 memcpy(tmp, RndA, rndlen);
908 memcpy(tmp + rndlen, rotRndB, rndlen);
909 if (g_debugMode > 1) {
910 PrintAndLogEx(DEBUG, "rotRndB: %s", sprint_hex(rotRndB, rndlen));
911 PrintAndLogEx(DEBUG, "Both: %s", sprint_hex(tmp, 16));
913 tdes_nxp_send(tmp, both, 16, key->data, IV, 2);
914 if (g_debugMode > 1) {
915 PrintAndLogEx(DEBUG, "EncBoth: %s", sprint_hex(both, 16));
917 } else if (payload->algo == MFDES_ALGO_3K3DES) {
918 uint8_t tmp[32] = {0x00};
919 memcpy(tmp, RndA, rndlen);
920 memcpy(tmp + rndlen, rotRndB, rndlen);
921 if (g_debugMode > 1) {
922 PrintAndLogEx(DEBUG, "rotRndB: %s", sprint_hex(rotRndB, rndlen));
923 PrintAndLogEx(DEBUG, "Both3k3: %s", sprint_hex(tmp, 32));
925 tdes_nxp_send(tmp, both, 32, key->data, IV, 3);
926 if (g_debugMode > 1) {
927 PrintAndLogEx(DEBUG, "EncBoth: %s", sprint_hex(both, 32));
930 } else if (payload->mode == MFDES_AUTH_AES) {
931 uint8_t tmp[32] = {0x00};
932 memcpy(tmp, RndA, rndlen);
933 memcpy(tmp + rndlen, rotRndB, rndlen);
934 if (g_debugMode > 1) {
935 PrintAndLogEx(DEBUG, "rotRndB: %s", sprint_hex(rotRndB, rndlen));
936 PrintAndLogEx(DEBUG, "Both3k3: %s", sprint_hex(tmp, 32));
938 if (payload->algo == MFDES_ALGO_AES) {
939 if (mbedtls_aes_setkey_enc(&ctx, key->data, 128) != 0) {
940 return 6;
942 mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_ENCRYPT, 32, IV, tmp, both);
943 if (g_debugMode > 1) {
944 PrintAndLogEx(DEBUG, "EncBoth: %s", sprint_hex(both, 32));
949 uint32_t bothlen = 16;
950 if (payload->algo == MFDES_ALGO_AES || payload->algo == MFDES_ALGO_3K3DES) {
951 bothlen = 32;
953 if (payload->mode != MFDES_AUTH_PICC) {
954 sAPDU apdu = {0x90, MFDES_ADDITIONAL_FRAME, 0x00, 0x00, bothlen, both};
955 int res = send_desfire_cmd(&apdu, false, recv_data, &recv_len, &sw, 0, false);
956 if (res != PM3_SUCCESS) {
957 return 7;
959 } else {
960 /*cmd[0] = ADDITIONAL_FRAME;
961 memcpy(cmd + 1, both, 16);
962 len = DesfireAPDU(cmd, 1 + 16, resp);
964 if (res != PM3_SUCCESS) {
965 PrintAndLogEx(SUCCESS, "Sending auth command %02X " _RED_("failed"),subcommand);
966 return PM3_ESOFT;
970 if (!recv_len) {
971 return 8;
974 if (payload->mode != MFDES_AUTH_PICC) {
975 if (sw != status(MFDES_S_OPERATION_OK)) {
976 return 9;
978 } else {
979 /*if (resp[1] != 0x00) {
980 PrintAndLogEx(ERR,"Authentication failed. Card timeout.");
981 return PM3_ESOFT;
985 // Part 4
986 // tag->session_key = &default_key;
987 struct desfire_key *p = realloc (tag->session_key,sizeof(struct desfire_key));
988 if (!p) {
989 PrintAndLogEx(FAILED, "Cannot allocate memory for session keys");
990 free(tag->session_key);
991 return PM3_EMALLOC;
993 tag->session_key = p;
995 memset (tag->session_key, 0x00, sizeof(struct desfire_key));
997 Desfire_session_key_new(RndA, RndB, key, tag->session_key);
999 if (payload->mode != MFDES_AUTH_PICC) {
1000 memcpy(encRndA, recv_data, rndlen);
1001 } else {
1002 memcpy(encRndA, recv_data + 2, rndlen);
1005 if (payload->mode == MFDES_AUTH_DES || payload->mode == MFDES_AUTH_ISO || payload->mode == MFDES_AUTH_PICC) {
1006 if (payload->algo == MFDES_ALGO_DES)
1007 des_decrypt(encRndA, encRndA, key->data);
1008 else if (payload->algo == MFDES_ALGO_3DES)
1009 tdes_nxp_receive(encRndA, encRndA, rndlen, key->data, IV, 2);
1010 else if (payload->algo == MFDES_ALGO_3K3DES)
1011 tdes_nxp_receive(encRndA, encRndA, rndlen, key->data, IV, 3);
1012 } else if (payload->mode == MFDES_AUTH_AES) {
1013 if (mbedtls_aes_setkey_dec(&ctx, key->data, 128) != 0) {
1014 return 10;
1016 mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_DECRYPT, rndlen, IV, encRndA, encRndA);
1019 rol(RndA, rndlen);
1020 for (uint32_t x = 0; x < rndlen; x++) {
1021 if (RndA[x] != encRndA[x]) {
1022 if (g_debugMode > 1) {
1023 PrintAndLogEx(DEBUG, "Expected_RndA : %s", sprint_hex(RndA, rndlen));
1024 PrintAndLogEx(DEBUG, "Generated_RndA : %s", sprint_hex(encRndA, rndlen));
1026 return 11;
1030 // If the 3Des key first 8 bytes = 2nd 8 Bytes then we are really using Singe Des
1031 // As such we need to set the session key such that the 2nd 8 bytes = 1st 8 Bytes
1032 if (payload->algo == MFDES_ALGO_3DES) {
1033 if (memcmp(key->data,&key->data[8],8) == 0)
1034 memcpy(&tag->session_key->data[8], tag->session_key->data, 8);
1037 rpayload->sessionkeylen = payload->keylen;
1038 memcpy(rpayload->sessionkey, tag->session_key->data, rpayload->sessionkeylen);
1039 memset(tag->ivect, 0, MAX_CRYPTO_BLOCK_SIZE);
1040 tag->authenticated_key_no = payload->keyno;
1042 if (tag->authentication_scheme == AS_NEW) {
1043 cmac_generate_subkeys(tag->session_key, MCD_RECEIVE);
1045 return PM3_SUCCESS;
1048 static void AuthToError(int error) {
1049 switch (error) {
1050 case 1:
1051 PrintAndLogEx(SUCCESS, "Sending auth command failed");
1052 break;
1053 case 2:
1054 PrintAndLogEx(ERR, "Authentication failed. No data received");
1055 break;
1056 case 3:
1057 PrintAndLogEx(ERR, "Authentication failed. Invalid key number.");
1058 break;
1059 case 4:
1060 PrintAndLogEx(ERR, "Authentication failed. Length of answer doesn't match algo length");
1061 break;
1062 case 5:
1063 PrintAndLogEx(ERR, "mbedtls_aes_setkey_dec failed");
1064 break;
1065 case 6:
1066 PrintAndLogEx(ERR, "mbedtls_aes_setkey_enc failed");
1067 break;
1068 case 7:
1069 PrintAndLogEx(SUCCESS, "Sending auth command failed");
1070 break;
1071 case 8:
1072 PrintAndLogEx(ERR, "Authentication failed. Card timeout.");
1073 break;
1074 case 9:
1075 PrintAndLogEx(ERR, "Authentication failed.");
1076 break;
1077 case 10:
1078 PrintAndLogEx(ERR, "mbedtls_aes_setkey_dec failed");
1079 break;
1080 case 11:
1081 PrintAndLogEx(ERR, "Authentication failed. Cannot verify Session Key.");
1082 break;
1083 default:
1084 break;
1088 // -- test if card supports 0x0A
1089 static int test_desfire_authenticate(void) {
1090 uint8_t data[] = {0x00};
1091 sAPDU apdu = {0x90, MFDES_AUTHENTICATE, 0x00, 0x00, 0x01, data}; // 0x0A, KEY 0
1092 uint32_t recv_len = 0;
1093 uint16_t sw = 0;
1094 int res = send_desfire_cmd(&apdu, true, NULL, &recv_len, &sw, 0, false);
1095 if (res == PM3_SUCCESS)
1096 if (sw == status(MFDES_ADDITIONAL_FRAME)) {
1097 DropFieldDesfire();
1098 return res;
1100 return res;
1103 // -- test if card supports 0x1A
1104 static int test_desfire_authenticate_iso(void) {
1105 uint8_t data[] = {0x00};
1106 sAPDU apdu = {0x90, MFDES_AUTHENTICATE_ISO, 0x00, 0x00, 0x01, data}; // 0x1A, KEY 0
1107 uint32_t recv_len = 0;
1108 uint16_t sw = 0;
1109 int res = send_desfire_cmd(&apdu, true, NULL, &recv_len, &sw, 0, false);
1110 if (res == PM3_SUCCESS)
1111 if (sw == status(MFDES_ADDITIONAL_FRAME)) {
1112 DropFieldDesfire();
1113 return res;
1115 return res;
1118 // -- test if card supports 0xAA
1119 static int test_desfire_authenticate_aes(void) {
1120 uint8_t data[] = {0x00};
1121 sAPDU apdu = {0x90, MFDES_AUTHENTICATE_AES, 0x00, 0x00, 0x01, data}; // 0xAA, KEY 0
1122 uint32_t recv_len = 0;
1123 uint16_t sw = 0;
1124 int res = send_desfire_cmd(&apdu, true, NULL, &recv_len, &sw, 0, false);
1125 if (res == PM3_SUCCESS)
1126 if (sw == status(MFDES_ADDITIONAL_FRAME)) {
1127 DropFieldDesfire();
1128 return res;
1130 return res;
1133 // --- GET FREE MEM
1134 static int desfire_print_freemem(uint32_t free_mem) {
1135 PrintAndLogEx(SUCCESS, " Available free memory on card : " _GREEN_("%d bytes"), free_mem);
1136 return PM3_SUCCESS;
1139 static int handler_desfire_freemem(uint32_t *free_mem) {
1140 if (free_mem == NULL) return PM3_EINVARG;
1142 uint8_t data[] = {0x00};
1143 sAPDU apdu = {0x90, MFDES_GET_FREE_MEMORY, 0x00, 0x00, 0x00, data}; // 0x6E
1144 *free_mem = 0;
1145 uint32_t recv_len = 0;
1146 uint16_t sw = 0;
1147 uint8_t fmem[4] = {0};
1149 size_t plen = apdu.Lc;
1150 uint8_t *p = mifare_cryto_preprocess_data(tag, (uint8_t *)apdu.data, &plen, 0, MDCM_PLAIN | CMAC_COMMAND);
1151 apdu.Lc = (uint8_t)plen;
1152 apdu.data = p;
1154 int res = send_desfire_cmd(&apdu, true, fmem, &recv_len, &sw, 0, true);
1156 if (res != PM3_SUCCESS)
1157 return res;
1159 size_t dlen = recv_len;
1160 p = mifare_cryto_postprocess_data(tag, apdu.data, &dlen, MDCM_PLAIN | CMAC_COMMAND | CMAC_VERIFY);
1161 (void)p;
1162 if (sw != status(MFDES_S_OPERATION_OK))
1163 return PM3_ESOFT;
1165 *free_mem = le24toh(fmem);
1166 return res;
1169 static int mifare_desfire_change_key(uint8_t key_no, uint8_t *new_key, uint8_t new_algo, uint8_t *old_key, uint8_t old_algo, uint8_t aes_version) {
1171 if (new_key == NULL || old_key == NULL) {
1172 return PM3_EINVARG;
1175 // AID == 000000 6bits LSB needs to be 0
1176 key_no &= 0x0F;
1179 Desfire treats Des keys as TDes but with the first half = 2nd half
1180 As such, we should be able to convert the Des to TDes then run the code as TDes
1182 if (new_algo == MFDES_ALGO_DES) {
1183 memcpy(&new_key[8], new_key, 8);
1184 new_algo = MFDES_ALGO_3DES;
1187 if (old_algo == MFDES_ALGO_DES) {
1188 memcpy(&old_key[8], old_key, 8);
1189 old_algo = MFDES_ALGO_3DES;
1193 * Because new crypto methods can be setup only at application creation,
1194 * changing the card master key to one of them require a key_no tweak.
1196 if (0x000000 == tag->selected_application) {
1198 // PICC master key, 6bits LSB needs to be 0
1199 key_no = 0x00;
1201 // PICC master key, keyalgo specific 2bit MSB
1202 switch (new_algo) {
1203 case MFDES_ALGO_DES:
1204 case MFDES_ALGO_3DES:
1205 break; // 00xx xxx
1206 case MFDES_ALGO_3K3DES:
1207 key_no |= 0x40; // 01xx xxx
1208 break;
1209 case MFDES_ALGO_AES:
1210 key_no |= 0x80; // 10xx xxx
1211 break;
1215 keyno 1b
1216 key 8b
1217 cpy 8b
1218 crc 2b
1219 padding
1222 // Variable length ciphered key data 24-42 bytes plus padding..
1223 uint8_t data[64] = {key_no};
1224 sAPDU apdu = {0x90, MFDES_CHANGE_KEY, 0x00, 0x00, 0x01, data}; // 0xC4
1226 size_t cmdcnt = 0;
1227 uint8_t csPkt[100] = {0x00}; // temp storage for AES/3K3Des packet to calculate checksum (size ????)
1229 uint8_t new_key_length = 16;
1230 switch (new_algo) {
1232 // We have converted the DES to 3DES above,so this will never hit
1233 case MFDES_ALGO_DES:
1234 memcpy(data + cmdcnt + 1, new_key, new_key_length);
1235 memcpy(data + cmdcnt + 1 + new_key_length, new_key, new_key_length);
1236 break;
1238 case MFDES_ALGO_3DES:
1239 case MFDES_ALGO_AES:
1240 new_key_length = 16;
1241 memcpy(data + cmdcnt + 1, new_key, new_key_length);
1242 break;
1243 case MFDES_ALGO_3K3DES:
1244 new_key_length = 24;
1245 memcpy(data + cmdcnt + 1, new_key, new_key_length);
1246 break;
1249 if ((tag->authenticated_key_no & 0x0f) != (key_no & 0x0f)) {
1250 if (old_key) {
1251 for (uint32_t n = 0; n < new_key_length; n++) {
1252 data[cmdcnt + 1 + n] ^= old_key[n];
1257 cmdcnt += new_key_length;
1259 if (new_algo == MFDES_ALGO_AES) {
1260 data[cmdcnt + 1] = aes_version;
1261 cmdcnt += 1;
1264 if ((tag->authenticated_key_no & 0x0f) != (key_no & 0x0f)) {
1265 switch (tag->authentication_scheme) {
1266 case AS_LEGACY:
1267 iso14443a_crc_append(data + 1, cmdcnt);
1268 cmdcnt += 2;
1270 // iso14443a_crc(new_key, new_key_length, data + cmdcnt);
1271 // Add offset + 1 for key no. at start
1272 iso14443a_crc(new_key, new_key_length, data + 1 + cmdcnt);
1273 cmdcnt += 2;
1274 break;
1275 case AS_NEW:
1276 if (new_algo == MFDES_ALGO_AES) {
1277 // AES Checksum must cover : C4<KeyNo> <PrevKey XOR Newkey> <NewKeyVer>
1278 // C4 01 A0B08090E0F0C0D02030001060704050 03
1279 // 19 bytes
1280 //uint8_t csPkt[30] = {0x00};
1281 csPkt[0] = MFDES_CHANGE_KEY;
1282 memcpy(&csPkt[1], data, 18);
1284 desfire_crc32(csPkt, 19, data + 1 + cmdcnt);
1285 } else if (new_algo == MFDES_ALGO_3K3DES) {
1286 // 3K3Des checksum must cover : C4 <KeyNo> <PrevKey XOR NewKey>
1287 csPkt[0] = MFDES_CHANGE_KEY;
1288 memcpy (&csPkt[1], data, 25);
1289 desfire_crc32(csPkt, 26, data + 1 + cmdcnt);
1290 } else {
1291 desfire_crc32_append(data + 1, cmdcnt);
1293 cmdcnt += 4;
1295 desfire_crc32(new_key, new_key_length, data + 1 + cmdcnt);
1296 cmdcnt += 4;
1297 break;
1299 } else {
1300 switch (tag->authentication_scheme) {
1301 case AS_LEGACY:
1302 iso14443a_crc_append(data + 1, cmdcnt);
1303 cmdcnt += 2;
1304 break;
1305 case AS_NEW:
1306 if (new_algo == MFDES_ALGO_AES) {
1307 // AES Checksum must cover : C4<KeyNo> <Newkey data> <NewKeyVer>
1308 // C4 01 A0B08090E0F0C0D02030001060704050 03
1309 csPkt[0] = MFDES_CHANGE_KEY;
1310 memcpy(&csPkt[1], data, 18);
1311 desfire_crc32(csPkt, 19, data + 1 + cmdcnt);
1312 } else if (new_algo == MFDES_ALGO_3K3DES) {
1313 // 3K3Des checksum must cover : C4 <KeyNo> <Newkey Data>
1314 csPkt[0] = MFDES_CHANGE_KEY;
1315 memcpy (&csPkt[1], data, 25);
1316 desfire_crc32(csPkt, 26, data + 1 + cmdcnt);
1317 } else {
1318 desfire_crc32_append(data + 1, cmdcnt);
1320 cmdcnt += 4;
1321 // desfire_crc32_append(data, cmdcnt);
1322 // cmdcnt += 4;
1323 break;
1327 uint8_t *p = mifare_cryto_preprocess_data(tag, data + 1, (size_t *)&cmdcnt, 0, MDCM_ENCIPHERED | ENC_COMMAND | NO_CRC);
1328 apdu.Lc = (uint8_t)cmdcnt + 1;
1329 // apdu.data = p;
1330 // the above data pointed to from p did not have the key no. at the start, so copy preprocessed data after the key no.
1331 memcpy(&data[1], p, cmdcnt);
1332 apdu.data = data;
1334 uint32_t recv_len = 0;
1335 uint16_t sw = 0;
1337 // If we call send_desfire with 2nd option (turn field on), it will turn off then on
1338 // leading to loosing the authentication on the aid, so lets not turn on here.
1339 // int res = send_desfire_cmd(&apdu, true, NULL, &recv_len, &sw, 0, true);
1340 int res = send_desfire_cmd(&apdu, false, NULL, &recv_len, &sw, 0, true);
1342 if (res != PM3_SUCCESS) {
1343 PrintAndLogEx(WARNING, _RED_("can't change key -> %s"), GetErrorString(res, &sw));
1344 DropFieldDesfire();
1345 return res;
1348 size_t sn = recv_len;
1351 if ((new_algo == MFDES_ALGO_AES) || (new_algo == MFDES_ALGO_3K3DES))
1353 // AES expects us to Calculate CMAC for status byte : OK 0x00 (0x91 00)
1354 // As such if we get this far without an error, we should be good
1355 // Since we are dropping the field, we dont need to maintain the CMAC etc.
1356 // Setting sn = 1 will allow the post process to just exit (as status only)
1358 // Simular 3K3Des has some work to validate, but as long as the reply code was 00
1359 // e.g. 02 fe ec 77 ca 13 e0 c2 06 [91 00 (OK)] 69 67
1361 sn = 1;
1364 p = mifare_cryto_postprocess_data(tag, data, &sn, MDCM_PLAIN | CMAC_COMMAND | CMAC_VERIFY);
1366 // Should be finished processing the changekey so lets ensure the field is dropped.
1367 DropFieldDesfire();
1369 if (!p) {
1371 Note in my testing on an EV1, the AES password did change, with the number of returned bytes was 8, expected 9 <status><8 byte cmac>
1372 As such !p is true and the code reports "Error on changing key"; so comment back to user until its fixed.
1374 Note: as at 19 May 2021, with the sn = 1 patch above, this should no longer be reachable!
1376 if (new_algo == MFDES_ALGO_AES) {
1377 PrintAndLogEx(WARNING, "AES Key may have been changed, please check new password with the auth command.");
1380 return PM3_ESOFT;
1384 * If we changed the current authenticated key, we are not authenticated
1385 * anymore.
1387 if (key_no == tag->authenticated_key_no) {
1388 free(tag->session_key);
1389 tag->session_key = NULL;
1392 return PM3_SUCCESS;
1395 // --- GET SIGNATURE
1396 static int desfire_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signature, size_t signature_len, nxp_cardtype_t card_type) {
1397 (void)card_type;
1399 if (uid == NULL) {
1400 PrintAndLogEx(DEBUG, "UID=NULL");
1401 return PM3_EINVARG;
1403 if (signature == NULL) {
1404 PrintAndLogEx(DEBUG, "SIGNATURE=NULL");
1405 return PM3_EINVARG;
1407 // ref: MIFARE Desfire Originality Signature Validation
1408 // See tools/recover_pk.py to recover Pk from UIDs and signatures
1409 #define PUBLIC_DESFIRE_ECDA_KEYLEN 57
1410 const ecdsa_publickey_t nxp_desfire_public_keys[] = {
1411 {"NTAG424DNA, DESFire EV2", "048A9B380AF2EE1B98DC417FECC263F8449C7625CECE82D9B916C992DA209D68422B81EC20B65A66B5102A61596AF3379200599316A00A1410"},
1412 {"NTAG413DNA, DESFire EV1", "04BB5D514F7050025C7D0F397310360EEC91EAF792E96FC7E0F496CB4E669D414F877B7B27901FE67C2E3B33CD39D1C797715189AC951C2ADD"},
1413 {"DESFire EV2", "04B304DC4C615F5326FE9383DDEC9AA892DF3A57FA7FFB3276192BC0EAA252ED45A865E3B093A3D0DCE5BE29E92F1392CE7DE321E3E5C52B3A"},
1414 {"DESFire EV3", "041DB46C145D0A36539C6544BD6D9B0AA62FF91EC48CBC6ABAE36E0089A46F0D08C8A715EA40A63313B92E90DDC1730230E0458A33276FB743"},
1415 {"NTAG424DNA, NTAG424DNATT, DESFire Light EV2", "04B304DC4C615F5326FE9383DDEC9AA892DF3A57FA7FFB3276192BC0EAA252ED45A865E3B093A3D0DCE5BE29E92F1392CE7DE321E3E5C52B3B"},
1416 {"DESFire Light", "040E98E117AAA36457F43173DC920A8757267F44CE4EC5ADD3C54075571AEBBF7B942A9774A1D94AD02572427E5AE0A2DD36591B1FB34FCF3D"},
1417 {"MIFARE Plus EV1", "044409ADC42F91A8394066BA83D872FB1D16803734E911170412DDF8BAD1A4DADFD0416291AFE1C748253925DA39A5F39A1C557FFACD34C62E"},
1418 {"MIFARE Pluc Evx", "04BB49AE4447E6B1B6D21C098C1538B594A11A4A1DBF3D5E673DEACDEB3CC512D1C08AFA1A2768CE20A200BACD2DC7804CD7523A0131ABF607"},
1422 uint32_t i;
1423 bool is_valid = false;
1425 for (i = 0; i < ARRAYLEN(nxp_desfire_public_keys); i++) {
1427 int dl = 0;
1428 uint8_t key[PUBLIC_DESFIRE_ECDA_KEYLEN];
1429 param_gethex_to_eol(nxp_desfire_public_keys[i].value, 0, key, PUBLIC_DESFIRE_ECDA_KEYLEN, &dl);
1431 int res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP224R1, key, uid, uidlen, signature, signature_len, false);
1432 is_valid = (res == 0);
1433 if (is_valid)
1434 break;
1436 // PrintAndLogEx(NORMAL, "");
1437 // PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature"));
1438 if (is_valid == false || i == ARRAYLEN(nxp_desfire_public_keys)) {
1439 PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp224r1");
1440 PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, 16));
1441 PrintAndLogEx(INFO, " : %s", sprint_hex_inrow(signature + 16, 16));
1442 PrintAndLogEx(INFO, " : %s", sprint_hex_inrow(signature + 32, 16));
1443 PrintAndLogEx(INFO, " : %s", sprint_hex_inrow(signature + 48, signature_len - 48));
1444 PrintAndLogEx(SUCCESS, " Signature verification: " _RED_("failed"));
1445 return PM3_ESOFT;
1448 PrintAndLogEx(INFO, " IC signature public key name: " _GREEN_("%s"), nxp_desfire_public_keys[i].desc);
1449 PrintAndLogEx(INFO, "IC signature public key value: %.32s", nxp_desfire_public_keys[i].value);
1450 PrintAndLogEx(INFO, " : %.32s", nxp_desfire_public_keys[i].value + 32);
1451 PrintAndLogEx(INFO, " : %.32s", nxp_desfire_public_keys[i].value + 64);
1452 PrintAndLogEx(INFO, " : %.32s", nxp_desfire_public_keys[i].value + 96);
1453 PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp224r1");
1454 PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, 16));
1455 PrintAndLogEx(INFO, " : %s", sprint_hex_inrow(signature + 16, 16));
1456 PrintAndLogEx(INFO, " : %s", sprint_hex_inrow(signature + 32, 16));
1457 PrintAndLogEx(INFO, " : %s", sprint_hex_inrow(signature + 48, signature_len - 48));
1458 PrintAndLogEx(SUCCESS, " Signature verification: " _GREEN_("successful"));
1459 return PM3_SUCCESS;
1462 static int handler_desfire_signature(uint8_t *signature, size_t *signature_len) {
1464 if (signature == NULL) {
1465 PrintAndLogEx(DEBUG, "SIGNATURE=NULL");
1466 return PM3_EINVARG;
1468 if (signature_len == NULL) {
1469 PrintAndLogEx(DEBUG, "SIGNATURE_LEN=NULL");
1470 return PM3_EINVARG;
1473 uint8_t c[] = {0x00};
1474 sAPDU apdu = {0x90, MFDES_READSIG, 0x00, 0x00, sizeof(c), c}; // 0x3C
1476 uint32_t recv_len = 0;
1477 uint16_t sw = 0;
1478 int res = send_desfire_cmd(&apdu, true, signature, &recv_len, &sw, 0, true);
1479 if (res == PM3_SUCCESS) {
1480 if (recv_len != 56) {
1481 *signature_len = 0;
1482 res = PM3_ESOFT;
1483 } else {
1484 *signature_len = recv_len;
1487 DropFieldDesfire();
1488 return res;
1491 // --- KEY VERSION
1492 static int desfire_print_keyversion(uint8_t key_idx, uint8_t key_version) {
1493 PrintAndLogEx(SUCCESS, " Key [%u] Version : %d (0x%02x)", key_idx, key_version, key_version);
1494 return PM3_SUCCESS;
1497 static int handler_desfire_keyversion(uint8_t curr_key, uint8_t *num_versions) {
1498 if (num_versions == NULL) {
1499 PrintAndLogEx(DEBUG, "NUM_VERSIONS=NULL");
1500 return PM3_EINVARG;
1502 sAPDU apdu = {0x90, MFDES_GET_KEY_VERSION, 0x00, 0x00, 0x01, &curr_key}; //0x64
1503 uint32_t recv_len = 0;
1504 uint16_t sw = 0;
1505 int res = send_desfire_cmd(&apdu, false, num_versions, &recv_len, &sw, 0, true);
1507 if (res != PM3_SUCCESS)
1508 return res;
1510 if (sw != status(MFDES_S_OPERATION_OK))
1511 return PM3_ESOFT;
1513 return res;
1516 // --- KEY SETTING Application Master Key
1517 static int desfire_print_amk_keysetting(uint8_t key_settings, uint8_t num_keys, int algo) {
1518 PrintAndLogEx(SUCCESS, " AID Key settings : 0x%02x", key_settings);
1519 // 2 MSB denotes
1520 const char *str = " Max key number and type : %d, " _YELLOW_("%s");
1522 if (algo == MFDES_ALGO_DES)
1523 PrintAndLogEx(SUCCESS, str, num_keys & 0x3F, "(3)DES");
1524 else if (algo == MFDES_ALGO_AES)
1525 PrintAndLogEx(SUCCESS, str, num_keys & 0x3F, "AES");
1526 else if (algo == MFDES_ALGO_3K3DES)
1527 PrintAndLogEx(SUCCESS, str, num_keys & 0x3F, "3K3DES");
1529 //PrintAndLogEx(SUCCESS, " Max number of keys in AID : %d", num_keys & 0x3F);
1530 PrintAndLogEx(INFO, "-------------------------------------------------------------");
1531 PrintAndLogEx(SUCCESS, " Changekey Access rights");
1533 // Access rights.
1534 uint8_t rights = ((key_settings >> 4) & 0x0F);
1535 switch (rights) {
1536 case 0x0:
1537 PrintAndLogEx(SUCCESS, " -- AMK authentication is necessary to change any key (default)");
1538 break;
1539 case 0xE:
1540 PrintAndLogEx(SUCCESS, " -- Authentication with the key to be changed (same KeyNo) is necessary to change a key");
1541 break;
1542 case 0xF:
1543 PrintAndLogEx(SUCCESS, " -- All keys (except AMK,see Bit0) within this application are frozen");
1544 break;
1545 default:
1546 PrintAndLogEx(SUCCESS,
1547 " -- Authentication with the specified key is necessary to change any key.\n"
1548 "A change key and a PICC master key (CMK) can only be changed after authentication with the master key.\n"
1549 "For keys other then the master or change key, an authentication with the same key is needed."
1551 break;
1554 PrintAndLogEx(SUCCESS, " [%c...] AMK Configuration changeable : %s", (key_settings & (1 << 3)) ? '1' : '0', (key_settings & (1 << 3)) ? _GREEN_("YES") : "NO (frozen)");
1555 PrintAndLogEx(SUCCESS, " [.%c..] AMK required for create/delete : %s", (key_settings & (1 << 2)) ? '1' : '0', (key_settings & (1 << 2)) ? "NO" : "YES");
1556 PrintAndLogEx(SUCCESS, " [..%c.] Directory list access with AMK : %s", (key_settings & (1 << 1)) ? '1' : '0', (key_settings & (1 << 1)) ? "NO" : "YES");
1557 PrintAndLogEx(SUCCESS, " [...%c] AMK is changeable : %s", (key_settings & (1 << 0)) ? '1' : '0', (key_settings & (1 << 0)) ? _GREEN_("YES") : "NO (frozen)");
1558 return PM3_SUCCESS;
1561 // --- KEY SETTING PICC Master Key (CMK)
1562 static int desfire_print_piccmk_keysetting(uint8_t key_settings, uint8_t num_keys, int algo) {
1563 //PrintAndLogEx(INFO, "--- " _CYAN_("PICC Master Key (CMK) settings"));
1564 // number of Master keys (0x01)
1565 PrintAndLogEx(SUCCESS, " Number of Masterkeys : " _YELLOW_("%u"), (num_keys & 0x3F));
1566 const char *str = " Operation of PICC master key : " _YELLOW_("%s");
1568 if (algo == MFDES_ALGO_DES)
1569 PrintAndLogEx(SUCCESS, str, "(3)DES");
1570 else if (algo == MFDES_ALGO_AES)
1571 PrintAndLogEx(SUCCESS, str, "AES");
1572 else if (algo == MFDES_ALGO_3K3DES)
1573 PrintAndLogEx(SUCCESS, str, "3K3DES");
1575 uint8_t cmk_num_versions = 0;
1576 if (handler_desfire_keyversion(0, &cmk_num_versions) == PM3_SUCCESS) {
1577 PrintAndLogEx(SUCCESS, " PICC Master key Version : " _YELLOW_("%d (0x%02x)"), cmk_num_versions, cmk_num_versions);
1580 PrintAndLogEx(INFO, " ----------------------------------------------------------");
1582 // Authentication tests
1583 int res = test_desfire_authenticate();
1584 if (res == PM3_SUCCESS)
1585 PrintAndLogEx(SUCCESS, " [0x0A] Authenticate : %s", (res == PM3_SUCCESS) ? _YELLOW_("YES") : "NO");
1587 res = test_desfire_authenticate_iso();
1588 if (res == PM3_SUCCESS)
1589 PrintAndLogEx(SUCCESS, " [0x1A] Authenticate ISO : %s", (res == PM3_SUCCESS) ? _YELLOW_("YES") : "NO");
1591 res = test_desfire_authenticate_aes();
1592 if (res == PM3_SUCCESS)
1593 PrintAndLogEx(SUCCESS, " [0xAA] Authenticate AES : %s", (res == PM3_SUCCESS) ? _YELLOW_("YES") : "NO");
1595 PrintAndLogEx(INFO, "-------------------------------------------------------------");
1596 PrintAndLogEx(INFO, " Key setting: 0x%02X [%c%c%c%c]",
1597 key_settings,
1598 (key_settings & (1 << 3)) ? '1' : '0',
1599 (key_settings & (1 << 2)) ? '1' : '0',
1600 (key_settings & (1 << 1)) ? '1' : '0',
1601 (key_settings & (1 << 0)) ? '1' : '0'
1604 PrintAndLogEx(SUCCESS, " [%c...] CMK Configuration changeable : %s", (key_settings & (1 << 3)) ? '1' : '0', (key_settings & (1 << 3)) ? _GREEN_("YES") : "NO (frozen)");
1605 PrintAndLogEx(SUCCESS, " [.%c..] CMK required for create/delete : %s", (key_settings & (1 << 2)) ? '1' : '0', (key_settings & (1 << 2)) ? _GREEN_("NO") : "YES");
1606 PrintAndLogEx(SUCCESS, " [..%c.] Directory list access with CMK : %s", (key_settings & (1 << 1)) ? '1' : '0', (key_settings & (1 << 1)) ? _GREEN_("NO") : "YES");
1607 PrintAndLogEx(SUCCESS, " [...%c] CMK is changeable : %s", (key_settings & (1 << 0)) ? '1' : '0', (key_settings & (1 << 0)) ? _GREEN_("YES") : "NO (frozen)");
1608 return PM3_SUCCESS;
1611 static int handler_desfire_getkeysettings(uint8_t *key_settings, uint8_t *num_keys) {
1612 if (key_settings == NULL) {
1613 PrintAndLogEx(DEBUG, "KEY_SETTINGS=NULL");
1614 return PM3_EINVARG;
1616 if (num_keys == NULL) {
1617 PrintAndLogEx(DEBUG, "NUM_KEYS=NULL");
1618 return PM3_EINVARG;
1620 sAPDU apdu = {0x90, MFDES_GET_KEY_SETTINGS, 0x00, 0x00, 0x00, NULL}; //0x45
1622 uint32_t recv_len = 0;
1623 uint16_t sw = 0;
1624 uint8_t data[2] = {0};
1625 int res = send_desfire_cmd(&apdu, false, data, &recv_len, &sw, 0, true);
1627 if (res != PM3_SUCCESS)
1628 return res;
1629 if (sw != status(MFDES_S_OPERATION_OK))
1630 return PM3_ESOFT;
1632 *key_settings = data[0];
1633 *num_keys = data[1];
1634 return res;
1637 static int handler_desfire_getuid(uint8_t *uid) {
1638 if (uid == NULL) {
1639 PrintAndLogEx(DEBUG, "UID=NULL");
1640 return PM3_EINVARG;
1642 sAPDU apdu = {0x90, MFDES_GET_UID, 0x00, 0x00, 0x00, NULL}; //0x51
1643 uint32_t recv_len = 0;
1644 uint16_t sw = 0;
1646 // Setup the pre-process to update the IV etc. (not needed in the apdu to send to card)
1647 size_t plen = 1;
1648 uint8_t tmp_data[100] = { 0x00 }; // Note sure on size, but 100 is more then enough
1649 tmp_data[0] = MFDES_GET_UID;
1650 int8_t *p = mifare_cryto_preprocess_data(tag, tmp_data, &plen, 0, MDCM_PLAIN | CMAC_COMMAND);
1651 (void)p;
1653 // Send request/apdu
1654 int res = send_desfire_cmd(&apdu, false, uid, &recv_len, &sw, 0, true);
1656 if (res != PM3_SUCCESS)
1657 return res;
1659 if (sw != status(MFDES_S_OPERATION_OK))
1660 return PM3_ESOFT;
1662 // decrypt response
1663 size_t dlen = recv_len;
1664 p = mifare_cryto_postprocess_data(tag, uid, &dlen, CMAC_COMMAND | CMAC_VERIFY | MAC_VERIFY | MDCM_ENCIPHERED);
1665 (void)p;
1667 DropFieldDesfire();
1669 return res;
1672 static int handler_desfire_commit_transaction(void) {
1673 sAPDU apdu = {0x90, MFDES_COMMIT_TRANSACTION, 0x00, 0x00, 0x00, NULL}; //0xC7
1674 uint32_t recv_len = 0;
1675 uint16_t sw = 0;
1676 int res = send_desfire_cmd(&apdu, false, NULL, &recv_len, &sw, 0, true);
1678 if (res != PM3_SUCCESS)
1679 return res;
1681 if (sw != status(MFDES_S_OPERATION_OK))
1682 return PM3_ESOFT;
1684 return res;
1687 /*static int handler_desfire_abort_transaction(void) {
1688 sAPDU apdu = {0x90, MFDES_ABORT_TRANSACTION, 0x00, 0x00, 0x00, NULL}; //0xA7
1689 uint32_t recv_len = 0;
1690 uint16_t sw = 0;
1691 int res = send_desfire_cmd(&apdu, false, NULL, &recv_len, &sw, 0, true);
1693 if (res != PM3_SUCCESS)
1694 return res;
1696 if (sw != status(MFDES_S_OPERATION_OK))
1697 return PM3_ESOFT;
1699 return res;
1702 // --- GET APPIDS
1703 static int handler_desfire_appids(uint8_t *dest, uint32_t *app_ids_len) {
1704 if (dest == NULL) {
1705 PrintAndLogEx(DEBUG, "DEST=NULL");
1706 return PM3_EINVARG;
1708 if (app_ids_len == NULL) {
1709 PrintAndLogEx(DEBUG, "APP_IDS_LEN=NULL");
1710 return PM3_EINVARG;
1713 sAPDU apdu = {0x90, MFDES_GET_APPLICATION_IDS, 0x00, 0x00, 0x00, NULL}; //0x6a
1714 uint32_t recv_len = 0;
1715 uint16_t sw = 0;
1716 int res = send_desfire_cmd(&apdu, true, dest, &recv_len, &sw, 0, true);
1718 if (res != PM3_SUCCESS)
1719 return res;
1721 if (sw != status(MFDES_S_OPERATION_OK))
1722 return PM3_ESOFT;
1724 *app_ids_len = (uint8_t)(recv_len & 0xFF);
1725 return res;
1728 // --- GET DF NAMES
1729 static int handler_desfire_dfnames(dfname_t *dest, uint8_t *dfname_count) {
1731 if (g_debugMode > 1) {
1732 if (dest == NULL) PrintAndLogEx(ERR, "DEST = NULL");
1733 if (dfname_count == NULL) PrintAndLogEx(ERR, "DFNAME_COUNT = NULL");
1736 if (dest == NULL || dfname_count == NULL)
1737 return PM3_EINVARG;
1739 *dfname_count = 0;
1740 sAPDU apdu = {0x90, MFDES_GET_DF_NAMES, 0x00, 0x00, 0x00, NULL}; //0x6d
1741 uint32_t recv_len = 0;
1742 uint16_t sw = 0;
1743 int res = send_desfire_cmd(&apdu, true, (uint8_t *)dest, &recv_len, &sw, sizeof(dfname_t), true);
1744 if (res != PM3_SUCCESS) {
1745 return res;
1748 if (sw != status(MFDES_S_OPERATION_OK))
1749 return PM3_ESOFT;
1751 *dfname_count = recv_len;
1752 return res;
1755 static int handler_desfire_select_application(uint8_t *aid) {
1756 if (g_debugMode > 1) {
1757 if (aid == NULL) {
1758 PrintAndLogEx(ERR, "AID=NULL");
1761 if (aid == NULL) {
1762 return PM3_EINVARG;
1765 sAPDU apdu = {0x90, MFDES_SELECT_APPLICATION, 0x00, 0x00, 0x03, aid}; //0x5a
1766 uint32_t recv_len = 0;
1767 uint16_t sw = 0;
1769 int res = send_desfire_cmd(&apdu, !tag->rf_field_on, NULL, &recv_len, &sw, sizeof(dfname_t), true);
1770 if (res != PM3_SUCCESS) {
1771 PrintAndLogEx(WARNING,
1772 _RED_(" Can't select AID 0x%X -> %s"),
1773 (aid[2] << 16) + (aid[1] << 8) + aid[0],
1774 GetErrorString(res, &sw)
1776 DropFieldDesfire();
1777 return res;
1779 memcpy(&tag->selected_application, aid, 3);
1780 return PM3_SUCCESS;
1783 static int key_setting_to_algo(uint8_t aid[3], uint8_t *key_setting, mifare_des_authalgo_t *algo, uint8_t *num_keys) {
1784 int res = handler_desfire_select_application(aid);
1785 if (res != PM3_SUCCESS) return res;
1787 *num_keys = 0;
1788 res = handler_desfire_getkeysettings(key_setting, num_keys);
1789 if (res == PM3_SUCCESS) {
1790 switch (*num_keys >> 6) {
1791 case 0:
1792 *algo = MFDES_ALGO_DES;
1793 break;
1794 case 1:
1795 *algo = MFDES_ALGO_3K3DES;
1796 break;
1797 case 2:
1798 *algo = MFDES_ALGO_AES;
1799 break;
1802 return res;
1805 static int handler_desfire_fileids(uint8_t *dest, uint32_t *file_ids_len) {
1806 if (g_debugMode > 1) {
1807 if (dest == NULL) PrintAndLogEx(ERR, "DEST=NULL");
1808 if (file_ids_len == NULL) PrintAndLogEx(ERR, "FILE_IDS_LEN=NULL");
1810 if (dest == NULL || file_ids_len == NULL) return PM3_EINVARG;
1811 sAPDU apdu = {0x90, MFDES_GET_FILE_IDS, 0x00, 0x00, 0x00, NULL}; //0x6f
1812 uint32_t recv_len = 0;
1813 uint16_t sw = 0;
1814 *file_ids_len = 0;
1815 int res = send_desfire_cmd(&apdu, false, dest, &recv_len, &sw, 0, true);
1816 if (res != PM3_SUCCESS) {
1817 PrintAndLogEx(WARNING, _RED_(" Can't get file ids -> %s"), GetErrorString(res, &sw));
1818 DropFieldDesfire();
1819 return res;
1821 *file_ids_len = recv_len;
1822 return res;
1825 // none, verified
1826 static int handler_desfire_filesettings(uint8_t file_id, uint8_t *dest, uint32_t *destlen) {
1827 if (g_debugMode > 1) {
1828 if (dest == NULL) PrintAndLogEx(ERR, "DEST=NULL");
1829 if (destlen == NULL) PrintAndLogEx(ERR, "DESTLEN=NULL");
1831 if (dest == NULL || destlen == NULL) return PM3_EINVARG;
1832 sAPDU apdu = {0x90, MFDES_GET_FILE_SETTINGS, 0x00, 0x00, 0x01, &file_id}; // 0xF5
1833 uint16_t sw = 0;
1834 int res = send_desfire_cmd(&apdu, false, dest, destlen, &sw, 0, true);
1835 if (res != PM3_SUCCESS) {
1836 PrintAndLogEx(WARNING, _RED_(" Can't get file settings -> %s"), GetErrorString(res, &sw));
1837 DropFieldDesfire();
1838 return res;
1840 return res;
1843 static int handler_desfire_createapp(aidhdr_t *aidhdr, bool usename, bool usefid) {
1844 if (aidhdr == NULL) return PM3_EINVARG;
1846 sAPDU apdu = {0x90, MFDES_CREATE_APPLICATION, 0x00, 0x00, sizeof(aidhdr_t), (uint8_t *)aidhdr}; // 0xCA
1848 if (usename == false) {
1849 apdu.Lc = apdu.Lc - sizeof(aidhdr->name);
1851 if (usefid == false) {
1852 apdu.Lc = apdu.Lc - sizeof(aidhdr->fid);
1854 uint8_t *data = NULL;
1856 // skip over FID if not used.
1857 if (usefid == false && usename) {
1858 data = calloc(apdu.Lc, sizeof(uint8_t));
1859 apdu.data = data;
1861 memcpy(data, aidhdr->aid, sizeof(aidhdr->aid));
1862 data[3] = aidhdr->keysetting1;
1863 data[4] = aidhdr->keysetting2;
1864 memcpy(data + 5, aidhdr->name, sizeof(aidhdr->name));
1866 PrintAndLogEx(INFO, "new data: %s", sprint_hex_inrow(data, apdu.Lc));
1869 uint16_t sw = 0;
1870 uint32_t recvlen = 0;
1871 int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true);
1872 if (data != NULL) {
1873 free(data);
1875 if (res != PM3_SUCCESS) {
1876 PrintAndLogEx(WARNING, _RED_(" Can't create aid -> %s"), GetErrorString(res, &sw));
1877 DropFieldDesfire();
1879 return res;
1882 static int handler_desfire_deleteapp(const uint8_t *aid) {
1883 if (aid == NULL) {
1884 return PM3_EINVARG;
1886 sAPDU apdu = {0x90, MFDES_DELETE_APPLICATION, 0x00, 0x00, 3, (uint8_t *)aid}; // 0xDA
1887 uint16_t sw = 0;
1888 uint32_t recvlen = 0;
1889 int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true);
1890 if (res != PM3_SUCCESS) {
1891 PrintAndLogEx(WARNING, _RED_(" Can't delete aid -> %s"), GetErrorString(res, &sw));
1892 DropFieldDesfire();
1894 return res;
1897 static int handler_desfire_credit(mfdes_value_t *value, uint8_t cs) {
1898 sAPDU apdu = {0x90, MFDES_CREDIT, 0x00, 0x00, 1 + 4, (uint8_t *)value}; // 0x0C
1899 uint16_t sw = 0;
1900 uint32_t recvlen = 0;
1902 size_t plen = apdu.Lc;
1903 uint8_t *p = mifare_cryto_preprocess_data(tag, (uint8_t *)apdu.data, &plen, 0, cs | MAC_COMMAND | CMAC_COMMAND | ENC_COMMAND);
1904 apdu.Lc = (uint8_t)plen;
1905 apdu.data = p;
1907 int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true);
1908 if (res != PM3_SUCCESS) {
1909 PrintAndLogEx(WARNING, _RED_(" Can't credit value -> %s"), GetErrorString(res, &sw));
1910 DropFieldDesfire();
1911 return res;
1913 return res;
1916 static int handler_desfire_limitedcredit(mfdes_value_t *value, uint8_t cs) {
1917 sAPDU apdu = {0x90, MFDES_LIMITED_CREDIT, 0x00, 0x00, 1 + 4, (uint8_t *)value}; // 0x1C
1918 uint16_t sw = 0;
1919 uint32_t recvlen = 0;
1921 size_t plen = apdu.Lc;
1922 uint8_t *p = mifare_cryto_preprocess_data(tag, (uint8_t *)apdu.data, &plen, 0, cs | MAC_COMMAND | CMAC_COMMAND | ENC_COMMAND);
1923 apdu.Lc = (uint8_t)plen;
1924 apdu.data = p;
1926 int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true);
1927 if (res != PM3_SUCCESS) {
1928 PrintAndLogEx(WARNING, _RED_(" Can't credit limited value -> %s"), GetErrorString(res, &sw));
1929 DropFieldDesfire();
1930 return res;
1932 return res;
1935 static int handler_desfire_debit(mfdes_value_t *value, uint8_t cs) {
1936 sAPDU apdu = {0x90, MFDES_DEBIT, 0x00, 0x00, 1 + 4, (uint8_t *)value}; // 0xDC
1937 uint16_t sw = 0;
1938 uint32_t recvlen = 0;
1940 size_t plen = apdu.Lc;
1941 uint8_t *p = mifare_cryto_preprocess_data(tag, (uint8_t *)apdu.data, &plen, 0, cs | MAC_COMMAND | CMAC_COMMAND | ENC_COMMAND);
1942 apdu.Lc = (uint8_t)plen;
1943 apdu.data = p;
1945 int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true);
1946 if (res != PM3_SUCCESS) {
1947 PrintAndLogEx(WARNING, _RED_(" Can't debit value -> %s"), GetErrorString(res, &sw));
1948 DropFieldDesfire();
1949 return res;
1951 return res;
1954 static int handler_desfire_readdata(mfdes_data_t *data, MFDES_FILE_TYPE_T type, uint8_t cs) {
1955 if (data->fileno > 0x1F) {
1956 return PM3_EINVARG;
1959 sAPDU apdu = {0x90, MFDES_READ_DATA, 0x00, 0x00, 1 + 3 + 3, (uint8_t *)data}; // 0xBD
1960 if (type == MFDES_RECORD_FILE) {
1961 apdu.INS = MFDES_READ_RECORDS; //0xBB
1964 // we need the CMD 0xBD <data> to calc the CMAC
1965 uint8_t tmp_data[8]; // Since the APDU is hardcoded to 7 bytes of payload 7+1 = 8 is enough.
1966 tmp_data[0] = apdu.INS;
1967 memcpy(&tmp_data[1], data, 7);
1969 // size_t plen = apdu.Lc;
1970 // uint8_t *p = mifare_cryto_preprocess_data(tag, (uint8_t *)data, &plen, 0, MDCM_PLAIN | CMAC_COMMAND);
1971 // apdu.Lc = (uint8_t)plen;
1972 // apdu.data = p;
1974 size_t plen = 8;
1975 uint8_t *p = mifare_cryto_preprocess_data(tag, tmp_data, &plen, 0, MDCM_PLAIN | CMAC_COMMAND);
1976 (void)p;
1977 // apdu data does not need the cmd, so use the original read command data.
1978 apdu.Lc = 7;
1979 apdu.data = (uint8_t *)data;
1981 uint16_t sw = 0;
1982 uint32_t resplen = 0;
1983 int res = send_desfire_cmd(&apdu, false, data->data, &resplen, &sw, 0, true);
1984 if (res != PM3_SUCCESS) {
1985 PrintAndLogEx(WARNING, _RED_(" Can't read data -> %s"), GetErrorString(res, &sw));
1986 DropFieldDesfire();
1987 return res;
1990 size_t dlen = resplen;
1991 p = mifare_cryto_postprocess_data(tag, data->data, &dlen, cs | CMAC_COMMAND | CMAC_VERIFY | MAC_VERIFY);
1992 (void)p;
1994 if (dlen != -1)
1995 resplen = dlen;
1997 memcpy(data->length, &resplen, 3);
1998 return res;
2001 static int handler_desfire_getvalue(mfdes_value_t *value, uint32_t *resplen, uint8_t cs) {
2003 if (value->fileno > 0x1F)
2004 return PM3_EINVARG;
2006 sAPDU apdu = {0x90, MFDES_GET_VALUE, 0x00, 0x00, 0x01, &value->fileno}; // 0xBD
2007 uint16_t sw = 0;
2008 *resplen = 0;
2010 size_t plen = apdu.Lc;
2011 uint8_t *p = mifare_cryto_preprocess_data(tag, (uint8_t *)apdu.data, &plen, 0, MDCM_PLAIN | CMAC_COMMAND);
2012 apdu.Lc = (uint8_t)plen;
2013 apdu.data = p;
2015 int res = send_desfire_cmd(&apdu, false, value->value, resplen, &sw, 0, true);
2016 if (res != PM3_SUCCESS) {
2017 PrintAndLogEx(WARNING, _RED_(" Can't read data -> %s"), GetErrorString(res, &sw));
2018 DropFieldDesfire();
2019 return res;
2021 size_t dlen = (size_t) * resplen;
2022 p = mifare_cryto_postprocess_data(tag, value->value, &dlen, cs | CMAC_COMMAND | CMAC_VERIFY | MAC_VERIFY);
2023 (void)p;
2024 return res;
2027 static int handler_desfire_writedata(mfdes_data_t *data, MFDES_FILE_TYPE_T type, uint8_t cs) {
2028 /* LC FN OF OF OF LN LN LN DD DD DD
2029 90 3d 00 00 16 01 00 00 00 0f 00 00 00 0f 20 00 3b 00 34 04 06 e1 04 0f fe 00 00 00
2030 90 3d 00 00 09 02 00 00 00 02 00 00 00 00 00
2033 if (data->fileno > 0x1F) {
2034 return PM3_EINVARG;
2037 uint32_t datatowrite = le24toh(data->length);
2038 uint32_t offset = le24toh(data->offset);
2039 uint32_t datasize, recvlen = 0;
2040 int res = PM3_SUCCESS;
2041 uint16_t sw = 0;
2043 mfdes_data_t sdata;
2044 sAPDU apdu = {0x90, MFDES_WRITE_DATA, 0x00, 0x00, 0, (uint8_t *) &sdata}; // 0x3D
2046 uint8_t tmp[61] = {0};
2047 tmp[0] = MFDES_WRITE_DATA;
2048 tmp[1] = data->fileno;
2049 apdu.data = &tmp[1]; // tmp[0] is holding the OPCODE for macd calc, so we dont want it in the apdu
2051 if (type == MFDES_RECORD_FILE) {
2052 apdu.INS = MFDES_WRITE_RECORD;
2055 while (datatowrite) {
2057 if (datatowrite > 52)
2058 datasize = 52;
2059 else
2060 datasize = datatowrite;
2062 // Build packet to pre-process (using CMD FN OFFSET LEN DATA)
2063 tmp[2] = offset & 0xFF;
2064 tmp[3] = (offset >> 8) & 0xFF;
2065 tmp[4] = (offset >> 16) & 0xFF;
2066 tmp[5] = datasize & 0xFF;
2067 tmp[6] = (datasize >> 8) & 0xFF;
2068 tmp[7] = (datasize >> 16) & 0xFF;
2069 memcpy(&tmp[8], (uint8_t *)&data->data[offset], datasize);
2071 size_t plen = datasize + 8;
2072 uint8_t *p = mifare_cryto_preprocess_data(tag, tmp, &plen, 8, cs | MAC_COMMAND | CMAC_COMMAND | ENC_COMMAND);
2074 // Copy actual data as needed to create APDU Format
2075 if (plen != -1) {
2076 memcpy(&tmp[8], &p[8], plen - 8);
2077 // need to drop the OpCode from plen
2078 apdu.Lc = plen - 1;
2082 // we dont want to change the value of datasize, so delt with above without change
2083 // Doing so can create wrong offsets and endless loop.
2084 if (plen != -1) datasize = (uint8_t)plen;
2085 memcpy(&tmp[7], p, datasize);
2087 apdu.Lc = datasize + 1 + 3 + 3;
2090 res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true);
2091 if (res != PM3_SUCCESS) {
2092 PrintAndLogEx(WARNING, _RED_(" Can't write data -> %s"), GetErrorString(res, &sw));
2093 DropFieldDesfire();
2094 return res;
2096 offset += datasize;
2097 datatowrite -= datasize;
2099 if (type == MFDES_RECORD_FILE) {
2100 if (handler_desfire_commit_transaction() != PM3_SUCCESS) {
2101 PrintAndLogEx(WARNING, _RED_(" Can't commit transaction -> %s"), GetErrorString(res, &sw));
2102 DropFieldDesfire();
2103 return res;
2106 return res;
2109 static int handler_desfire_deletefile(uint8_t file_no) {
2110 if (file_no > 0x1F)
2111 return PM3_EINVARG;
2113 sAPDU apdu = {0x90, MFDES_DELETE_FILE, 0x00, 0x00, 1, &file_no}; // 0xDF
2114 uint16_t sw = 0;
2115 uint32_t recvlen = 0;
2116 int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true);
2117 if (res != PM3_SUCCESS) {
2118 PrintAndLogEx(WARNING, _RED_(" Can't delete file -> %s"), GetErrorString(res, &sw));
2119 DropFieldDesfire();
2120 return res;
2122 return res;
2125 static int handler_desfire_clear_record_file(uint8_t file_no) {
2126 if (file_no > 0x1F)
2127 return PM3_EINVARG;
2129 sAPDU apdu = {0x90, MFDES_CLEAR_RECORD_FILE, 0x00, 0x00, 1, &file_no}; // 0xEB
2130 uint16_t sw = 0;
2131 uint32_t recvlen = 0;
2132 int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true);
2133 if (res != PM3_SUCCESS) {
2134 PrintAndLogEx(WARNING, _RED_(" Can't clear record file -> %s"), GetErrorString(res, &sw));
2135 DropFieldDesfire();
2136 return res;
2137 } else {
2138 res = handler_desfire_commit_transaction();
2139 if (res != PM3_SUCCESS) {
2140 PrintAndLogEx(WARNING, _RED_(" Can't commit transaction -> %s"), GetErrorString(res, &sw));
2141 DropFieldDesfire();
2142 return res;
2145 return res;
2148 static int handler_desfire_create_value_file(mfdes_value_file_t *value) {
2149 if (value->fileno > 0x1F) return PM3_EINVARG;
2151 sAPDU apdu = {0x90, MFDES_CREATE_VALUE_FILE, 0x00, 0x00, sizeof(mfdes_value_file_t), (uint8_t *)value}; // 0xCc
2153 uint16_t sw = 0;
2154 uint32_t recvlen = 0;
2155 int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true);
2156 if (res != PM3_SUCCESS) {
2157 PrintAndLogEx(WARNING, _RED_(" Can't create value -> %s"), GetErrorString(res, &sw));
2158 DropFieldDesfire();
2159 return res;
2161 return res;
2164 static int handler_desfire_create_std_file(mfdes_file_t *file) {
2165 if (file->fileno > 0x1F)
2166 return PM3_EINVARG;
2168 sAPDU apdu = {0x90, MFDES_CREATE_STD_DATA_FILE, 0x00, 0x00, sizeof(mfdes_file_t), (uint8_t *)file}; // 0xCD
2170 uint16_t sw = 0;
2171 uint32_t recvlen = 0;
2172 int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true);
2173 if (res != PM3_SUCCESS) {
2174 PrintAndLogEx(WARNING, _RED_(" Can't create file -> %s"), GetErrorString(res, &sw));
2175 DropFieldDesfire();
2176 return res;
2178 return res;
2181 static int handler_desfire_create_linearrecordfile(mfdes_linear_t *file) {
2182 if (file->fileno > 0x1F)
2183 return PM3_EINVARG;
2185 if (memcmp(file->recordsize, "\x00\x00\x00", 3) == 0) return PM3_EINVARG;
2186 sAPDU apdu = {0x90, MFDES_CREATE_LINEAR_RECORD_FILE, 0x00, 0x00, sizeof(mfdes_linear_t), (uint8_t *)file}; // 0xC1
2188 uint16_t sw = 0;
2189 uint32_t recvlen = 0;
2190 int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true);
2191 if (res != PM3_SUCCESS) {
2192 PrintAndLogEx(WARNING, _RED_(" Can't create linear record file -> %s"), GetErrorString(res, &sw));
2193 DropFieldDesfire();
2194 return res;
2196 return res;
2199 static int handler_desfire_create_cyclicrecordfile(mfdes_linear_t *file) {
2200 if (memcmp(file->recordsize, "\x00\x00\x00", 3) == 0)
2201 return PM3_EINVARG;
2203 if (file->fileno > 0x1F)
2204 return PM3_EINVARG;
2206 sAPDU apdu = {0x90, MFDES_CREATE_CYCLIC_RECORD_FILE, 0x00, 0x00, sizeof(mfdes_linear_t), (uint8_t *)file}; // 0xC0
2208 uint16_t sw = 0;
2209 uint32_t recvlen = 0;
2210 int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true);
2211 if (res != PM3_SUCCESS) {
2212 PrintAndLogEx(WARNING, _RED_(" Can't create cyclic record file -> %s"), GetErrorString(res, &sw));
2213 DropFieldDesfire();
2214 return res;
2216 return res;
2219 static int handler_desfire_create_backup_file(mfdes_file_t *file) {
2220 if (file->fileno > 0x1F) return PM3_EINVARG;
2222 sAPDU apdu = {0x90, MFDES_CREATE_BACKUP_DATA_FILE, 0x00, 0x00, sizeof(mfdes_file_t), (uint8_t *)file}; // 0xCB
2224 uint16_t sw = 0;
2225 uint32_t recvlen = 0;
2226 int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true);
2227 if (res != PM3_SUCCESS) {
2228 PrintAndLogEx(WARNING, _RED_(" Can't create backup file -> %s"), GetErrorString(res, &sw));
2229 DropFieldDesfire();
2230 return res;
2232 return res;
2235 static int getKeySettings(uint8_t *aid) {
2236 if (aid == NULL) return PM3_EINVARG;
2238 uint8_t num_keys = 0;
2239 uint8_t key_setting = 0;
2240 int res = 0;
2241 if (memcmp(aid, "\x00\x00\x00", 3) == 0) {
2243 // CARD MASTER KEY
2244 //PrintAndLogEx(INFO, "--- " _CYAN_("CMK - PICC, Card Master Key settings"));
2246 // KEY Settings - AMK
2247 mifare_des_authalgo_t algo = MFDES_ALGO_DES;
2248 res = key_setting_to_algo(aid, &key_setting, &algo, &num_keys);
2250 if (res == PM3_SUCCESS) {
2251 desfire_print_piccmk_keysetting(key_setting, num_keys, algo);
2252 } else {
2253 PrintAndLogEx(WARNING, _RED_(" Can't read PICC Master key settings"));
2256 } else {
2258 // AID - APPLICATION MASTER KEYS
2259 //PrintAndLogEx(SUCCESS, "--- " _CYAN_("AMK - Application Master Key settings"));
2260 res = handler_desfire_select_application(aid);
2261 if (res != PM3_SUCCESS) return res;
2263 // KEY Settings - AMK
2264 mifare_des_authalgo_t algo = MFDES_ALGO_DES;
2265 res = key_setting_to_algo(aid, &key_setting, &algo, &num_keys);
2266 if (res == PM3_SUCCESS) {
2267 desfire_print_amk_keysetting(key_setting, num_keys, algo);
2268 } else {
2269 PrintAndLogEx(WARNING, _RED_(" Can't read Application Master key settings"));
2272 // KEY VERSION - AMK
2273 uint8_t num_version = 0;
2274 if (handler_desfire_keyversion(0, &num_version) == PM3_SUCCESS) {
2275 PrintAndLogEx(INFO, "-------------------------------------------------------------");
2276 PrintAndLogEx(INFO, " Application keys");
2277 desfire_print_keyversion(0, num_version);
2278 } else {
2279 PrintAndLogEx(WARNING, " Can't read AID master key version. Trying all keys");
2282 // From 0x01 to numOfKeys. We already got 0x00. (AMK)
2283 num_keys &= 0x3F;
2284 if (num_keys > 1) {
2285 for (uint8_t i = 0x01; i < num_keys; ++i) {
2286 if (handler_desfire_keyversion(i, &num_version) == PM3_SUCCESS) {
2287 desfire_print_keyversion(i, num_version);
2288 } else {
2289 PrintAndLogEx(WARNING, " Can't read key %d (0x%02x) version", i, i);
2295 DropFieldDesfire();
2296 return PM3_SUCCESS;
2299 static void swap32(uint8_t *data) {
2300 if (data == NULL) return;
2301 uint8_t tmp = data[0];
2302 data[0] = data[3];
2303 data[3] = tmp;
2304 tmp = data[2];
2305 data[2] = data[1];
2306 data[1] = tmp;
2309 static void swap24(uint8_t *data) {
2310 if (data == NULL) return;
2311 uint8_t tmp = data[0];
2312 data[0] = data[2];
2313 data[2] = tmp;
2316 static void swap16(uint8_t *data) {
2317 if (data == NULL) return;
2318 uint8_t tmp = data[0];
2319 data[0] = data[1];
2320 data[1] = tmp;
2323 static int desfire_authenticate(int cmdAuthMode, int cmdAuthAlgo, uint8_t *aid, uint8_t *key, int cmdKeyNo, uint8_t cmdKdfAlgo, uint8_t kdfInputLen, uint8_t *kdfInput, mfdes_auth_res_t *rpayload) {
2324 switch (cmdAuthMode) {
2325 case MFDES_AUTH_DES:
2326 if (cmdAuthAlgo != MFDES_ALGO_DES && cmdAuthAlgo != MFDES_ALGO_3DES) {
2327 PrintAndLogEx(NORMAL, "Crypto algo not valid for the auth des mode");
2328 return PM3_EINVARG;
2330 break;
2331 case MFDES_AUTH_ISO:
2332 if (cmdAuthAlgo != MFDES_ALGO_3DES && cmdAuthAlgo != MFDES_ALGO_3K3DES) {
2333 PrintAndLogEx(NORMAL, "Crypto algo not valid for the auth iso mode");
2334 return PM3_EINVARG;
2336 break;
2337 case MFDES_AUTH_AES:
2338 if (cmdAuthAlgo != MFDES_ALGO_AES) {
2339 PrintAndLogEx(NORMAL, "Crypto algo not valid for the auth aes mode");
2340 return PM3_EINVARG;
2342 break;
2343 case MFDES_AUTH_PICC:
2344 if (cmdAuthAlgo != MFDES_AUTH_DES) {
2345 PrintAndLogEx(NORMAL, "Crypto algo not valid for the auth picc mode");
2346 return PM3_EINVARG;
2348 break;
2349 default:
2350 PrintAndLogEx(WARNING, "Wrong Auth mode (%d) -> (1=normal, 2=iso, 3=aes)", cmdAuthMode);
2351 return PM3_EINVARG;
2354 int keylength = 16;
2356 switch (cmdAuthAlgo) {
2357 case MFDES_ALGO_3DES:
2358 keylength = 16;
2359 break;
2360 case MFDES_ALGO_3K3DES:
2361 keylength = 24;
2362 break;
2363 case MFDES_ALGO_AES:
2364 keylength = 16;
2365 break;
2366 default:
2367 cmdAuthAlgo = MFDES_ALGO_DES;
2368 keylength = 8;
2369 break;
2372 switch (cmdKdfAlgo) {
2373 case MFDES_KDF_ALGO_AN10922:
2374 // TODO: 2TDEA and 3TDEA keys use an input length of 1-15 bytes
2375 if (cmdAuthAlgo != MFDES_ALGO_AES) {
2376 PrintAndLogEx(FAILED, "Crypto algo not valid for the KDF AN10922 algo.");
2377 return PM3_EINVARG;
2379 if (kdfInputLen < 1 || kdfInputLen > 31) {
2380 PrintAndLogEx(FAILED, "KDF AN10922 algo requires an input of length 1-31 bytes.");
2381 return PM3_EINVARG;
2383 break;
2384 case MFDES_KDF_ALGO_GALLAGHER:
2385 // TODO: 2TDEA and 3TDEA keys use an input length of 1-15 bytes
2386 if (cmdAuthAlgo != MFDES_ALGO_AES) {
2387 PrintAndLogEx(FAILED, "Crypto algo not valid for the KDF AN10922 algo.");
2388 return PM3_EINVARG;
2390 break;
2391 // KDF input arg is ignored as it'll be generated.
2392 case MFDES_KDF_ALGO_NONE:
2393 break;
2394 default:
2395 PrintAndLogEx(WARNING, "KDF algo %d is not supported.", cmdKdfAlgo);
2396 return PM3_EINVARG;
2399 // KEY
2400 int res = handler_desfire_select_application(aid);
2401 if (res != PM3_SUCCESS) return res;
2403 if (memcmp(aid, "\x00\x00\x00", 3) != 0) {
2404 uint8_t file_ids[33] = {0};
2405 uint32_t file_ids_len = 0;
2406 res = handler_desfire_fileids(file_ids, &file_ids_len);
2407 if (res != PM3_SUCCESS) return res;
2410 mfdes_authinput_t payload;
2411 payload.keylen = keylength;
2412 memcpy(payload.key, key, keylength);
2413 payload.mode = cmdAuthMode;
2414 payload.algo = cmdAuthAlgo;
2415 payload.keyno = cmdKeyNo;
2416 payload.kdfAlgo = cmdKdfAlgo;
2417 payload.kdfInputLen = kdfInputLen;
2418 memcpy(payload.kdfInput, kdfInput, kdfInputLen);
2420 int error = handler_desfire_auth(&payload, rpayload);
2421 if (error == PM3_SUCCESS) {
2422 memcpy(&currentauth[payload.keyno], &payload, sizeof(mfdes_authinput_t));
2425 return error;
2428 static int CmdHF14ADesGetUID(const char *Cmd) {
2429 CLIParserContext *ctx;
2430 CLIParserInit(&ctx, "hf mfdes getuid",
2431 "Get UID from a MIFARE DESfire tag",
2432 "hf mfdes getuid");
2434 void *argtable[] = {
2435 arg_param_begin,
2436 arg_param_end
2438 CLIExecWithReturn(ctx, Cmd, argtable, true);
2439 CLIParserFree(ctx);
2441 uint8_t uid[16] = {0};
2442 int res = handler_desfire_getuid(uid);
2443 if (res != PM3_SUCCESS) {
2444 DropFieldDesfire();
2445 PrintAndLogEx(ERR, "Error on getting uid.");
2446 return res;
2449 // This could be done better. by the crc calc checks.
2450 // Extract the Card UID length (needs rework to allow for 10 Byte UID
2451 uint8_t uidlen = 16;
2453 // Get datalen <uid len> + <crclen> by removing padding.
2454 while ((uidlen > 0) && (uid[uidlen - 1] == 0x00))
2455 uidlen--;
2457 if (tag->authentication_scheme == AS_LEGACY)
2458 uidlen -= 2; // 2 byte crc
2459 else
2460 uidlen -= 4; // 4 byte crc
2462 if (uidlen <= 4) // < incase we trimmed a CRC 00 or more
2463 uidlen = 4;
2464 else
2465 uidlen = 7;
2467 PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(uid, uidlen));
2468 return res;
2471 static int CmdHF14ADesSelectApp(const char *Cmd) {
2472 CLIParserContext *ctx;
2473 CLIParserInit(&ctx, "hf mfdes selectaid",
2474 "Select Application ID",
2475 "hf mfdes selectaid -a 123456"
2478 void *argtable[] = {
2479 arg_param_begin,
2480 arg_strx0("a", "aid", "<hex>", "App ID to select as hex bytes (3 bytes, big endian)"),
2481 arg_param_end
2483 CLIExecWithReturn(ctx, Cmd, argtable, false);
2484 int aidlength = 3;
2485 uint8_t aid[3] = {0};
2486 CLIGetHexWithReturn(ctx, 1, aid, &aidlength);
2487 CLIParserFree(ctx);
2489 swap24(aid);
2491 if (aidlength != 3) {
2492 PrintAndLogEx(ERR, "AID must have 3 bytes length");
2493 return PM3_EINVARG;
2496 int res = handler_desfire_select_application(aid);
2497 if (res != PM3_SUCCESS) {
2498 PrintAndLogEx(ERR, "Error on selecting aid.");
2499 DropFieldDesfire();
2500 } else {
2501 PrintAndLogEx(SUCCESS, "Successfully selected aid.");
2503 return res;
2506 static int CmdHF14ADesCreateApp(const char *Cmd) {
2507 CLIParserContext *ctx;
2508 CLIParserInit(&ctx, "hf mfdes createaid",
2509 "Create Application ID",
2510 "hf mfdes createaid -a 123456 -f 1111 -k 0E -l 2E --name Test"
2513 void *argtable[] = {
2514 arg_param_begin,
2515 arg_strx0("a", "aid", "<hex>", "App ID to create as hex bytes (3 hex bytes)"),
2516 arg_strx0("f", "fid", "<hex>", "File ID to create"),
2517 arg_strx0("k", "ks1", "<hex>", "Key Setting 1 (Application Master Key Settings)"),
2518 arg_strx0("l", "ks2", "<hex>", "Key Setting 2"),
2519 arg_str0(NULL, "name", "<ascii>", "App ISO-4 Name"),
2520 arg_param_end
2522 CLIExecWithReturn(ctx, Cmd, argtable, false);
2523 /* KeySetting 1 (AMK Setting):
2524 0: Allow change master key
2525 1: Free Directory list access without master key
2526 0: AMK auth needed for GetFileSettings and GetKeySettings
2527 1: No AMK auth needed for GetFileIDs, GetISOFileIDs, GetFileSettings, GetKeySettings
2528 2: Free create/delete without master key
2529 0: CreateFile/DeleteFile only with AMK auth
2530 1: CreateFile/DeleteFile always
2531 3: Configuration changable
2532 0: Configuration frozen
2533 1: Configuration changable if authenticated with AMK (default)
2534 4-7: ChangeKey Access Rights
2535 0: Application master key needed (default)
2536 0x1..0xD: Auth with specific key needed to change any key
2537 0xE: Auth with the key to be changed (same KeyNo) is necessary to change a key
2538 0xF: All Keys within this application are frozen
2541 /* KeySetting 2:
2542 0..3: Number of keys stored within the application (max. 14 keys)
2543 4: RFU
2544 5: Use of 2 byte ISO FID, 0: No, 1: Yes
2545 6..7: Crypto Method 00: DES/3DES, 01: 3K3DES, 10: AES
2546 Example:
2547 2E = FID, DES, 14 keys
2548 6E = FID, 3K3DES, 14 keys
2549 AE = FID, AES, 14 keys
2551 int aidlength = 3;
2552 uint8_t aid[3] = {0};
2553 CLIGetHexWithReturn(ctx, 1, aid, &aidlength);
2555 int fidlength = 2;
2556 uint8_t fid[2] = {0};
2557 CLIGetHexWithReturn(ctx, 2, fid, &fidlength);
2559 int keylen1 = 1;
2560 uint8_t keysetting1[1] = {0};
2561 CLIGetHexWithReturn(ctx, 3, keysetting1, &keylen1);
2563 int keylen2 = 1;
2564 uint8_t keysetting2[1] = {0};
2565 CLIGetHexWithReturn(ctx, 4, keysetting2, &keylen2);
2567 int namelen = 16;
2568 uint8_t name[16] = {0};
2569 CLIGetStrWithReturn(ctx, 5, name, &namelen);
2570 CLIParserFree(ctx);
2572 swap24(aid);
2573 swap16(fid);
2575 if (aidlength != 3) {
2576 PrintAndLogEx(ERR, "AID must have 3 bytes length");
2577 return PM3_EINVARG;
2580 if (fidlength != 2 && fidlength != 0) {
2581 PrintAndLogEx(ERR, "FID must have 2 bytes length");
2582 return PM3_EINVARG;
2585 bool usefid = (fidlength != 0);
2587 if (keylen1 != 1) {
2588 PrintAndLogEx(ERR, "Keysetting1 must have 1 byte length");
2589 return PM3_EINVARG;
2592 if (keylen2 != 1) {
2593 PrintAndLogEx(ERR, "Keysetting2 must have 1 byte length");
2594 return PM3_EINVARG;
2597 if (namelen > 16) {
2598 PrintAndLogEx(ERR, "Name has a max. of 16 bytes length");
2599 return PM3_EINVARG;
2601 bool usename = true;
2602 if (namelen == 0) usename = false;
2604 //90 ca 00 00 0e 3cb849 09 22 10e1 d27600 00850101 00
2605 /*char name[]="Test";
2606 uint8_t aid[]={0x12,0x34,0x56};
2607 uint8_t fid[]={0x11,0x22};
2608 uint8_t keysetting1=0xEE;
2609 uint8_t keysetting2=0xEE;*/
2611 if (memcmp(aid, "\x00\x00\x00", 3) == 0) {
2612 PrintAndLogEx(WARNING, _RED_(" Creating root aid 000000 is forbidden"));
2613 return PM3_ESOFT;
2616 aidhdr_t aidhdr;
2617 memcpy(aidhdr.aid, aid, sizeof(aid));
2618 aidhdr.keysetting1 = keysetting1[0];
2619 aidhdr.keysetting2 = keysetting2[0];
2621 if (usefid)
2622 memcpy(aidhdr.fid, fid, sizeof(aidhdr.fid));
2624 if (usename)
2625 memcpy(aidhdr.name, name, sizeof(aidhdr.name));
2627 PrintAndLogEx(INFO, "Creating AID using:");
2628 PrintAndLogEx(INFO, "AID %s", sprint_hex_inrow(aidhdr.aid, sizeof(aidhdr.aid)));
2629 PrintAndLogEx(INFO, "Key set1 0x%02X", aidhdr.keysetting1);
2630 PrintAndLogEx(INFO, "Key Set2 0x%02X", aidhdr.keysetting2);
2631 if (usefid)
2632 PrintAndLogEx(INFO, "FID %s", sprint_hex_inrow(aidhdr.fid, sizeof(aidhdr.fid)));
2633 if (usename)
2634 PrintAndLogEx(INFO, "DF Name %s", aidhdr.name);
2637 uint8_t rootaid[3] = {0x00, 0x00, 0x00};
2638 int res = handler_desfire_select_application(rootaid);
2639 if (res != PM3_SUCCESS) {
2640 DropFieldDesfire();
2641 return res;
2645 int res = handler_desfire_createapp(&aidhdr, usename, usefid);
2646 DropFieldDesfire();
2647 if (res == PM3_SUCCESS) {
2648 PrintAndLogEx(SUCCESS, "Successfully created aid.");
2650 return res;
2653 static int CmdHF14ADesDeleteApp(const char *Cmd) {
2654 CLIParserContext *ctx;
2655 CLIParserInit(&ctx, "hf mfdes deleteaid",
2656 "Delete Application ID",
2657 "hf mfdes deleteaid -a 123456"
2660 void *argtable[] = {
2661 arg_param_begin,
2662 arg_strx0("a", "aid", "<hex>", "App ID to delete (3 hex bytes, big endian)"),
2663 arg_param_end
2665 CLIExecWithReturn(ctx, Cmd, argtable, false);
2666 int aidlength = 3;
2667 uint8_t aid[3] = {0};
2668 CLIGetHexWithReturn(ctx, 1, aid, &aidlength);
2669 CLIParserFree(ctx);
2670 swap24(aid);
2671 if (aidlength != 3) {
2672 PrintAndLogEx(ERR, "AID must have 3 bytes length.");
2673 return PM3_EINVARG;
2676 if (memcmp(aid, "\x00\x00\x00", 3) == 0) {
2677 PrintAndLogEx(WARNING, _RED_(" Deleting root aid 000000 is forbidden."));
2678 return PM3_ESOFT;
2681 int res = handler_desfire_deleteapp(aid);
2682 DropFieldDesfire();
2684 if (res == PM3_SUCCESS) {
2685 PrintAndLogEx(SUCCESS, "Successfully deleted aid.");
2687 return res;
2690 static int selectfile(uint8_t *aid, uint8_t fileno, uint8_t *cs) {
2691 if (handler_desfire_select_application(aid) != PM3_SUCCESS) {
2692 PrintAndLogEx(ERR, _RED_(" Couldn't select aid."));
2693 return PM3_ESOFT;
2697 uint8_t filesettings[20] = {0};
2698 uint32_t fileset_len = 0;
2699 int res = handler_desfire_filesettings(fileno, filesettings, &fileset_len);
2700 if (res != PM3_SUCCESS) return res;
2702 if (tag->session_key != NULL) {
2704 uint8_t keyno = tag->authenticated_key_no;
2705 if (currentauth[keyno].keyno == keyno) {
2707 mfdes_auth_res_t rpayload;
2708 if (handler_desfire_auth(&currentauth[keyno], &rpayload) != PM3_SUCCESS) {
2709 PrintAndLogEx(ERR, _RED_(" Couldn't authenticate key."));
2710 return PM3_ESOFT;
2713 } else if (keyno != 0xE) {
2714 PrintAndLogEx(ERR, _RED_(" Please authenticate first."));
2715 return PM3_ESOFT;
2718 *cs = filesettings[1];
2719 return res;
2722 static int CmdHF14ADesClearRecordFile(const char *Cmd) {
2723 CLIParserContext *ctx;
2724 CLIParserInit(&ctx, "hf mfdes clearfile",
2725 "Clear record file\nMake sure to select aid or authenticate aid before running this command.",
2726 "hf mfdes clearfile -n 01"
2729 void *argtable[] = {
2730 arg_param_begin,
2731 arg_int0("n", "fileno", "<dec>", "File Number (0 - 31)"),
2732 arg_strx0("a", "aid", "<hex>", "App ID to select as hex bytes (3 bytes, big endian)"),
2733 arg_param_end
2735 CLIExecWithReturn(ctx, Cmd, argtable, false);
2736 int fno = arg_get_int_def(ctx, 1, 0);
2737 int aidlength = 3;
2738 uint8_t aid[3] = {0};
2739 CLIGetHexWithReturn(ctx, 2, aid, &aidlength);
2740 swap24(aid);
2741 CLIParserFree(ctx);
2743 if (fno > 0x1F) {
2744 PrintAndLogEx(ERR, "File number range is invalid (exp 0 - 31), got %d", fno);
2745 return PM3_EINVARG;
2748 if (aidlength != 3 && aidlength != 0) {
2749 PrintAndLogEx(ERR, _RED_(" The given aid must have 3 bytes (big endian)."));
2750 return PM3_ESOFT;
2751 } else if (aidlength == 0) {
2752 if (memcmp(&tag->selected_application, aid, 3) == 0) {
2753 PrintAndLogEx(ERR, _RED_(" You need to select an aid first."));
2754 return PM3_ESOFT;
2756 memcpy(aid, (uint8_t *)&tag->selected_application, 3);
2758 uint8_t cs = 0;
2759 if (selectfile(aid, fno, &cs) != PM3_SUCCESS) {
2760 PrintAndLogEx(ERR, _RED_(" Error on selecting file."));
2761 return PM3_ESOFT;
2764 int res = handler_desfire_clear_record_file(fno);
2765 if (res == PM3_SUCCESS) {
2766 PrintAndLogEx(SUCCESS, "Successfully cleared record file.");
2767 } else {
2768 PrintAndLogEx(ERR, "Error on deleting file : %d", res);
2770 DropFieldDesfire();
2771 return res;
2774 static int CmdHF14ADesDeleteFile(const char *Cmd) {
2775 CLIParserContext *ctx;
2776 CLIParserInit(&ctx, "hf mfdes deletefile",
2777 "Delete File",
2778 "hf mfdes deletefile -n 01 -> Make sure to select aid or authenticate aid before running this command."
2781 void *argtable[] = {
2782 arg_param_begin,
2783 arg_int0("n", "fileno", "<dec>", "File Number (0 - 31)"),
2784 arg_strx0("a", "aid", "<hex>", "App ID to select as hex bytes (3 bytes, big endian)"),
2785 arg_param_end
2788 CLIExecWithReturn(ctx, Cmd, argtable, false);
2789 int fno = arg_get_int_def(ctx, 1, 0);
2791 int aidlength = 3;
2792 uint8_t aid[3] = {0};
2793 CLIGetHexWithReturn(ctx, 2, aid, &aidlength);
2794 swap24(aid);
2795 CLIParserFree(ctx);
2797 if (fno > 0x1F) {
2798 PrintAndLogEx(ERR, "File number range is invalid (exp 0 - 31), got %d", fno);
2799 return PM3_EINVARG;
2802 if (aidlength != 3 && aidlength != 0) {
2803 PrintAndLogEx(ERR, _RED_(" The given aid must have 3 bytes (big endian)."));
2804 return PM3_ESOFT;
2805 } else if (aidlength == 0) {
2806 if (memcmp(&tag->selected_application, aid, 3) == 0) {
2807 PrintAndLogEx(ERR, _RED_(" You need to select an aid first."));
2808 return PM3_ESOFT;
2810 memcpy(aid, (uint8_t *)&tag->selected_application, 3);
2812 uint8_t cs = 0;
2813 if (selectfile(aid, fno, &cs) != PM3_SUCCESS) {
2814 PrintAndLogEx(ERR, _RED_(" Error on selecting file."));
2815 return PM3_ESOFT;
2818 int res = handler_desfire_deletefile(fno);
2819 if (res == PM3_SUCCESS) {
2820 PrintAndLogEx(SUCCESS, "Successfully deleted file..");
2821 } else {
2822 PrintAndLogEx(ERR, "Error on deleting file : %d", res);
2824 DropFieldDesfire();
2825 return res;
2828 static int CmdHF14ADesCreateFile(const char *Cmd) {
2829 CLIParserContext *ctx;
2830 CLIParserInit(&ctx, "hf mfdes createfile",
2831 "Create Standard/Backup File",
2832 "hf mfdes createfile -f 0001 -n 01 -c 0 -r EEEE -s 000100 -a 123456"
2835 void *argtable[] = {
2836 arg_param_begin,
2837 arg_int0("n", "fileno", "<dec>", "File Number (0 - 31)"),
2838 arg_strx0("f", "fileid", "<hex>", "ISO FID (2 hex bytes, big endian)"),
2839 arg_int0("c", "com", "<dec>", "Communication setting (0 = Plain, 1 = Plain + MAC, 3 = Enciphered)"),
2840 arg_strx0("r", "rights", "<hex>", "Access rights (2 hex bytes -> RW/Chg/R/W, 0x0 - 0xD Key, 0xE Free, 0xF Denied)"),
2841 arg_strx0("s", "filesize", "<hex>", "File size (3 hex bytes, big endian)"),
2842 arg_lit0("b", "backup", "Create backupfile instead of standard file"),
2843 arg_strx0("a", "aid", "<hex>", "App ID to select as hex bytes (3 bytes, big endian)"),
2844 arg_param_end
2847 CLIExecWithReturn(ctx, Cmd, argtable, false);
2848 int fno = arg_get_int_def(ctx, 1, 0);
2850 int fidlength = 0;
2851 uint8_t fid[2] = {0};
2852 int res_flen = CLIParamHexToBuf(arg_get_str(ctx, 2), fid, 2, &fidlength);
2854 uint8_t comset = arg_get_int(ctx, 3);
2855 int arlength = 0;
2856 uint8_t ar[2] = {0};
2857 CLIGetHexWithReturn(ctx, 4, ar, &arlength);
2859 int fsizelen = 0;
2860 uint8_t filesize[3] = {0};
2861 CLIGetHexWithReturn(ctx, 5, filesize, &fsizelen);
2863 bool isbackup = arg_get_lit(ctx, 6);
2864 int aidlength = 3;
2865 uint8_t aid[3] = {0};
2866 CLIGetHexWithReturn(ctx, 7, aid, &aidlength);
2867 swap24(aid);
2868 CLIParserFree(ctx);
2870 swap16(fid);
2871 swap24(filesize);
2873 if (fno > 0x1F) {
2874 PrintAndLogEx(ERR, "File number range is invalid (exp 0 - 31), got %d", fno);
2875 return PM3_EINVARG;
2877 if (comset != 0 && comset != 1 && comset != 3) {
2878 PrintAndLogEx(ERR, "Communication setting must be either 0=Plain, 1=Plain+MAC or 3=Encrypt.");
2879 return PM3_EINVARG;
2882 if (arlength != 2) {
2883 PrintAndLogEx(ERR, "Access rights must have 2 hex bytes length.");
2884 return PM3_EINVARG;
2887 if (fsizelen != 3) {
2888 PrintAndLogEx(ERR, "Filesize must have 3 hex bytes length.");
2889 return PM3_EINVARG;
2892 if (res_flen || fidlength != 2) {
2893 PrintAndLogEx(ERR, "ISO File id must have 2 hex bytes length.");
2894 return PM3_EINVARG;
2897 mfdes_file_t ft;
2898 memcpy(ft.fid, fid, 2);
2899 memcpy(ft.filesize, filesize, 3);
2900 ft.fileno = fno;
2901 ft.comset = comset;
2902 memcpy(ft.access_rights, ar, 2);
2904 if (aidlength != 3 && aidlength != 0) {
2905 PrintAndLogEx(ERR, _RED_(" The given aid must have 3 bytes (big endian)."));
2906 DropFieldDesfire();
2907 return PM3_ESOFT;
2908 } else if (aidlength == 0) {
2909 if (memcmp(&tag->selected_application, aid, 3) == 0) {
2910 PrintAndLogEx(ERR, _RED_(" You need to select an aid first."));
2911 DropFieldDesfire();
2912 return PM3_ESOFT;
2914 memcpy(aid, (uint8_t *)&tag->selected_application, 3);
2917 // int res;
2918 // a select here seems to invalidate the current authentication with AMK and create file fails if not open access.
2919 // This will be managed when we track Authenticated or Note, so a place holder comment as a reminder.
2920 int res = handler_desfire_select_application(aid);
2921 if (res != PM3_SUCCESS) {
2922 PrintAndLogEx(ERR, "Couldn't select aid. Error %d", res);
2923 DropFieldDesfire();
2924 return res;
2927 if (isbackup)
2928 res = handler_desfire_create_backup_file(&ft);
2929 else
2930 res = handler_desfire_create_std_file(&ft);
2932 if (res == PM3_SUCCESS)
2933 PrintAndLogEx(SUCCESS, "Successfully created standard / backup file.");
2934 else
2935 PrintAndLogEx(ERR, "Couldn't create standard / backup file. Error %d", res);
2937 DropFieldDesfire();
2938 return res;
2941 static int CmdHF14ADesGetValueData(const char *Cmd) {
2942 CLIParserContext *ctx;
2943 CLIParserInit(&ctx, "hf mfdes getvalue",
2944 "Get value from value file\n"
2945 "Make sure to select aid or authenticate aid before running this command.",
2946 "hf mfdes getvalue -n 03"
2949 void *argtable[] = {
2950 arg_param_begin,
2951 arg_int0("n", "fileno", "<dec>", "File Number (0 - 31)"),
2952 arg_strx0("a", "aid", "<hex>", "App ID to select as hex bytes (3 bytes, big endian)"),
2953 arg_param_end
2955 CLIExecWithReturn(ctx, Cmd, argtable, false);
2957 int fno = arg_get_int_def(ctx, 1, 0);
2958 int aidlength = 3;
2959 uint8_t aid[3] = {0};
2960 CLIGetHexWithReturn(ctx, 2, aid, &aidlength);
2961 swap24(aid);
2963 CLIParserFree(ctx);
2965 if (fno > 0x1F) {
2966 PrintAndLogEx(ERR, "File number range is invalid (exp 0 - 31), got %d", fno);
2967 return PM3_EINVARG;
2970 mfdes_value_t value = {
2971 .fileno = fno
2974 if (aidlength != 3 && aidlength != 0) {
2975 PrintAndLogEx(ERR, _RED_(" The given aid must have 3 bytes (big endian)."));
2976 return PM3_ESOFT;
2977 } else if (aidlength == 0) {
2978 if (memcmp(&tag->selected_application, aid, 3) == 0) {
2979 PrintAndLogEx(ERR, _RED_(" You need to select an aid first."));
2980 return PM3_ESOFT;
2982 memcpy(aid, (uint8_t *)&tag->selected_application, 3);
2984 uint8_t cs = 0;
2985 if (selectfile(aid, value.fileno, &cs) != PM3_SUCCESS) {
2986 PrintAndLogEx(ERR, _RED_(" Error on selecting file."));
2987 return PM3_ESOFT;
2990 uint32_t len = 0;
2991 int res = handler_desfire_getvalue(&value, &len, cs);
2992 if (res == PM3_SUCCESS) {
2993 PrintAndLogEx(SUCCESS, "Successfully read value from File %u:", value.fileno);
2994 PrintAndLogEx(NORMAL, "\nOffset | Data | Ascii");
2995 PrintAndLogEx(NORMAL, "----------------------------------------------------------------------------");
2996 for (uint32_t i = 0; i < len; i += 16) {
2997 PrintAndLogEx(NORMAL, "%02d/0x%02X | %s| %s", i, i, sprint_hex(&value.value[i], len > 16 ? 16 : len), sprint_ascii(&value.value[i], len > 16 ? 16 : len));
2999 } else {
3000 PrintAndLogEx(ERR, "Couldn't read value. Error %d", res);
3002 DropFieldDesfire();
3003 return res;
3006 static int CmdHF14ADesReadData(const char *Cmd) {
3007 CLIParserContext *ctx;
3008 CLIParserInit(&ctx, "hf mfdes read",
3009 "Read data from File\n"
3010 "Make sure to select aid or authenticate aid before running this command.",
3011 "hf mfdes read -n 1 -t 0 -o 000000 -l 000000 -a 123456\n"
3012 "hf mfdes read -n 1 -t 0 --> Read all data from standard file, fileno 1"
3015 void *argtable[] = {
3016 arg_param_begin,
3017 arg_int0("n", "fileno", "<dec>", "File Number (0 - 31)"),
3018 arg_strx0("o", "offset", "<hex>", "File Offset (3 hex bytes, big endian)"),
3019 arg_strx0("l", "length", "<hex>", "Length to read (3 hex bytes, big endian -> 000000 = Read all data)"),
3020 arg_int0("t", "type", "<dec>", "File Type (0 = Standard / Backup, 1 = Record)"),
3021 arg_strx0("a", "aid", "<hex>", "App ID to select (3 hex bytes, big endian)"),
3022 arg_param_end
3025 CLIExecWithReturn(ctx, Cmd, argtable, false);
3026 int fno = arg_get_int_def(ctx, 1, 0);
3028 int offsetlength = 0;
3029 uint8_t offset[3] = {0};
3030 int res_offset = CLIParamHexToBuf(arg_get_str(ctx, 2), offset, 3, &offsetlength);
3032 int flength = 0;
3033 uint8_t filesize[3] = {0};
3034 int res_flen = CLIParamHexToBuf(arg_get_str(ctx, 3), filesize, 3, &flength);
3036 int type = arg_get_int(ctx, 4);
3038 int aidlength = 3;
3039 uint8_t aid[3] = {0};
3040 CLIGetHexWithReturn(ctx, 5, aid, &aidlength);
3041 swap24(aid);
3042 CLIParserFree(ctx);
3044 if (type > 1) {
3045 PrintAndLogEx(ERR, "Invalid file type (0 = Standard/Backup, 1 = Record)");
3046 return PM3_EINVARG;
3049 if (res_offset || (offsetlength != 3 && offsetlength != 0)) {
3050 PrintAndLogEx(ERR, "Offset needs 3 hex bytes");
3051 return PM3_EINVARG;
3054 if (fno > 0x1F) {
3055 PrintAndLogEx(ERR, "File number range is invalid (exp 0 - 31), got %d", fno);
3056 return PM3_EINVARG;
3059 if (res_flen) {
3060 PrintAndLogEx(ERR, "File size input error");
3061 return PM3_EINVARG;
3064 swap24(filesize);
3065 swap24(offset);
3067 mfdes_data_t ft;
3068 memcpy(ft.offset, offset, 3);
3069 memcpy(ft.length, filesize, 3);
3070 ft.fileno = fno;
3072 uint32_t bytestoread = (uint32_t)le24toh(filesize);
3073 bytestoread &= 0xFFFFFF;
3075 if (bytestoread == 0)
3076 bytestoread = 0xFFFFFF;
3078 if (aidlength != 3 && aidlength != 0) {
3079 PrintAndLogEx(ERR, _RED_(" The given aid must have 3 bytes (big endian)."));
3080 return PM3_ESOFT;
3081 } else if (aidlength == 0) {
3082 if (memcmp(&tag->selected_application, aid, 3) == 0) {
3083 PrintAndLogEx(ERR, _RED_(" You need to select an aid first."));
3084 return PM3_ESOFT;
3086 memcpy(aid, (uint8_t *)&tag->selected_application, 3);
3088 uint8_t cs = 0;
3089 if (selectfile(aid, ft.fileno, &cs) != PM3_SUCCESS) {
3090 PrintAndLogEx(ERR, _RED_(" Error on selecting file."));
3091 return PM3_ESOFT;
3094 uint8_t *data = (uint8_t *)calloc(bytestoread, sizeof(uint8_t));
3095 int res = PM3_ESOFT;
3096 if (data != NULL) {
3097 ft.data = data;
3098 res = handler_desfire_readdata(&ft, type, cs);
3099 if (res == PM3_SUCCESS) {
3100 uint32_t len = le24toh(ft.length);
3102 PrintAndLogEx(SUCCESS, "Read %u bytes from file %d", ft.fileno, len);
3103 PrintAndLogEx(INFO, "Offset | Data | Ascii");
3104 PrintAndLogEx(INFO, "----------------------------------------------------------------------------");
3106 for (uint32_t i = 0; i < len; i += 16) {
3107 uint32_t l = len - i;
3108 PrintAndLogEx(INFO, "%3d/0x%02X | %s| %s", i, i, sprint_hex(&ft.data[i], l > 16 ? 16 : l), sprint_ascii(&ft.data[i], l > 16 ? 16 : l));
3110 } else {
3111 PrintAndLogEx(ERR, "Couldn't read data. Error %d", res);
3112 DropFieldDesfire();
3113 return res;
3115 free(data);
3117 DropFieldDesfire();
3118 return res;
3121 static int CmdHF14ADesChangeValue(const char *Cmd) {
3122 CLIParserContext *ctx;
3123 CLIParserInit(&ctx, "hf mfdes changevalue",
3124 "Change value (credit / limitedcredit / debit)\n"
3125 "Make sure to select aid or authenticate aid before running this command.",
3126 "hf mfdes changevalue -n 03 -m 0 -d 00000001"
3129 void *argtable[] = {
3130 arg_param_begin,
3131 arg_int0("n", "fileno", "<dec>", "File Number (0 - 31)"),
3132 arg_strx0("d", "value", "<hex>", "Value to increase (4 hex bytes, big endian)"),
3133 arg_int0("m", "mode", "<dec>", "Mode (0 = Credit, 1 = Limited Credit, 2 = Debit)"),
3134 arg_strx0("a", "aid", "<hex>", "App ID to select as hex bytes (3 bytes, big endian)"),
3135 arg_param_end
3138 CLIExecWithReturn(ctx, Cmd, argtable, false);
3140 mfdes_value_t value;
3141 value.fileno = arg_get_int_def(ctx, 1, 0);
3143 int vlength = 0x0;
3144 int res_val = CLIParamHexToBuf(arg_get_str(ctx, 2), value.value, 4, &vlength);
3146 int mode = arg_get_int(ctx, 3);
3147 int aidlength = 3;
3148 uint8_t aid[3] = {0};
3149 CLIGetHexWithReturn(ctx, 4, aid, &aidlength);
3150 swap24(aid);
3152 CLIParserFree(ctx);
3154 if (mode > 2) {
3155 PrintAndLogEx(ERR, "Invalid mode (0 = Credit, 1 = LimitedCredit, 2 = Debit)");
3156 return PM3_EINVARG;
3159 if (res_val || vlength != 4) {
3160 PrintAndLogEx(ERR, "Value needs 4 hex bytes.");
3161 return PM3_EINVARG;
3163 swap32(value.value);
3165 if (value.fileno > 0x1F) {
3166 PrintAndLogEx(ERR, "File number range is invalid (exp 0 - 31), got %d", value.fileno);
3167 return PM3_EINVARG;
3170 if (aidlength != 3 && aidlength != 0) {
3171 PrintAndLogEx(ERR, _RED_(" The given aid must have 3 bytes (big endian)."));
3172 return PM3_ESOFT;
3173 } else if (aidlength == 0) {
3174 if (memcmp(&tag->selected_application, aid, 3) == 0) {
3175 PrintAndLogEx(ERR, _RED_(" You need to select an aid first."));
3176 return PM3_ESOFT;
3178 memcpy(aid, (uint8_t *)&tag->selected_application, 3);
3180 uint8_t cs = 0;
3181 if (selectfile(aid, value.fileno, &cs) != PM3_SUCCESS) {
3182 PrintAndLogEx(ERR, _RED_(" Error on selecting file."));
3183 return PM3_ESOFT;
3187 int res = PM3_ESOFT;
3188 if (mode == 0) {
3189 res = handler_desfire_credit(&value, cs);
3190 } else if (mode == 1) {
3191 res = handler_desfire_limitedcredit(&value, cs);
3192 } else if (mode == 2) {
3193 res = handler_desfire_debit(&value, cs);
3196 if (res == PM3_SUCCESS) {
3197 if (handler_desfire_commit_transaction() == PM3_SUCCESS) {
3198 PrintAndLogEx(SUCCESS, "Successfully changed value in value file.");
3199 } else {
3200 PrintAndLogEx(ERR, "Couldn't commit the transaction. Error %d", res);
3202 } else {
3203 PrintAndLogEx(ERR, "Couldn't change value in value file. Error %d", res);
3205 DropFieldDesfire();
3206 return res;
3209 static int CmdHF14ADesWriteData(const char *Cmd) {
3211 CLIParserContext *ctx;
3212 CLIParserInit(&ctx, "hf mfdes write",
3213 "Write data to file\n"
3214 "Make sure to select aid or authenticate aid before running this command.",
3215 "hf mfdes write -n 01 -t 0 -o 000000 -d 3132333435363738"
3218 void *argtable[] = {
3219 arg_param_begin,
3220 arg_int0("n", "fileno", "<dec>", "File Number (0 - 31)"),
3221 arg_strx0("o", "offset", "<hex>", "File Offset (3 hex bytes, big endian), optional"),
3222 arg_strx0("d", "data", "<hex>", "Data to write (hex bytes, 256 bytes max)"),
3223 arg_int0("t", "type", "<dec>", "File Type (0 = Standard / Backup, 1 = Record)"),
3224 arg_strx0("a", "aid", "<hex>", "App ID to select as hex bytes (3 bytes, big endian)"),
3225 arg_param_end
3228 CLIExecWithReturn(ctx, Cmd, argtable, false);
3229 int fno = arg_get_int_def(ctx, 1, 0);
3231 int offsetlength = 0;
3232 uint8_t offset[3] = {0};
3233 int res_offset = CLIParamHexToBuf(arg_get_str(ctx, 2), offset, 3, &offsetlength);
3235 // iceman: we only have a 1024 byte commandline input array. So this is pointlessly large.
3236 // with 2char hex, 512bytes could be input.
3237 // Instead large binary inputs should be BINARY files and written to card.
3238 int dlength = 512;
3239 uint8_t data[512] = {0};
3240 int res_data = CLIParamHexToBuf(arg_get_str(ctx, 3), data, 512, &dlength);
3242 int type = arg_get_int(ctx, 4);
3243 int aidlength = 3;
3244 uint8_t aid[3] = {0};
3245 CLIGetHexWithReturn(ctx, 5, aid, &aidlength);
3246 swap24(aid);
3248 CLIParserFree(ctx);
3250 swap24(offset);
3252 if (type < 0 || type > 1) {
3253 PrintAndLogEx(ERR, "Unknown type (0=Standard/Backup, 1=Record)");
3254 return PM3_EINVARG;
3257 if (res_data || dlength == 0) {
3258 PrintAndLogEx(ERR, "Data needs some hex bytes to write");
3259 return PM3_EINVARG;
3262 if (res_offset || (offsetlength != 3 && offsetlength != 0)) {
3263 PrintAndLogEx(ERR, "Offset needs 3 hex bytes");
3264 return PM3_EINVARG;
3267 if (fno > 0x1F) {
3268 PrintAndLogEx(ERR, "File number range is invalid (exp 0 - 31), got %d", fno);
3269 return PM3_EINVARG;
3272 mfdes_data_t ft;
3274 memcpy(ft.offset, offset, 3);
3275 htole24(dlength, ft.length);
3276 ft.fileno = fno;
3278 if (aidlength != 3 && aidlength != 0) {
3279 PrintAndLogEx(ERR, _RED_(" The given aid must have 3 bytes (big endian)."));
3280 return PM3_ESOFT;
3281 } else if (aidlength == 0) {
3282 if (memcmp(&tag->selected_application, aid, 3) == 0) {
3283 PrintAndLogEx(ERR, _RED_(" You need to select an aid first."));
3284 return PM3_ESOFT;
3286 memcpy(aid, (uint8_t *)&tag->selected_application, 3);
3288 uint8_t cs = 0;
3289 if (selectfile(aid, fno, &cs) != PM3_SUCCESS) {
3290 PrintAndLogEx(ERR, _RED_(" Error on selecting file."));
3291 DropFieldDesfire();
3292 return PM3_ESOFT;
3295 int res = PM3_ESOFT;
3296 ft.data = data;
3297 res = handler_desfire_writedata(&ft, type, cs);
3298 if (res == PM3_SUCCESS) {
3299 PrintAndLogEx(SUCCESS, "Successfully wrote data");
3300 } else {
3301 PrintAndLogEx(ERR, "Couldn't read data. Error %d", res);
3303 DropFieldDesfire();
3304 return res;
3307 static int CmdHF14ADesCreateRecordFile(const char *Cmd) {
3308 CLIParserContext *ctx;
3309 CLIParserInit(&ctx, "hf mfdes createrecordfile",
3310 "Create Linear / Cyclic Record File\n"
3311 "Make sure to select aid or authenticate aid before running this command.",
3312 "hf mfdes createrecordfile -f 1122 -n 02 -c 0 -r EEEE -s 000010 -m 000005 -a 123456"
3315 void *argtable[] = {
3316 arg_param_begin,
3317 arg_int0("n", "fileno", "<dec>", "File Number (0 - 31)"),
3318 arg_strx0("f", "fileid", "<hex>", "ISO FID (2 hex bytes, big endian)"),
3319 arg_int0("c", "com", "<dec>", "Communication setting (0 = Plain, 1 = Plain + MAC, 3 = Enciphered)"),
3320 // arg_strx0("s", "recordsize", "<hex>", "Record size (3 hex bytes, big endian, 000001 to FFFFFF)"),
3321 arg_strx0("r", "rights", "<hex>", "Access rights (2 hex bytes -> RW/Chg/R/W, 0x0 - 0xD Key, 0xE Free, 0xF Denied)"),
3322 arg_strx0("s", "size", "<hex>", "Record size (3 hex bytes, big endian, 000001 to FFFFFF)"),
3323 arg_strx0("m", "maxrecord", "<hex>", "Max. Number of Records (3 hex bytes, big endian)"),
3324 arg_lit0("b", "cyclic", "Create cyclic record file instead of linear record file"),
3325 arg_strx0("a", "aid", "<hex>", "App ID to select as hex bytes (3 bytes, big endian)"),
3326 arg_param_end
3329 CLIExecWithReturn(ctx, Cmd, argtable, false);
3330 int fno = arg_get_int_def(ctx, 1, 0);
3332 int fidlength = 0;
3333 uint8_t fid[2] = {0};
3334 int res_flen = CLIParamHexToBuf(arg_get_str(ctx, 2), fid, 2, &fidlength);
3336 uint8_t comset = arg_get_int(ctx, 3);
3338 int arlength = 0;
3339 uint8_t ar[2] = {0};
3340 CLIGetHexWithReturn(ctx, 4, ar, &arlength);
3342 int rsizelen = 0;
3343 uint8_t recordsize[3] = {0};
3344 CLIGetHexWithReturn(ctx, 5, recordsize, &rsizelen);
3346 int msizelen = 0;
3347 uint8_t maxnumrecords[3] = {0};
3348 CLIGetHexWithReturn(ctx, 6, maxnumrecords, &msizelen);
3350 bool cyclic = arg_get_lit(ctx, 7);
3352 int aidlength = 3;
3353 uint8_t aid[3] = {0};
3354 CLIGetHexWithReturn(ctx, 8, aid, &aidlength);
3355 swap24(aid);
3356 CLIParserFree(ctx);
3358 swap16(fid);
3359 swap24(recordsize);
3360 swap24(maxnumrecords);
3362 if (msizelen != 3) {
3363 PrintAndLogEx(ERR, "Maximum number of records must have 3 hex bytes length.");
3364 return PM3_EINVARG;
3367 if (memcmp("\x00\x00\x00", maxnumrecords, 3) == 0x0) {
3368 PrintAndLogEx(ERR, "Maximum number of records is invalid (0x000001-0xFFFFFF).");
3369 return PM3_EINVARG;
3372 if (fno > 0x1F) {
3373 PrintAndLogEx(ERR, "File number range is invalid (exp 0 - 31), got %d", fno);
3374 return PM3_EINVARG;
3377 if (comset != 0 && comset != 1 && comset != 3) {
3378 PrintAndLogEx(ERR, "Communication setting must be either 0=Plain, 1=Plain+MAC or 3=Encrypt.");
3379 return PM3_EINVARG;
3382 if (arlength != 2) {
3383 PrintAndLogEx(ERR, "Access rights must have 2 hex bytes length.");
3384 return PM3_EINVARG;
3387 if (rsizelen != 3) {
3388 PrintAndLogEx(ERR, "Recordsize must have 3 hex bytes length.");
3389 return PM3_EINVARG;
3392 if (res_flen || fidlength != 2) {
3393 PrintAndLogEx(ERR, "ISO File id must have 2 hex bytes length.");
3394 return PM3_EINVARG;
3397 mfdes_linear_t ft = {
3398 .fileno = fno,
3399 .comset = comset
3401 memcpy(ft.fid, fid, 2);
3402 memcpy(ft.access_rights, ar, 2);
3403 memcpy(ft.recordsize, recordsize, 3);
3404 memcpy(ft.maxnumrecords, maxnumrecords, 3);
3406 if (aidlength != 3 && aidlength != 0) {
3407 PrintAndLogEx(ERR, _RED_(" The given aid must have 3 bytes (big endian)."));
3408 return PM3_ESOFT;
3409 } else if (aidlength == 0) {
3410 if (memcmp(&tag->selected_application, aid, 3) == 0) {
3411 PrintAndLogEx(ERR, _RED_(" You need to select an aid first."));
3412 return PM3_ESOFT;
3414 memcpy(aid, (uint8_t *)&tag->selected_application, 3);
3416 if (handler_desfire_select_application(aid) != PM3_SUCCESS) {
3417 PrintAndLogEx(ERR, _RED_(" Error on selecting aid."));
3418 return PM3_ESOFT;
3421 int res = PM3_SUCCESS;
3422 if (cyclic) {
3423 res = handler_desfire_create_cyclicrecordfile(&ft);
3424 } else {
3425 res = handler_desfire_create_linearrecordfile(&ft);
3428 if (res == PM3_SUCCESS) {
3429 PrintAndLogEx(SUCCESS, "Successfully created linear/cyclic record file.");
3430 } else {
3431 PrintAndLogEx(ERR, "Couldn't create linear/cyclic record file. Error %d", res);
3433 DropFieldDesfire();
3434 return res;
3437 static int CmdHF14ADesCreateValueFile(const char *Cmd) {
3438 CLIParserContext *ctx;
3439 CLIParserInit(&ctx, "hf mfdes createvaluefile",
3440 "Create Value File\n"
3441 "Make sure to select aid or authenticate aid before running this command.",
3442 "hf mfdes createvaluefile -n 03 -c 0 -r EEEE -l 00000000 -u 00002000 --val 00000001 -m 02 -a 123456\n"
3445 void *argtable[] = {
3446 arg_param_begin,
3447 arg_int0("n", "fileno", "<dec>", "File Number (0 - 31)"),
3448 arg_int0("c", "com", "<dec>", "Communication setting (0 = Plain, 1 = Plain + MAC, 3 = Enciphered)"),
3449 arg_strx0("r", "rights", "<hex>", "Access rights (2 hex bytes -> RW/Chg/R/W, 0x0 - 0xD Key, 0xE Free, 0xF Denied)"),
3450 arg_strx0("l", "lower", "<hex>", "Lower limit (4 hex bytes, big endian)"),
3451 arg_strx0("u", "upper", "<hex>", "Upper limit (4 hex bytes, big endian)"),
3452 arg_strx0(NULL, "val", "<hex>", "Value (4 hex bytes, big endian)"),
3453 arg_int0("m", NULL, "<dec>", "Limited Credit enabled (Bit 0 = Limited Credit, 1 = FreeValue)"),
3454 arg_strx0("a", "aid", "<hex>", "App ID to select as hex bytes (3 bytes,big endian,optional)"),
3455 arg_param_end
3458 CLIExecWithReturn(ctx, Cmd, argtable, false);
3459 int fno = arg_get_int_def(ctx, 1, 0);
3460 uint8_t comset = arg_get_int(ctx, 2);
3462 int arlength = 0;
3463 uint8_t ar[2] = {0};
3464 CLIGetHexWithReturn(ctx, 3, ar, &arlength);
3466 int lllen = 0;
3467 uint8_t lowerlimit[4] = {0};
3468 CLIGetHexWithReturn(ctx, 4, lowerlimit, &lllen);
3470 int ullen = 0;
3471 uint8_t upperlimit[4] = {0};
3472 CLIGetHexWithReturn(ctx, 5, upperlimit, &ullen);
3474 int vllen = 0;
3475 uint8_t value[4] = {0};
3476 CLIGetHexWithReturn(ctx, 6, value, &vllen);
3478 uint8_t limited = arg_get_int_def(ctx, 7, 0);
3480 int aidlength = 3;
3481 uint8_t aid[3] = {0};
3482 CLIGetHexWithReturn(ctx, 8, aid, &aidlength);
3483 swap24(aid);
3484 CLIParserFree(ctx);
3486 swap32(lowerlimit);
3487 swap32(upperlimit);
3488 swap32(value);
3490 if (fno > 0x1F) {
3491 PrintAndLogEx(ERR, "File number range is invalid (exp 0 - 31), got %d", fno);
3492 return PM3_EINVARG;
3495 if (comset != 0 && comset != 1 && comset != 3) {
3496 PrintAndLogEx(ERR, "Communication setting must be either 0=Plain, 1=Plain+MAC or 3=Encrypt");
3497 return PM3_EINVARG;
3500 if (arlength != 2) {
3501 PrintAndLogEx(ERR, "Access rights must have 2 hex bytes length");
3502 return PM3_EINVARG;
3505 if (lllen != 4) {
3506 PrintAndLogEx(ERR, "Lower limit must have 4 hex bytes length");
3507 return PM3_EINVARG;
3510 if (ullen != 4) {
3511 PrintAndLogEx(ERR, "Upper limit must have 4 hex bytes length");
3512 return PM3_EINVARG;
3515 if (vllen != 4) {
3516 PrintAndLogEx(ERR, "Value must have 4 hex bytes length");
3517 return PM3_EINVARG;
3520 mfdes_value_file_t ft = {
3521 .fileno = fno,
3522 .comset = comset,
3523 .limitedcreditenabled = limited,
3526 memcpy(ft.access_rights, ar, 2);
3527 memcpy(ft.lowerlimit, lowerlimit, 4);
3528 memcpy(ft.upperlimit, upperlimit, 4);
3529 memcpy(ft.value, value, 4);
3531 if (aidlength != 3 && aidlength != 0) {
3532 PrintAndLogEx(ERR, _RED_(" The given aid must have 3 bytes (big endian)."));
3533 return PM3_ESOFT;
3534 } else if (aidlength == 0) {
3535 if (memcmp(&tag->selected_application, aid, 3) == 0) {
3536 PrintAndLogEx(ERR, _RED_(" You need to select an aid first."));
3537 return PM3_ESOFT;
3539 memcpy(aid, (uint8_t *)&tag->selected_application, 3);
3542 if (handler_desfire_select_application(aid) != PM3_SUCCESS) {
3543 PrintAndLogEx(ERR, _RED_(" Error on selecting aid."));
3544 return PM3_ESOFT;
3547 int res = handler_desfire_create_value_file(&ft);
3548 if (res == PM3_SUCCESS) {
3549 PrintAndLogEx(SUCCESS, "Successfully created value file.");
3550 } else {
3551 PrintAndLogEx(ERR, "Couldn't create value file. Error %d", res);
3553 DropFieldDesfire();
3554 return res;
3557 static int CmdHF14ADesFormatPICC(const char *Cmd) {
3558 CLIParserContext *ctx;
3559 CLIParserInit(&ctx, "hf mfdes formatpicc",
3560 "Formats MIFARE DESFire PICC to factory state\n"
3561 "Make sure to authenticate picc before running this command.",
3562 "hf mfdes formatpicc"
3564 void *argtable[] = {
3565 arg_param_begin,
3566 arg_param_end
3568 CLIExecWithReturn(ctx, Cmd, argtable, true);
3569 CLIParserFree(ctx);
3570 sAPDU apdu = {0x90, MFDES_FORMAT_PICC, 0x00, 0x00, 0, NULL}; // 0xDF
3571 uint16_t sw = 0;
3572 uint32_t recvlen = 0;
3573 int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true);
3574 if (res != PM3_SUCCESS) {
3575 PrintAndLogEx(WARNING, _RED_(" Can't format picc -> %s"), GetErrorString(res, &sw));
3576 } else {
3577 PrintAndLogEx(INFO, "Card successfully reset");
3579 DropFieldDesfire();
3580 return res;
3583 static int CmdHF14ADesInfo(const char *Cmd) {
3584 CLIParserContext *ctx;
3585 CLIParserInit(&ctx, "hf mfdes info",
3586 "Get info from MIFARE DESfire tags",
3587 "hf mfdes info");
3589 void *argtable[] = {
3590 arg_param_begin,
3591 arg_param_end
3593 CLIExecWithReturn(ctx, Cmd, argtable, true);
3594 CLIParserFree(ctx);
3596 DropFieldDesfire();
3598 mfdes_info_res_t info;
3599 int res = mfdes_get_info(&info);
3600 if (res != PM3_SUCCESS) {
3601 return res;
3604 nxp_cardtype_t cardtype = getCardType(info.versionHW[3], info.versionHW[4]);
3605 if (cardtype == PLUS_EV1) {
3606 PrintAndLogEx(INFO, "Card seems to be MIFARE Plus EV1. Try " _YELLOW_("`hf mfp info`"));
3607 return PM3_SUCCESS;
3610 PrintAndLogEx(NORMAL, "");
3611 PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------");
3612 PrintAndLogEx(INFO, "-------------------------------------------------------------");
3613 PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(info.uid, info.uidlen));
3614 PrintAndLogEx(SUCCESS, " Batch number: " _GREEN_("%s"), sprint_hex(info.details + 7, 5));
3615 PrintAndLogEx(SUCCESS, " Production date: week " _GREEN_("%02x") " / " _GREEN_("20%02x"), info.details[12], info.details[13]);
3616 PrintAndLogEx(NORMAL, "");
3617 PrintAndLogEx(INFO, "--- " _CYAN_("Hardware Information"));
3618 PrintAndLogEx(INFO, " raw: %s", sprint_hex_inrow(info.versionHW, sizeof(info.versionHW)));
3620 PrintAndLogEx(INFO, " Vendor Id: " _YELLOW_("%s"), getTagInfo(info.versionHW[0]));
3621 PrintAndLogEx(INFO, " Type: " _YELLOW_("0x%02X"), info.versionHW[1]);
3622 PrintAndLogEx(INFO, " Subtype: " _YELLOW_("0x%02X"), info.versionHW[2]);
3623 PrintAndLogEx(INFO, " Version: %s", getVersionStr(info.versionHW[3], info.versionHW[4]));
3624 PrintAndLogEx(INFO, " Storage size: %s", getCardSizeStr(info.versionHW[5]));
3625 PrintAndLogEx(INFO, " Protocol: %s", getProtocolStr(info.versionHW[6], true));
3626 PrintAndLogEx(NORMAL, "");
3627 PrintAndLogEx(INFO, "--- " _CYAN_("Software Information"));
3628 PrintAndLogEx(INFO, " raw: %s", sprint_hex_inrow(info.versionSW, sizeof(info.versionSW)));
3629 PrintAndLogEx(INFO, " Vendor Id: " _YELLOW_("%s"), getTagInfo(info.versionSW[0]));
3630 PrintAndLogEx(INFO, " Type: " _YELLOW_("0x%02X"), info.versionSW[1]);
3631 PrintAndLogEx(INFO, " Subtype: " _YELLOW_("0x%02X"), info.versionSW[2]);
3632 PrintAndLogEx(INFO, " Version: " _YELLOW_("%d.%d"), info.versionSW[3], info.versionSW[4]);
3633 PrintAndLogEx(INFO, " Storage size: %s", getCardSizeStr(info.versionSW[5]));
3634 PrintAndLogEx(INFO, " Protocol: %s", getProtocolStr(info.versionSW[6], false));
3636 PrintAndLogEx(NORMAL, "");
3637 PrintAndLogEx(INFO, "--- " _CYAN_("Card capabilities"));
3638 uint8_t major = info.versionSW[3];
3639 uint8_t minor = info.versionSW[4];
3640 if (major == 0 && minor == 4)
3641 PrintAndLogEx(INFO, "\t0.4 - DESFire MF3ICD40, No support for APDU (only native commands)");
3642 if (major == 0 && minor == 5)
3643 PrintAndLogEx(INFO, "\t0.5 - DESFire MF3ICD40, Support for wrapping commands inside ISO 7816 style APDUs");
3644 if (major == 0 && minor == 6)
3645 PrintAndLogEx(INFO, "\t0.6 - DESFire MF3ICD40, Add ISO/IEC 7816 command set compatibility");
3646 if (major == 1 && minor == 3)
3647 PrintAndLogEx(INFO, "\t1.3 - DESFire Ev1 MF3ICD21/41/81, Support extended APDU commands, EAL4+");
3648 if (major == 1 && minor == 4)
3649 PrintAndLogEx(INFO, "\t1.4 - DESFire Ev1 MF3ICD21/41/81, EAL4+");
3650 if (major == 2 && minor == 0)
3651 PrintAndLogEx(INFO, "\t2.0 - DESFire Ev2, Originality check, proximity check, EAL5");
3652 if (major == 3 && minor == 0)
3653 PrintAndLogEx(INFO, "\t3.0 - DESFire Ev3, Originality check, proximity check, badass EAL6 ?");
3655 if (major == 0 && minor == 2)
3656 PrintAndLogEx(INFO, "\t0.2 - DESFire Light, Originality check, ");
3658 if (cardtype == DESFIRE_EV2 ||
3659 cardtype == DESFIRE_LIGHT ||
3660 cardtype == DESFIRE_EV3 ||
3661 cardtype == NTAG413DNA) {
3662 // Signature originality check
3663 uint8_t signature[56] = {0};
3664 size_t signature_len = 0;
3666 PrintAndLogEx(NORMAL, "");
3667 PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature"));
3668 if (handler_desfire_signature(signature, &signature_len) == PM3_SUCCESS) {
3669 desfire_print_signature(info.uid, info.uidlen, signature, signature_len, cardtype);
3670 } else {
3671 PrintAndLogEx(WARNING, "--- Card doesn't support GetSignature cmd");
3675 // Master Key settings
3676 uint8_t master_aid[3] = {0x00, 0x00, 0x00};
3677 getKeySettings(master_aid);
3679 if (cardtype != DESFIRE_LIGHT) {
3680 // Free memory on card
3681 PrintAndLogEx(NORMAL, "");
3682 PrintAndLogEx(INFO, "--- " _CYAN_("Free memory"));
3683 uint32_t free_mem = 0;
3684 if (handler_desfire_freemem(&free_mem) == PM3_SUCCESS) {
3685 desfire_print_freemem(free_mem);
3686 } else {
3687 PrintAndLogEx(SUCCESS, " Card doesn't support 'free mem' cmd");
3689 PrintAndLogEx(INFO, "-------------------------------------------------------------");
3693 iso14a_card_select_t card;
3694 res = SelectCard14443A_4(true, false, &card);
3695 if (res == PM3_SUCCESS) {
3696 static const char STANDALONE_DESFIRE[] = { 0x75, 0x77, 0x81, 0x02};
3697 static const char JCOP_DESFIRE[] = { 0x75, 0xf7, 0xb1, 0x02 };
3698 static const char JCOP3_DESFIRE[] = { 0x78, 0x77, 0x71, 0x02 };
3700 if (card.sak == 0x20) {
3702 if (card.ats_len >= 5) {
3703 if (str_startswith((const char *)card.ats + 1, STANDALONE_DESFIRE)) {
3704 PrintAndLogEx(INFO, "Standalone DESFire");
3706 if (str_startswith((const char *)card.ats + 1, JCOP_DESFIRE)) {
3707 PrintAndLogEx(INFO, "JCOP DESFire");
3710 if (card.ats_len == 4) {
3711 if (str_startswith((const char *)card.ats + 1, JCOP3_DESFIRE)) {
3712 PrintAndLogEx(INFO, "JCOP3 DESFire");
3719 Card Master key (CMK) 0x00 AID = 00 00 00 (card level)
3720 Application Master Key (AMK) 0x00 AID != 00 00 00
3721 Application keys (APK) 0x01-0x0D
3722 Application free 0x0E
3723 Application never 0x0F
3725 ACCESS RIGHTS:
3726 keys 0,1,2,3 C
3727 keys 4,5,6,7 RW
3728 keys 8,9,10,11 W
3729 keys 12,13,14,15 R
3733 DropFieldDesfire();
3734 return PM3_SUCCESS;
3737 static void DecodeFileType(uint8_t filetype) {
3738 switch (filetype) {
3739 case 0x00:
3740 PrintAndLogEx(INFO, " File Type: 0x%02X -> Standard Data File", filetype);
3741 break;
3742 case 0x01:
3743 PrintAndLogEx(INFO, " File Type: 0x%02X -> Backup Data File", filetype);
3744 break;
3745 case 0x02:
3746 PrintAndLogEx(INFO, " File Type: 0x%02X -> Value Files with Backup", filetype);
3747 break;
3748 case 0x03:
3749 PrintAndLogEx(INFO, " File Type: 0x%02X -> Linear Record Files with Backup", filetype);
3750 break;
3751 case 0x04:
3752 PrintAndLogEx(INFO, " File Type: 0x%02X -> Cyclic Record Files with Backup", filetype);
3753 break;
3754 default:
3755 PrintAndLogEx(INFO, " File Type: 0x%02X", filetype);
3756 break;
3760 static void DecodeComSet(uint8_t comset) {
3761 switch (comset) {
3762 case 0x00:
3763 PrintAndLogEx(INFO, " Com.Setting: 0x%02X -> Plain", comset);
3764 break;
3765 case 0x01:
3766 PrintAndLogEx(INFO, " Com.Setting: 0x%02X -> Plain + MAC", comset);
3767 break;
3768 case 0x03:
3769 PrintAndLogEx(INFO, " Com.Setting: 0x%02X -> Enciphered", comset);
3770 break;
3771 default:
3772 PrintAndLogEx(INFO, " Com.Setting: 0x%02X", comset);
3773 break;
3777 static char *DecodeAccessValue(uint8_t value) {
3779 char *car = (char *)calloc(255, sizeof(char));
3780 if (car == NULL)
3781 return NULL;
3783 switch (value) {
3784 case 0xE:
3785 strcat(car, "(Free Access)");
3786 break;
3787 case 0xF:
3788 strcat(car, "(Denied Access)");
3789 break;
3790 default:
3791 snprintf(car, 255, "(Access Key: %d)", value);
3792 break;
3794 return car;
3797 static void DecodeAccessRights(uint16_t accrights) {
3798 int change_access_rights = accrights & 0xF;
3799 int read_write_access = (accrights >> 4) & 0xF;
3800 int write_access = (accrights >> 8) & 0xF;
3801 int read_access = (accrights >> 12) & 0xF;
3802 char *car = DecodeAccessValue(change_access_rights);
3803 if (car == NULL) return;
3805 char *rwa = DecodeAccessValue(read_write_access);
3806 if (rwa == NULL) {
3807 free(car);
3808 return;
3811 char *wa = DecodeAccessValue(write_access);
3812 if (wa == NULL) {
3813 free(car);
3814 free(rwa);
3815 return;
3818 char *ra = DecodeAccessValue(read_access);
3819 if (ra == NULL) {
3820 free(car);
3821 free(rwa);
3822 free(wa);
3823 return;
3826 PrintAndLogEx(INFO, " Access Rights: 0x%04X - Change %s - RW %s - W %s - R %s", accrights, car, rwa, wa, ra);
3827 free(car);
3828 free(rwa);
3829 free(wa);
3830 free(ra);
3833 static int DecodeFileSettings(uint8_t *src, int src_len, int maclen) {
3834 uint8_t filetype = src[0];
3835 uint8_t comset = src[1];
3837 uint16_t accrights = (src[3] << 8) + src[2];
3838 if (src_len == 1 + 1 + 2 + 3 + maclen) {
3839 int filesize = (src[6] << 16) + (src[5] << 8) + src[4];
3840 DecodeFileType(filetype);
3841 DecodeComSet(comset);
3842 DecodeAccessRights(accrights);
3843 PrintAndLogEx(INFO, " Filesize: %d (0x%X)", filesize, filesize);
3844 return PM3_SUCCESS;
3845 } else if (src_len == 1 + 1 + 2 + 4 + 4 + 4 + 1 + maclen) {
3846 int lowerlimit = (src[7] << 24) + (src[6] << 16) + (src[5] << 8) + src[4];
3847 int upperlimit = (src[11] << 24) + (src[10] << 16) + (src[9] << 8) + src[8];
3848 int limitcredvalue = (src[15] << 24) + (src[14] << 16) + (src[13] << 8) + src[12];
3849 uint8_t limited_credit_enabled = src[17];
3850 DecodeFileType(filetype);
3851 DecodeComSet(comset);
3852 DecodeAccessRights(accrights);
3853 PrintAndLogEx(INFO, " Lower limit: %d (0x%X) - Upper limit: %d (0x%X) - limited credit value: %d (0x%X) - limited credit enabled: %d", lowerlimit, lowerlimit, upperlimit, upperlimit, limitcredvalue, limitcredvalue, limited_credit_enabled);
3854 return PM3_SUCCESS;
3855 } else if (src_len == 1 + 1 + 2 + 3 + 3 + 3 + maclen) {
3856 uint32_t recordsize = (src[6] << 16) + (src[5] << 8) + src[4];
3857 uint32_t maxrecords = (src[9] << 16) + (src[8] << 8) + src[7];
3858 uint32_t currentrecord = (src[12] << 16) + (src[11] << 8) + src[10];
3859 DecodeFileType(filetype);
3860 DecodeComSet(comset);
3861 DecodeAccessRights(accrights);
3862 PrintAndLogEx(INFO, " Record size: %d (0x%X) - MaxNumberRecords: %d (0x%X) - Current Number Records: %d (0x%X)", recordsize, recordsize, maxrecords, maxrecords, currentrecord, currentrecord);
3863 return PM3_SUCCESS;
3865 return PM3_ESOFT;
3868 static int CmdHF14ADesDump(const char *Cmd) {
3870 CLIParserContext *ctx;
3871 CLIParserInit(&ctx, "hf mfdes dump",
3872 "Tries to dump all files on a DESFire tag",
3873 "hf mfdes dump");
3875 void *argtable[] = {
3876 arg_param_begin,
3877 // arg_strx0("a", "aid", "<aid>", "Use specific AID (3 hex bytes, big endian)"),
3878 arg_param_end
3880 CLIExecWithReturn(ctx, Cmd, argtable, true);
3881 CLIParserFree(ctx);
3883 (void)Cmd; // Cmd is not used so far
3884 DropFieldDesfire();
3886 uint8_t aid[3] = {0};
3887 uint8_t app_ids[78] = {0};
3888 uint32_t app_ids_len = 0;
3890 uint8_t file_ids[33] = {0};
3891 uint32_t file_ids_len = 0;
3893 dfname_t dfnames[255];
3894 uint8_t dfname_count = 0;
3896 if (handler_desfire_appids(app_ids, &app_ids_len) != PM3_SUCCESS) {
3897 PrintAndLogEx(ERR, "Can't get list of applications on tag");
3898 DropFieldDesfire();
3899 return PM3_ESOFT;
3902 if (handler_desfire_dfnames(dfnames, &dfname_count) != PM3_SUCCESS) {
3903 PrintAndLogEx(WARNING, _RED_("Can't get DF Names"));
3906 PrintAndLogEx(NORMAL, "");
3907 PrintAndLogEx(INFO, "-- " _CYAN_("MIFARE DESFire Dump") " ----------------------");
3908 PrintAndLogEx(INFO, "-------------------------------------------------------------");
3910 for (uint32_t i = 0; i < app_ids_len; i += 3) {
3912 aid[0] = app_ids[i];
3913 aid[1] = app_ids[i + 1];
3914 aid[2] = app_ids[i + 2];
3916 PrintAndLogEx(SUCCESS, " AID : " _GREEN_("%02X%02X%02X"), aid[2], aid[1], aid[0]);
3917 if ((aid[2] >> 4) == 0xF) {
3918 uint16_t short_aid = ((aid[2] & 0xF) << 12) | (aid[1] << 4) | (aid[0] >> 4);
3919 PrintAndLogEx(SUCCESS, " AID mapped to MIFARE Classic AID (MAD): " _YELLOW_("%02X"), short_aid);
3920 PrintAndLogEx(SUCCESS, " MAD AID Cluster 0x%02X : " _YELLOW_("%s"), short_aid >> 8, cluster_to_text(short_aid >> 8));
3921 MADDFDecodeAndPrint(short_aid);
3922 } else {
3923 AIDDFDecodeAndPrint(aid);
3925 for (uint8_t m = 0; m < dfname_count; m++) {
3926 if (dfnames[m].aid[0] == aid[0] && dfnames[m].aid[1] == aid[1] && dfnames[m].aid[2] == aid[2]) {
3927 PrintAndLogEx(SUCCESS, " - DF " _YELLOW_("%02X%02X") " Name : " _YELLOW_("%s"), dfnames[m].fid[1], dfnames[m].fid[0], dfnames[m].name);
3931 uint8_t num_keys = 0;
3932 uint8_t key_setting = 0;
3933 int res = handler_desfire_getkeysettings(&key_setting, &num_keys);
3934 if (res != PM3_SUCCESS) continue;
3936 res = handler_desfire_select_application(aid);
3937 if (res != PM3_SUCCESS) continue;
3939 res = handler_desfire_fileids(file_ids, &file_ids_len);
3940 if (res != PM3_SUCCESS) continue;
3942 for (int j = (int)file_ids_len - 1; j >= 0; j--) {
3943 PrintAndLogEx(SUCCESS, "\n\n Fileid %d (0x%02x)", file_ids[j], file_ids[j]);
3945 uint8_t filesettings[20] = {0};
3946 uint32_t fileset_len = 0;
3948 res = handler_desfire_filesettings(file_ids[j], filesettings, &fileset_len);
3949 if (res != PM3_SUCCESS) continue;
3951 int maclen = 0; // To be implemented
3953 if (fileset_len == 1 + 1 + 2 + 3 + maclen) {
3954 int filesize = (filesettings[6] << 16) + (filesettings[5] << 8) + filesettings[4];
3955 mfdes_data_t fdata;
3956 fdata.fileno = file_ids[j];
3957 memset(fdata.offset, 0, 3);
3958 memset(fdata.length, 0, 3);
3960 uint8_t *data = (uint8_t *)calloc(filesize, sizeof(uint8_t));
3961 if (data == NULL) {
3962 DropFieldDesfire();
3963 return PM3_EMALLOC;
3966 fdata.data = data;
3967 res = handler_desfire_readdata(&fdata, MFDES_DATA_FILE, filesettings[1]);
3968 if (res == PM3_SUCCESS) {
3969 PrintAndLogEx(NORMAL, "\nOffset | Data | Ascii");
3970 PrintAndLogEx(NORMAL, "----------------------------------------------------------------------------");
3971 uint32_t len = le24toh(fdata.length);
3972 for (uint32_t n = 0; n < len; n += 16) {
3973 PrintAndLogEx(NORMAL, "%02d/0x%02X | %s| %s", n, n, sprint_hex(&fdata.data[n], len > 16 ? 16 : len), sprint_ascii(&fdata.data[n], len > 16 ? 16 : len));
3975 } else {
3976 PrintAndLogEx(ERR, "Couldn't read value. Error %d", res);
3977 res = handler_desfire_select_application(aid);
3978 if (res != PM3_SUCCESS) continue;
3981 free(data);
3983 } else if (fileset_len == 1 + 1 + 2 + 4 + 4 + 4 + 1 + maclen) {
3984 PrintAndLogEx(NORMAL, "\n\nValue file: 0x%0x", file_ids[j]);
3985 mfdes_value_t value;
3986 value.fileno = file_ids[j];
3987 uint32_t len = 0;
3988 res = handler_desfire_getvalue(&value, &len, filesettings[1]);
3989 if (res == PM3_SUCCESS) {
3990 PrintAndLogEx(NORMAL, "\nOffset | Value | Ascii");
3991 PrintAndLogEx(NORMAL, "----------------------------------------------------------------------------");
3992 for (uint32_t n = 0; n < len; n += 16) {
3993 PrintAndLogEx(NORMAL, "%02d/0x%02X | %s| %s", n, n, sprint_hex(&value.value[n], len > 16 ? 16 : len), sprint_ascii(&value.value[n], len > 16 ? 16 : len));
3995 } else {
3996 PrintAndLogEx(ERR, "Couldn't read value. Error %d", res);
3997 res = handler_desfire_select_application(aid);
3998 if (res != PM3_SUCCESS) continue;
4001 } else if (fileset_len == 1 + 1 + 2 + 3 + 3 + 3 + maclen) {
4002 uint32_t maxrecords = (filesettings[9] << 16) + (filesettings[8] << 8) + filesettings[7];
4003 uint32_t filesize = (filesettings[6] << 16) + (filesettings[5] << 8) + filesettings[4];
4004 mfdes_data_t fdata;
4005 fdata.fileno = file_ids[j];
4006 memset(fdata.length, 0, 3);
4007 uint8_t *data = (uint8_t *)calloc(filesize, sizeof(uint8_t));
4008 if (data == NULL) {
4009 DropFieldDesfire();
4010 return PM3_EMALLOC;
4013 fdata.data = data;
4014 for (uint32_t offset = 0; offset < maxrecords; offset++) {
4015 PrintAndLogEx(NORMAL, "\n\nRecord offset: %024x", offset);
4016 memset(data, 0, filesize);
4017 fdata.offset[0] = offset & 0xFF;
4018 fdata.offset[1] = (offset >> 8) & 0xFF;
4019 fdata.offset[2] = (offset >> 16) & 0xFF;
4020 res = handler_desfire_readdata(&fdata, MFDES_RECORD_FILE, filesettings[1]);
4021 if (res == PM3_SUCCESS) {
4022 PrintAndLogEx(NORMAL, "\nOffset | Data | Ascii");
4023 PrintAndLogEx(NORMAL, "----------------------------------------------------------------------------");
4024 uint32_t len = le24toh(fdata.length);
4025 for (uint32_t n = 0; n < len; n += 16) {
4026 PrintAndLogEx(NORMAL, "%02d/0x%02X | %s| %s", n, n, sprint_hex(&fdata.data[n], len > 16 ? 16 : len), sprint_ascii(&fdata.data[n], len > 16 ? 16 : len));
4028 } else {
4029 res = handler_desfire_select_application(aid);
4030 if (res != PM3_SUCCESS) continue;
4033 free(data);
4038 PrintAndLogEx(INFO, "-------------------------------------------------------------");
4039 DropFieldDesfire();
4040 return PM3_SUCCESS;
4043 static int CmdHF14ADesEnumApplications(const char *Cmd) {
4044 CLIParserContext *ctx;
4045 CLIParserInit(&ctx, "hf mfdes enum",
4046 "Enumerate all AID's on MIFARE DESfire tag",
4047 "hf mfdes enum");
4049 void *argtable[] = {
4050 arg_param_begin,
4051 arg_param_end
4053 CLIExecWithReturn(ctx, Cmd, argtable, true);
4054 CLIParserFree(ctx);
4056 DropFieldDesfire();
4058 uint8_t aid[3] = {0};
4059 uint8_t app_ids[78] = {0};
4060 uint32_t app_ids_len = 0;
4062 uint8_t file_ids[33] = {0};
4063 uint32_t file_ids_len = 0;
4065 dfname_t dfnames[255];
4066 uint8_t dfname_count = 0;
4068 if (handler_desfire_appids(app_ids, &app_ids_len) != PM3_SUCCESS) {
4069 PrintAndLogEx(ERR, "Can't get list of applications on tag");
4070 DropFieldDesfire();
4071 return PM3_ESOFT;
4074 if (handler_desfire_dfnames(dfnames, &dfname_count) != PM3_SUCCESS) {
4075 PrintAndLogEx(WARNING, _RED_("Can't get DF Names"));
4078 PrintAndLogEx(NORMAL, "");
4079 PrintAndLogEx(INFO, "-- MIFARE DESFire Enumerate applications --------------------");
4080 PrintAndLogEx(INFO, "-------------------------------------------------------------");
4081 PrintAndLogEx(SUCCESS, " Tag report " _GREEN_("%d") " application%c", app_ids_len / 3, (app_ids_len == 3) ? ' ' : 's');
4083 for (uint32_t i = 0; i < app_ids_len; i += 3) {
4085 aid[0] = app_ids[i];
4086 aid[1] = app_ids[i + 1];
4087 aid[2] = app_ids[i + 2];
4089 PrintAndLogEx(NORMAL, "");
4091 if (memcmp(aid, "\x00\x00\x00", 3) == 0) {
4092 // CARD MASTER KEY
4093 PrintAndLogEx(INFO, "--- " _CYAN_("CMK - PICC, Card Master Key settings"));
4094 } else {
4095 PrintAndLogEx(SUCCESS, "--- " _CYAN_("AMK - Application Master Key settings"));
4098 PrintAndLogEx(SUCCESS, " AID : " _GREEN_("%02X%02X%02X"), aid[2], aid[1], aid[0]);
4099 if ((aid[2] >> 4) == 0xF) {
4100 uint16_t short_aid = ((aid[2] & 0xF) << 12) | (aid[1] << 4) | (aid[0] >> 4);
4101 PrintAndLogEx(SUCCESS, " AID mapped to MIFARE Classic AID (MAD): " _YELLOW_("%02X"), short_aid);
4102 PrintAndLogEx(SUCCESS, " MAD AID Cluster 0x%02X : " _YELLOW_("%s"), short_aid >> 8, cluster_to_text(short_aid >> 8));
4103 MADDFDecodeAndPrint(short_aid);
4104 } else {
4105 AIDDFDecodeAndPrint(aid);
4107 for (uint8_t m = 0; m < dfname_count; m++) {
4108 if (dfnames[m].aid[0] == aid[0] && dfnames[m].aid[1] == aid[1] && dfnames[m].aid[2] == aid[2]) {
4109 PrintAndLogEx(SUCCESS, " - DF " _YELLOW_("%02X%02X") " Name : " _YELLOW_("%s"), dfnames[m].fid[1], dfnames[m].fid[0], dfnames[m].name);
4113 int res = getKeySettings(aid);
4114 if (res != PM3_SUCCESS) continue;
4116 res = handler_desfire_select_application(aid);
4117 if (res != PM3_SUCCESS) continue;
4119 res = handler_desfire_fileids(file_ids, &file_ids_len);
4120 if (res != PM3_SUCCESS) continue;
4122 PrintAndLogEx(SUCCESS, " Tag report " _GREEN_("%d") " file%c", file_ids_len, (file_ids_len == 1) ? ' ' : 's');
4123 for (int j = (int)file_ids_len - 1; j >= 0; j--) {
4124 PrintAndLogEx(SUCCESS, " Fileid %d (0x%02x)", file_ids[j], file_ids[j]);
4126 uint8_t filesettings[20] = {0};
4127 uint32_t fileset_len = 0;
4128 uint32_t maclen = 0; // To be implemented
4130 res = handler_desfire_filesettings(file_ids[j], filesettings, &fileset_len);
4131 if (res != PM3_SUCCESS) continue;
4133 if (DecodeFileSettings(filesettings, fileset_len, maclen) != PM3_SUCCESS) {
4134 PrintAndLogEx(INFO, " Settings [%u] %s", fileset_len, sprint_hex(filesettings, fileset_len));
4139 PrintAndLogEx(INFO, "-------------------------------------------------------------");
4140 DropFieldDesfire();
4141 return PM3_SUCCESS;
4144 static int CmdHF14ADesBruteApps(const char *Cmd) {
4145 CLIParserContext *ctx;
4146 CLIParserInit(&ctx, "hf mfdes bruteaid",
4147 "Recover AIDs by bruteforce.\n"
4148 "WARNING: This command takes a long time",
4149 "hf mfdes bruteaid -> Search all apps\n"
4150 "hf mfdes bruteaid -s F0000F -i 16 -> Search MAD range manually");
4152 void *argtable[] = {
4153 arg_param_begin,
4154 arg_strx0("s", "start", "<hex>", "Starting App ID as hex bytes (3 bytes, big endian)"),
4155 arg_strx0("e", "end", "<hex>", "Last App ID as hex bytes (3 bytes, big endian)"),
4156 arg_int0("i", "step", "<dec>", "Increment step when bruteforcing"),
4157 arg_lit0("m", "mad", "Only bruteforce the MAD range"),
4158 arg_param_end
4160 CLIExecWithReturn(ctx, Cmd, argtable, true);
4161 uint8_t startAid[3] = {0};
4162 uint8_t endAid[3] = {0xFF, 0xFF, 0xFF};
4163 int startLen = 0;
4164 int endLen = 0;
4165 CLIGetHexWithReturn(ctx, 1, startAid, &startLen);
4166 CLIGetHexWithReturn(ctx, 2, endAid, &endLen);
4167 uint32_t idIncrement = arg_get_int_def(ctx, 3, 1);
4168 bool mad = arg_get_lit(ctx, 4);
4169 CLIParserFree(ctx);
4170 // TODO: We need to check the tag version, EV1 should stop after 26 apps are found
4171 if (mad) {
4172 idIncrement = 0x10;
4173 startAid[0] = 0xF0;
4174 startAid[1] = 0x00;
4175 startAid[2] = 0x0F;
4177 uint32_t idStart = le24toh(startAid);
4178 uint32_t idEnd = le24toh(endAid);
4179 PrintAndLogEx(INFO, "Enumerating through all AIDs manually, this will take a while!");
4180 for (uint32_t id = idStart; id <= idEnd && id >= idStart; id += idIncrement) {
4181 if (kbd_enter_pressed()) break;
4182 int progress = ((id - idStart) * 100) / ((idEnd - idStart));
4183 PrintAndLogEx(INPLACE, "Progress: %d %%, current AID: %06X", progress, id);
4184 uint8_t appId[3] = {0};
4185 htole24(id, appId);
4186 sAPDU apdu = {0x90, MFDES_SELECT_APPLICATION, 0x00, 0x00, 0x03, appId}; //0x5a
4187 uint16_t sw = 0;
4188 uint8_t data[255 * 5] = {0x00};
4189 uint32_t resplen = 0;
4190 DESFIRESendApdu(!tag->rf_field_on, true, apdu, data, sizeof(data), &resplen, &sw);
4191 if (sw == status(MFDES_S_OPERATION_OK)) {
4192 printf("\33[2K\r"); // clear current line before printing
4193 PrintAndLogEx(SUCCESS, "Got new APPID %06X", id);
4196 PrintAndLogEx(SUCCESS, "Done");
4197 DropFieldDesfire();
4198 return PM3_SUCCESS;
4201 static int CmdHF14ADesChangeKey(const char *Cmd) {
4202 CLIParserContext *ctx;
4203 CLIParserInit(&ctx, "hf mfdes changekey",
4204 "Change MIFARE DESFire Key.\n"
4205 "Make sure to select aid or authenticate aid before running this command.",
4206 "hf mfdes changekey -n 0 -t 1 -k 0000000000000000 -u 1 -j 0102030405060708 -> DES, keynumber 0"
4209 void *argtable[] = {
4210 arg_param_begin,
4211 arg_int0("n", "keyno", "<dec>", "Key number used for authentification"),
4212 arg_int0("t", "algo", "<dec>", "Current key algo (1 = DES, 2 = 3DES(2K2DES), 3 = 3K3DES, 4 = AES)"),
4213 arg_str0("k", "key", "<hex>", "Current Key (HEX 8-24 bytes)"),
4214 arg_int0("u", "newalgo", "<dec>", "New key algo (1 = DES, 2 = 3DES(2K2DES), 3 = 3K3DES, 4 = AES)"),
4215 arg_str0("j", "newkey", "<hex>", "New Key (HEX 8-24 bytes)"),
4216 arg_int0("v", "aesver", "<dec>", "AES version (if AES is used)"),
4217 arg_param_end
4219 CLIExecWithReturn(ctx, Cmd, argtable, false);
4221 uint8_t cmdKeyNo = arg_get_int_def(ctx, 1, 0);
4222 uint8_t cmdAuthAlgo = arg_get_int_def(ctx, 2, 0);
4223 uint8_t key[24] = {0};
4224 int keylen = 0;
4225 int res_klen = CLIParamHexToBuf(arg_get_str(ctx, 3), key, 24, &keylen);
4227 uint8_t newcmdAuthAlgo = arg_get_int_def(ctx, 4, 0);
4228 uint8_t newkey[24] = {0};
4229 int newkeylen = 0;
4230 int res_newklen = CLIParamHexToBuf(arg_get_str(ctx, 5), newkey, 24, &newkeylen);
4232 uint8_t aesversion = arg_get_int_def(ctx, 6, 0);
4233 CLIParserFree(ctx);
4235 //DropFieldDesfire();
4236 // NR DESC KEYLENGHT
4237 // ------------------------
4238 // 1 = DES 8
4239 // 2 = 3DES 16
4240 // 3 = 3K 3DES 24
4241 // 4 = AES 16
4242 uint8_t keylength = 8;
4243 if (cmdAuthAlgo == MFDES_ALGO_AES) {
4244 keylength = 16;
4245 } else if (cmdAuthAlgo == MFDES_ALGO_3DES) {
4246 keylength = 16;
4247 } else if (cmdAuthAlgo == MFDES_ALGO_DES) {
4248 keylength = 8;
4249 } else if (cmdAuthAlgo == MFDES_ALGO_3K3DES) {
4250 keylength = 24;
4253 uint8_t newkeylength = 8;
4254 if (newcmdAuthAlgo == MFDES_ALGO_AES) {
4255 newkeylength = 16;
4256 } else if (newcmdAuthAlgo == MFDES_ALGO_3DES) {
4257 newkeylength = 16;
4258 } else if (newcmdAuthAlgo == MFDES_ALGO_DES) {
4259 newkeylength = 8;
4260 } else if (newcmdAuthAlgo == MFDES_ALGO_3K3DES) {
4261 newkeylength = 24;
4264 if (res_klen || (keylen < 8) || (keylen > 24)) {
4265 PrintAndLogEx(ERR, "Specified key must have %d bytes length", keylen);
4266 return PM3_EINVARG;
4269 if (res_newklen || (newkeylen < 8) || (newkeylen > 24)) {
4270 PrintAndLogEx(ERR, "Specified new key must have %d bytes length", newkeylen);
4271 return PM3_EINVARG;
4274 if (keylen != keylength) {
4275 PrintAndLogEx(WARNING, "Key must include %d hex symbols, got %d", keylength, keylen);
4276 return PM3_EINVARG;
4279 if (newkeylen != newkeylength) {
4280 PrintAndLogEx(WARNING, "New key must include %d hex symbols, got %d", keylength, newkeylen);
4281 return PM3_EINVARG;
4284 PrintAndLogEx(INFO, "changing key number " _YELLOW_("0x%02x"), cmdKeyNo);
4285 PrintAndLogEx(INFO, "old key: %s ( %s )", sprint_hex_inrow(key, keylen), getEncryptionAlgoStr(cmdAuthAlgo));
4286 PrintAndLogEx(INFO, "new key: %s ( %s )", sprint_hex_inrow(newkey, newkeylen), getEncryptionAlgoStr(newcmdAuthAlgo));
4288 int res = mifare_desfire_change_key(cmdKeyNo, newkey, newcmdAuthAlgo, key, cmdAuthAlgo, aesversion);
4289 if (res == PM3_SUCCESS) {
4290 PrintAndLogEx(SUCCESS, "Change key ( " _GREEN_("ok") " )");
4291 } else {
4292 PrintAndLogEx(FAILED, "Change key ( " _RED_("fail") " )");
4294 return res;
4298 // MIAFRE DESFire Authentication
4300 #define BUFSIZE 256
4301 static int CmdHF14ADesAuth(const char *Cmd) {
4302 //DropFieldDesfire();
4303 // NR DESC KEYLENGHT
4304 // ------------------------
4305 // 1 = DES 8
4306 // 2 = 3DES 16
4307 // 3 = 3K 3DES 24
4308 // 4 = AES 16
4309 uint8_t keylength = 8;
4311 CLIParserContext *ctx;
4312 CLIParserInit(&ctx, "hf mfdes auth",
4313 "Authenticates MIFARE DESFire using Key",
4314 "hf mfdes auth -m 3 -t 4 -a 808301 -n 0 -k 00000000000000000000000000000000 -> AES,keynumber 0, aid 0x803201\n"
4315 "hf mfdes auth -m 2 -t 2 -a 000000 -n 1 -k 00000000000000000000000000000000 -> 3DES,keynumber 1, aid 0x000000\n"
4316 "hf mfdes auth -m 1 -t 1 -a 000000 -n 2 -k 0000000000000000 -> DES,keynumber 2, aid 0x000000\n"
4317 "hf mfdes auth -m 1 -t 1 -a 000000 -n 0 -> DES, defaultkey, aid 0x000000\n"
4318 "hf mfdes auth -m 2 -t 2 -a 000000 -n 0 -> 3DES, defaultkey, aid 0x000000\n"
4319 "hf mfdes auth -m 3 -t 4 -a 000000 -n 0 -> 3K3DES, defaultkey, aid 0x000000\n"
4320 "hf mfdes auth -m 3 -t 4 -a 000000 -n 0 -> AES, defaultkey, aid 0x000000"
4323 void *argtable[] = {
4324 arg_param_begin,
4325 arg_int0("m", "type", "<type>", "Auth type (1=normal, 2=iso, 3=aes)"),
4326 arg_int0("t", "algo", "<algo>", "Crypt algo (1=DES, 2=3DES(2K2DES), 3=3K3DES, 4=AES)"),
4327 arg_strx0("a", "aid", "<aid>", "AID used for authentification (HEX 3 bytes)"),
4328 arg_int0("n", "keyno", "<keyno>", "Key number used for authentification"),
4329 arg_str0("k", "key", "<Key>", "Key for checking (HEX 8-24 bytes)"),
4330 arg_int0("d", "kdf", "<kdf>", "Key Derivation Function (KDF) (0=None, 1=AN10922, 2=Gallagher)"),
4331 arg_str0("i", "kdfi", "<kdfi>", "KDF input (HEX 1-31 bytes)"),
4332 arg_param_end
4334 CLIExecWithReturn(ctx, Cmd, argtable, false);
4336 uint8_t cmdAuthMode = arg_get_int_def(ctx, 1, 0);
4337 uint8_t cmdAuthAlgo = arg_get_int_def(ctx, 2, 0);
4339 int aidlength = 3;
4340 uint8_t aid[3] = {0};
4341 CLIGetHexWithReturn(ctx, 3, aid, &aidlength);
4342 swap24(aid);
4343 uint8_t cmdKeyNo = arg_get_int_def(ctx, 4, 0);
4345 uint8_t key[24] = {0};
4346 int keylen = 0;
4347 CLIGetHexWithReturn(ctx, 5, key, &keylen);
4349 uint8_t cmdKDFAlgo = arg_get_int_def(ctx, 6, 0);
4350 // Get KDF input
4351 uint8_t kdfInput[31] = {0};
4352 int kdfInputLen = 0;
4353 CLIGetHexWithReturn(ctx, 7, kdfInput, &kdfInputLen);
4355 CLIParserFree(ctx);
4357 if (cmdAuthAlgo == MFDES_ALGO_AES) {
4358 if (keylen == 0) {
4359 keylen = 16;
4360 memcpy(key, aesdefaultkeys[0], keylen);
4362 keylength = 16;
4363 } else if (cmdAuthAlgo == MFDES_ALGO_3DES) {
4364 if (keylen == 0) {
4365 keylen = 16;
4366 memcpy(key, aesdefaultkeys[0], keylen);
4368 keylength = 16;
4369 } else if (cmdAuthAlgo == MFDES_ALGO_DES) {
4370 if (keylen == 0) {
4371 keylen = 8;
4372 memcpy(key, desdefaultkeys[0], keylen);
4374 keylength = 8;
4375 } else if (cmdAuthAlgo == MFDES_ALGO_3K3DES) {
4376 if (keylen == 0) {
4377 keylen = 24;
4378 memcpy(key, k3kdefaultkeys[0], keylen);
4380 keylength = 24;
4383 if ((keylen < 8) || (keylen > 24)) {
4384 PrintAndLogEx(ERR, "Specified key must have %d bytes length.", keylen);
4385 return PM3_EINVARG;
4388 if (keylen != keylength) {
4389 PrintAndLogEx(WARNING, "Key must include %d HEX symbols", keylength);
4390 return PM3_EINVARG;
4393 // AID
4394 if (aidlength != 3) {
4395 PrintAndLogEx(WARNING, "aid must include %d HEX symbols", 3);
4396 return PM3_EINVARG;
4399 mfdes_auth_res_t rpayload;
4400 int error = desfire_authenticate(cmdAuthMode, cmdAuthAlgo, aid, key, cmdKeyNo, cmdKDFAlgo, kdfInputLen, kdfInput, &rpayload);
4401 if (error == PM3_SUCCESS) {
4402 PrintAndLogEx(SUCCESS, " Key : " _GREEN_("%s"), sprint_hex(key, keylength));
4403 PrintAndLogEx(SUCCESS, " SESSION : " _GREEN_("%s"), sprint_hex(rpayload.sessionkey, keylength));
4404 PrintAndLogEx(INFO, "-------------------------------------------------------------");
4405 } else {
4406 AuthToError(error);
4407 return PM3_ESOFT;
4409 PrintAndLogEx(INFO, "-------------------------------------------------------------");
4410 return PM3_SUCCESS;
4413 static void DesFill2bPattern(
4414 uint8_t deskeyList[MAX_KEYS_LIST_LEN][8], uint32_t *deskeyListLen,
4415 uint8_t aeskeyList[MAX_KEYS_LIST_LEN][16], uint32_t *aeskeyListLen,
4416 uint8_t k3kkeyList[MAX_KEYS_LIST_LEN][24], uint32_t *k3kkeyListLen, uint32_t *startPattern) {
4418 for (uint32_t pt = *startPattern; pt < 0x10000; pt++) {
4419 if (*deskeyListLen != MAX_KEYS_LIST_LEN) {
4420 deskeyList[*deskeyListLen][0] = (pt >> 8) & 0xff;
4421 deskeyList[*deskeyListLen][1] = pt & 0xff;
4422 memcpy(&deskeyList[*deskeyListLen][2], &deskeyList[*deskeyListLen][0], 2);
4423 memcpy(&deskeyList[*deskeyListLen][4], &deskeyList[*deskeyListLen][0], 4);
4424 (*deskeyListLen)++;
4426 if (*aeskeyListLen != MAX_KEYS_LIST_LEN) {
4427 aeskeyList[*aeskeyListLen][0] = (pt >> 8) & 0xff;
4428 aeskeyList[*aeskeyListLen][1] = pt & 0xff;
4429 memcpy(&aeskeyList[*aeskeyListLen][2], &aeskeyList[*aeskeyListLen][0], 2);
4430 memcpy(&aeskeyList[*aeskeyListLen][4], &aeskeyList[*aeskeyListLen][0], 4);
4431 memcpy(&aeskeyList[*aeskeyListLen][8], &aeskeyList[*aeskeyListLen][0], 8);
4432 (*aeskeyListLen)++;
4434 if (*k3kkeyListLen != MAX_KEYS_LIST_LEN) {
4435 k3kkeyList[*k3kkeyListLen][0] = (pt >> 8) & 0xff;
4436 k3kkeyList[*k3kkeyListLen][1] = pt & 0xff;
4437 memcpy(&k3kkeyList[*k3kkeyListLen][2], &k3kkeyList[*k3kkeyListLen][0], 2);
4438 memcpy(&k3kkeyList[*k3kkeyListLen][4], &k3kkeyList[*k3kkeyListLen][0], 4);
4439 memcpy(&k3kkeyList[*k3kkeyListLen][8], &k3kkeyList[*k3kkeyListLen][0], 8);
4440 memcpy(&k3kkeyList[*k3kkeyListLen][16], &k3kkeyList[*k3kkeyListLen][0], 4);
4441 (*k3kkeyListLen)++;
4444 *startPattern = pt;
4445 if ((*deskeyListLen == MAX_KEYS_LIST_LEN) &&
4446 (*aeskeyListLen == MAX_KEYS_LIST_LEN) &&
4447 (*k3kkeyListLen == MAX_KEYS_LIST_LEN)) {
4448 break;
4451 (*startPattern)++;
4454 static int AuthCheckDesfire(uint8_t *aid,
4455 uint8_t deskeyList[MAX_KEYS_LIST_LEN][8], uint32_t deskeyListLen,
4456 uint8_t aeskeyList[MAX_KEYS_LIST_LEN][16], uint32_t aeskeyListLen,
4457 uint8_t k3kkeyList[MAX_KEYS_LIST_LEN][24], uint32_t k3kkeyListLen,
4458 uint8_t cmdKdfAlgo, uint8_t kdfInputLen, uint8_t *kdfInput,
4459 uint8_t foundKeys[4][0xE][24 + 1], bool *result) {
4461 uint32_t curaid = (aid[0] & 0xFF) + ((aid[1] & 0xFF) << 8) + ((aid[2] & 0xFF) << 16);
4463 int res = handler_desfire_select_application(aid);
4464 if (res != PM3_SUCCESS) {
4465 PrintAndLogEx(ERR, "AID 0x%06X does not exist.", curaid);
4466 return res;
4469 int usedkeys[0xF] = {0};
4470 bool des = false;
4471 bool tdes = false;
4472 bool aes = false;
4473 bool k3kdes = false;
4475 uint8_t num_keys = 0;
4476 uint8_t key_setting = 0;
4477 res = handler_desfire_getkeysettings(&key_setting, &num_keys);
4478 if (res != PM3_SUCCESS) {
4479 PrintAndLogEx(ERR, "Could not get key settings");
4480 return res;
4483 if (memcmp(aid, "\x00\x00\x00", 3) != 0) {
4484 uint8_t file_ids[33] = {0};
4485 uint32_t file_ids_len = 0;
4486 // Get File IDs
4487 if (handler_desfire_fileids(file_ids, &file_ids_len) == PM3_SUCCESS) {
4489 for (int j = (int)file_ids_len - 1; j >= 0; j--) {
4491 uint8_t filesettings[20] = {0};
4492 uint32_t fileset_len = 0;
4494 res = handler_desfire_filesettings(file_ids[j], filesettings, &fileset_len);
4495 if (res == PM3_SUCCESS) {
4497 uint16_t accrights = (filesettings[3] << 8) + filesettings[2];
4498 uint8_t change_access_rights = accrights & 0xF;
4499 uint8_t read_write_access = (accrights >> 4) & 0xF;
4500 uint8_t write_access = (accrights >> 8) & 0xF;
4501 uint8_t read_access = (accrights >> 12) & 0xF;
4503 if (change_access_rights == 0xE) change_access_rights = 0x0;
4504 if (read_write_access == 0xE) read_write_access = 0x0;
4505 if (write_access == 0xE) write_access = 0x0;
4506 if (read_access == 0xE) read_access = 0x0;
4508 usedkeys[change_access_rights] = 1;
4509 usedkeys[read_write_access] = 1;
4510 usedkeys[write_access] = 1;
4511 usedkeys[read_access] = 1;
4513 if (res == PM3_SUCCESS) {
4514 switch (num_keys >> 6) {
4515 case 0:
4516 des = true;
4517 tdes = true;
4518 break;
4519 case 1:
4520 k3kdes = true;
4521 break;
4522 case 2:
4523 aes = true;
4524 break;
4525 default:
4526 break;
4532 if (file_ids_len == 0) {
4533 for (uint8_t z = 0; z < 0xE; z++) {
4534 usedkeys[z] = 1;
4535 des = true;
4536 tdes = true;
4537 aes = true;
4538 k3kdes = true;
4542 } else {
4543 des = true;
4546 int error;
4547 bool badlen = false;
4549 if (des) {
4551 for (uint8_t keyno = 0; keyno < 0xE; keyno++) {
4553 if (usedkeys[keyno] == 1 && foundKeys[0][keyno][0] == 0) {
4554 for (uint32_t curkey = 0; curkey < deskeyListLen; curkey++) {
4555 mfdes_auth_res_t rpayload;
4556 error = desfire_authenticate(MFDES_AUTH_DES, MFDES_ALGO_DES, aid, deskeyList[curkey], keyno, 0, 0, NULL, &rpayload);
4557 if (error == PM3_SUCCESS) {
4558 PrintAndLogEx(SUCCESS, "AID 0x%06X, Found DES Key %u : " _GREEN_("%s"), curaid, keyno, sprint_hex(deskeyList[curkey], 8));
4559 foundKeys[0][keyno][0] = 0x01;
4560 *result = true;
4561 memcpy(&foundKeys[0][keyno][1], deskeyList[curkey], 8);
4562 break;
4563 } else if (error < 7) {
4564 badlen = true;
4565 DropFieldDesfire();
4566 res = handler_desfire_select_application(aid);
4567 if (res != PM3_SUCCESS) {
4568 return res;
4570 break;
4573 if (badlen == true) {
4574 badlen = false;
4575 break;
4581 if (tdes) {
4583 for (uint8_t keyno = 0; keyno < 0xE; keyno++) {
4585 if (usedkeys[keyno] == 1 && foundKeys[1][keyno][0] == 0) {
4586 for (uint32_t curkey = 0; curkey < aeskeyListLen; curkey++) {
4587 mfdes_auth_res_t rpayload;
4588 error = desfire_authenticate(MFDES_AUTH_DES, MFDES_ALGO_3DES, aid, aeskeyList[curkey], keyno, 0, 0, NULL, &rpayload);
4589 if (error == PM3_SUCCESS) {
4590 PrintAndLogEx(SUCCESS, "AID 0x%06X, Found 3DES Key %u : " _GREEN_("%s"), curaid, keyno, sprint_hex(aeskeyList[curkey], 16));
4591 foundKeys[1][keyno][0] = 0x01;
4592 *result = true;
4593 memcpy(&foundKeys[1][keyno][1], aeskeyList[curkey], 16);
4594 break;
4595 } else if (error < 7) {
4596 badlen = true;
4597 DropFieldDesfire();
4598 res = handler_desfire_select_application(aid);
4599 if (res != PM3_SUCCESS) {
4600 return res;
4602 break;
4605 if (badlen == true) {
4606 badlen = false;
4607 break;
4613 if (aes) {
4615 for (uint8_t keyno = 0; keyno < 0xE; keyno++) {
4617 if (usedkeys[keyno] == 1 && foundKeys[2][keyno][0] == 0) {
4618 for (uint32_t curkey = 0; curkey < aeskeyListLen; curkey++) {
4619 mfdes_auth_res_t rpayload;
4620 error = desfire_authenticate(MFDES_AUTH_AES, MFDES_ALGO_AES, aid, aeskeyList[curkey], keyno, cmdKdfAlgo, kdfInputLen, kdfInput, &rpayload);
4621 if (error == PM3_SUCCESS) {
4622 PrintAndLogEx(SUCCESS, "AID 0x%06X, Found AES Key %u : " _GREEN_("%s"), curaid, keyno, sprint_hex(aeskeyList[curkey], 16));
4623 foundKeys[2][keyno][0] = 0x01;
4624 *result = true;
4625 memcpy(&foundKeys[2][keyno][1], aeskeyList[curkey], 16);
4626 break;
4627 } else if (error < 7) {
4628 badlen = true;
4629 DropFieldDesfire();
4630 res = handler_desfire_select_application(aid);
4631 if (res != PM3_SUCCESS) {
4632 return res;
4634 break;
4637 if (badlen == true) {
4638 badlen = false;
4639 break;
4645 if (k3kdes) {
4647 for (uint8_t keyno = 0; keyno < 0xE; keyno++) {
4649 if (usedkeys[keyno] == 1 && foundKeys[3][keyno][0] == 0) {
4650 for (uint32_t curkey = 0; curkey < k3kkeyListLen; curkey++) {
4651 mfdes_auth_res_t rpayload;
4652 error = desfire_authenticate(MFDES_AUTH_ISO, MFDES_ALGO_3K3DES, aid, k3kkeyList[curkey], keyno, 0, 0, NULL, &rpayload);
4653 if (error == PM3_SUCCESS) {
4654 PrintAndLogEx(SUCCESS, "AID 0x%06X, Found 3K3 Key %u : " _GREEN_("%s"), curaid, keyno, sprint_hex(k3kkeyList[curkey], 24));
4655 foundKeys[3][keyno][0] = 0x01;
4656 *result = true;
4657 memcpy(&foundKeys[3][keyno][1], k3kkeyList[curkey], 16);
4658 break;
4659 } else if (error < 7) {
4660 badlen = true;
4661 DropFieldDesfire();
4662 res = handler_desfire_select_application(aid);
4663 if (res != PM3_SUCCESS) {
4664 return res;
4666 break;
4670 if (badlen == true) {
4671 break;
4676 DropFieldDesfire();
4677 return PM3_SUCCESS;
4680 static int CmdHF14aDesChk(const char *Cmd) {
4681 int res;
4682 uint8_t deskeyList[MAX_KEYS_LIST_LEN][8] = {{0}};
4683 uint8_t aeskeyList[MAX_KEYS_LIST_LEN][16] = {{0}};
4684 uint8_t k3kkeyList[MAX_KEYS_LIST_LEN][MAX_KEY_LEN] = {{0}};
4685 uint32_t deskeyListLen = 0;
4686 uint32_t aeskeyListLen = 0;
4687 uint32_t k3kkeyListLen = 0;
4688 uint8_t foundKeys[4][0xE][24 + 1] = {{{0}}};
4690 CLIParserContext *ctx;
4691 CLIParserInit(&ctx, "hf mfdes chk",
4692 "Checks keys with MIFARE DESFire card.",
4693 "hf mfdes chk -a 123456 -k 000102030405060708090a0b0c0d0e0f -> check key on aid 0x123456\n"
4694 "hf mfdes chk -d mfdes_default_keys -> check keys from dictionary against all existing aid on card\n"
4695 "hf mfdes chk -d mfdes_default_keys -a 123456 -> check keys from dictionary against aid 0x123456\n"
4696 "hf mfdes chk -a 123456 --pattern1b -j keys -> check all 1-byte keys pattern on aid 0x123456 and save found keys to json\n"
4697 "hf mfdes chk -a 123456 --pattern2b --startp2b FA00 -> check all 2-byte keys pattern on aid 0x123456. Start from key FA00FA00...FA00");
4699 void *argtable[] = {
4700 arg_param_begin,
4701 arg_strx0("a", "aid", "<aid>", "Use specific AID (3 hex bytes, big endian)"),
4702 arg_str0("k", "key", "<Key>", "Key for checking (HEX 16 bytes)"),
4703 arg_str0("d", "dict", "<file>", "File with keys dictionary"),
4704 arg_lit0(NULL, "pattern1b", "Check all 1-byte combinations of key (0000...0000, 0101...0101, 0202...0202, ...)"),
4705 arg_lit0(NULL, "pattern2b", "Check all 2-byte combinations of key (0000...0000, 0001...0001, 0002...0002, ...)"),
4706 arg_str0(NULL, "startp2b", "<Pattern>", "Start key (2-byte HEX) for 2-byte search (use with `--pattern2b`)"),
4707 arg_str0("j", "json", "<file>", "Json file to save keys"),
4708 arg_lit0("v", "verbose", "Verbose mode."),
4709 arg_int0("f", "kdf", "<kdf>", "Key Derivation Function (KDF) (0=None, 1=AN10922, 2=Gallagher)"),
4710 arg_str0("i", "kdfi", "<kdfi>", "KDF input (HEX 1-31 bytes)"),
4711 arg_param_end
4713 CLIExecWithReturn(ctx, Cmd, argtable, false);
4715 int aidlength = 0;
4716 uint8_t aid[3] = {0};
4717 CLIGetHexWithReturn(ctx, 1, aid, &aidlength);
4718 swap24(aid);
4719 uint8_t vkey[16] = {0};
4720 int vkeylen = 0;
4721 CLIGetHexWithReturn(ctx, 2, vkey, &vkeylen);
4723 if (vkeylen > 0) {
4724 if (vkeylen == 8) {
4725 memcpy(&deskeyList[deskeyListLen], vkey, 8);
4726 deskeyListLen++;
4727 } else if (vkeylen == 16) {
4728 memcpy(&aeskeyList[aeskeyListLen], vkey, 16);
4729 aeskeyListLen++;
4730 } else if (vkeylen == 24) {
4731 memcpy(&k3kkeyList[k3kkeyListLen], vkey, 16);
4732 k3kkeyListLen++;
4733 } else {
4734 PrintAndLogEx(ERR, "Specified key must have 8, 16 or 24 bytes length.");
4735 CLIParserFree(ctx);
4736 return PM3_EINVARG;
4740 uint8_t dict_filename[FILE_PATH_SIZE + 2] = {0};
4741 int dict_filenamelen = 0;
4742 if (CLIParamStrToBuf(arg_get_str(ctx, 3), dict_filename, FILE_PATH_SIZE, &dict_filenamelen)) {
4743 PrintAndLogEx(FAILED, "File name too long or invalid.");
4744 CLIParserFree(ctx);
4745 return PM3_EINVARG;
4748 bool pattern1b = arg_get_lit(ctx, 4);
4749 bool pattern2b = arg_get_lit(ctx, 5);
4751 if (pattern1b && pattern2b) {
4752 PrintAndLogEx(ERR, "Pattern search mode must be 2-byte or 1-byte only.");
4753 CLIParserFree(ctx);
4754 return PM3_EINVARG;
4757 if (dict_filenamelen && (pattern1b || pattern2b)) {
4758 PrintAndLogEx(ERR, "Pattern search mode and dictionary mode can't be used in one command.");
4759 CLIParserFree(ctx);
4760 return PM3_EINVARG;
4763 uint32_t startPattern = 0x0000;
4764 uint8_t vpattern[2];
4765 int vpatternlen = 0;
4766 CLIGetHexWithReturn(ctx, 6, vpattern, &vpatternlen);
4767 if (vpatternlen > 0) {
4768 if (vpatternlen <= 2) {
4769 startPattern = (vpattern[0] << 8) + vpattern[1];
4770 } else {
4771 PrintAndLogEx(ERR, "Pattern must be 2-byte length.");
4772 CLIParserFree(ctx);
4773 return PM3_EINVARG;
4775 if (!pattern2b)
4776 PrintAndLogEx(WARNING, "Pattern entered, but search mode not is 2-byte search.");
4779 uint8_t jsonname[250] = {0};
4780 int jsonnamelen = 0;
4781 if (CLIParamStrToBuf(arg_get_str(ctx, 7), jsonname, sizeof(jsonname), &jsonnamelen)) {
4782 PrintAndLogEx(ERR, "Invalid json name.");
4783 CLIParserFree(ctx);
4784 return PM3_EINVARG;
4786 jsonname[jsonnamelen] = 0;
4788 bool verbose = arg_get_lit(ctx, 8);
4790 // Get KDF input
4791 uint8_t kdfInput[31] = {0};
4792 int kdfInputLen = 0;
4793 uint8_t cmdKDFAlgo = arg_get_int_def(ctx, 9, 0);
4794 CLIGetHexWithReturn(ctx, 10, kdfInput, &kdfInputLen);
4796 CLIParserFree(ctx);
4798 // 1-byte pattern search mode
4799 if (pattern1b) {
4800 for (uint32_t i = 0; i < 0x100; i++)
4801 memset(aeskeyList[i], i, 16);
4802 for (uint32_t i = 0; i < 0x100; i++)
4803 memset(deskeyList[i], i, 8);
4804 for (uint32_t i = 0; i < 0x100; i++)
4805 memset(k3kkeyList[i], i, 24);
4806 aeskeyListLen = 0x100;
4807 deskeyListLen = 0x100;
4808 k3kkeyListLen = 0x100;
4811 // 2-byte pattern search mode
4812 if (pattern2b) {
4813 DesFill2bPattern(deskeyList, &deskeyListLen, aeskeyList, &aeskeyListLen, k3kkeyList, &k3kkeyListLen, &startPattern);
4816 // dictionary mode
4817 size_t endFilePosition = 0;
4818 if (dict_filenamelen) {
4820 res = loadFileDICTIONARYEx((char *)dict_filename, deskeyList, sizeof(deskeyList), NULL, 8, &deskeyListLen, 0, &endFilePosition, true);
4821 if (res == PM3_SUCCESS && endFilePosition)
4822 PrintAndLogEx(SUCCESS, "First part of des dictionary successfully loaded.");
4824 endFilePosition = 0;
4825 res = loadFileDICTIONARYEx((char *)dict_filename, aeskeyList, sizeof(aeskeyList), NULL, 16, &aeskeyListLen, 0, &endFilePosition, true);
4826 if (res == PM3_SUCCESS && endFilePosition)
4827 PrintAndLogEx(SUCCESS, "First part of aes dictionary successfully loaded.");
4829 endFilePosition = 0;
4830 res = loadFileDICTIONARYEx((char *)dict_filename, k3kkeyList, sizeof(k3kkeyList), NULL, 24, &k3kkeyListLen, 0, &endFilePosition, true);
4831 if (res == PM3_SUCCESS && endFilePosition)
4832 PrintAndLogEx(SUCCESS, "First part of k3kdes dictionary successfully loaded.");
4834 endFilePosition = 0;
4837 if (aeskeyListLen == 0 && deskeyListLen == 0 && k3kkeyListLen == 0) {
4838 PrintAndLogEx(ERR, "No keys provided. Nothing to check.");
4839 return PM3_EINVARG;
4842 if (aeskeyListLen != 0) {
4843 PrintAndLogEx(INFO, "Loaded " _YELLOW_("%"PRIu32) " aes keys", aeskeyListLen);
4846 if (deskeyListLen != 0) {
4847 PrintAndLogEx(INFO, "Loaded " _YELLOW_("%"PRIu32) " des keys", deskeyListLen);
4850 if (k3kkeyListLen != 0) {
4851 PrintAndLogEx(INFO, "Loaded " _YELLOW_("%"PRIu32) " k3kdes keys", k3kkeyListLen);
4854 if (verbose == false)
4855 PrintAndLogEx(INFO, "Search keys:");
4857 bool result = false;
4858 uint8_t app_ids[78] = {0};
4859 uint32_t app_ids_len = 0;
4861 clearCommandBuffer();
4863 mfdes_info_res_t info = {0};
4864 res = mfdes_get_info(&info);
4865 if (res != PM3_SUCCESS) {
4866 return res;
4868 // TODO: Store this UID someowhere not global
4869 memcpy(tag->info.uid, info.uid, info.uidlen);
4870 tag->info.uidlen = info.uidlen;
4872 if (handler_desfire_appids(app_ids, &app_ids_len) != PM3_SUCCESS) {
4873 PrintAndLogEx(ERR, "Can't get list of applications on tag");
4874 DropFieldDesfire();
4875 return PM3_ESOFT;
4878 if (aidlength != 0) {
4879 memcpy(&app_ids[0], aid, 3);
4880 app_ids_len = 3;
4883 for (uint32_t x = 0; x < app_ids_len / 3; x++) {
4885 uint32_t curaid = (app_ids[x * 3] & 0xFF) + ((app_ids[(x * 3) + 1] & 0xFF) << 8) + ((app_ids[(x * 3) + 2] & 0xFF) << 16);
4886 PrintAndLogEx(ERR, "Checking aid 0x%06X...", curaid);
4888 res = AuthCheckDesfire(&app_ids[x * 3], deskeyList, deskeyListLen, aeskeyList, aeskeyListLen, k3kkeyList, k3kkeyListLen, cmdKDFAlgo, kdfInputLen, kdfInput, foundKeys, &result);
4889 if (res == PM3_EOPABORTED) {
4890 break;
4893 if (pattern2b && startPattern < 0x10000) {
4894 if (verbose == false)
4895 PrintAndLogEx(NORMAL, "p" NOLF);
4897 aeskeyListLen = 0;
4898 deskeyListLen = 0;
4899 k3kkeyListLen = 0;
4900 DesFill2bPattern(deskeyList, &deskeyListLen, aeskeyList, &aeskeyListLen, k3kkeyList, &k3kkeyListLen, &startPattern);
4901 continue;
4904 if (dict_filenamelen) {
4905 if (verbose == false)
4906 PrintAndLogEx(NORMAL, "d" NOLF);
4908 uint32_t keycnt = 0;
4909 res = loadFileDICTIONARYEx((char *)dict_filename, deskeyList, sizeof(deskeyList), NULL, 16, &keycnt, endFilePosition, &endFilePosition, false);
4910 if (res == PM3_SUCCESS && endFilePosition)
4911 deskeyListLen = keycnt;
4913 keycnt = 0;
4914 res = loadFileDICTIONARYEx((char *)dict_filename, aeskeyList, sizeof(aeskeyList), NULL, 16, &keycnt, endFilePosition, &endFilePosition, false);
4915 if (res == PM3_SUCCESS && endFilePosition)
4916 aeskeyListLen = keycnt;
4918 keycnt = 0;
4919 res = loadFileDICTIONARYEx((char *)dict_filename, k3kkeyList, sizeof(k3kkeyList), NULL, 16, &keycnt, endFilePosition, &endFilePosition, false);
4920 if (res == PM3_SUCCESS && endFilePosition)
4921 k3kkeyListLen = keycnt;
4923 continue;
4926 if (verbose == false)
4927 PrintAndLogEx(NORMAL, "");
4929 // save keys to json
4930 if ((jsonnamelen > 0) && result) {
4931 // MIFARE DESFire info
4932 SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT, 0, 0, NULL, 0);
4934 PacketResponseNG resp;
4935 WaitForResponse(CMD_ACK, &resp);
4937 iso14a_card_select_t card;
4938 memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t));
4940 uint64_t select_status = resp.oldarg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision
4942 uint8_t data[10 + 1 + 2 + 1 + 256 + (4 * 0xE * (24 + 1))] = {0};
4943 uint8_t atslen = 0;
4944 if (select_status == 1 || select_status == 2) {
4945 memcpy(data, card.uid, card.uidlen);
4946 data[10] = card.sak;
4947 data[11] = card.atqa[1];
4948 data[12] = card.atqa[0];
4949 atslen = card.ats_len;
4950 data[13] = atslen;
4951 memcpy(&data[14], card.ats, atslen);
4954 // length: UID(10b)+SAK(1b)+ATQA(2b)+ATSlen(1b)+ATS(atslen)+foundKeys[2][64][AES_KEY_LEN + 1]
4955 memcpy(&data[14 + atslen], foundKeys, 4 * 0xE * (24 + 1));
4956 saveFileJSON((char *)jsonname, jsfMfDesfireKeys, data, 0xE, NULL);
4959 return PM3_SUCCESS;
4962 static int CmdHF14ADesList(const char *Cmd) {
4963 return CmdTraceListAlias(Cmd, "hf mfdes", "des");
4967 static int CmdHF14aDesNDEFRead(const char *Cmd) {
4968 DropFieldDesfire();
4970 CLIParserContext *ctx;
4971 CLIParserInit(&ctx, "hf mfdes ndefread",
4972 "Prints NFC Data Exchange Format (NDEF)",
4973 "hf mfdes ndefread -> shows NDEF data\n"
4974 "hf mfdes ndefread -v -> shows NDEF parsed and raw data\n"
4975 "hf mfdes ndefread -a e103 -k d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7 -> shows NDEF data with custom AID and key");
4977 void *argtable[] = {
4978 arg_param_begin,
4979 arg_litn("v", "verbose", 0, 2, "show technical data"),
4980 arg_str0(NULL, "aid", "<aid>", "replace default aid for NDEF"),
4981 arg_str0("k", "key", "<key>", "replace default key for NDEF"),
4982 arg_param_end
4984 CLIExecWithReturn(ctx, Cmd, argtable, true);
4986 bool verbose = arg_get_lit(ctx, 1);
4987 bool verbose2 = arg_get_lit(ctx, 1) > 1;
4988 uint8_t aid[2] = {0};
4989 int aidlen;
4990 CLIGetHexWithReturn(ctx, 2, aid, &aidlen);
4991 uint8_t key[16] = {0};
4992 int keylen;
4993 CLIGetHexWithReturn(ctx, 3, key, &keylen);
4995 CLIParserFree(ctx);
4997 uint32_t ndefAID = 0xEEEE10;
4998 if (aidlen == 2) {
4999 ndefAID = (aid[0] << 16) | (aid[1] << 8) | aid[2];
5002 // set default NDEF key
5003 uint8_t ndefkey[16] = {0};
5004 memcpy(ndefkey, g_mifarep_ndef_key, 16);
5006 // user supplied key
5007 if (keylen == 16) {
5008 memcpy(ndefkey, key, 16);
5011 int file_ids_len = 0;
5013 for (int j = (int)file_ids_len - 1; j >= 0; j--) {
5014 PrintAndLogEx(SUCCESS, "\n\n Fileid %d (0x%02x)", file_ids[j], file_ids[j]);
5016 uint8_t filesettings[20] = {0};
5017 uint32_t fileset_len = 0;
5019 int res = handler_desfire_filesettings(file_ids[j], filesettings, &fileset_len);
5020 if (res != PM3_SUCCESS) continue;
5022 int maclen = 0; // To be implemented
5024 if (fileset_len == 1 + 1 + 2 + 3 + maclen) {
5025 int filesize = (filesettings[6] << 16) + (filesettings[5] << 8) + filesettings[4];
5026 mfdes_data_t fdata;
5027 fdata.fileno = file_ids[j];
5028 memset(fdata.offset, 0, 3);
5029 memset(fdata.length, 0, 3);
5031 uint8_t *data = (uint8_t *)calloc(filesize, sizeof(uint8_t));
5032 if (data == NULL) {
5033 DropFieldDesfire();
5034 return PM3_EMALLOC;
5037 fdata.data = data;
5038 res = handler_desfire_readdata(&fdata, MFDES_DATA_FILE, filesettings[1]);
5039 if (res == PM3_SUCCESS) {
5040 uint32_t len = le24toh(fdata.length);
5041 NDEFDecodeAndPrint(data, datalen, verbose);
5043 } else {
5044 PrintAndLogEx(ERR, "Couldn't read value. Error %d", res);
5045 res = handler_desfire_select_application(aid);
5046 if (res != PM3_SUCCESS) continue;
5049 free(data);
5053 if (!datalen) {
5054 PrintAndLogEx(ERR, "no NDEF data");
5055 return PM3_SUCCESS;
5058 if (verbose2) {
5059 PrintAndLogEx(NORMAL, "");
5060 PrintAndLogEx(INFO, "--- " _CYAN_("DESFire NDEF raw") " ----------------");
5061 print_buffer(data, datalen, 1);
5064 PrintAndLogEx(HINT, "Try " _YELLOW_("`hf mfdes ndefread -vv`") " for more details");
5065 return PM3_SUCCESS;
5069 static int CmdHF14aDesMAD(const char *Cmd) {
5070 DropFieldDesfire();
5072 CLIParserContext *ctx;
5073 CLIParserInit(&ctx, "hf mfdes mad",
5074 "Prints MIFARE Application directory (MAD)",
5075 "hf mfdes mad -> shows MAD data\n"
5076 "hf mfdes mad -v -> shows MAD parsed and raw data\n"
5077 "hf mfdes mad -a e103 -k d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7 -> shows MAD data with custom AID and key");
5079 void *argtable[] = {
5080 arg_param_begin,
5081 arg_litn("v", "verbose", 0, 2, "show technical data"),
5082 arg_str0(NULL, "aid", "<aid>", "replace default aid for MAD"),
5083 arg_str0("k", "key", "<key>", "replace default key for MAD"),
5084 arg_param_end
5086 CLIExecWithReturn(ctx, Cmd, argtable, true);
5088 CLIParserFree(ctx);
5090 PrintAndLogEx(HINT, "Try " _YELLOW_("`hf mfdes mad -v`") " for more details");
5091 return PM3_SUCCESS;
5095 /*static int CmdTest(const char *Cmd) {
5096 (void)Cmd; // Cmd is not used so far
5097 uint8_t IV[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
5098 uint8_t key[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
5100 uint8_t encRndB[8] = {0x1A, 0xBE, 0x10, 0x8D, 0x09, 0xE0, 0x18, 0x13};
5101 uint8_t RndB[8] = {0};
5102 uint8_t RndA[8] = {0x6E, 0x6A, 0xEB, 0x86, 0x6E, 0x6A, 0xEB, 0x86};
5103 tdes_nxp_receive(encRndB, RndB, 8, key, IV, 2);
5104 uint8_t rotRndB[8] = {0};
5105 memcpy(rotRndB, RndB, 8);
5106 rol(rotRndB, 8);
5107 uint8_t tmp[16] = {0x00};
5108 uint8_t both[16] = {0x00};
5109 memcpy(tmp, RndA, 8);
5110 memcpy(tmp + 8, rotRndB, 8);
5111 PrintAndLogEx(INFO, "3keyenc: %s", sprint_hex(tmp, 16));
5112 PrintAndLogEx(SUCCESS, " Res : " _GREEN_("%s"), sprint_hex(IV, 8));
5113 tdes_nxp_send(tmp, both, 16, key, IV, 2);
5114 PrintAndLogEx(SUCCESS, " Res : " _GREEN_("%s"), sprint_hex(both, 16));
5115 return PM3_SUCCESS;
5119 static command_t CommandTable[] = {
5120 {"help", CmdHelp, AlwaysAvailable, "This help"},
5121 {"-----------", CmdHelp, IfPm3Iso14443a, "---------------------- " _CYAN_("general") " ----------------------"},
5122 {"auth", CmdHF14ADesAuth, IfPm3Iso14443a, "Tries a MIFARE DesFire Authentication"},
5123 {"changekey", CmdHF14ADesChangeKey, IfPm3Iso14443a, "Change Key"},
5124 {"chk", CmdHF14aDesChk, IfPm3Iso14443a, "Check keys"},
5125 {"enum", CmdHF14ADesEnumApplications, IfPm3Iso14443a, "Tries enumerate all applications"},
5126 {"formatpicc", CmdHF14ADesFormatPICC, IfPm3Iso14443a, "Format PICC"},
5127 {"getuid", CmdHF14ADesGetUID, IfPm3Iso14443a, "Get random uid"},
5128 {"info", CmdHF14ADesInfo, IfPm3Iso14443a, "Tag information"},
5129 {"list", CmdHF14ADesList, AlwaysAvailable, "List DESFire (ISO 14443A) history"},
5130 // {"ndefread", CmdHF14aDesNDEFRead, IfPm3Iso14443a, "Prints NDEF records from card"},
5131 // {"mad", CmdHF14aDesMAD, IfPm3Iso14443a, "Prints MAD records from card"},
5132 {"-----------", CmdHelp, IfPm3Iso14443a, "-------------------- " _CYAN_("Applications") " -------------------"},
5133 {"bruteaid", CmdHF14ADesBruteApps, IfPm3Iso14443a, "Recover AIDs by bruteforce"},
5134 {"createaid", CmdHF14ADesCreateApp, IfPm3Iso14443a, "Create Application ID"},
5135 {"deleteaid", CmdHF14ADesDeleteApp, IfPm3Iso14443a, "Delete Application ID"},
5136 {"selectaid", CmdHF14ADesSelectApp, IfPm3Iso14443a, "Select Application ID"},
5137 {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("Files") " -----------------------"},
5138 {"changevalue", CmdHF14ADesChangeValue, IfPm3Iso14443a, "Write value of a value file (credit/debit/clear)"},
5139 {"clearfile", CmdHF14ADesClearRecordFile, IfPm3Iso14443a, "Clear record File"},
5140 {"createfile", CmdHF14ADesCreateFile, IfPm3Iso14443a, "Create Standard/Backup File"},
5141 {"createvaluefile", CmdHF14ADesCreateValueFile, IfPm3Iso14443a, "Create Value File"},
5142 {"createrecordfile", CmdHF14ADesCreateRecordFile, IfPm3Iso14443a, "Create Linear/Cyclic Record File"},
5143 {"deletefile", CmdHF14ADesDeleteFile, IfPm3Iso14443a, "Create Delete File"},
5144 {"dump", CmdHF14ADesDump, IfPm3Iso14443a, "Dump all files"},
5145 {"getvalue", CmdHF14ADesGetValueData, IfPm3Iso14443a, "Get value of file"},
5146 {"read", CmdHF14ADesReadData, IfPm3Iso14443a, "Read data from standard/backup/record file"},
5147 {"write", CmdHF14ADesWriteData, IfPm3Iso14443a, "Write data to standard/backup/record file"},
5148 {NULL, NULL, NULL, NULL}
5151 static int CmdHelp(const char *Cmd) {
5152 (void)Cmd; // Cmd is not used so far
5153 CmdsHelp(CommandTable);
5154 return PM3_SUCCESS;
5157 int CmdHFMFDes(const char *Cmd) {
5158 clearCommandBuffer();
5159 return CmdsParse(CommandTable, Cmd);
5163 ToDo:
5165 Native Cmds
5166 -----------
5167 ChangeKeySettings 0x5F
5168 SetConfiguration
5169 GetISOFileIDs
5170 GetCardUID
5171 ChangeFileSettings
5173 ISO/IEC 7816 Cmds
5174 -----------------
5175 'A4' Select
5176 'B0' Read Binary
5177 'D6' Update Binary
5178 'B2' Read Records
5179 'E2' Append Records
5180 '84' Get Challenge
5181 '88' Internal Authenticate
5182 '82' External Authenticate