Merge pull request #2654 from Antiklesys/master
[RRG-proxmark3.git] / client / src / mifare / desfirecore.c
blob7bf69218453474c4003f6727730ef4bb57d62e5c
1 //-----------------------------------------------------------------------------
2 // Borrowed initially from https://github.com/nfc-tools/libfreefare
3 // Copyright (C) 2010, Romain Tartiere.
4 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
5 //
6 // This program is free software: you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation, either version 3 of the License, or
9 // (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // See LICENSE.txt for the text of the license.
17 //-----------------------------------------------------------------------------
18 // High frequency Desfire core functions
19 //-----------------------------------------------------------------------------
20 // Info from here and many other sources from the public internet sites
21 // https://github.com/revk/DESFireAES
22 // https://github.com/step21/desfire_rfid
23 // https://github.com/patsys/desfire-python/blob/master/Desfire/DESFire.py
24 //-----------------------------------------------------------------------------
26 #include "desfirecore.h"
27 #include <stdlib.h>
28 #include <string.h>
29 #include <util.h>
30 #include "commonutil.h"
31 #include "generator.h"
32 #include "aes.h"
33 #include "ui.h"
34 #include "crc.h"
35 #include "crc16.h" // crc16 ccitt
36 #include "crc32.h"
37 #include "protocols.h" // ISO7816 APDU return codes
38 #include "cmdhf14a.h"
39 #include "iso7816/apduinfo.h" // APDU manipulation / errorcodes
40 #include "iso7816/iso7816core.h" // APDU logging
41 #include "util_posix.h" // msleep
42 #include "desfiresecurechan.h"
43 #include "mifare/mad.h"
44 #include "mifare/aiddesfire.h"
47 const CLIParserOption DesfireAlgoOpts[] = {
48 {T_DES, "des"},
49 {T_3DES, "2tdea"},
50 {T_3K3DES, "3tdea"},
51 {T_AES, "aes"},
52 {0, NULL},
54 const size_t DesfireAlgoOptsLen = ARRAYLEN(DesfireAlgoOpts);
56 const CLIParserOption DesfireKDFAlgoOpts[] = {
57 {MFDES_KDF_ALGO_NONE, "none"},
58 {MFDES_KDF_ALGO_AN10922, "an10922"},
59 {MFDES_KDF_ALGO_GALLAGHER, "gallagher"},
60 {0, NULL},
62 const size_t DesfireKDFAlgoOptsLen = ARRAYLEN(DesfireKDFAlgoOpts);
64 const CLIParserOption DesfireCommunicationModeOpts[] = {
65 {DCMPlain, "plain"},
66 {DCMMACed, "mac"},
67 {DCMEncrypted, "encrypt"},
68 {0, NULL},
70 const size_t DesfireCommunicationModeOptsLen = ARRAYLEN(DesfireCommunicationModeOpts);
72 const CLIParserOption DesfireCommandSetOpts[] = {
73 {DCCNative, "native"},
74 {DCCNativeISO, "niso"},
75 {DCCISO, "iso"},
76 {0, NULL},
78 const size_t DesfireCommandSetOptsLen = ARRAYLEN(DesfireCommandSetOpts);
80 const CLIParserOption DesfireSecureChannelOpts[] = {
81 {DACd40, "d40"},
82 {DACEV1, "ev1"},
83 {DACEV2, "ev2"},
84 {DACLRP, "lrp"},
85 {0, NULL},
87 const size_t DesfireSecureChannelOptsLen = ARRAYLEN(DesfireSecureChannelOpts);
89 const CLIParserOption DesfireFileAccessModeOpts[] = {
90 {0x00, "key0"},
91 {0x01, "key1"},
92 {0x02, "key2"},
93 {0x03, "key3"},
94 {0x04, "key4"},
95 {0x05, "key5"},
96 {0x06, "key6"},
97 {0x07, "key7"},
98 {0x08, "key8"},
99 {0x09, "key9"},
100 {0x0a, "key10"},
101 {0x0b, "key11"},
102 {0x0c, "key12"},
103 {0x0d, "key13"},
104 {0x0e, "free"},
105 {0x0f, "deny"},
106 {0, NULL},
109 const CLIParserOption DesfireValueFileOperOpts[] = {
110 {MFDES_GET_VALUE, "get"},
111 {MFDES_CREDIT, "credit"},
112 {MFDES_LIMITED_CREDIT, "limcredit"},
113 {MFDES_DEBIT, "debit"},
114 {0xff, "clear"},
115 {0, NULL},
118 const CLIParserOption DesfireReadFileTypeOpts[] = {
119 {RFTAuto, "auto"},
120 {RFTData, "data"},
121 {RFTValue, "value"},
122 {RFTRecord, "record"},
123 {RFTMAC, "mac"},
124 {0, NULL},
127 static const char *getstatus(const uint16_t *sw) {
128 if (sw == NULL) return "--> sw argument error. This should never happen !";
129 if (((*sw >> 8) & 0xFF) == 0x91) {
130 switch (*sw & 0xFF) {
131 case MFDES_E_OUT_OF_EEPROM:
132 return "Out of Eeprom, insufficient NV-Memory to complete command";
133 case MFDES_E_ILLEGAL_COMMAND_CODE:
134 return "Command code not supported";
136 case MFDES_E_INTEGRITY_ERROR:
137 return "CRC or MAC does not match data / Padding bytes invalid";
139 case MFDES_E_NO_SUCH_KEY:
140 return "Invalid key number specified";
142 case MFDES_E_LENGTH:
143 return "Length of command string invalid";
145 case MFDES_E_PERMISSION_DENIED:
146 return "Current configuration/status does not allow the requested command";
148 case MFDES_E_PARAMETER_ERROR:
149 return "Value of the parameter(s) invalid";
151 case MFDES_E_APPLICATION_NOT_FOUND:
152 return "Requested AID not present on PICC";
154 case MFDES_E_APPL_INTEGRITY:
155 return "Application integrity error, application will be disabled";
157 case MFDES_E_AUTHENTICATION_ERROR:
158 return "Current authentication status does not allow the requested command";
160 case MFDES_E_BOUNDARY:
161 return "Attempted to read/write data from/to beyond the file's/record's limit";
163 case MFDES_E_PICC_INTEGRITY:
164 return "PICC integrity error, PICC will be disabled";
166 case MFDES_E_COMMAND_ABORTED:
167 return "Previous command was not fully completed / Not all Frames were requested or provided by the PCD";
169 case MFDES_E_PICC_DISABLED:
170 return "PICC was disabled by an unrecoverable error";
172 case MFDES_E_COUNT:
173 return "Application count is limited to 28, not addition CreateApplication possible";
175 case MFDES_E_DUPLICATE:
176 return "Duplicate entry: File/Application/ISO Text does already exist";
178 case MFDES_E_EEPROM:
179 return "Eeprom error due to loss of power, internal backup/rollback mechanism activated";
181 case MFDES_E_FILE_NOT_FOUND:
182 return "Specified file number does not exist";
184 case MFDES_E_FILE_INTEGRITY:
185 return "File integrity error, file will be disabled";
187 default:
188 return "Unknown error";
191 return "Unknown error";
194 const char *DesfireGetErrorString(int res, uint16_t *sw) {
195 switch (res) {
196 case PM3_EAPDU_FAIL:
197 return getstatus(sw);
198 case PM3_EUNDEF:
199 return "Undefined error";
200 case PM3_EINVARG:
201 return "Invalid argument(s)";
202 case PM3_EDEVNOTSUPP:
203 return "Operation not supported by device";
204 case PM3_ETIMEOUT:
205 return "Operation timed out";
206 case PM3_EOPABORTED:
207 return "Operation aborted (by user)";
208 case PM3_ENOTIMPL:
209 return "Not (yet) implemented";
210 case PM3_ERFTRANS:
211 return "Error while RF transmission";
212 case PM3_EIO:
213 return "Input / output error";
214 case PM3_EOVFLOW:
215 return "Buffer overflow";
216 case PM3_ESOFT:
217 return "Software error";
218 case PM3_EFLASH:
219 return "Flash error";
220 case PM3_EMALLOC:
221 return "Memory allocation error";
222 case PM3_EFILE:
223 return "File error";
224 case PM3_ENOTTY:
225 return "Generic TTY error";
226 case PM3_EINIT:
227 return "Initialization error";
228 case PM3_EWRONGANSWER:
229 return "Expected a different answer error";
230 case PM3_EOUTOFBOUND:
231 return "Memory out-of-bounds error";
232 case PM3_ECARDEXCHANGE:
233 return "Exchange with card error";
234 case PM3_EAPDU_ENCODEFAIL:
235 return "Failed to create APDU";
236 case PM3_ENODATA:
237 return "No data";
238 case PM3_EFATAL:
239 return "Fatal error";
240 default:
241 break;
243 return "";
246 const char *DesfireAuthErrorToStr(int error) {
247 switch (error) {
248 case 1:
249 return "Sending auth command failed";
250 case 2:
251 return "Authentication failed. No data received";
252 case 3:
253 return "Authentication failed. Invalid key number.";
254 case 4:
255 return "Authentication failed. Length of answer doesn't match algo length";
256 case 5:
257 return "mbedtls_aes_setkey_dec failed";
258 case 6:
259 return "mbedtls_aes_setkey_enc failed";
260 case 7:
261 return "Sending auth command failed";
262 case 8:
263 return "Authentication failed. Card timeout.";
264 case 9:
265 return "Authentication failed.";
266 case 10:
267 return "mbedtls_aes_setkey_dec failed";
268 case 11:
269 return "Authentication failed. Cannot verify Session Key.";
270 case 12:
271 return "Authentication failed. Cannot verify CMAC.";
272 case 50:
273 return "PICC returned not an AES answer";
274 case 51:
275 return "PICC returned not an LRP answer";
276 case 100:
277 return "Can't find auth method for provided channel parameters.";
278 case 200:
279 return "Can't select application.";
280 case 201:
281 return "Authentication returned no error but channel not authenticated.";
282 case 202:
283 return "Can't select application by ISO ID.";
284 case 203:
285 return "Can't select file by ISO ID.";
286 case 301:
287 return "ISO Get challenge error.";
288 case 302:
289 return "ISO Get challenge returned wrong length.";
290 case 303:
291 return "Crypto encode piccrnd1 error.";
292 case 304:
293 return "External authenticate error.";
294 case 305:
295 return "Internal authenticate error.";
296 case 306:
297 return "Internal authenticate returned wrong length.";
298 case 307:
299 return "Crypto decode piccrnd2 error.";
300 case 308:
301 return "Random numbers don't match. Authentication failed.";
302 default:
303 break;
305 return "";
308 const char *DesfireSelectWayToStr(DesfireISOSelectWay way) {
309 switch (way) {
310 case ISW6bAID:
311 return "AID";
312 case ISWMF:
313 return "MF";
314 case ISWIsoID:
315 return "ISO ID";
316 case ISWDFName:
317 return "DF Name";
318 default:
319 break;
321 return "";
324 char *DesfireWayIDStr(DesfireISOSelectWay way, uint32_t id) {
325 static char str[200] = {0};
327 if (way == ISWMF || way == ISWDFName)
328 snprintf(str, sizeof(str), "%s", DesfireSelectWayToStr(way));
329 else
330 snprintf(str, sizeof(str), "%s %0*x", DesfireSelectWayToStr(way), (way == ISW6bAID) ? 6 : 4, id);
332 return str;
335 bool DesfireMFSelected(DesfireISOSelectWay way, uint32_t id) {
336 switch (way) {
337 case ISW6bAID:
338 return (id == 0x000000);
339 case ISWMF:
340 return true;
341 case ISWIsoID:
342 return (id == 0x3f00);
343 case ISWDFName:
344 return false;
345 default:
346 break;
348 return false;
351 // iceman todo: use commonutil.c instead
352 uint32_t DesfireAIDByteToUint(const uint8_t *data) {
353 return data[0] + (data[1] << 8) + (data[2] << 16);
356 void DesfireAIDUintToByte(uint32_t aid, uint8_t *data) {
357 data[0] = aid & 0xff;
358 data[1] = (aid >> 8) & 0xff;
359 data[2] = (aid >> 16) & 0xff;
362 static uint8_t DesfireKeyToISOKey(DesfireCryptoAlgorithm keytype) {
363 switch (keytype) {
364 case T_DES:
365 return 0x02;
366 case T_3DES:
367 return 0x02;
368 case T_3K3DES:
369 return 0x04;
370 case T_AES:
371 return 0x09;
373 return 0x00;
376 static uint8_t DesfireGetRndLenForKey(DesfireCryptoAlgorithm keytype) {
377 switch (keytype) {
378 case T_DES:
379 return 0x08;
380 case T_3DES:
381 return 0x08;
382 case T_3K3DES:
383 return 0x10;
384 case T_AES:
385 return 0x10;
387 return 0x00;
390 void DesfirePrintContext(DesfireContext_t *ctx) {
391 PrintAndLogEx(INFO, "Key num: %d Key algo: %s Key[%d]: %s",
392 ctx->keyNum,
393 CLIGetOptionListStr(DesfireAlgoOpts, ctx->keyType),
394 desfire_get_key_length(ctx->keyType),
395 sprint_hex(ctx->key,
396 desfire_get_key_length(ctx->keyType)));
398 if (ctx->kdfAlgo != MFDES_KDF_ALGO_NONE) {
399 PrintAndLogEx(INFO, "KDF algo: %s KDF input[%d]: %s", CLIGetOptionListStr(DesfireKDFAlgoOpts, ctx->kdfAlgo), ctx->kdfInputLen, sprint_hex(ctx->kdfInput, ctx->kdfInputLen));
400 PrintAndLogEx(INFO, "AID: %06x UID[%d]: %s", ctx->selectedAID, ctx->uidlen, sprint_hex(ctx->uid, ctx->uidlen));
403 PrintAndLogEx(INFO, "Secure channel: %s Command set: %s Communication mode: %s",
404 CLIGetOptionListStr(DesfireSecureChannelOpts, ctx->secureChannel),
405 CLIGetOptionListStr(DesfireCommandSetOpts, ctx->cmdSet),
406 CLIGetOptionListStr(DesfireCommunicationModeOpts, ctx->commMode));
409 if (DesfireIsAuthenticated(ctx)) {
410 if (memcmp(ctx->sessionKeyMAC, ctx->sessionKeyEnc, desfire_get_key_length(ctx->keyType)) == 0) {
411 PrintAndLogEx(INFO, "Session key [%d]: %s ",
412 desfire_get_key_length(ctx->keyType),
413 sprint_hex(ctx->sessionKeyEnc, desfire_get_key_length(ctx->keyType)));
414 } else {
415 PrintAndLogEx(INFO, "Session key MAC [%d]: %s ",
416 desfire_get_key_length(ctx->keyType),
417 sprint_hex(ctx->sessionKeyMAC, desfire_get_key_length(ctx->keyType)));
418 PrintAndLogEx(INFO, " ENC: %s",
419 sprint_hex(ctx->sessionKeyEnc, desfire_get_key_length(ctx->keyType)));
421 PrintAndLogEx(INFO, " IV [%zu]: %s",
422 desfire_get_key_block_length(ctx->keyType),
423 sprint_hex(ctx->IV, desfire_get_key_block_length(ctx->keyType)));
424 if (ctx->secureChannel == DACEV2) {
425 PrintAndLogEx(INFO, " TI: %s cmdCntr: 0x%04x",
426 sprint_hex(ctx->TI, 4),
427 ctx->cmdCntr);
433 static int DESFIRESendApduEx(bool activate_field, sAPDU_t apdu, uint16_t le, uint8_t *result, uint32_t max_result_len, uint32_t *result_len, uint16_t *sw) {
434 if (result_len) *result_len = 0;
435 if (sw) *sw = 0;
437 uint16_t isw = 0;
438 int res = 0;
440 if (activate_field) {
441 DropField();
442 msleep(50);
445 uint8_t data[APDU_RES_LEN] = {0};
447 // COMPUTE APDU
448 int datalen = 0;
449 if (APDUEncodeS(&apdu, false, le, data, &datalen)) { // 100 == with Le
450 PrintAndLogEx(ERR, "APDU encoding error.");
451 return PM3_EAPDU_ENCODEFAIL;
454 if (GetAPDULogging())
455 PrintAndLogEx(SUCCESS, ">>>> %s", sprint_hex(data, datalen));
457 res = ExchangeAPDU14a(data, datalen, activate_field, true, result, max_result_len, (int *)result_len);
458 if (res != PM3_SUCCESS) {
459 return res;
462 if (GetAPDULogging())
463 PrintAndLogEx(SUCCESS, "<<<< %s", sprint_hex(result, *result_len));
465 if (*result_len < 2) {
466 return PM3_SUCCESS;
469 *result_len -= 2;
470 isw = (result[*result_len] << 8) + result[*result_len + 1];
471 if (sw)
472 *sw = isw;
474 if (isw != ISO7816_OK &&
475 isw != DESFIRE_GET_ISO_STATUS(MFDES_S_OPERATION_OK) &&
476 isw != DESFIRE_GET_ISO_STATUS(MFDES_S_SIGNATURE) &&
477 isw != DESFIRE_GET_ISO_STATUS(MFDES_S_ADDITIONAL_FRAME) &&
478 isw != DESFIRE_GET_ISO_STATUS(MFDES_S_NO_CHANGES)) {
479 if (GetAPDULogging()) {
480 if (isw >> 8 == 0x61) {
481 PrintAndLogEx(ERR, "APDU chaining len: 0x%02x -->", isw & 0xff);
482 } else {
483 PrintAndLogEx(ERR, "APDU(%02x%02x) ERROR: [0x%4X] %s", apdu.CLA, apdu.INS, isw, GetAPDUCodeDescription(isw >> 8, isw & 0xff));
484 return PM3_EAPDU_FAIL;
487 return PM3_EAPDU_FAIL;
489 return PM3_SUCCESS;
492 static int DESFIRESendApdu(bool activate_field, sAPDU_t apdu, uint8_t *result, uint32_t max_result_len, uint32_t *result_len, uint16_t *sw) {
493 return DESFIRESendApduEx(activate_field, apdu, APDU_INCLUDE_LE_00, result, max_result_len, result_len, sw);
496 static int DESFIRESendRaw(bool activate_field, uint8_t *data, size_t datalen, uint8_t *result, uint32_t max_result_len, uint32_t *result_len, uint8_t *respcode) {
497 *result_len = 0;
498 if (respcode) {
499 *respcode = 0xff;
502 if (activate_field) {
503 DropField();
504 msleep(50);
507 if (GetAPDULogging()) {
508 PrintAndLogEx(SUCCESS, "raw>> %s", sprint_hex(data, datalen));
511 int res = ExchangeRAW14a(data, datalen, activate_field, true, result, max_result_len, (int *)result_len, true);
512 if (res != PM3_SUCCESS) {
513 return res;
516 if (GetAPDULogging()) {
517 PrintAndLogEx(SUCCESS, "raw<< %s", sprint_hex(result, *result_len));
520 if (*result_len < 1) {
521 return PM3_SUCCESS;
524 *result_len -= (1 + 2);
526 uint8_t rcode = result[0];
527 if (respcode) {
528 *respcode = rcode;
531 memmove(&result[0], &result[1], *result_len);
533 if (rcode != MFDES_S_OPERATION_OK &&
534 rcode != MFDES_S_SIGNATURE &&
535 rcode != MFDES_S_ADDITIONAL_FRAME &&
536 rcode != MFDES_S_NO_CHANGES) {
538 if (GetAPDULogging()) {
539 PrintAndLogEx(ERR, "Command (%02x) ERROR: 0x%02x", data[0], rcode);
541 return PM3_EAPDU_FAIL;
543 return PM3_SUCCESS;
546 static int DesfireExchangeNative(bool activate_field, DesfireContext_t *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen, bool enable_chaining, size_t splitbysize) {
547 if (resplen) {
548 *resplen = 0;
551 if (respcode) {
552 *respcode = 0xff;
555 uint8_t *buf = calloc(DESFIRE_BUFFER_SIZE, 1);
556 if (buf == NULL) {
557 return PM3_EMALLOC;
560 uint32_t buflen = 0;
561 uint32_t pos = 0;
562 uint32_t i = 1;
564 uint8_t rcode = 0xff;
565 uint8_t cdata[1024] = {0};
566 uint32_t cdatalen = 0;
567 cdata[0] = cmd;
568 memcpy(&cdata[1], data, datalen);
569 cdatalen = datalen + 1;
571 int res;
572 size_t len;
573 // tx chaining
574 size_t sentdatalen = 0;
575 while (cdatalen >= sentdatalen) {
577 if ((cdatalen - sentdatalen) > DESFIRE_TX_FRAME_MAX_LEN)
578 len = DESFIRE_TX_FRAME_MAX_LEN;
579 else
580 len = cdatalen - sentdatalen;
582 size_t sendindx = sentdatalen;
583 size_t sendlen = len;
584 if (sentdatalen > 0) {
585 sendindx--;
586 sendlen++;
587 cdata[sendindx] = MFDES_ADDITIONAL_FRAME;
590 res = DESFIRESendRaw(activate_field, &cdata[sendindx], sendlen, buf, DESFIRE_BUFFER_SIZE, &buflen, &rcode);
591 if (res != PM3_SUCCESS) {
592 uint16_t ssw = DESFIRE_GET_ISO_STATUS(rcode);
593 PrintAndLogEx(DEBUG, "error DESFIRESendRaw %s", DesfireGetErrorString(res, &ssw));
594 free(buf);
595 return res;
598 sentdatalen += len;
599 if ((rcode != MFDES_ADDITIONAL_FRAME) || (buflen > 0)) {
600 if (sentdatalen != cdatalen) {
601 PrintAndLogEx(WARNING, "Tx chaining error. Needs to send: %d but sent: %zu", cdatalen, sentdatalen);
603 break;
607 // rx
608 if (resp) {
609 if (splitbysize) {
610 resp[0] = buflen;
611 memcpy(&resp[1], buf, buflen);
612 } else {
613 memcpy(resp, buf, buflen);
616 if (respcode != NULL) {
617 *respcode = rcode;
620 pos += buflen;
622 if (enable_chaining == false) {
623 if (rcode == MFDES_S_OPERATION_OK ||
624 rcode == MFDES_ADDITIONAL_FRAME) {
626 if (resplen) {
627 *resplen = pos;
630 free(buf);
631 return PM3_SUCCESS;
634 while (rcode == MFDES_ADDITIONAL_FRAME) {
635 cdata[0] = MFDES_ADDITIONAL_FRAME; //0xAF
637 res = DESFIRESendRaw(false, cdata, 1, buf, DESFIRE_BUFFER_SIZE, &buflen, &rcode);
638 if (res != PM3_SUCCESS) {
639 uint16_t ssw = DESFIRE_GET_ISO_STATUS(rcode);
640 PrintAndLogEx(DEBUG, "error DESFIRESendRaw %s", DesfireGetErrorString(res, &ssw));
641 return res;
644 if (respcode != NULL) {
645 *respcode = rcode;
648 if (resp != NULL) {
649 if (splitbysize) {
650 resp[i * splitbysize] = buflen;
651 memcpy(&resp[i * splitbysize + 1], buf, buflen);
652 i += 1;
653 } else {
654 memcpy(&resp[pos], buf, buflen);
657 pos += buflen;
659 if (rcode != MFDES_ADDITIONAL_FRAME)
660 break;
663 if (resplen) {
664 *resplen = (splitbysize) ? i : pos;
667 free(buf);
668 return PM3_SUCCESS;
671 static int DesfireExchangeISONative(bool activate_field, DesfireContext_t *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen, bool enable_chaining, size_t splitbysize) {
672 if (resplen) {
673 *resplen = 0;
676 if (respcode) {
677 *respcode = 0xFF;
680 uint16_t sw = 0;
681 uint8_t *buf = calloc(DESFIRE_BUFFER_SIZE, 1);
682 if (buf == NULL) {
683 return PM3_EMALLOC;
686 uint32_t buflen = 0;
687 uint32_t pos = 0;
688 uint32_t i = 1;
690 sAPDU_t apdu = {
691 .CLA = MFDES_NATIVE_ISO7816_WRAP_CLA, //0x90
692 .INS = cmd,
693 .P1 = 0,
694 .P2 = 0,
697 int res;
698 // tx chaining
699 size_t sentdatalen = 0;
700 while (datalen >= sentdatalen) {
701 if (datalen - sentdatalen > DESFIRE_TX_FRAME_MAX_LEN) {
702 apdu.Lc = DESFIRE_TX_FRAME_MAX_LEN;
703 } else {
704 apdu.Lc = datalen - sentdatalen;
707 apdu.data = &data[sentdatalen];
709 if (sentdatalen > 0) {
710 apdu.INS = MFDES_ADDITIONAL_FRAME;
713 res = DESFIRESendApdu(activate_field, apdu, buf, DESFIRE_BUFFER_SIZE, &buflen, &sw);
714 if (res != PM3_SUCCESS) {
715 PrintAndLogEx(DEBUG, "error DESFIRESendApdu %s", DesfireGetErrorString(res, &sw));
716 free(buf);
717 return res;
720 sentdatalen += apdu.Lc;
721 if (sw != DESFIRE_GET_ISO_STATUS(MFDES_ADDITIONAL_FRAME) || buflen > 0) {
722 if (sentdatalen != datalen) {
723 PrintAndLogEx(WARNING, "Tx chaining error. Needs to send: %zu but sent: %zu", datalen, sentdatalen);
725 break;
729 if (respcode != NULL && ((sw & 0xFF00) == 0x9100)) {
730 *respcode = sw & 0xFF;
733 if (resp) {
734 if (splitbysize) {
735 resp[0] = buflen;
736 memcpy(&resp[1], buf, buflen);
737 } else {
738 memcpy(resp, buf, buflen);
742 pos += buflen;
743 if (enable_chaining == false) {
744 if (sw == DESFIRE_GET_ISO_STATUS(MFDES_S_OPERATION_OK) ||
745 sw == DESFIRE_GET_ISO_STATUS(MFDES_ADDITIONAL_FRAME)) {
747 if (resplen) {
748 *resplen = pos;
751 free(buf);
752 return PM3_SUCCESS;
755 while (sw == DESFIRE_GET_ISO_STATUS(MFDES_ADDITIONAL_FRAME)) {
756 apdu.CLA = MFDES_NATIVE_ISO7816_WRAP_CLA; //0x90
757 apdu.INS = MFDES_ADDITIONAL_FRAME; //0xAF
758 apdu.Lc = 0;
759 apdu.P1 = 0;
760 apdu.P2 = 0;
761 apdu.data = NULL;
763 buflen = 0;
765 res = DESFIRESendApdu(false, apdu, buf, DESFIRE_BUFFER_SIZE, &buflen, &sw);
766 if (res != PM3_SUCCESS) {
767 PrintAndLogEx(DEBUG, "error DESFIRESendApdu %s", DesfireGetErrorString(res, &sw));
768 free(buf);
769 return res;
772 if (respcode != NULL && ((sw & 0xFF00) == 0x9100)) {
773 *respcode = sw & 0xFF;
776 if (resp != NULL) {
777 if (splitbysize) {
778 resp[i * splitbysize] = buflen;
779 memcpy(&resp[i * splitbysize + 1], buf, buflen);
780 i += 1;
781 } else {
782 memcpy(resp + (pos), buf, buflen);
786 pos += buflen;
788 if (sw != DESFIRE_GET_ISO_STATUS(MFDES_ADDITIONAL_FRAME)) {
789 break;
794 if (resplen) {
795 *resplen = (splitbysize) ? i : pos;
798 free(buf);
799 return PM3_SUCCESS;
802 static int DesfireExchangeISO(bool activate_field, DesfireContext_t *ctx, sAPDU_t apdu, uint16_t le, uint8_t *resp, size_t *resplen, uint16_t *sw) {
803 uint8_t *data = calloc(DESFIRE_BUFFER_SIZE, 1);
804 if (data == NULL) {
805 return PM3_EMALLOC;
808 uint32_t datalen = 0;
809 int res = DESFIRESendApduEx(activate_field, apdu, le, data, DESFIRE_BUFFER_SIZE, &datalen, sw);
811 if (res == PM3_SUCCESS) {
812 DesfireSecureChannelDecode(ctx, data, datalen, 0, resp, resplen);
815 free(data);
816 return res;
819 // move data from blockdata [format: <length, data><length, data>...] to single data block
820 static void DesfireJoinBlockToBytes(uint8_t *blockdata, size_t blockdatacount, size_t blockdatasize, uint8_t *dstdata, size_t *dstdatalen) {
821 *dstdatalen = 0;
822 for (int i = 0; i < blockdatacount; i++) {
823 memcpy(&dstdata[*dstdatalen], &blockdata[i * blockdatasize + 1], blockdata[i * blockdatasize]);
824 *dstdatalen += blockdata[i * blockdatasize];
828 // move data from single data block to blockdata [format: <length, data><length, data>...]
829 // lengths in the blockdata is not changed. result - in the blockdata
830 static void DesfireSplitBytesToBlock(uint8_t *blockdata, size_t *blockdatacount, size_t blockdatasize, uint8_t *dstdata, size_t dstdatalen) {
831 size_t len = 0;
832 for (int i = 0; i < *blockdatacount; i++) {
833 memset(&blockdata[i * blockdatasize + 1], 0, blockdatasize - 1);
834 size_t tlen = len + blockdata[i * blockdatasize];
835 if (tlen > dstdatalen) {
836 tlen = dstdatalen;
838 if (tlen >= len)
839 blockdata[i * blockdatasize] = tlen - len;
840 else
841 blockdata[i * blockdatasize] = 0;
844 if (len == tlen) {
845 *blockdatacount = i;
846 break;
849 memcpy(&blockdata[i * blockdatasize + 1], &dstdata[len], tlen - len);
850 len = tlen;
854 int DesfireExchangeEx(bool activate_field, DesfireContext_t *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode,
855 uint8_t *resp, size_t *resplen, bool enable_chaining, size_t splitbysize) {
856 int res = PM3_SUCCESS;
858 if (PrintChannelModeWarning(cmd, ctx->secureChannel, ctx->cmdSet, ctx->commMode) == false) {
859 DesfirePrintContext(ctx);
862 uint8_t *databuf = calloc(DESFIRE_BUFFER_SIZE, 1);
863 if (databuf == NULL) {
864 return PM3_EMALLOC;
867 size_t databuflen = 0;
869 switch (ctx->cmdSet) {
870 case DCCNative:
871 case DCCNativeISO:
872 DesfireSecureChannelEncode(ctx, cmd, data, datalen, databuf, &databuflen);
874 if (ctx->cmdSet == DCCNative) {
875 res = DesfireExchangeNative(activate_field, ctx, cmd, databuf, databuflen, respcode, databuf, &databuflen, enable_chaining, splitbysize);
876 } else {
877 res = DesfireExchangeISONative(activate_field, ctx, cmd, databuf, databuflen, respcode, databuf, &databuflen, enable_chaining, splitbysize);
880 if (splitbysize) {
881 uint8_t sdata[DESFIRE_BUFFER_SIZE] = {0};
882 size_t sdatalen = 0;
883 DesfireJoinBlockToBytes(databuf, databuflen, splitbysize, sdata, &sdatalen);
885 //PrintAndLogEx(INFO, "block : %s", sprint_hex(sdata, sdatalen));
886 DesfireSecureChannelDecode(ctx, sdata, sdatalen, *respcode, resp, resplen);
888 DesfireSplitBytesToBlock(databuf, &databuflen, splitbysize, resp, *resplen);
889 memcpy(resp, databuf, databuflen * splitbysize);
890 *resplen = databuflen;
891 } else {
892 DesfireSecureChannelDecode(ctx, databuf, databuflen, *respcode, resp, resplen);
894 break;
895 case DCCISO:
896 free(databuf);
897 return PM3_EAPDU_FAIL;
898 break;
901 free(databuf);
902 return res;
905 int DesfireExchange(DesfireContext_t *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen) {
906 return DesfireExchangeEx(false, ctx, cmd, data, datalen, respcode, resp, resplen, true, 0);
909 int DesfireSelectAID(DesfireContext_t *ctx, uint8_t *aid1, uint8_t *aid2) {
910 if (aid1 == NULL) {
911 return PM3_EINVARG;
914 uint8_t data[6] = {0};
915 memcpy(data, aid1, 3);
916 if (aid2 != NULL) {
917 memcpy(&data[3], aid2, 3);
920 uint8_t resp[257] = {0};
921 size_t resplen = 0;
922 uint8_t respcode = 0;
924 ctx->secureChannel = DACNone;
925 int res = DesfireExchangeEx(true, ctx, MFDES_SELECT_APPLICATION, data, (aid2 == NULL) ? 3 : 6, &respcode, resp, &resplen, true, 0);
926 if (res == PM3_SUCCESS) {
927 if (resplen != 0) {
928 return PM3_ECARDEXCHANGE;
931 // select operation fail
932 if (respcode != MFDES_S_OPERATION_OK) {
933 return PM3_EAPDU_FAIL;
936 DesfireClearSession(ctx);
937 ctx->appSelected = (aid1[0] != 0x00 || aid1[1] != 0x00 || aid1[2] != 0x00);
938 ctx->selectedAID = DesfireAIDByteToUint(aid1);
940 return PM3_SUCCESS;
943 return res;
946 int DesfireSelectAIDHex(DesfireContext_t *ctx, uint32_t aid1, bool select_two, uint32_t aid2) {
947 uint8_t data[6] = {0};
949 DesfireAIDUintToByte(aid1, data);
950 DesfireAIDUintToByte(aid2, &data[3]);
952 return DesfireSelectAID(ctx, data, (select_two) ? &data[3] : NULL);
955 int DesfireSelectAIDHexNoFieldOn(DesfireContext_t *ctx, uint32_t aid) {
956 uint8_t data[3] = {0};
958 DesfireAIDUintToByte(aid, data);
960 uint8_t resp[257] = {0};
961 size_t resplen = 0;
962 uint8_t respcode = 0;
964 ctx->secureChannel = DACNone;
965 int res = DesfireExchangeEx(false, ctx, MFDES_SELECT_APPLICATION, data, 3, &respcode, resp, &resplen, true, 0);
966 if (res == PM3_SUCCESS) {
967 if (resplen != 0)
968 return PM3_ECARDEXCHANGE;
970 // select operation fail
971 if (respcode != MFDES_S_OPERATION_OK)
972 return PM3_EAPDU_FAIL;
974 DesfireClearSession(ctx);
975 ctx->appSelected = (aid != 0x000000);
976 ctx->selectedAID = aid;
978 return PM3_SUCCESS;
980 return res;
983 void DesfirePrintMADAID(uint32_t appid, bool verbose) {
984 uint8_t aid[3] = {0};
985 DesfireAIDUintToByte(appid, aid);
986 if ((aid[2] >> 4) != 0xF)
987 return;
989 uint16_t short_aid = ((aid[2] & 0xF) << 12) | (aid[1] << 4) | (aid[0] >> 4);
991 PrintAndLogEx(SUCCESS, "MIFARE Classic ID (MAD): " _YELLOW_("%04X") " ver: " _YELLOW_("%01X") " AID: " _YELLOW_("%06x") " MAD AID Cluster[0x%02X]: " _YELLOW_("%s"),
992 short_aid,
993 appid & 0x0f,
994 appid,
995 short_aid >> 8,
996 nxp_cluster_to_text(short_aid >> 8));
997 if (verbose) {
998 if (appid == 0xffffff)
999 PrintAndLogEx(SUCCESS, " Card issuer information application");
1000 else
1001 MADDFDecodeAndPrint(short_aid, verbose);
1005 void DesfirePrintAIDFunctions(uint32_t appid) {
1006 uint8_t aid[3] = {0};
1007 DesfireAIDUintToByte(appid, aid);
1008 if ((aid[2] >> 4) == 0xF) {
1009 uint16_t short_aid = ((aid[2] & 0xF) << 12) | (aid[1] << 4) | (aid[0] >> 4);
1010 PrintAndLogEx(SUCCESS, " AID mapped to MIFARE Classic AID (MAD): " _YELLOW_("%02X"), short_aid);
1011 PrintAndLogEx(SUCCESS, " MAD AID Cluster 0x%02X : " _YELLOW_("%s"), short_aid >> 8, nxp_cluster_to_text(short_aid >> 8));
1012 MADDFDecodeAndPrint(short_aid, false);
1013 } else {
1014 AIDDFDecodeAndPrint(aid);
1018 int DesfireSelectAndAuthenticateEx(DesfireContext_t *dctx, DesfireSecureChannel secureChannel, uint32_t aid, bool noauth, bool verbose) {
1019 if (verbose)
1020 DesfirePrintContext(dctx);
1022 // needs card uid for diversification
1023 if (dctx->kdfAlgo == MFDES_KDF_ALGO_GALLAGHER)
1024 DesfireGetCardUID(dctx);
1026 bool isosw = false;
1027 if (dctx->cmdSet == DCCISO) {
1028 dctx->cmdSet = DCCNativeISO;
1029 isosw = true;
1030 if (verbose)
1031 PrintAndLogEx(INFO, "Switch to " _CYAN_("native") " for select");
1034 int res;
1035 if (aid == 0x000000) {
1036 res = DesfireAnticollision(verbose);
1037 if (res != PM3_SUCCESS) {
1038 PrintAndLogEx(ERR, "Desfire anticollision " _RED_("error") ".");
1039 return 200;
1041 if (verbose)
1042 PrintAndLogEx(INFO, "Anticollision " _GREEN_("ok"));
1043 } else {
1044 res = DesfireSelectAIDHex(dctx, aid, false, 0);
1045 if (res != PM3_SUCCESS) {
1046 PrintAndLogEx(ERR, "Desfire select " _RED_("error") ".");
1047 return 200;
1049 if (verbose)
1050 PrintAndLogEx(INFO, "App %06x " _GREEN_("selected"), aid);
1053 if (isosw)
1054 dctx->cmdSet = DCCISO;
1056 if (noauth == false) {
1057 res = DesfireAuthenticate(dctx, secureChannel, verbose);
1058 if (res != PM3_SUCCESS) {
1059 PrintAndLogEx(ERR, "Desfire authenticate " _RED_("error") ". Result: [%d] %s", res, DesfireAuthErrorToStr(res));
1060 return res;
1063 if (DesfireIsAuthenticated(dctx)) {
1064 if (verbose)
1065 PrintAndLogEx(INFO, "Desfire " _GREEN_("authenticated"));
1066 } else {
1067 return 201;
1071 return PM3_SUCCESS;
1074 int DesfireSelectAndAuthenticate(DesfireContext_t *dctx, DesfireSecureChannel secureChannel, uint32_t aid, bool verbose) {
1075 return DesfireSelectAndAuthenticateEx(dctx, secureChannel, aid, false, verbose);
1078 int DesfireSelectAndAuthenticateW(DesfireContext_t *dctx, DesfireSecureChannel secureChannel, DesfireISOSelectWay way, uint32_t id, bool selectfile, uint16_t isofileid, bool noauth, bool verbose) {
1079 if (verbose)
1080 DesfirePrintContext(dctx);
1082 int res = 0;
1083 if (way == ISW6bAID && dctx->cmdSet == DCCISO) {
1084 dctx->cmdSet = DCCNativeISO;
1085 if (verbose)
1086 PrintAndLogEx(INFO, "Select via " _CYAN_("native iso wrapping") " interface");
1088 res = DesfireSelectAIDHex(dctx, id, false, 0);
1089 if (res != PM3_SUCCESS) {
1090 PrintAndLogEx(ERR, "Desfire select " _RED_("error") ".");
1091 return 200;
1093 if (verbose)
1094 PrintAndLogEx(INFO, "App %06x via native iso channel is " _GREEN_("selected"), id);
1096 dctx->cmdSet = DCCISO;
1097 } else {
1098 res = DesfireSelectEx(dctx, true, way, id, NULL);
1099 if (res != PM3_SUCCESS) {
1100 PrintAndLogEx(ERR, "Desfire %s select " _RED_("error") ".", DesfireSelectWayToStr(way));
1101 return 202;
1103 if (verbose)
1104 PrintAndLogEx(INFO, "%s is " _GREEN_("selected"), DesfireWayIDStr(way, id));
1107 if (selectfile) {
1108 res = DesfireSelectEx(dctx, false, ISWIsoID, isofileid, NULL);
1109 if (res != PM3_SUCCESS) {
1110 PrintAndLogEx(ERR, "Desfire iso file select " _RED_("error") ".");
1111 return 203;
1114 if (verbose)
1115 PrintAndLogEx(INFO, "Application %s file iso id %04x is " _GREEN_("selected"), DesfireWayIDStr(way, id), isofileid);
1118 if (!noauth) {
1119 res = DesfireAuthenticate(dctx, secureChannel, verbose);
1120 if (res != PM3_SUCCESS) {
1121 PrintAndLogEx(ERR, "Desfire authenticate " _RED_("error") ". Result: [%d] %s", res, DesfireAuthErrorToStr(res));
1122 return res;
1125 if (DesfireIsAuthenticated(dctx)) {
1126 if (verbose)
1127 PrintAndLogEx(INFO, "Desfire " _GREEN_("authenticated"));
1128 } else {
1129 return 201;
1133 return PM3_SUCCESS;
1136 int DesfireSelectAndAuthenticateAppW(DesfireContext_t *dctx, DesfireSecureChannel secureChannel, DesfireISOSelectWay way, uint32_t id, bool noauth, bool verbose) {
1137 return DesfireSelectAndAuthenticateW(dctx, secureChannel, way, id, false, 0, noauth, verbose);
1140 int DesfireSelectAndAuthenticateISO(DesfireContext_t *dctx, DesfireSecureChannel secureChannel, bool useaid, uint32_t aid, uint16_t isoappid, bool selectfile, uint16_t isofileid, bool noauth, bool verbose) {
1141 return DesfireSelectAndAuthenticateW(dctx, secureChannel, useaid ? ISW6bAID : ISWIsoID, useaid ? aid : isoappid, selectfile, isofileid, noauth, verbose);
1144 static int DesfireAuthenticateEV1(DesfireContext_t *dctx, DesfireSecureChannel secureChannel, bool verbose) {
1145 // 3 different way to authenticate AUTH (CRC16) , AUTH_ISO (CRC32) , AUTH_AES (CRC32)
1146 // 4 different crypto arg1 DES, 3DES, 3K3DES, AES
1147 // 3 different communication modes, PLAIN,MAC,CRYPTO
1149 DesfireClearSession(dctx);
1151 if (secureChannel == DACNone)
1152 return PM3_SUCCESS;
1154 uint8_t keybytes[24] = {0};
1155 // Crypt constants
1156 uint8_t IV[16] = {0};
1157 uint8_t RndA[16] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16};
1158 uint8_t RndB[16] = {0};
1159 uint8_t encRndB[16] = {0};
1160 uint8_t rotRndB[16] = {0}; //RndB'
1161 uint8_t both[32 + 1] = {0}; // ek/dk_keyNo(RndA+RndB')
1163 // Part 1
1164 memcpy(keybytes, dctx->key, desfire_get_key_length(dctx->keyType));
1166 uint8_t subcommand = MFDES_AUTHENTICATE;
1167 if (secureChannel == DACEV1) {
1168 if (dctx->keyType == T_AES)
1169 subcommand = MFDES_AUTHENTICATE_AES;
1170 else
1171 subcommand = MFDES_AUTHENTICATE_ISO;
1174 size_t recv_len = 0;
1175 uint8_t respcode = 0;
1176 uint8_t recv_data[256] = {0};
1178 if (verbose)
1179 PrintAndLogEx(INFO, _CYAN_("Auth:") " cmd: 0x%02x keynum: 0x%02x", subcommand, dctx->keyNum);
1181 // Let's send our auth command
1182 int res = DesfireExchangeEx(false, dctx, subcommand, &dctx->keyNum, 1, &respcode, recv_data, &recv_len, false, 0);
1183 if (res != PM3_SUCCESS) {
1184 return 1;
1187 if (!recv_len) {
1188 return 2;
1191 if (respcode != MFDES_ADDITIONAL_FRAME) {
1192 return 3;
1195 uint32_t expectedlen = 8;
1196 if (dctx->keyType == T_AES || dctx->keyType == T_3K3DES) {
1197 expectedlen = 16;
1200 if (recv_len != expectedlen) {
1201 return 4;
1204 // Part 2
1205 uint32_t rndlen = recv_len;
1206 memcpy(encRndB, recv_data, rndlen);
1209 // Part 3
1210 DesfireCryptoEncDecEx(dctx, DCOMainKey, encRndB, rndlen, RndB, false, false, IV);
1212 if (g_debugMode > 1) {
1213 PrintAndLogEx(DEBUG, "encRndB: %s", sprint_hex(encRndB, 8));
1214 PrintAndLogEx(DEBUG, "RndB: %s", sprint_hex(RndB, 8));
1217 // - Rotate RndB by 8 bits
1218 memcpy(rotRndB, RndB, rndlen);
1219 rol(rotRndB, rndlen);
1221 uint8_t encRndA[16] = {0x00};
1223 // - Encrypt our response
1224 if (secureChannel == DACd40) {
1225 memset(IV, 0, DESFIRE_MAX_CRYPTO_BLOCK_SIZE);
1226 DesfireCryptoEncDecEx(dctx, DCOMainKey, RndA, rndlen, encRndA, true, true, IV);
1228 memcpy(both, encRndA, rndlen);
1229 bin_xor(rotRndB, encRndA, rndlen);
1231 memset(IV, 0, DESFIRE_MAX_CRYPTO_BLOCK_SIZE);
1232 DesfireCryptoEncDecEx(dctx, DCOMainKey, rotRndB, rndlen, encRndB, true, true, IV);
1234 memcpy(both + rndlen, encRndB, rndlen);
1235 } else if (secureChannel == DACEV1) {
1236 uint8_t tmp[32] = {0x00};
1237 memcpy(tmp, RndA, rndlen);
1238 memcpy(tmp + rndlen, rotRndB, rndlen);
1239 if (g_debugMode > 1) {
1240 PrintAndLogEx(DEBUG, "rotRndB: %s", sprint_hex(rotRndB, rndlen));
1241 PrintAndLogEx(DEBUG, "Both : %s", sprint_hex(tmp, 32));
1243 DesfireCryptoEncDecEx(dctx, DCOMainKey, tmp, rndlen * 2, both, true, true, IV);
1246 uint32_t bothlen = 16;
1247 if (dctx->keyType == T_AES || dctx->keyType == T_3K3DES) {
1248 bothlen = 32;
1251 res = DesfireExchangeEx(false, dctx, MFDES_ADDITIONAL_FRAME, both, bothlen, &respcode, recv_data, &recv_len, false, 0);
1252 if (res != PM3_SUCCESS) {
1253 return 7;
1256 if (!recv_len) {
1257 return 8;
1260 if (respcode != MFDES_S_OPERATION_OK) {
1261 return 9;
1264 // Part 4
1265 memcpy(encRndA, recv_data, rndlen);
1267 //PrintAndLogEx(INFO, "encRndA : %s", sprint_hex(encRndA, rndlen));
1268 //PrintAndLogEx(INFO, "IV : %s", sprint_hex(IV, rndlen));
1270 if (secureChannel == DACd40)
1271 memset(IV, 0, DESFIRE_MAX_CRYPTO_BLOCK_SIZE);
1272 DesfireCryptoEncDecEx(dctx, DCOMainKey, encRndA, rndlen, encRndA, false, false, IV);
1274 // generate session key from rnda and rndb. before rol(RndA)!
1275 DesfireGenSessionKeyEV1(RndA, RndB, dctx->keyType, dctx->sessionKeyEnc);
1277 rol(RndA, rndlen);
1278 //PrintAndLogEx(INFO, "Expected_RndA : %s", sprint_hex(RndA, rndlen));
1279 //PrintAndLogEx(INFO, "Generated_RndA : %s", sprint_hex(encRndA, rndlen));
1280 for (uint32_t x = 0; x < rndlen; x++) {
1281 if (RndA[x] != encRndA[x]) {
1282 if (g_debugMode > 1) {
1283 PrintAndLogEx(DEBUG, "Expected_RndA : %s", sprint_hex(RndA, rndlen));
1284 PrintAndLogEx(DEBUG, "Generated_RndA : %s", sprint_hex(encRndA, rndlen));
1286 return 11;
1290 // If the 3Des key first 8 bytes = 2nd 8 Bytes then we are really using Singe Des
1291 // As such we need to set the session key such that the 2nd 8 bytes = 1st 8 Bytes
1292 if (dctx->keyType == T_3DES) {
1293 if (memcmp(dctx->key, &dctx->key[8], 8) == 0)
1294 memcpy(&dctx->sessionKeyEnc[8], dctx->sessionKeyEnc, 8);
1297 memset(dctx->IV, 0, DESFIRE_MAX_KEY_SIZE);
1298 dctx->secureChannel = secureChannel;
1299 memcpy(dctx->sessionKeyMAC, dctx->sessionKeyEnc, desfire_get_key_length(dctx->keyType));
1300 if (verbose)
1301 PrintAndLogEx(INFO, _GREEN_("Session key") " : %s", sprint_hex(dctx->sessionKeyEnc, desfire_get_key_length(dctx->keyType)));
1303 return PM3_SUCCESS;
1306 static int DesfireAuthenticateEV2(DesfireContext_t *dctx, DesfireSecureChannel secureChannel, bool firstauth, bool verbose) {
1307 // Crypt constants
1308 uint8_t IV[16] = {0};
1309 uint8_t RndA[CRYPTO_AES_BLOCK_SIZE] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16};
1310 uint8_t RndB[CRYPTO_AES_BLOCK_SIZE] = {0};
1311 uint8_t encRndB[CRYPTO_AES_BLOCK_SIZE] = {0};
1312 uint8_t rotRndA[CRYPTO_AES_BLOCK_SIZE] = {0}; //RndA'
1313 uint8_t rotRndB[CRYPTO_AES_BLOCK_SIZE] = {0}; //RndB'
1314 uint8_t both[CRYPTO_AES_BLOCK_SIZE * 2 + 1] = {0}; // ek/dk_keyNo(RndA+RndB')
1316 uint8_t subcommand = firstauth ? MFDES_AUTHENTICATE_EV2F : MFDES_AUTHENTICATE_EV2NF;
1317 uint8_t *key = dctx->key;
1319 size_t recv_len = 0;
1320 uint8_t respcode = 0;
1321 uint8_t recv_data[256] = {0};
1323 if (verbose)
1324 PrintAndLogEx(INFO, _CYAN_("Auth %s:") " cmd: 0x%02x keynum: 0x%02x key: %s", (firstauth) ? "first" : "non-first", subcommand, dctx->keyNum, sprint_hex(key, 16));
1326 // Let's send our auth command
1327 uint8_t cdata[] = {dctx->keyNum, 0x00};
1328 int res = DesfireExchangeEx(false, dctx, subcommand, cdata, (firstauth) ? sizeof(cdata) : 1, &respcode, recv_data, &recv_len, false, 0);
1329 if (res != PM3_SUCCESS) {
1330 return 1;
1333 if (!recv_len) {
1334 return 2;
1337 if (respcode != MFDES_ADDITIONAL_FRAME) {
1338 return 3;
1341 size_t rdataindx = 0;
1342 if (recv_len != CRYPTO_AES_BLOCK_SIZE) {
1343 if (recv_len == CRYPTO_AES_BLOCK_SIZE + 1) {
1344 if (recv_data[0] != 0x00)
1345 return 50;
1346 rdataindx = 1;
1347 } else {
1348 return 4;
1352 // Part 2
1353 memcpy(encRndB, &recv_data[rdataindx], 16);
1355 // Part 3
1356 if (aes_decode(IV, key, encRndB, RndB, CRYPTO_AES_BLOCK_SIZE))
1357 return 5;
1359 if (g_debugMode > 1) {
1360 PrintAndLogEx(DEBUG, "encRndB: %s", sprint_hex(encRndB, CRYPTO_AES_BLOCK_SIZE));
1361 PrintAndLogEx(DEBUG, "RndB: %s", sprint_hex(RndB, CRYPTO_AES_BLOCK_SIZE));
1364 // - Rotate RndB by 8 bits
1365 memcpy(rotRndB, RndB, CRYPTO_AES_BLOCK_SIZE);
1366 rol(rotRndB, CRYPTO_AES_BLOCK_SIZE);
1368 // - Encrypt our response
1369 uint8_t tmp[32] = {0x00};
1370 memcpy(tmp, RndA, CRYPTO_AES_BLOCK_SIZE);
1371 memcpy(tmp + CRYPTO_AES_BLOCK_SIZE, rotRndB, CRYPTO_AES_BLOCK_SIZE);
1372 if (g_debugMode > 1) {
1373 PrintAndLogEx(DEBUG, "rotRndB: %s", sprint_hex(rotRndB, CRYPTO_AES_BLOCK_SIZE));
1374 PrintAndLogEx(DEBUG, "Both: %s", sprint_hex(tmp, CRYPTO_AES_BLOCK_SIZE * 2));
1377 if (aes_encode(IV, key, tmp, both, CRYPTO_AES_BLOCK_SIZE * 2))
1378 return 6;
1379 if (g_debugMode > 1) {
1380 PrintAndLogEx(DEBUG, "EncBoth: %s", sprint_hex(both, CRYPTO_AES_BLOCK_SIZE * 2));
1383 res = DesfireExchangeEx(false, dctx, MFDES_ADDITIONAL_FRAME, both, CRYPTO_AES_BLOCK_SIZE * 2, &respcode, recv_data, &recv_len, false, 0);
1384 if (res != PM3_SUCCESS) {
1385 return 7;
1388 if (!recv_len) {
1389 return 8;
1392 if (respcode != MFDES_S_OPERATION_OK) {
1393 return 9;
1396 // Part 4
1397 uint8_t data[32] = {0};
1399 if (aes_decode(IV, key, recv_data, data, recv_len))
1400 return 10;
1402 // rotate rndA to check
1403 memcpy(rotRndA, RndA, CRYPTO_AES_BLOCK_SIZE);
1404 rol(rotRndA, CRYPTO_AES_BLOCK_SIZE);
1406 uint8_t *recRndA = (firstauth) ? &data[4] : data;
1408 if (memcmp(rotRndA, recRndA, CRYPTO_AES_BLOCK_SIZE) != 0) {
1409 if (g_debugMode > 1) {
1410 PrintAndLogEx(DEBUG, "Expected_RndA' : %s", sprint_hex(rotRndA, CRYPTO_AES_BLOCK_SIZE));
1411 PrintAndLogEx(DEBUG, "Generated_RndA' : %s", sprint_hex(recRndA, CRYPTO_AES_BLOCK_SIZE));
1413 return 11;
1416 if (firstauth) {
1417 dctx->cmdCntr = 0;
1418 memcpy(dctx->TI, data, 4);
1420 DesfireClearIV(dctx);
1421 DesfireGenSessionKeyEV2(dctx->key, RndA, RndB, true, dctx->sessionKeyEnc);
1422 DesfireGenSessionKeyEV2(dctx->key, RndA, RndB, false, dctx->sessionKeyMAC);
1423 dctx->secureChannel = secureChannel;
1425 if (verbose) {
1426 if (firstauth) {
1427 PrintAndLogEx(INFO, "TI : %s", sprint_hex(data, 4));
1428 PrintAndLogEx(INFO, "pic : %s", sprint_hex(&data[20], 6));
1429 PrintAndLogEx(INFO, "pcd : %s", sprint_hex(&data[26], 6));
1430 } else {
1431 PrintAndLogEx(INFO, "TI : %s", sprint_hex(dctx->TI, 4));
1433 PrintAndLogEx(INFO, "session key ENC: %s", sprint_hex(dctx->sessionKeyEnc, 16));
1434 PrintAndLogEx(INFO, "session key MAC: %s", sprint_hex(dctx->sessionKeyMAC, 16));
1437 return PM3_SUCCESS;
1440 static int DesfireAuthenticateISO(DesfireContext_t *dctx, DesfireSecureChannel secureChannel, bool verbose) {
1441 uint8_t rndlen = DesfireGetRndLenForKey(dctx->keyType);
1443 uint8_t hostrnd[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16};
1444 uint8_t hostrnd2[] = {0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01};
1446 uint8_t piccrnd[64];
1447 size_t xlen = 0;
1448 int res = DesfireISOGetChallenge(dctx, dctx->keyType, piccrnd, &xlen);
1449 if (res != PM3_SUCCESS)
1450 return 301;
1452 if (xlen != rndlen)
1453 return 302;
1455 uint8_t both[32] = {0};
1456 memcpy(both, hostrnd, rndlen);
1457 memcpy(&both[rndlen], piccrnd, rndlen);
1459 // encode
1460 DesfireClearIV(dctx);
1461 DesfireCryptoEncDec(dctx, DCOMainKey, both, rndlen * 2, both, true); // error 303
1463 // external authenticate
1464 res = DesfireISOExternalAuth(dctx, dctx->appSelected, dctx->keyNum, dctx->keyType, both);
1465 if (res != PM3_SUCCESS)
1466 return 304;
1468 // internal authenticate
1469 uint8_t rnddata[64] = {0};
1470 xlen = 0;
1471 res = DesfireISOInternalAuth(dctx, dctx->appSelected, dctx->keyNum, dctx->keyType, hostrnd2, rnddata, &xlen);
1472 if (res != PM3_SUCCESS)
1473 return 305;
1475 if (xlen != rndlen * 2)
1476 return 306;
1478 // decode rnddata
1479 uint8_t piccrnd2[64] = {0};
1480 DesfireCryptoEncDec(dctx, DCOMainKey, rnddata, rndlen * 2, piccrnd2, false); // error 307
1482 // check
1483 if (memcmp(hostrnd2, &piccrnd2[rndlen], rndlen) != 0)
1484 return 308;
1486 DesfireGenSessionKeyEV1(hostrnd, piccrnd2, dctx->keyType, dctx->sessionKeyEnc);
1487 DesfireClearIV(dctx);
1488 memcpy(dctx->sessionKeyMAC, dctx->sessionKeyEnc, desfire_get_key_length(dctx->keyType));
1489 dctx->secureChannel = secureChannel;
1491 if (verbose)
1492 PrintAndLogEx(INFO, "session key: %s", sprint_hex(dctx->sessionKeyEnc, desfire_get_key_length(dctx->keyType)));
1494 return PM3_SUCCESS;
1497 static int DesfireAuthenticateLRP(DesfireContext_t *dctx, DesfireSecureChannel secureChannel, bool firstauth, bool verbose) {
1498 // Crypt constants
1499 uint8_t RndA[CRYPTO_AES_BLOCK_SIZE] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16};
1500 uint8_t RndB[CRYPTO_AES_BLOCK_SIZE] = {0};
1501 uint8_t both[CRYPTO_AES_BLOCK_SIZE * 2 + 1] = {0};
1503 uint8_t subcommand = firstauth ? MFDES_AUTHENTICATE_EV2F : MFDES_AUTHENTICATE_EV2NF;
1504 uint8_t *key = dctx->key;
1506 size_t recv_len = 0;
1507 uint8_t respcode = 0;
1508 uint8_t recv_data[256] = {0};
1510 if (verbose)
1511 PrintAndLogEx(INFO, _CYAN_("Auth %s:") " cmd: 0x%02x keynum: 0x%02x key: %s", (firstauth) ? "first" : "non-first", subcommand, dctx->keyNum, sprint_hex(key, 16));
1513 // Let's send our auth command
1514 uint8_t cdata[] = {dctx->keyNum, 0x01, 0x02};
1515 int res = DesfireExchangeEx(false, dctx, subcommand, cdata, (firstauth) ? sizeof(cdata) : 1, &respcode, recv_data, &recv_len, false, 0);
1516 if (res != PM3_SUCCESS) {
1517 return 1;
1520 if (!recv_len) {
1521 return 2;
1524 if (respcode != MFDES_ADDITIONAL_FRAME) {
1525 return 3;
1528 if (recv_len != CRYPTO_AES_BLOCK_SIZE + 1) {
1529 return 4;
1532 if (recv_data[0] != 0x01)
1533 return 51;
1535 // PICC return RndB in plain
1536 memcpy(RndB, &recv_data[1], 16);
1538 if (g_debugMode > 1) {
1539 PrintAndLogEx(DEBUG, "RndB: %s", sprint_hex(RndB, CRYPTO_AES_BLOCK_SIZE));
1542 // cmac(sessionkey, rnda+rndb)
1543 uint8_t sessionkey[32] = {0};
1544 DesfireGenSessionKeyLRP(key, RndA, RndB, false, sessionkey);
1546 uint8_t tmp[CRYPTO_AES_BLOCK_SIZE * 4] = {0};
1547 memcpy(tmp, RndA, CRYPTO_AES_BLOCK_SIZE);
1548 memcpy(tmp + CRYPTO_AES_BLOCK_SIZE, RndB, CRYPTO_AES_BLOCK_SIZE);
1550 uint8_t cmac[CRYPTO_AES_BLOCK_SIZE] = {0};
1551 LRPContext_t ctx = {0};
1552 LRPSetKey(&ctx, sessionkey, 0, true);
1553 LRPCMAC(&ctx, tmp, 32, cmac);
1555 // response = rnda + cmac(sessionkey, rnda+rndb)
1556 memcpy(both, RndA, CRYPTO_AES_BLOCK_SIZE);
1557 memcpy(both + CRYPTO_AES_BLOCK_SIZE, cmac, CRYPTO_AES_BLOCK_SIZE);
1558 if (g_debugMode > 1) {
1559 PrintAndLogEx(DEBUG, "Both: %s", sprint_hex(tmp, CRYPTO_AES_BLOCK_SIZE * 2));
1562 res = DesfireExchangeEx(false, dctx, MFDES_ADDITIONAL_FRAME, both, CRYPTO_AES_BLOCK_SIZE * 2, &respcode, recv_data, &recv_len, false, 0);
1563 if (res != PM3_SUCCESS) {
1564 return 7;
1567 if (!recv_len) {
1568 return 8;
1571 if (respcode != MFDES_S_OPERATION_OK) {
1572 return 9;
1575 // Part 4
1576 uint8_t data[64] = {0};
1578 // clear IV here
1579 DesfireClearIV(dctx);
1581 // check mac
1582 memcpy(tmp, RndB, CRYPTO_AES_BLOCK_SIZE);
1583 memcpy(tmp + CRYPTO_AES_BLOCK_SIZE, RndA, CRYPTO_AES_BLOCK_SIZE);
1584 if (firstauth)
1585 memcpy(tmp + CRYPTO_AES_BLOCK_SIZE * 2, recv_data, CRYPTO_AES_BLOCK_SIZE);
1587 LRPSetKey(&ctx, sessionkey, 0, true);
1588 LRPCMAC(&ctx, tmp, (firstauth) ? CRYPTO_AES_BLOCK_SIZE * 3 : CRYPTO_AES_BLOCK_SIZE * 2, cmac);
1589 uint8_t *recCMAC = &recv_data[(firstauth) ? CRYPTO_AES_BLOCK_SIZE : 0];
1590 if (memcmp(recCMAC, cmac, CRYPTO_AES_BLOCK_SIZE) != 0) {
1591 if (g_debugMode > 1) {
1592 PrintAndLogEx(DEBUG, "Expected cmac : %s", sprint_hex(recCMAC, CRYPTO_AES_BLOCK_SIZE));
1593 PrintAndLogEx(DEBUG, "Generated cmac : %s", sprint_hex(cmac, CRYPTO_AES_BLOCK_SIZE));
1595 return 12;
1598 // decode data
1599 if (firstauth) {
1600 LRPSetKeyEx(&ctx, sessionkey, dctx->IV, 4 * 2, 1, false);
1601 size_t declen = 0;
1602 LRPDecode(&ctx, recv_data, 16, data, &declen);
1603 memcpy(dctx->IV, ctx.counter, 4);
1605 dctx->cmdCntr = 0;
1606 memcpy(dctx->TI, data, 4);
1609 memcpy(dctx->sessionKeyEnc, sessionkey, CRYPTO_AES_BLOCK_SIZE);
1610 memcpy(dctx->sessionKeyMAC, sessionkey, CRYPTO_AES_BLOCK_SIZE);
1611 dctx->secureChannel = secureChannel;
1613 if (verbose) {
1614 if (firstauth) {
1615 PrintAndLogEx(INFO, "TI : %s", sprint_hex(data, 4));
1616 PrintAndLogEx(INFO, "pic : %s", sprint_hex(&data[4], 6));
1617 PrintAndLogEx(INFO, "pcd : %s", sprint_hex(&data[10], 6));
1618 } else {
1619 PrintAndLogEx(INFO, "TI : %s", sprint_hex(dctx->TI, 4));
1621 PrintAndLogEx(INFO, "session key : %s", sprint_hex(dctx->sessionKeyEnc, 16));
1624 return PM3_SUCCESS;
1628 int DesfireAuthenticate(DesfireContext_t *dctx, DesfireSecureChannel secureChannel, bool verbose) {
1629 if (dctx->kdfAlgo == MFDES_KDF_ALGO_AN10922) {
1630 MifareKdfAn10922(dctx, DCOMasterKey, dctx->kdfInput, dctx->kdfInputLen);
1631 PrintAndLogEx(DEBUG, " Derrived key: " _GREEN_("%s"), sprint_hex(dctx->key, desfire_get_key_block_length(dctx->keyType)));
1632 } else if (dctx->kdfAlgo == MFDES_KDF_ALGO_GALLAGHER) {
1633 // We will overrite any provided KDF input since a gallagher specific KDF was requested.
1634 dctx->kdfInputLen = 11;
1636 if (mfdes_kdf_input_gallagher(dctx->uid, dctx->uidlen, dctx->keyNum, dctx->selectedAID, dctx->kdfInput, &dctx->kdfInputLen) != PM3_SUCCESS) {
1637 PrintAndLogEx(FAILED, "Could not generate Gallagher KDF input");
1639 PrintAndLogEx(DEBUG, " KDF Input: " _YELLOW_("%s"), sprint_hex(dctx->kdfInput, dctx->kdfInputLen));
1641 MifareKdfAn10922(dctx, DCOMasterKey, dctx->kdfInput, dctx->kdfInputLen);
1642 PrintAndLogEx(DEBUG, " Derrived key: " _GREEN_("%s"), sprint_hex(dctx->key, desfire_get_key_block_length(dctx->keyType)));
1645 if (dctx->cmdSet == DCCISO && secureChannel != DACEV2)
1646 return DesfireAuthenticateISO(dctx, secureChannel, verbose);
1648 if (secureChannel == DACd40 || secureChannel == DACEV1)
1649 return DesfireAuthenticateEV1(dctx, secureChannel, verbose);
1651 if (secureChannel == DACEV2)
1652 return DesfireAuthenticateEV2(dctx, secureChannel, (DesfireIsAuthenticated(dctx) == false), verbose); // non first auth if there is a working secure channel
1654 if (secureChannel == DACLRP)
1655 return DesfireAuthenticateLRP(dctx, secureChannel, (DesfireIsAuthenticated(dctx) == false), verbose);
1657 return 100;
1660 bool DesfireCheckAuthCmd(DesfireISOSelectWay way, uint32_t appID, uint8_t keyNum, uint8_t authcmd, bool checklrp) {
1661 size_t recv_len = 0;
1662 uint8_t respcode = 0;
1663 uint8_t recv_data[256] = {0};
1665 DesfireContext_t dctx = {0};
1666 dctx.keyNum = keyNum;
1667 dctx.commMode = DCMPlain;
1668 dctx.cmdSet = DCCNativeISO;
1670 // if cant select - return false
1671 int res = DesfireSelect(&dctx, way, appID, NULL);
1672 if (res != PM3_SUCCESS)
1673 return false;
1675 uint8_t data[] = {keyNum, 0x01, (checklrp) ? 0x02 : 0x00};
1676 uint8_t datalen = (authcmd == MFDES_AUTHENTICATE_EV2F) ? 3 : 1;
1677 res = DesfireExchangeEx(false, &dctx, authcmd, data, datalen, &respcode, recv_data, &recv_len, false, 0);
1678 DropField();
1680 if (checklrp)
1681 return (res == PM3_SUCCESS && respcode == 0xaf && recv_len == 17 && recv_data[0] == 0x01);
1682 else
1683 return (res == PM3_SUCCESS && respcode == 0xaf);
1686 static bool DesfireCheckISOAuthCmd(DesfireISOSelectWay way, uint32_t appID, char *dfname, uint8_t keyNum, DesfireCryptoAlgorithm keytype) {
1688 DesfireContext_t dctx = {0};
1689 dctx.keyNum = keyNum;
1690 dctx.commMode = DCMPlain;
1691 dctx.cmdSet = DCCISO;
1693 int res = DesfireSelect(&dctx, way, appID, dfname);
1694 if (res != PM3_SUCCESS)
1695 return false;
1697 bool app_level = !DesfireMFSelected(way, appID);
1698 uint8_t rndlen = DesfireGetRndLenForKey(keytype);
1700 uint8_t piccrnd[64] = {0};
1701 size_t xlen = 0;
1702 res = DesfireISOGetChallenge(&dctx, keytype, piccrnd, &xlen);
1703 if (res != PM3_SUCCESS || xlen != rndlen)
1704 return false;
1706 uint8_t resp[250] = {0};
1707 size_t resplen = 0;
1709 uint16_t sw = 0;
1710 uint8_t p1 = DesfireKeyToISOKey(keytype);
1711 uint8_t p2 = ((app_level) ? 0x80 : 0x00) | keyNum;
1712 res = DesfireExchangeISO(false, &dctx, (sAPDU_t) {0x00, ISO7816_EXTERNAL_AUTHENTICATION, p1, p2, rndlen * 2, piccrnd}, 0, resp, &resplen, &sw);
1713 DropField();
1714 return (sw == ISO7816_OK || sw == ISO7816_SECURITY_STATUS_NOT_SATISFIED);
1717 void DesfireCheckAuthCommands(DesfireISOSelectWay way, uint32_t appID, char *dfname, uint8_t keyNum, AuthCommandsChk_t *authCmdCheck) {
1718 memset(authCmdCheck, 0, sizeof(AuthCommandsChk_t));
1720 authCmdCheck->auth = DesfireCheckAuthCmd(way, appID, keyNum, MFDES_AUTHENTICATE, false);
1721 authCmdCheck->authISO = DesfireCheckAuthCmd(way, appID, keyNum, MFDES_AUTHENTICATE_ISO, false);
1722 authCmdCheck->authAES = DesfireCheckAuthCmd(way, appID, keyNum, MFDES_AUTHENTICATE_AES, false);
1723 authCmdCheck->authEV2 = DesfireCheckAuthCmd(way, appID, keyNum, MFDES_AUTHENTICATE_EV2F, false);
1724 authCmdCheck->authISONative = DesfireCheckISOAuthCmd(way, appID, dfname, keyNum, T_DES);
1725 authCmdCheck->authLRP = DesfireCheckAuthCmd(way, appID, keyNum, MFDES_AUTHENTICATE_EV2F, true);
1726 authCmdCheck->checked = true;
1729 void DesfireCheckAuthCommandsPrint(AuthCommandsChk_t *authCmdCheck) {
1730 PrintAndLogEx(SUCCESS, " Auth.............. %s", authCmdCheck->auth ? _GREEN_("YES") : _RED_("NO"));
1731 PrintAndLogEx(SUCCESS, " Auth ISO.......... %s", authCmdCheck->authISO ? _GREEN_("YES") : _RED_("NO"));
1732 PrintAndLogEx(SUCCESS, " Auth AES.......... %s", authCmdCheck->authAES ? _GREEN_("YES") : _RED_("NO"));
1733 PrintAndLogEx(SUCCESS, " Auth Ev2.......... %s", authCmdCheck->authEV2 ? _GREEN_("YES") : _RED_("NO"));
1734 PrintAndLogEx(SUCCESS, " Auth ISO Native... %s", authCmdCheck->authISONative ? _GREEN_("YES") : _RED_("NO"));
1735 PrintAndLogEx(SUCCESS, " Auth LRP.......... %s", authCmdCheck->authLRP ? _GREEN_("YES") : _RED_("NO"));
1738 int DesfireFillPICCInfo(DesfireContext_t *dctx, PICCInfo_t *PICCInfo, bool deepmode) {
1739 uint8_t buf[250] = {0};
1740 size_t buflen = 0;
1742 uint32_t freemem = 0;
1743 int res = DesfireGetFreeMem(dctx, &freemem);
1744 if (res == PM3_SUCCESS)
1745 PICCInfo->freemem = freemem;
1746 else
1747 PICCInfo->freemem = 0xffffffff;
1749 PICCInfo->keySettings = 0;
1750 PICCInfo->numKeysRaw = 0;
1751 PICCInfo->keyVersion0 = 0;
1752 res = DesfireGetKeySettings(dctx, buf, &buflen);
1753 if (res == PM3_SUCCESS && buflen >= 2) {
1754 PICCInfo->keySettings = buf[0];
1755 PICCInfo->numKeysRaw = buf[1];
1756 PICCInfo->numberOfKeys = PICCInfo->numKeysRaw & 0x1f;
1757 if (PICCInfo->numKeysRaw > 0) {
1758 uint8_t keyNum0 = 0;
1759 res = DesfireGetKeyVersion(dctx, &keyNum0, 1, buf, &buflen);
1760 if (res == PM3_SUCCESS && buflen > 0) {
1761 PICCInfo->keyVersion0 = buf[0];
1766 // field on-off zone
1767 if (deepmode)
1768 DesfireCheckAuthCommands(ISW6bAID, 0x000000, NULL, 0, &PICCInfo->authCmdCheck);
1770 return PM3_SUCCESS;
1773 static int AppListSearchAID(uint32_t appNum, AppListS AppList, size_t appcount) {
1774 for (int i = 0; i < appcount; i++)
1775 if (AppList[i].appNum == appNum)
1776 return i;
1778 return -1;
1781 int DesfireFillAppList(DesfireContext_t *dctx, PICCInfo_t *PICCInfo, AppListS appList, bool deepmode, bool readFiles, bool fillAppSettings) {
1782 uint8_t buf[250] = {0};
1783 size_t buflen = 0;
1785 int res = DesfireGetAIDList(dctx, buf, &buflen);
1786 if (res != PM3_SUCCESS) {
1787 PrintAndLogEx(ERR, "Desfire GetAIDList command " _RED_("error") ". Result: %d", res);
1788 DropField();
1789 return PM3_ESOFT;
1792 PICCInfo->appCount = buflen / 3;
1793 for (int i = 0; i < buflen; i += 3)
1794 appList[i / 3].appNum = DesfireAIDByteToUint(&buf[i]);
1796 // result bytes: 3, 2, 1-16. total record size = 24
1797 res = DesfireGetDFList(dctx, buf, &buflen);
1798 if (res != PM3_SUCCESS) {
1799 PrintAndLogEx(WARNING, "Desfire GetDFList command " _RED_("error") ". Result: %d", res);
1800 } else if (buflen > 0) {
1801 for (int i = 0; i < buflen; i++) {
1802 int indx = AppListSearchAID(DesfireAIDByteToUint(&buf[i * 24 + 1]), appList, PICCInfo->appCount);
1803 if (indx >= 0) {
1804 appList[indx].appISONum = MemLeToUint2byte(&buf[i * 24 + 1 + 3]);
1805 memcpy(
1806 appList[indx].appDFName,
1807 &buf[i * 24 + 1 + 5],
1808 // str_nlen((char *)&buf[i * 24 + 1 + 5], 16)
1815 // field on-off zone
1816 DesfireFillPICCInfo(dctx, PICCInfo, deepmode);
1818 if (fillAppSettings && PICCInfo->appCount > 0) {
1819 for (int i = 0; i < PICCInfo->appCount; i++) {
1820 if (i == 0)
1821 res = DesfireSelectAIDHex(dctx, appList[i].appNum, false, 0);
1822 else
1823 res = DesfireSelectAIDHexNoFieldOn(dctx, appList[i].appNum);
1824 if (res != PM3_SUCCESS)
1825 continue;
1827 DesfireGetKeySettings(dctx, buf, &buflen);
1828 if (res == PM3_SUCCESS && buflen >= 2) {
1829 appList[i].keySettings = buf[0];
1830 appList[i].numKeysRaw = buf[1];
1831 appList[i].numberOfKeys = appList[i].numKeysRaw & 0x1f;
1832 appList[i].isoFileIDEnabled = ((appList[i].numKeysRaw & 0x20) != 0);
1833 appList[i].keyType = DesfireKeyTypeToAlgo(appList[i].numKeysRaw >> 6);
1835 if (appList[i].numberOfKeys > 0)
1836 for (uint8_t keyn = 0; keyn < appList[i].numberOfKeys; keyn++) {
1837 res = DesfireGetKeyVersion(dctx, &keyn, 1, buf, &buflen);
1838 if (res == PM3_SUCCESS && buflen > 0) {
1839 appList[i].keyVersions[keyn] = buf[0];
1843 appList[i].filesReaded = false;
1844 if (readFiles) {
1845 res = DesfireFillFileList(dctx, appList[i].fileList, &appList[i].filesCount, &appList[i].isoPresent);
1846 appList[i].filesReaded = (res == PM3_SUCCESS);
1852 // field on-off zone
1853 if (fillAppSettings && PICCInfo->appCount > 0 && deepmode) {
1854 for (int i = 0; i < PICCInfo->appCount; i++) {
1855 DesfireCheckAuthCommands(ISW6bAID, appList[i].appNum, appList[i].appDFName, 0, &appList[i].authCmdCheck);
1859 return PM3_SUCCESS;
1862 void DesfirePrintPICCInfo(DesfireContext_t *dctx, PICCInfo_t *PICCInfo) {
1863 PrintAndLogEx(SUCCESS, "------------------------------------ " _CYAN_("PICC level") " -------------------------------------");
1864 if (PICCInfo->freemem == 0xffffffff)
1865 PrintAndLogEx(SUCCESS, "Applications count: " _GREEN_("%zu") " free memory " _YELLOW_("n/a"), PICCInfo->appCount);
1866 else
1867 PrintAndLogEx(SUCCESS, "Applications count: " _GREEN_("%zu") " free memory " _GREEN_("%d") " bytes", PICCInfo->appCount, PICCInfo->freemem);
1868 if (PICCInfo->authCmdCheck.checked) {
1869 PrintAndLogEx(SUCCESS, "PICC level auth commands: ");
1870 DesfireCheckAuthCommandsPrint(&PICCInfo->authCmdCheck);
1872 if (PICCInfo->numberOfKeys > 0) {
1873 PrintKeySettings(PICCInfo->keySettings, PICCInfo->numKeysRaw, false, true);
1874 PrintAndLogEx(SUCCESS, "PICC key 0 version: %d (0x%02x)", PICCInfo->keyVersion0, PICCInfo->keyVersion0);
1878 void DesfirePrintAppList(DesfireContext_t *dctx, PICCInfo_t *PICCInfo, AppListS appList) {
1879 if (PICCInfo->appCount == 0)
1880 return;
1882 PrintAndLogEx(NORMAL, "");
1883 PrintAndLogEx(SUCCESS, "--------------------------------- " _CYAN_("Applications list") " ---------------------------------");
1885 for (int i = 0; i < PICCInfo->appCount; i++) {
1886 PrintAndLogEx(SUCCESS, _CYAN_("Application number: 0x%02X"), appList[i].appNum);
1887 PrintAndLogEx(SUCCESS, " ISO id.... " _GREEN_("0x%04X"), appList[i].appISONum);
1888 PrintAndLogEx(SUCCESS, " DF name... " _GREEN_("%s") " ( %s)", appList[i].appDFName, sprint_hex((uint8_t *)appList[i].appDFName, sizeof(appList[i].appDFName)));
1890 DesfirePrintAIDFunctions(appList[i].appNum);
1892 if (PICCInfo->authCmdCheck.checked) {
1893 PrintAndLogEx(SUCCESS, "Auth commands: ");
1894 DesfireCheckAuthCommandsPrint(&appList[i].authCmdCheck);
1895 PrintAndLogEx(SUCCESS, "");
1898 if (appList[i].numberOfKeys > 0) {
1899 PrintKeySettings(appList[i].keySettings, appList[i].numKeysRaw, true, true);
1901 if (appList[i].numberOfKeys > 0) {
1902 PrintAndLogEx(SUCCESS, "Key versions [0..%d]: " NOLF, appList[i].numberOfKeys - 1);
1903 for (uint8_t keyn = 0; keyn < appList[i].numberOfKeys; keyn++) {
1904 PrintAndLogEx(NORMAL, "%s %02x" NOLF, (keyn == 0) ? "" : ",", appList[i].keyVersions[keyn]);
1906 PrintAndLogEx(NORMAL, "\n");
1909 if (appList[i].filesReaded) {
1910 PrintAndLogEx(SUCCESS, "Application have " _GREEN_("%zu") " files", appList[i].filesCount);
1912 if (appList[i].filesCount > 0) {
1913 for (int fnum = 0; fnum < appList[i].filesCount; fnum++) {
1914 PrintAndLogEx(NORMAL, "");
1915 PrintAndLogEx(SUCCESS, "--------------------------------- " _CYAN_("File %02x") " ----------------------------------", appList[i].fileList[fnum].fileNum);
1916 PrintAndLogEx(SUCCESS, "File ID : " _GREEN_("%02x"), appList[i].fileList[fnum].fileNum);
1917 if (appList[i].isoPresent) {
1918 if (appList[i].fileList[fnum].fileISONum != 0)
1919 PrintAndLogEx(SUCCESS, "File ISO ID : %04x", appList[i].fileList[fnum].fileISONum);
1920 else
1921 PrintAndLogEx(SUCCESS, "File ISO ID : " _YELLOW_("n/a"));
1923 DesfirePrintFileSettingsExtended(&appList[i].fileList[fnum].fileSettings);
1926 PrintAndLogEx(NORMAL, "");
1932 static int DesfireCommandEx(DesfireContext_t *dctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *resp, size_t *resplen, int checklength, size_t splitbysize) {
1933 if (resplen) {
1934 *resplen = 0;
1937 uint8_t respcode = 0xFF;
1939 uint8_t *xresp = calloc(DESFIRE_BUFFER_SIZE, 1);
1940 if (xresp == NULL) {
1941 return PM3_EMALLOC;
1944 size_t xresplen = 0;
1945 int res = DesfireExchangeEx(false, dctx, cmd, data, datalen, &respcode, xresp, &xresplen, true, splitbysize);
1946 if (res != PM3_SUCCESS) {
1947 free(xresp);
1948 return res;
1951 if (respcode != MFDES_S_OPERATION_OK) {
1952 free(xresp);
1953 return PM3_EAPDU_FAIL;
1956 if (checklength >= 0 && xresplen != checklength) {
1957 free(xresp);
1958 return PM3_EAPDU_FAIL;
1961 if (resplen) {
1962 *resplen = xresplen;
1965 if (resp) {
1966 memcpy(resp, xresp, (splitbysize == 0) ? xresplen : xresplen * splitbysize);
1969 free(xresp);
1970 return PM3_SUCCESS;
1973 static int DesfireCommand(DesfireContext_t *dctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *resp, size_t *resplen, int checklength) {
1974 return DesfireCommandEx(dctx, cmd, data, datalen, resp, resplen, checklength, 0);
1977 static int DesfireCommandNoData(DesfireContext_t *dctx, uint8_t cmd) {
1978 return DesfireCommand(dctx, cmd, NULL, 0, NULL, NULL, 0);
1981 static int DesfireCommandTxData(DesfireContext_t *dctx, uint8_t cmd, uint8_t *data, size_t datalen) {
1982 return DesfireCommand(dctx, cmd, data, datalen, NULL, NULL, 0);
1985 static int DesfireCommandRxData(DesfireContext_t *dctx, uint8_t cmd, uint8_t *resp, size_t *resplen, int checklength) {
1986 return DesfireCommand(dctx, cmd, NULL, 0, resp, resplen, checklength);
1989 int DesfireFormatPICC(DesfireContext_t *dctx) {
1990 return DesfireCommandNoData(dctx, MFDES_FORMAT_PICC);
1993 int DesfireGetFreeMem(DesfireContext_t *dctx, uint32_t *freemem) {
1994 *freemem = 0;
1996 uint8_t resp[257] = {0};
1997 size_t resplen = 0;
1998 int res = DesfireCommandRxData(dctx, MFDES_GET_FREE_MEMORY, resp, &resplen, 3);
1999 if (res == PM3_SUCCESS) {
2000 *freemem = DesfireAIDByteToUint(resp);
2002 return res;
2005 int DesfireReadSignature(DesfireContext_t *dctx, uint8_t sid, uint8_t *resp, size_t *resplen) {
2006 *resplen = 0;
2008 uint8_t xresp[257] = {0};
2009 size_t xresplen = 0;
2010 uint8_t respcode = 0xff;
2012 int res = DesfireExchange(dctx, MFDES_READSIG, &sid, 1, &respcode, xresp, &xresplen);
2013 if (res != PM3_SUCCESS) {
2014 return res;
2017 if (respcode != 0x90) {
2018 return PM3_EAPDU_FAIL;
2021 memcpy(resp, xresp, xresplen);
2023 *resplen = xresplen;
2025 return PM3_SUCCESS;
2028 int DesfireGetUID(DesfireContext_t *dctx, uint8_t *resp, size_t *resplen) {
2029 return DesfireCommandRxData(dctx, MFDES_GET_UID, resp, resplen, -1);
2032 int DesfireGetAIDList(DesfireContext_t *dctx, uint8_t *resp, size_t *resplen) {
2033 return DesfireCommandRxData(dctx, MFDES_GET_APPLICATION_IDS, resp, resplen, -1);
2036 int DesfireGetDFList(DesfireContext_t *dctx, uint8_t *resp, size_t *resplen) {
2037 return DesfireCommandEx(dctx, MFDES_GET_DF_NAMES, NULL, 0, resp, resplen, -1, 24);
2040 int DesfireCreateApplication(DesfireContext_t *dctx, uint8_t *appdata, size_t appdatalen) {
2041 return DesfireCommandTxData(dctx, MFDES_CREATE_APPLICATION, appdata, appdatalen);
2044 int DesfireDeleteApplication(DesfireContext_t *dctx, uint32_t aid) {
2045 uint8_t data[3] = {0};
2046 DesfireAIDUintToByte(aid, data);
2047 return DesfireCommandTxData(dctx, MFDES_DELETE_APPLICATION, data, sizeof(data));
2050 int DesfireGetKeySettings(DesfireContext_t *dctx, uint8_t *resp, size_t *resplen) {
2051 return DesfireCommandRxData(dctx, MFDES_GET_KEY_SETTINGS, resp, resplen, -1);
2054 int DesfireGetKeyVersion(DesfireContext_t *dctx, uint8_t *data, size_t len, uint8_t *resp, size_t *resplen) {
2055 return DesfireCommand(dctx, MFDES_GET_KEY_VERSION, data, len, resp, resplen, -1);
2058 int DesfireChangeKeySettings(DesfireContext_t *dctx, uint8_t *data, size_t len) {
2059 return DesfireCommandTxData(dctx, MFDES_CHANGE_KEY_SETTINGS, data, len);
2062 int DesfireChangeKeyCmd(DesfireContext_t *dctx, uint8_t *data, size_t datalen, uint8_t *resp, size_t *resplen) {
2063 return DesfireCommand(dctx, MFDES_CHANGE_KEY, data, datalen, resp, resplen, -1);
2066 int DesfireSetConfigurationCmd(DesfireContext_t *dctx, uint8_t *data, size_t len, uint8_t *resp, size_t *resplen) {
2067 return DesfireCommand(dctx, MFDES_CHANGE_CONFIGURATION, data, len, resp, resplen, -1);
2070 int DesfireChangeFileSettings(DesfireContext_t *dctx, uint8_t *data, size_t datalen) {
2071 return DesfireCommandTxData(dctx, MFDES_CHANGE_FILE_SETTINGS, data, datalen);
2074 int DesfireGetFileIDList(DesfireContext_t *dctx, uint8_t *resp, size_t *resplen) {
2075 return DesfireCommandRxData(dctx, MFDES_GET_FILE_IDS, resp, resplen, -1);
2078 int DesfireGetFileISOIDList(DesfireContext_t *dctx, uint8_t *resp, size_t *resplen) {
2079 return DesfireCommandRxData(dctx, MFDES_GET_ISOFILE_IDS, resp, resplen, -1);
2082 int DesfireGetFileSettings(DesfireContext_t *dctx, uint8_t fileid, uint8_t *resp, size_t *resplen) {
2083 return DesfireCommand(dctx, MFDES_GET_FILE_SETTINGS, &fileid, 1, resp, resplen, -1);
2086 int DesfireFileSettingsStruct(DesfireContext_t *dctx, uint8_t fileid, FileSettings_t *fsettings) {
2087 uint8_t resp[250] = {0};
2088 size_t resplen = 0;
2089 int res = DesfireGetFileSettings(dctx, fileid, resp, &resplen);
2090 if (res == PM3_SUCCESS && resplen > 0 && fsettings != NULL)
2091 DesfireFillFileSettings(resp, resplen, fsettings);
2093 return res;
2096 int DesfireFillFileList(DesfireContext_t *dctx, FileList_t FileList, size_t *filescount, bool *isopresent) {
2097 uint8_t buf[APDU_RES_LEN] = {0};
2098 size_t buflen = 0;
2100 *filescount = 0;
2101 *isopresent = false;
2102 memset(FileList, 0, sizeof(FileList_t));
2104 int res = DesfireGetFileIDList(dctx, buf, &buflen);
2105 if (res != PM3_SUCCESS) {
2106 PrintAndLogEx(ERR, "Desfire GetFileIDList command " _RED_("error") ". Result: %d", res);
2107 return PM3_ESOFT;
2110 if (buflen == 0)
2111 return PM3_SUCCESS;
2113 for (int i = 0; i < buflen; i++) {
2114 FileList[i].fileNum = buf[i];
2115 DesfireFileSettingsStruct(dctx, FileList[i].fileNum, &FileList[i].fileSettings);
2117 *filescount = buflen;
2119 buflen = 0;
2120 res = DesfireGetFileISOIDList(dctx, buf, &buflen);
2121 if (res != PM3_SUCCESS) {
2122 PrintAndLogEx(ERR, "Desfire GetFileISOIDList command " _RED_("error") ". Result: %d", res);
2125 size_t isoindx = 0;
2126 if (buflen > 0) {
2127 for (int i = 0; i < *filescount; i++) {
2128 if (FileList[i].fileSettings.fileType != 0x02 && FileList[i].fileSettings.fileType != 0x05) {
2129 FileList[i].fileISONum = MemLeToUint2byte(&buf[isoindx * 2]);
2130 isoindx++;
2134 if (isoindx * 2 != buflen)
2135 PrintAndLogEx(WARNING, "Wrong ISO ID list length. must be %zu but %zu", buflen, isoindx * 2);
2136 } else {
2137 PrintAndLogEx(WARNING, "ISO ID list returned no data");
2140 *isopresent = (isoindx > 0);
2142 return PM3_SUCCESS;
2145 int DesfireCreateFile(DesfireContext_t *dctx, uint8_t ftype, uint8_t *fdata, size_t fdatalen, bool checklen) {
2146 const DesfireCreateFileCommands_t *rcmd = GetDesfireFileCmdRec(ftype);
2147 if (rcmd == NULL)
2148 return -100;
2149 if (checklen && fdatalen != (rcmd->createlen + 1) && fdatalen != (rcmd->createlen + 1 + (rcmd->mayHaveISOfid ? 2 : 0)))
2150 return -110;
2152 return DesfireCommandTxData(dctx, rcmd->cmd, fdata, fdatalen);
2155 int DesfireDeleteFile(DesfireContext_t *dctx, uint8_t fnum) {
2156 return DesfireCommandTxData(dctx, MFDES_DELETE_FILE, &fnum, 1);
2159 int DesfireClearRecordFile(DesfireContext_t *dctx, uint8_t fnum) {
2160 return DesfireCommandTxData(dctx, MFDES_CLEAR_RECORD_FILE, &fnum, 1);
2163 int DesfireCommitReaderID(DesfireContext_t *dctx, uint8_t *readerid, size_t readeridlen, uint8_t *resp, size_t *resplen) {
2164 uint8_t rid[16] = {0};
2165 // command use 16b reader id only
2166 memcpy(rid, readerid, MIN(readeridlen, 16));
2167 return DesfireCommand(dctx, MFDES_COMMIT_READER_ID, rid, 16, resp, resplen, -1);
2170 int DesfireCommitTransactionEx(DesfireContext_t *dctx, bool enable_options, uint8_t options, uint8_t *resp, size_t *resplen) {
2171 if (enable_options)
2172 return DesfireCommand(dctx, MFDES_COMMIT_TRANSACTION, &options, 1, resp, resplen, -1);
2173 else
2174 return DesfireCommandNoData(dctx, MFDES_COMMIT_TRANSACTION);
2177 int DesfireCommitTransaction(DesfireContext_t *dctx, bool enable_options, uint8_t options) {
2178 uint8_t resp[250] = {0};
2179 size_t resplen = 0;
2180 return DesfireCommitTransactionEx(dctx, enable_options, options, resp, &resplen);
2183 int DesfireAbortTransaction(DesfireContext_t *dctx) {
2184 return DesfireCommandNoData(dctx, MFDES_ABORT_TRANSACTION);
2187 int DesfireReadFile(DesfireContext_t *dctx, uint8_t fnum, uint32_t offset, uint32_t len, uint8_t *resp, size_t *resplen) {
2188 uint8_t data[10] = {0};
2189 data[0] = fnum;
2190 Uint3byteToMemLe(&data[1], offset);
2191 Uint3byteToMemLe(&data[4], len);
2192 return DesfireCommand(dctx, (dctx->isoChaining) ? MFDES_READ_DATA2 : MFDES_READ_DATA, data, 7, resp, resplen, -1);
2195 int DesfireWriteFile(DesfireContext_t *dctx, uint8_t fnum, uint32_t offset, uint32_t len, uint8_t *data) {
2196 uint8_t xdata[1024] = {0};
2197 xdata[0] = fnum;
2198 Uint3byteToMemLe(&xdata[1], offset);
2199 Uint3byteToMemLe(&xdata[4], len);
2200 memcpy(&xdata[7], data, len);
2202 return DesfireCommandTxData(dctx, (dctx->isoChaining) ? MFDES_WRITE_DATA2 : MFDES_WRITE_DATA, xdata, 7 + len);
2205 int DesfireValueFileOperations(DesfireContext_t *dctx, uint8_t fid, uint8_t operation, uint32_t *value) {
2206 uint8_t data[10] = {0};
2207 data[0] = fid;
2208 size_t datalen = (operation == MFDES_GET_VALUE) ? 1 : 5;
2209 if (value)
2210 Uint4byteToMemLe(&data[1], *value);
2212 uint8_t resp[250] = {0};
2213 size_t resplen = 0;
2215 int res = DesfireCommand(dctx, operation, data, datalen, resp, &resplen, -1);
2217 if (resplen == 4 && value) {
2218 *value = MemLeToUint4byte(resp);
2220 return res;
2223 int DesfireReadRecords(DesfireContext_t *dctx, uint8_t fnum, uint32_t recnum, uint32_t reccount, uint8_t *resp, size_t *resplen) {
2224 uint8_t data[10] = {0};
2225 data[0] = fnum;
2226 Uint3byteToMemLe(&data[1], recnum);
2227 Uint3byteToMemLe(&data[4], reccount);
2229 return DesfireCommand(dctx, (dctx->isoChaining) ? MFDES_READ_RECORDS2 : MFDES_READ_RECORDS, data, 7, resp, resplen, -1);
2232 int DesfireWriteRecord(DesfireContext_t *dctx, uint8_t fnum, uint32_t offset, uint32_t len, uint8_t *data) {
2233 uint8_t xdata[1024] = {0};
2234 xdata[0] = fnum;
2235 Uint3byteToMemLe(&xdata[1], offset);
2236 Uint3byteToMemLe(&xdata[4], len);
2237 memcpy(&xdata[7], data, len);
2239 return DesfireCommandTxData(dctx, (dctx->isoChaining) ? MFDES_WRITE_RECORD2 : MFDES_WRITE_RECORD, xdata, 7 + len);
2242 int DesfireUpdateRecord(DesfireContext_t *dctx, uint8_t fnum, uint32_t recnum, uint32_t offset, uint32_t len, uint8_t *data) {
2243 uint8_t xdata[1024] = {0};
2244 xdata[0] = fnum;
2245 Uint3byteToMemLe(&xdata[1], recnum);
2246 Uint3byteToMemLe(&xdata[4], offset);
2247 Uint3byteToMemLe(&xdata[7], len);
2248 memcpy(&xdata[10], data, len);
2250 return DesfireCommandTxData(dctx, (dctx->isoChaining) ? MFDES_UPDATE_RECORD2 : MFDES_UPDATE_RECORD, xdata, 10 + len);
2253 static void PrintKeySettingsPICC(uint8_t keysettings, uint8_t numkeys, bool print2ndbyte) {
2254 PrintAndLogEx(SUCCESS, "PICC level rights:");
2255 PrintAndLogEx(SUCCESS, "[%c...] CMK Configuration changeable : %s", (keysettings & (1 << 3)) ? '1' : '0', (keysettings & (1 << 3)) ? _GREEN_("YES") : _RED_("NO (frozen)"));
2256 PrintAndLogEx(SUCCESS, "[.%c..] CMK required for create/delete : %s", (keysettings & (1 << 2)) ? '1' : '0', (keysettings & (1 << 2)) ? _GREEN_("NO") : "YES");
2257 PrintAndLogEx(SUCCESS, "[..%c.] Directory list access with CMK : %s", (keysettings & (1 << 1)) ? '1' : '0', (keysettings & (1 << 1)) ? _GREEN_("NO") : "YES");
2258 PrintAndLogEx(SUCCESS, "[...%c] CMK is changeable : %s", (keysettings & (1 << 0)) ? '1' : '0', (keysettings & (1 << 0)) ? _GREEN_("YES") : _RED_("NO (frozen)"));
2259 PrintAndLogEx(SUCCESS, "");
2261 if (print2ndbyte) {
2262 DesfirePrintCardKeyType(numkeys >> 6);
2263 PrintAndLogEx(SUCCESS, "key count: %d", numkeys & 0x0f);
2267 static void PrintKeySettingsApp(uint8_t keysettings, uint8_t numkeys, bool print2ndbyte) {
2268 // Access rights.
2269 PrintAndLogEx(SUCCESS, "Application level rights:");
2270 uint8_t rights = ((keysettings >> 4) & 0x0F);
2271 switch (rights) {
2272 case 0x0:
2273 PrintAndLogEx(SUCCESS, "-- AMK authentication is necessary to change any key (default)");
2274 break;
2275 case 0xE:
2276 PrintAndLogEx(SUCCESS, "-- Authentication with the key to be changed (same KeyNo) is necessary to change a key");
2277 break;
2278 case 0xF:
2279 PrintAndLogEx(SUCCESS, "-- All keys (except AMK,see Bit0) within this application are frozen");
2280 break;
2281 default:
2282 PrintAndLogEx(SUCCESS,
2283 "-- Authentication with the specified key " _YELLOW_("(0x%02x)") " is necessary to change any key.\n"
2284 "A change key and a PICC master key (CMK) can only be changed after authentication with the master key.\n"
2285 "For keys other then the master or change key, an authentication with the same key is needed.",
2286 rights & 0x0f
2288 break;
2291 PrintAndLogEx(SUCCESS, "[%c...] AMK Configuration changeable : %s", (keysettings & (1 << 3)) ? '1' : '0', (keysettings & (1 << 3)) ? _GREEN_("YES") : _RED_("NO (frozen)"));
2292 PrintAndLogEx(SUCCESS, "[.%c..] AMK required for create/delete : %s", (keysettings & (1 << 2)) ? '1' : '0', (keysettings & (1 << 2)) ? _GREEN_("NO") : "YES");
2293 PrintAndLogEx(SUCCESS, "[..%c.] Directory list access with AMK : %s", (keysettings & (1 << 1)) ? '1' : '0', (keysettings & (1 << 1)) ? _GREEN_("NO") : "YES");
2294 PrintAndLogEx(SUCCESS, "[...%c] AMK is changeable : %s", (keysettings & (1 << 0)) ? '1' : '0', (keysettings & (1 << 0)) ? _GREEN_("YES") : _RED_("NO (frozen)"));
2295 PrintAndLogEx(SUCCESS, "");
2297 if (print2ndbyte) {
2298 DesfirePrintCardKeyType(numkeys >> 6);
2299 PrintAndLogEx(SUCCESS, "key count: %d", numkeys & 0x0f);
2300 if (numkeys & 0x20)
2301 PrintAndLogEx(SUCCESS, "iso file id: enabled");
2302 PrintAndLogEx(SUCCESS, "");
2306 void PrintKeySettings(uint8_t keysettings, uint8_t numkeys, bool applevel, bool print2ndbyte) {
2307 if (applevel)
2308 PrintKeySettingsApp(keysettings, numkeys, print2ndbyte);
2309 else
2310 PrintKeySettingsPICC(keysettings, numkeys, print2ndbyte);
2313 static const char *DesfireUnknownStr = "unknown";
2314 static const char *DesfireDisabledStr = "disabled";
2315 static const char *DesfireFreeStr = "free";
2316 static const char *DesfireNAStr = "n/a";
2317 static const DesfireCreateFileCommands_t DesfireFileCommands[] = {
2318 {0x00, "Standard data", MFDES_CREATE_STD_DATA_FILE, 6, 6, true},
2319 {0x01, "Backup data", MFDES_CREATE_BACKUP_DATA_FILE, 6, 6, true},
2320 {0x02, "Value", MFDES_CREATE_VALUE_FILE, 16, 16, false},
2321 {0x03, "Linear Record", MFDES_CREATE_LINEAR_RECORD_FILE, 12, 9, true},
2322 {0x04, "Cyclic Record", MFDES_CREATE_CYCLIC_RECORD_FILE, 12, 9, true},
2323 {0x05, "Transaction MAC", MFDES_CREATE_TRANS_MAC_FILE, 5, 21, false},
2326 const DesfireCreateFileCommands_t *GetDesfireFileCmdRec(uint8_t type) {
2327 for (int i = 0; i < ARRAYLEN(DesfireFileCommands); i++) {
2328 if (DesfireFileCommands[i].id == type) {
2329 return &DesfireFileCommands[i];
2332 return NULL;
2335 const char *GetDesfireFileType(uint8_t type) {
2336 const DesfireCreateFileCommands_t *res = GetDesfireFileCmdRec(type);
2337 if (res != NULL)
2338 return res->text;
2339 else
2340 return DesfireUnknownStr;
2343 static const char *DesfireCommunicationModes[] = {
2344 "Plain",
2345 "MAC",
2346 "Plain rfu",
2347 "Full",
2350 static const char *GetDesfireCommunicationMode(uint8_t mode) {
2351 if (mode < ARRAYLEN(DesfireCommunicationModes))
2352 return DesfireCommunicationModes[mode];
2353 else
2354 return DesfireUnknownStr;
2357 static const char *DesfireKeyTypeStr[] = {
2358 "2tdea",
2359 "3tdea",
2360 "aes",
2361 "rfu",
2364 static const char *GetDesfireKeyType(uint8_t keytype) {
2365 if (keytype < ARRAYLEN(DesfireKeyTypeStr))
2366 return DesfireKeyTypeStr[keytype];
2367 else
2368 return DesfireUnknownStr;
2371 const char *GetDesfireAccessRightStr(uint8_t right) {
2373 if (right <= 0x0d) {
2374 static char int_access_str[200];
2375 snprintf(int_access_str, sizeof(int_access_str), "key 0x%02x", right);
2376 return int_access_str;
2379 if (right == 0x0e)
2380 return DesfireFreeStr;
2382 if (right == 0x0f)
2383 return DesfireDisabledStr;
2385 return DesfireUnknownStr;
2388 const char *AccessRightShortStr[] = {
2389 "key0",
2390 "key1",
2391 "key2",
2392 "key3",
2393 "key4",
2394 "key5",
2395 "key6",
2396 "key7",
2397 "key8",
2398 "key9",
2399 "keyA",
2400 "keyB",
2401 "keyC",
2402 "keyD",
2403 "free",
2404 "deny"
2407 const char *GetDesfireAccessRightShortStr(uint8_t right) {
2408 if (right > 0x0F) {
2409 return DesfireNAStr;
2412 return AccessRightShortStr[right];
2415 void DesfireEncodeFileAcessMode(uint8_t *mode, uint8_t r, uint8_t w, uint8_t rw, uint8_t ch) {
2416 mode[0] = (ch & 0x0f) | ((rw << 4) & 0xf0);
2417 mode[1] = (w & 0x0f) | ((r << 4) & 0xf0);
2420 void DesfireDecodeFileAcessMode(const uint8_t *mode, uint8_t *r, uint8_t *w, uint8_t *rw, uint8_t *ch) {
2421 // read
2422 if (r)
2423 *r = (mode[1] >> 4) & 0x0F; // hi 2b
2424 // write
2425 if (w)
2426 *w = mode[1] & 0x0F;
2427 // read/write
2428 if (rw)
2429 *rw = (mode[0] >> 4) & 0x0F; // low 2b
2430 // change
2431 if (ch)
2432 *ch = mode[0] & 0x0F;
2435 void DesfirePrintAccessRight(uint8_t *data) {
2436 uint8_t r = 0, w = 0, rw = 0, ch = 0;
2437 DesfireDecodeFileAcessMode(data, &r, &w, &rw, &ch);
2438 PrintAndLogEx(SUCCESS, " read......... %s", GetDesfireAccessRightStr(r));
2439 PrintAndLogEx(SUCCESS, " write........ %s", GetDesfireAccessRightStr(w));
2440 PrintAndLogEx(SUCCESS, " read/write... %s", GetDesfireAccessRightStr(rw));
2441 PrintAndLogEx(SUCCESS, " change....... %s", GetDesfireAccessRightStr(ch));
2444 void DesfireFillFileSettings(uint8_t *data, size_t datalen, FileSettings_t *fsettings) {
2445 if (fsettings == NULL)
2446 return;
2448 memset(fsettings, 0, sizeof(FileSettings_t));
2450 if (datalen < 4)
2451 return;
2453 fsettings->fileType = data[0];
2454 fsettings->fileOption = data[1];
2455 fsettings->fileCommMode = data[1] & 0x03;
2456 fsettings->commMode = DesfireFileCommModeToCommMode(fsettings->fileCommMode);
2457 fsettings->additionalAccessRightsEn = ((data[1] & 0x80) != 0);
2458 fsettings->rawAccessRights = MemLeToUint2byte(&data[2]);
2459 DesfireDecodeFileAcessMode(&data[2], &fsettings->rAccess, &fsettings->wAccess, &fsettings->rwAccess, &fsettings->chAccess);
2461 int reclen = 0;
2462 switch (fsettings->fileType) {
2463 case 0x00:
2464 case 0x01: {
2465 fsettings->fileSize = MemLeToUint3byte(&data[4]);
2466 reclen = 4 + 3;
2467 break;
2469 case 0x02: {
2470 fsettings->lowerLimit = MemLeToUint4byte(&data[4]);
2471 fsettings->upperLimit = MemLeToUint4byte(&data[8]);
2472 fsettings->value = MemLeToUint4byte(&data[12]);
2473 fsettings->limitedCredit = data[16];
2474 reclen = 4 + 13;
2475 break;
2477 case 0x03:
2478 case 0x04: {
2479 fsettings->recordSize = MemLeToUint3byte(&data[4]);
2480 fsettings->maxRecordCount = MemLeToUint3byte(&data[7]);
2481 fsettings->curRecordCount = MemLeToUint3byte(&data[10]);
2482 reclen = 4 + 9;
2483 break;
2485 case 0x05: {
2486 fsettings->keyType = data[4];
2487 fsettings->keyVersion = data[5];
2488 break;
2490 default: {
2491 break;
2495 if (fsettings->additionalAccessRightsEn && reclen > 0 && datalen > reclen && datalen == reclen + data[reclen] * 2) {
2496 fsettings->additionalAccessRightsLength = data[reclen];
2498 for (int i = 0; i < fsettings->additionalAccessRightsLength; i++) {
2499 fsettings->additionalAccessRights[i] = MemLeToUint2byte(&data[reclen + 1 + i * 2]);
2504 static void DesfirePrintShortFileTypeSettings(FileSettings_t *fsettings) {
2505 switch (fsettings->fileType) {
2506 case 0x00:
2507 case 0x01: {
2508 PrintAndLogEx(NORMAL, "Size " _YELLOW_("%d") " / " _YELLOW_("0x%X") NOLF, fsettings->fileSize, fsettings->fileSize);
2509 break;
2511 case 0x02: {
2512 PrintAndLogEx(NORMAL, "Value [%d .. %d] lim cred: 0x%02x (%d [0x%x]) " NOLF,
2513 fsettings->lowerLimit,
2514 fsettings->upperLimit,
2515 fsettings->limitedCredit,
2516 fsettings->value,
2517 fsettings->value
2519 break;
2521 case 0x03:
2522 case 0x04: {
2523 PrintAndLogEx(NORMAL, "Rec cnt %d/%d size: %d [0x%x]b " NOLF,
2524 fsettings->curRecordCount,
2525 fsettings->maxRecordCount,
2526 fsettings->recordSize,
2527 fsettings->recordSize
2529 break;
2531 case 0x05: {
2532 PrintAndLogEx(NORMAL, "Key type: 0x%02x ver: 0x%02x " NOLF, fsettings->keyType, fsettings->keyVersion);
2533 break;
2535 default: {
2536 break;
2541 void DesfirePrintFileSettingsOneLine(FileSettings_t *fsettings) {
2542 PrintAndLogEx(NORMAL, "(%-5s) " NOLF, GetDesfireCommunicationMode(fsettings->fileCommMode));
2543 PrintAndLogEx(NORMAL, "[0x%02x] " _CYAN_("%-13s ") NOLF, fsettings->fileType, GetDesfireFileType(fsettings->fileType));
2545 DesfirePrintShortFileTypeSettings(fsettings);
2547 PrintAndLogEx(NORMAL, "(%s %s %s %s)",
2548 GetDesfireAccessRightShortStr(fsettings->rAccess),
2549 GetDesfireAccessRightShortStr(fsettings->wAccess),
2550 GetDesfireAccessRightShortStr(fsettings->rwAccess),
2551 GetDesfireAccessRightShortStr(fsettings->chAccess));
2554 void DesfirePrintFileSettingsTable(bool printheader, uint8_t id, bool isoidavail, uint16_t isoid, FileSettings_t *fsettings) {
2555 if (printheader) {
2556 PrintAndLogEx(SUCCESS, " ID |ISO ID| File type | Mode | Rights: raw, r w rw ch | File settings");
2557 PrintAndLogEx(SUCCESS, "----------------------------------------------------------------------------------------------------------");
2559 PrintAndLogEx(SUCCESS, " " _GREEN_("%02x") " |" NOLF, id);
2560 if (isoidavail) {
2561 if (isoid != 0)
2562 PrintAndLogEx(NORMAL, " " _CYAN_("%04x") " |" NOLF, isoid);
2563 else
2564 PrintAndLogEx(NORMAL, " " _YELLOW_("n/a ") " |" NOLF);
2565 } else {
2566 PrintAndLogEx(NORMAL, " |" NOLF);
2569 PrintAndLogEx(NORMAL, " 0x%02x " _CYAN_("%-15s") " |" NOLF, fsettings->fileType, GetDesfireFileType(fsettings->fileType));
2570 PrintAndLogEx(NORMAL, " %-5s |" NOLF, GetDesfireCommunicationMode(fsettings->fileCommMode));
2572 PrintAndLogEx(NORMAL, " %04x, %-4s %-4s %-4s %-4s |" NOLF,
2573 fsettings->rawAccessRights,
2574 GetDesfireAccessRightShortStr(fsettings->rAccess),
2575 GetDesfireAccessRightShortStr(fsettings->wAccess),
2576 GetDesfireAccessRightShortStr(fsettings->rwAccess),
2577 GetDesfireAccessRightShortStr(fsettings->chAccess));
2579 PrintAndLogEx(NORMAL, " " NOLF);
2580 DesfirePrintShortFileTypeSettings(fsettings);
2581 PrintAndLogEx(NORMAL, "");
2584 void DesfirePrintFileSettingsExtended(FileSettings_t *fsettings) {
2585 PrintAndLogEx(SUCCESS, "File type : " _CYAN_("%s") " [0x%02x]", GetDesfireFileType(fsettings->fileType), fsettings->fileType);
2586 PrintAndLogEx(SUCCESS, "Comm mode : %s", GetDesfireCommunicationMode(fsettings->fileCommMode));
2588 switch (fsettings->fileType) {
2589 case 0x00:
2590 case 0x01: {
2591 PrintAndLogEx(SUCCESS, "File size : %d [0x%x] bytes", fsettings->fileSize, fsettings->fileSize);
2592 break;
2594 case 0x02: {
2595 PrintAndLogEx(SUCCESS, "Lower limit : %d [0x%x]", fsettings->lowerLimit, fsettings->lowerLimit);
2596 PrintAndLogEx(SUCCESS, "Upper limit : %d [0x%x]", fsettings->upperLimit, fsettings->upperLimit);
2597 bool limited_credit_enabled = ((fsettings->limitedCredit & 0x01) != 0);
2598 PrintAndLogEx(SUCCESS, "Limited credit : [%d - %s] %d (0x%08X)", fsettings->limitedCredit, (limited_credit_enabled) ? "enabled" : "disabled", fsettings->value, fsettings->value);
2599 PrintAndLogEx(SUCCESS, "GetValue access : %s", ((fsettings->limitedCredit & 0x02) != 0) ? "Free" : "Not Free");
2600 break;
2602 case 0x03:
2603 case 0x04: {
2604 PrintAndLogEx(SUCCESS, "Record count : %d [0x%x]", fsettings->curRecordCount, fsettings->curRecordCount);
2605 PrintAndLogEx(SUCCESS, "Max record count: %d [0x%x]", fsettings->maxRecordCount, fsettings->maxRecordCount);
2606 PrintAndLogEx(SUCCESS, "Record size : %d [0x%x] bytes", fsettings->recordSize, fsettings->recordSize);
2607 break;
2609 case 0x05: {
2610 PrintAndLogEx(SUCCESS, "Key type : 0x%02x", fsettings->keyType);
2611 PrintAndLogEx(SUCCESS, "Key version : 0x%02x ", fsettings->keyVersion);
2612 break;
2614 default: {
2615 break;
2619 PrintAndLogEx(SUCCESS, "Access rights : %04x (" NOLF, fsettings->rawAccessRights);
2620 PrintAndLogEx(NORMAL, "r: %s " NOLF, GetDesfireAccessRightStr(fsettings->rAccess));
2621 PrintAndLogEx(NORMAL, "w: %s " NOLF, GetDesfireAccessRightStr(fsettings->wAccess));
2622 PrintAndLogEx(NORMAL, "rw: %s " NOLF, GetDesfireAccessRightStr(fsettings->rwAccess));
2623 PrintAndLogEx(NORMAL, "change: %s)", GetDesfireAccessRightStr(fsettings->chAccess));
2626 static void DesfirePrintFileSettDynPart(uint8_t filetype, uint8_t *data, size_t datalen, uint8_t *dynlen, bool create) {
2627 switch (filetype) {
2628 case 0x00:
2629 case 0x01: {
2630 int filesize = MemLeToUint3byte(&data[0]);
2631 PrintAndLogEx(INFO, "File size (bytes)... " _YELLOW_("%d") " / " _YELLOW_("0x%X"), filesize, filesize);
2632 *dynlen = 3;
2633 break;
2635 case 0x02: {
2636 int lowerlimit = MemLeToUint4byte(&data[0]);
2637 int upperlimit = MemLeToUint4byte(&data[4]);
2638 int value = MemLeToUint4byte(&data[8]);
2639 uint8_t limited_credit_enabled = data[12];
2641 PrintAndLogEx(INFO, "Lower limit... %d / 0x%08X", lowerlimit, lowerlimit);
2642 PrintAndLogEx(INFO, "Upper limit... %d / 0x%08X", upperlimit, upperlimit);
2643 if (create) {
2644 PrintAndLogEx(INFO, "Value............ %d / 0x%08X", value, value);
2645 PrintAndLogEx(INFO, "Limited credit... %d - %s"
2646 , limited_credit_enabled
2647 , ((limited_credit_enabled & 1) != 0) ? "enabled" : "disabled"
2649 } else {
2650 PrintAndLogEx(INFO, "Limited credit... %d - %s %d (0x%08X)"
2651 , limited_credit_enabled
2652 , ((limited_credit_enabled & 1) != 0) ? "enabled" : "disabled"
2653 , value
2654 , value
2657 PrintAndLogEx(INFO, "GetValue access... %s", ((limited_credit_enabled & 0x02) != 0) ? "Free" : "Not Free");
2659 *dynlen = 13;
2660 break;
2662 case 0x03:
2663 case 0x04: {
2664 uint32_t recordsize = MemLeToUint3byte(&data[0]);
2665 uint32_t maxrecords = MemLeToUint3byte(&data[3]);
2666 uint32_t currentrecord = 0;
2667 if (create == false)
2668 currentrecord = MemLeToUint3byte(&data[6]);
2670 PrintAndLogEx(INFO, "Record size....... %d / 0x%X bytes", recordsize, recordsize);
2671 PrintAndLogEx(INFO, "Max num records... %d / 0x%X", maxrecords, maxrecords);
2672 PrintAndLogEx(INFO, "Total size........ %d / 0x%X bytes", recordsize * maxrecords, recordsize * maxrecords);
2673 if (create == false)
2674 PrintAndLogEx(INFO, "Curr num records... %d / 0x%X", currentrecord, currentrecord);
2676 *dynlen = (create) ? 6 : 9;
2677 break;
2679 case 0x05: {
2680 PrintAndLogEx(INFO, "Key type [0x%02x] ... %s", data[0], GetDesfireKeyType(data[0]));
2681 *dynlen = 1;
2683 if (create) {
2684 PrintAndLogEx(INFO, "Key... %s", sprint_hex(&data[1], 16));
2685 *dynlen += 16;
2688 PrintAndLogEx(INFO, "Key version... %d / 0x%X", data[*dynlen], data[*dynlen]);
2689 (*dynlen)++;
2690 break;
2692 default: {
2693 break;
2698 void DesfirePrintFileSettings(uint8_t *data, size_t len) {
2699 if (len < 6) {
2700 PrintAndLogEx(ERR, "Wrong file settings length, expected 6> got %zu ", len);
2701 return;
2704 uint8_t filetype = data[0];
2705 PrintAndLogEx(INFO, "---- " _CYAN_("File settings") " ----");
2706 PrintAndLogEx(SUCCESS, "File type " _YELLOW_("0x%02x") " ..... %s file", filetype, GetDesfireFileType(filetype));
2707 PrintAndLogEx(SUCCESS, "File comm mode...... %s", GetDesfireCommunicationMode(data[1] & 0x03));
2708 bool addaccess = false;
2709 if (filetype != 0x05) {
2710 addaccess = ((data[1] & 0x80) != 0);
2711 PrintAndLogEx(SUCCESS, "Additional access... %s", (addaccess) ? "Yes" : "No");
2714 PrintAndLogEx(SUCCESS, "Access rights....... %04x", MemLeToUint2byte(&data[2]));
2715 DesfirePrintAccessRight(&data[2]); // 2 bytes
2717 uint8_t reclen = 0;
2718 DesfirePrintFileSettDynPart(filetype, &data[4], len - 4, &reclen, false);
2719 reclen += 4; // static part
2721 if (addaccess && filetype != 0x05 && reclen > 0 && len > reclen && len == reclen + data[reclen] * 2) {
2722 PrintAndLogEx(SUCCESS, "Add access records... %d", data[reclen]);
2723 for (int i = 0; i < data[reclen] * 2; i += 2) {
2724 PrintAndLogEx(SUCCESS, "Add access rights : [%d] %04x", i / 2, MemLeToUint2byte(&data[reclen + 1 + i]));
2725 DesfirePrintAccessRight(&data[reclen + 1 + i]);
2730 void DesfirePrintSetFileSettings(uint8_t *data, size_t len) {
2731 PrintAndLogEx(INFO, "---- " _CYAN_("Set file settings") " ----");
2732 PrintAndLogEx(SUCCESS, "File comm mode : %s", GetDesfireCommunicationMode(data[0] & 0x03));
2734 bool addaccess = ((data[0] & 0x80) != 0);
2735 PrintAndLogEx(SUCCESS, "Additional access: %s", (addaccess) ? "Yes" : "No");
2737 PrintAndLogEx(SUCCESS, "Access rights : %04x", MemLeToUint2byte(&data[1]));
2738 DesfirePrintAccessRight(&data[1]); //2 bytes
2740 if (addaccess && len > 3 && len == 4 + data[3] * 2) {
2741 PrintAndLogEx(SUCCESS, "Add access records: %d", data[3]);
2742 for (int i = 0; i < data[3] * 2; i += 2) {
2743 PrintAndLogEx(SUCCESS, "Add access rights : [%d] %04x", i / 2, MemLeToUint2byte(&data[4 + i]));
2744 DesfirePrintAccessRight(&data[4 + i]);
2749 void DesfirePrintCreateFileSettings(uint8_t filetype, uint8_t *data, size_t len) {
2750 const DesfireCreateFileCommands_t *ftyperec = GetDesfireFileCmdRec(filetype);
2751 if (ftyperec == NULL) {
2752 PrintAndLogEx(WARNING, "Unknown file type 0x%02x", filetype);
2753 return;
2756 bool isoidpresent = ftyperec->mayHaveISOfid && (len == ftyperec->createlen + 2 + 1);
2758 PrintAndLogEx(INFO, "---- " _CYAN_("Create file settings") " ----");
2759 PrintAndLogEx(SUCCESS, "File type : %s", ftyperec->text);
2760 PrintAndLogEx(SUCCESS, "File number : 0x%02X (%d)", data[0], data[0]);
2761 size_t xlen = 1;
2762 if (ftyperec->mayHaveISOfid) {
2763 if (isoidpresent) {
2764 PrintAndLogEx(SUCCESS, "File ISO number : 0x%04X", MemLeToUint2byte(&data[xlen]));
2765 xlen += 2;
2766 } else {
2767 PrintAndLogEx(SUCCESS, "File ISO number : n/a");
2771 PrintAndLogEx(SUCCESS, "File comm mode : %s", GetDesfireCommunicationMode(data[xlen] & 0x03));
2772 bool addaccess = ((data[xlen] & 0x80) != 0);
2773 PrintAndLogEx(SUCCESS, "Additional access: %s", (addaccess) ? "Yes" : "No");
2774 xlen++;
2776 PrintAndLogEx(SUCCESS, "Access rights : %04X", MemLeToUint2byte(&data[xlen]));
2777 DesfirePrintAccessRight(&data[xlen]);
2778 xlen += 2;
2780 // https://www.nxp.com/docs/en/data-sheet/MF2DLHX0.pdf
2781 // page 14
2782 // TransactionMAC file
2783 if (filetype == 0x05) {
2784 uint8_t read = 0;
2785 uint8_t write = 0;
2786 uint8_t readwrite = 0;
2787 uint8_t change = 0;
2788 DesfireDecodeFileAcessMode(&data[xlen - 2], &read, &write, &readwrite, &change);
2789 if (write != 0x0f)
2790 PrintAndLogEx(WARNING, "descr. : Write right should be set to F because write " _RED_("not allowed") ".");
2792 if (readwrite == 0x0f)
2793 PrintAndLogEx(SUCCESS, "descr. : ReadWrite right is %01X, CommitReaderID command disabled", readwrite);
2794 else if (readwrite == 0x0e)
2795 PrintAndLogEx(SUCCESS, "descr. : ReadWrite right is %01X, CommitReaderID command enabled with free access", readwrite);
2796 else if (readwrite <= 0x04)
2797 PrintAndLogEx(SUCCESS, "descr. : ReadWrite right is %01X, CommitReaderID command enabled with key 0x0%01x", readwrite, readwrite);
2798 else
2799 PrintAndLogEx(WARNING, "descr. : ReadWrite right must me 0..4,E,F instead of is %01X.", readwrite);
2802 uint8_t reclen = 0;
2803 DesfirePrintFileSettDynPart(filetype, &data[xlen], len - xlen, &reclen, true);
2804 xlen += reclen;
2807 int DesfireChangeKey(DesfireContext_t *dctx, bool change_master_key, uint8_t newkeynum, DesfireCryptoAlgorithm newkeytype, uint32_t newkeyver, uint8_t *newkey, DesfireCryptoAlgorithm oldkeytype, uint8_t *oldkey, bool verbose) {
2809 uint8_t okeybuf[DESFIRE_MAX_KEY_SIZE] = {0};
2810 uint8_t nkeybuf[DESFIRE_MAX_KEY_SIZE] = {0};
2811 uint8_t pckcdata[DESFIRE_MAX_KEY_SIZE + 10] = {0};
2812 uint8_t *cdata = &pckcdata[2];
2813 uint8_t keynodata = newkeynum & 0x3f;
2816 * Because new crypto methods can be setup only at application creation,
2817 * changing the card master key to one of them require a key_no tweak.
2819 if (change_master_key) {
2820 keynodata |= (DesfireKeyAlgoToType(newkeytype) & 0x03) << 6;
2823 pckcdata[0] = MFDES_CHANGE_KEY; // TODO
2824 pckcdata[1] = keynodata;
2826 // DES -> 2TDEA
2827 memcpy(okeybuf, oldkey, desfire_get_key_length(oldkeytype));
2828 if (oldkeytype == T_DES) {
2829 memcpy(&okeybuf[8], oldkey, 8);
2832 memcpy(nkeybuf, newkey, desfire_get_key_length(newkeytype));
2833 size_t nkeylen = desfire_get_key_length(newkeytype);
2834 if (newkeytype == T_DES) {
2835 memcpy(&nkeybuf[8], newkey, 8);
2836 nkeylen = desfire_get_key_length(T_3DES);
2839 // set key version for DES. if newkeyver > 0xff - setting key version is disabled
2840 if (newkeytype != T_AES && newkeyver < 0x100) {
2841 DesfireDESKeySetVersion(nkeybuf, newkeytype, newkeyver);
2842 if (verbose)
2843 PrintAndLogEx(INFO, "changed new key: %s [%d] %s", CLIGetOptionListStr(DesfireAlgoOpts, newkeytype), desfire_get_key_length(newkeytype), sprint_hex(nkeybuf, desfire_get_key_length(newkeytype)));
2846 // xor if we change current auth key
2847 if (newkeynum == dctx->keyNum) {
2848 memcpy(cdata, nkeybuf, nkeylen);
2849 } else {
2850 memcpy(cdata, nkeybuf, nkeylen);
2851 bin_xor(cdata, okeybuf, nkeylen);
2854 // add key version for AES
2855 size_t cdatalen = nkeylen;
2856 if (newkeytype == T_AES) {
2857 cdata[cdatalen] = newkeyver;
2858 cdatalen++;
2861 // add crc||crc_new_key
2862 if (dctx->secureChannel == DACd40) {
2863 iso14443a_crc_append(cdata, cdatalen);
2864 cdatalen += 2;
2865 if (newkeynum != dctx->keyNum) {
2866 iso14443a_crc(nkeybuf, nkeylen, &cdata[cdatalen]);
2867 cdatalen += 2;
2869 } else if (dctx->secureChannel == DACEV1) {
2870 // EV1 Checksum must cover : <KeyNo> <PrevKey XOR Newkey> [<AES NewKeyVer>]
2871 desfire_crc32_append(pckcdata, cdatalen + 2);
2872 cdatalen += 4;
2873 if (newkeynum != dctx->keyNum) {
2874 desfire_crc32(nkeybuf, nkeylen, &cdata[cdatalen]);
2875 cdatalen += 4;
2877 } else if (dctx->secureChannel == DACEV2 || dctx->secureChannel == DACLRP) {
2878 // EV2 : <PrevKey XOR Newkey> [<AES NewKeyVer>]
2879 if (newkeynum != dctx->keyNum) {
2880 desfire_crc32(nkeybuf, nkeylen, &cdata[cdatalen]);
2881 cdatalen += 4;
2885 // send command
2886 uint8_t resp[257] = {0};
2887 size_t resplen = 0;
2888 int res = DesfireChangeKeyCmd(dctx, &pckcdata[1], cdatalen + 1, resp, &resplen);
2890 // check response
2891 if (res == 0 && resplen > 0)
2892 res = -20;
2894 // clear auth
2895 if (newkeynum == dctx->keyNum)
2896 DesfireClearSession(dctx);
2898 return res;
2901 int DesfireSetConfiguration(DesfireContext_t *dctx, uint8_t paramid, uint8_t *param, size_t paramlen) {
2902 uint8_t cdata[200] = {0};
2903 cdata[0] = MFDES_CHANGE_CONFIGURATION;
2904 uint8_t *data = &cdata[1];
2905 data[0] = paramid;
2906 memcpy(&data[1], param, paramlen);
2907 size_t datalen = 1 + paramlen;
2909 // dynamic length
2910 if (paramid == 0x02 && dctx->commMode == DCMEncrypted)
2911 dctx->commMode = DCMEncryptedWithPadding;
2913 // send command
2914 uint8_t resp[257] = {0};
2915 size_t resplen = 0;
2916 int res = DesfireSetConfigurationCmd(dctx, data, datalen, resp, &resplen);
2918 // check response
2919 if (res == 0 && resplen > 0)
2920 res = -20;
2922 return res;
2925 int DesfireISOSelectEx(DesfireContext_t *dctx, bool fieldon, DesfireISOSelectControl cntr, uint8_t *data, uint8_t datalen, uint8_t *resp, size_t *resplen) {
2926 uint8_t xresp[250] = {0};
2927 size_t xresplen = 0;
2928 uint16_t sw = 0;
2929 int res = DesfireExchangeISO(fieldon, dctx, (sAPDU_t) {0x00, ISO7816_SELECT_FILE, cntr, ((resp == NULL) ? 0x0C : 0x00), datalen, data}, APDU_INCLUDE_LE_00, xresp, &xresplen, &sw);
2930 if (res == PM3_SUCCESS && sw != ISO7816_OK)
2931 return PM3_ESOFT;
2933 if (resp != NULL && resplen != NULL) {
2934 *resplen = xresplen;
2935 memcpy(resp, xresp, xresplen);
2938 DesfireClearSession(dctx);
2939 dctx->appSelected = !((cntr == ISSMFDFEF && datalen == 0) || (cntr == ISSEFByFileID && datalen == 2 && data[0] == 0 && data[1] == 0));
2940 dctx->selectedAID = 0;
2942 return res;
2945 int DesfireISOSelect(DesfireContext_t *dctx, DesfireISOSelectControl cntr, uint8_t *data, uint8_t datalen, uint8_t *resp, size_t *resplen) {
2946 return DesfireISOSelectEx(dctx, true, cntr, data, datalen, resp, resplen);
2949 int DesfireISOSelectDF(DesfireContext_t *dctx, char *dfname, uint8_t *resp, size_t *resplen) {
2950 return DesfireISOSelect(dctx, ISSDFName, (uint8_t *)dfname, str_nlen(dfname, 16), resp, resplen);
2953 int DesfireISOGetChallenge(DesfireContext_t *dctx, DesfireCryptoAlgorithm keytype, uint8_t *resp, size_t *resplen) {
2954 uint16_t sw = 0;
2955 int res = DesfireExchangeISO(false, dctx, (sAPDU_t) {0x00, ISO7816_GET_CHALLENGE, 0x00, 0x00, 0x00, NULL}, DesfireGetRndLenForKey(keytype), resp, resplen, &sw);
2956 if (res == PM3_SUCCESS && sw != ISO7816_OK)
2957 return PM3_ESOFT;
2959 return res;
2962 int DesfireISOExternalAuth(DesfireContext_t *dctx, bool app_level, uint8_t keynum, DesfireCryptoAlgorithm keytype, uint8_t *data) {
2963 uint8_t p1 = DesfireKeyToISOKey(keytype);
2964 uint8_t p2 = ((app_level) ? 0x80 : 0x00) | keynum;
2966 uint8_t resp[250] = {0};
2967 size_t resplen = 0;
2969 uint16_t sw = 0;
2970 int res = DesfireExchangeISO(false, dctx, (sAPDU_t) {0x00, ISO7816_EXTERNAL_AUTHENTICATION, p1, p2, DesfireGetRndLenForKey(keytype) * 2, data}, 0, resp, &resplen, &sw);
2971 if (res == PM3_SUCCESS && sw != ISO7816_OK)
2972 return PM3_ESOFT;
2974 return res;
2977 int DesfireISOInternalAuth(DesfireContext_t *dctx, bool app_level, uint8_t keynum, DesfireCryptoAlgorithm keytype, uint8_t *data, uint8_t *resp, size_t *resplen) {
2978 uint8_t keylen = DesfireGetRndLenForKey(keytype);
2979 uint8_t p1 = DesfireKeyToISOKey(keytype);
2980 uint8_t p2 = ((app_level) ? 0x80 : 0x00) | keynum;
2982 uint16_t sw = 0;
2983 int res = DesfireExchangeISO(false, dctx, (sAPDU_t) {0x00, ISO7816_INTERNAL_AUTHENTICATION, p1, p2, keylen, data}, keylen * 2, resp, resplen, &sw);
2984 if (res == PM3_SUCCESS && sw != ISO7816_OK)
2985 return PM3_ESOFT;
2987 return res;
2990 int DesfireISOReadBinary(DesfireContext_t *dctx, bool use_file_id, uint8_t fileid, uint16_t offset, uint8_t length, uint8_t *resp, size_t *resplen) {
2991 uint8_t p1 = 0;
2992 if (use_file_id)
2993 p1 = 0x80 | (fileid & 0x1f);
2994 else
2995 p1 = (offset >> 8) & 0x7f;
2996 uint8_t p2 = offset & 0xff;
2998 uint16_t sw = 0;
2999 int res = DesfireExchangeISO(false, dctx, (sAPDU_t) {0x00, ISO7816_READ_BINARY, p1, p2, 0, NULL}, (length == 0) ? APDU_INCLUDE_LE_00 : length, resp, resplen, &sw);
3000 if (res == PM3_SUCCESS && sw != ISO7816_OK)
3001 return PM3_ESOFT;
3003 return res;
3006 int DesfireISOUpdateBinary(DesfireContext_t *dctx, bool use_file_id, uint8_t fileid, uint16_t offset, uint8_t *data, size_t datalen) {
3007 uint8_t p1 = 0;
3008 if (use_file_id)
3009 p1 = 0x80 | (fileid & 0x1f);
3010 else
3011 p1 = (offset >> 8) & 0x7f;
3012 uint8_t p2 = offset & 0xff;
3014 uint8_t resp[250] = {0};
3015 size_t resplen = 0;
3017 uint16_t sw = 0;
3018 int res = DesfireExchangeISO(false, dctx, (sAPDU_t) {0x00, ISO7816_UPDATE_BINARY, p1, p2, datalen, data}, 0, resp, &resplen, &sw);
3019 if (res == PM3_SUCCESS && sw != ISO7816_OK)
3020 return PM3_ESOFT;
3022 return res;
3025 int DesfireISOReadRecords(DesfireContext_t *dctx, uint8_t recordnum, bool read_all_records, uint8_t fileid, uint8_t length, uint8_t *resp, size_t *resplen) {
3026 uint8_t p2 = ((fileid & 0x1f) << 3) | ((read_all_records) ? 0x05 : 0x04);
3028 uint16_t sw = 0;
3029 int res = DesfireExchangeISO(false, dctx, (sAPDU_t) {0x00, ISO7816_READ_RECORDS, recordnum, p2, 0, NULL}, (length == 0) ? APDU_INCLUDE_LE_00 : length, resp, resplen, &sw);
3030 if (res == PM3_SUCCESS && sw != ISO7816_OK)
3031 return PM3_ESOFT;
3033 return res;
3036 int DesfireISOAppendRecord(DesfireContext_t *dctx, uint8_t fileid, uint8_t *data, size_t datalen) {
3037 uint8_t p2 = ((fileid & 0x1f) << 3);
3039 uint8_t resp[250] = {0};
3040 size_t resplen = 0;
3042 uint16_t sw = 0;
3043 int res = DesfireExchangeISO(false, dctx, (sAPDU_t) {0x00, ISO7816_APPEND_RECORD, 0x00, p2, datalen, data}, 0, resp, &resplen, &sw);
3044 if (res == PM3_SUCCESS && sw != ISO7816_OK)
3045 return PM3_ESOFT;
3047 return res;
3050 int DesfireGetCardUID(DesfireContext_t *ctx) {
3051 iso14a_card_select_t card = {0};
3053 SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT, 0, 0, NULL, 0);
3054 PacketResponseNG resp;
3055 if (WaitForResponseTimeout(CMD_ACK, &resp, 2500) == false) {
3056 PrintAndLogEx(WARNING, "timeout while waiting for reply.");
3057 return PM3_ETIMEOUT;
3060 memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t));
3061 uint64_t select_status = resp.oldarg[0];
3063 if (select_status == 0 || select_status == 2 || select_status == 3) {
3064 return PM3_ESOFT;
3067 memcpy(ctx->uid, card.uid, card.uidlen);
3068 ctx->uidlen = card.uidlen;
3070 return PM3_SUCCESS;
3073 int DesfireAnticollision(bool verbose) {
3074 return SelectCard14443A_4(false, verbose, NULL);
3077 int DesfireSelectEx(DesfireContext_t *ctx, bool fieldon, DesfireISOSelectWay way, uint32_t id, const char *dfname) {
3078 uint8_t resp[250] = {0};
3079 size_t resplen = 0;
3081 if (way == ISWMF || (way == ISWDFName && dfname == NULL)) {
3082 return DesfireISOSelectEx(ctx, fieldon, ISSMFDFEF, NULL, 0, resp, &resplen);
3083 } else if (way == ISW6bAID) {
3084 if (id == 0x000000 && fieldon)
3085 return DesfireAnticollision(false);
3087 DesfireCommandSet cmdset = ctx->cmdSet;
3088 int res;
3090 // if we try to select 6b AID via ISO channel - we can only switch the channel via the over channel because there is no equivalent command in the iso commands
3091 if (ctx->cmdSet == DCCISO)
3092 ctx->cmdSet = DCCNativeISO;
3094 if (fieldon)
3095 res = DesfireSelectAIDHex(ctx, id, false, 0);
3096 else
3097 res = DesfireSelectAIDHexNoFieldOn(ctx, id);
3099 ctx->cmdSet = cmdset;
3100 return res;
3101 } else if (way == ISWIsoID) {
3102 uint8_t data[2] = {0};
3103 Uint2byteToMemBe(data, id);
3104 return DesfireISOSelectEx(ctx, fieldon, ISSMFDFEF, data, 2, resp, &resplen);
3105 } else if (way == ISWDFName) {
3106 return DesfireISOSelectEx(ctx, fieldon, ISSMFDFEF, NULL, 0, resp, &resplen);
3108 return PM3_ESOFT;
3111 int DesfireSelect(DesfireContext_t *ctx, DesfireISOSelectWay way, uint32_t id, char *dfname) {
3112 return DesfireSelectEx(ctx, true, way, id, dfname);