1 //-----------------------------------------------------------------------------
2 // Copyright (C) 2014 Iceman
4 // This code is licensed to you under the terms of the GNU GPL, version 2 or,
5 // at your option, any later version. See the LICENSE.txt file for the text of
7 //-----------------------------------------------------------------------------
8 // High frequency MIFARE Desfire commands
9 //-----------------------------------------------------------------------------
10 // Code heavily modified by B.Kerler :)
12 #include "cmdhfmfdes.h"
17 #include "commonutil.h" // ARRAYLEN
18 #include "cmdparser.h" // command_t
23 #include "crypto/libpcrypto.h"
24 #include "protocols.h"
26 #include "cliparser.h"
27 #include "iso7816/apduinfo.h" // APDU manipulation / errorcodes
28 #include "iso7816/iso7816core.h" // APDU logging
29 #include "util_posix.h" // msleep
30 #include "mifare/desfire_crypto.h"
31 #include "crapto1/crapto1.h"
32 #include "fileutils.h"
33 #include "mifare/mifaredefault.h" // default keys
34 #include "nfc/ndef.h" // NDEF
35 #include "mifare/mad.h"
36 #include "generator.h"
37 #include "aiddesfire.h"
40 #define MAX_KEY_LEN 24
41 #define MAX_KEYS_LIST_LEN 1024
43 #define status(x) ( ((uint16_t)(0x91<<8)) + (uint16_t)x )
45 #ifndef DropFieldDesfire
46 #define DropFieldDesfire() { \
47 clearCommandBuffer(); \
48 SendCommandNG(CMD_HF_DROPFIELD, NULL, 0); \
49 tag->rf_field_on = false; \
50 PrintAndLogEx(DEBUG, "field dropped"); \
54 struct desfire_key default_key
= {0};
56 uint8_t desdefaultkeys
[3][8] = {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //Official
57 {0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47},
58 {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}
61 uint8_t aesdefaultkeys
[5][16] = {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //Official, TRF7970A
62 {0x79, 0x70, 0x25, 0x53, 0x79, 0x70, 0x25, 0x53, 0x79, 0x70, 0x25, 0x53, 0x79, 0x70, 0x25, 0x53}, // TRF7970A
63 {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}, // TRF7970A
64 {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f},
65 {0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f}
68 uint8_t k3kdefaultkeys
[1][24] = {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
70 struct desfire_tag mf_state
= {.session_key
= NULL
, .authentication_scheme
= AS_LEGACY
, .authenticated_key_no
= NOT_YET_AUTHENTICATED
, .crypto_buffer
= NULL
, .crypto_buffer_size
= 0, .selected_application
= 0};
71 static desfiretag_t tag
= &mf_state
;
73 typedef struct mfdes_authinput
{
82 } PACKED mfdes_authinput_t
;
84 static mfdes_authinput_t currentauth
[0xF] = {{.keyno
= -1}, {.keyno
= -1}, {.keyno
= -1}, {.keyno
= -1}, {.keyno
= -1}, {.keyno
= -1}, {.keyno
= -1}, {.keyno
= -1}, {.keyno
= -1}, {.keyno
= -1}, {.keyno
= -1}, {.keyno
= -1}, {.keyno
= -1}, {.keyno
= -1}, {.keyno
= -1}};
86 typedef struct mfdes_auth_res
{
87 uint8_t sessionkeylen
;
88 uint8_t sessionkey
[24];
89 } PACKED mfdes_auth_res_t
;
91 typedef struct mfdes_data
{
96 } PACKED mfdes_data_t
;
98 typedef struct mfdes_info_res
{
102 uint8_t versionHW
[7];
103 uint8_t versionSW
[7];
105 } PACKED mfdes_info_res_t
;
107 typedef struct mfdes_value
{
110 } PACKED mfdes_value_t
;
112 typedef struct mfdes_file
{
114 uint8_t fid
[2]; //03E1
116 uint8_t access_rights
[2]; ///EEEE
117 uint8_t filesize
[3]; //0F0000
118 } PACKED mfdes_file_t
;
120 typedef struct mfdes_linear
{
122 uint8_t fid
[2]; //03E1
124 uint8_t access_rights
[2]; ///EEEE
125 uint8_t recordsize
[3];
126 uint8_t maxnumrecords
[3];
127 } PACKED mfdes_linear_t
;
129 typedef struct mfdes_value_file
{
132 uint8_t access_rights
[2]; ///EEEE
133 uint8_t lowerlimit
[4];
134 uint8_t upperlimit
[4];
136 uint8_t limitedcreditenabled
;
137 } PACKED mfdes_value_file_t
;
145 // NXP Appnote AN10787 - Application Directory (MAD)
161 CL_CITYTRAFFIC
= 0x18,
168 CL_COMPANY_SERVICES
= 0x38,
170 CL_ACCESS_CONTROL_1
= 0x47,
173 CL_NED_DEFENCE
= 0x4A,
174 CL_BOSCH_TELECOM
= 0x4B,
176 CL_SKI_TICKET
= 0x50,
184 CL_CAR_RENTAL
= 0x78,
189 CL_CRUISESHIP
= 0x91,
215 static const char *cluster_to_text(uint8_t cluster
) {
218 return "card administration";
226 return "miscellaneous applications";
230 return "ferry traffic";
232 return "railway services";
234 return "miscellaneous applications";
238 return "security solutions";
240 return "city traffic";
242 return "Czech Railways";
244 return "bus services";
246 return "multi modal transit";
251 case CL_GENERIC_TRANS
:
252 return "generic transport";
253 case CL_COMPANY_SERVICES
:
254 return "company services";
256 return "city card services";
257 case CL_ACCESS_CONTROL_1
:
258 case CL_ACCESS_CONTROL_2
:
259 return "access control & security";
263 return "Ministry of Defence, Netherlands";
264 case CL_BOSCH_TELECOM
:
265 return "Bosch Telecom, Germany";
267 return "European Union Institutions";
269 return "ski ticketing";
271 return "SOAA standard for offline access standard";
273 return "access control & security";
277 return "non-food trade";
283 return "airport services";
287 return "Dutch government";
289 return "administration services";
291 return "electronic purse";
295 return "cruise ship";
303 return "health services";
309 return "entertainment & sports";
311 return "car parking";
313 return "fleet management";
315 return "fuel, gasoline";
317 return "info services";
334 return "miscellaneous applications";
352 typedef struct dfname
{
358 typedef struct aidhdr
{
366 static int CmdHelp(const char *Cmd
);
368 static const char *getEncryptionAlgoStr(uint8_t algo
) {
370 case MFDES_ALGO_AES
:
372 case MFDES_ALGO_3DES
:
374 case MFDES_ALGO_DES
:
376 case MFDES_ALGO_3K3DES
:
383 The 7 MSBits (= n) code the storage size itself based on 2^n,
384 the LSBit is set to '0' if the size is exactly 2^n
385 and set to '1' if the storage size is between 2^n and 2^(n+1).
386 For this version of DESFire the 7 MSBits are set to 0x0C (2^12 = 4096) and the LSBit is '0'.
388 static char *getCardSizeStr(uint8_t fsize
) {
390 static char buf
[40] = {0x00};
393 uint16_t usize
= 1 << (((uint16_t)fsize
>> 1) + 1);
394 uint16_t lsize
= 1 << ((uint16_t)fsize
>> 1);
398 snprintf(retStr
, sizeof(buf
), "0x%02X ( " _GREEN_("%d - %d bytes") " )", fsize
, usize
, lsize
);
400 snprintf(retStr
, sizeof(buf
), "0x%02X ( " _GREEN_("%d bytes") " )", fsize
, lsize
);
404 static char *getProtocolStr(uint8_t id
, bool hw
) {
406 static char buf
[50] = {0x00};
410 snprintf(retStr
, sizeof(buf
), "0x%02X ( " _YELLOW_("ISO 14443-3 MIFARE, 14443-4") " )", id
);
411 } else if (id
== 0x05) {
413 snprintf(retStr
, sizeof(buf
), "0x%02X ( " _YELLOW_("ISO 14443-2, 14443-3") " )", id
);
415 snprintf(retStr
, sizeof(buf
), "0x%02X ( " _YELLOW_("ISO 14443-3, 14443-4") " )", id
);
417 snprintf(retStr
, sizeof(buf
), "0x%02X ( " _YELLOW_("Unknown") " )", id
);
422 static char *getVersionStr(uint8_t major
, uint8_t minor
) {
424 static char buf
[40] = {0x00};
428 snprintf(retStr
, sizeof(buf
), "%x.%x ( " _GREEN_("DESFire MF3ICD40") " )", major
, minor
);
429 else if (major
== 0x01 && minor
== 0x00)
430 snprintf(retStr
, sizeof(buf
), "%x.%x ( " _GREEN_("DESFire EV1") " )", major
, minor
);
431 else if (major
== 0x12 && minor
== 0x00)
432 snprintf(retStr
, sizeof(buf
), "%x.%x ( " _GREEN_("DESFire EV2") " )", major
, minor
);
433 else if (major
== 0x42 && minor
== 0x00)
434 snprintf(retStr
, sizeof(buf
), "%x.%x ( " _GREEN_("DESFire EV2") " )", major
, minor
);
435 else if (major
== 0x33 && minor
== 0x00)
436 snprintf(retStr
, sizeof(buf
), "%x.%x ( " _GREEN_("DESFire EV3") " )", major
, minor
);
437 else if (major
== 0x30 && minor
== 0x00)
438 snprintf(retStr
, sizeof(buf
), "%x.%x ( " _GREEN_("DESFire Light") " )", major
, minor
);
439 else if (major
== 0x10 && minor
== 0x00)
440 snprintf(retStr
, sizeof(buf
), "%x.%x ( " _GREEN_("NTAG413DNA") " )", major
, minor
);
442 snprintf(retStr
, sizeof(buf
), "%x.%x ( " _YELLOW_("Unknown") " )", major
, minor
);
445 //04 01 01 01 00 1A 05
448 static int DESFIRESendApdu(bool activate_field
, bool leavefield_on
, sAPDU apdu
, uint8_t *result
, uint32_t max_result_len
, uint32_t *result_len
, uint16_t *sw
) {
456 if (activate_field
) {
462 uint8_t data
[APDU_RES_LEN
] = {0};
466 //if (APDUEncodeS(&apdu, false, IncludeLe ? 0x100 : 0x00, data, &datalen)) {
467 if (APDUEncodeS(&apdu
, false, 0x100, data
, &datalen
)) {
468 PrintAndLogEx(ERR
, "APDU encoding error.");
469 return PM3_EAPDU_ENCODEFAIL
;
472 if (GetAPDULogging() || (g_debugMode
> 1))
473 PrintAndLogEx(SUCCESS
, ">>>> %s", sprint_hex(data
, datalen
));
475 res
= ExchangeAPDU14a(data
, datalen
, activate_field
, leavefield_on
, result
, max_result_len
, (int *)result_len
);
476 if (res
!= PM3_SUCCESS
) {
480 if (activate_field
) {
481 PrintAndLogEx(DEBUG
, "field up");
482 tag
->rf_field_on
= true;
485 if (GetAPDULogging() || (g_debugMode
> 1))
486 PrintAndLogEx(SUCCESS
, "<<<< %s", sprint_hex(result
, *result_len
));
488 if (*result_len
< 2) {
493 isw
= (result
[*result_len
] << 8) + result
[*result_len
+ 1];
497 if (isw
!= 0x9000 && isw
!= status(MFDES_S_OPERATION_OK
) && isw
!= status(MFDES_S_SIGNATURE
) && isw
!= status(MFDES_S_ADDITIONAL_FRAME
) && isw
!= status(MFDES_S_NO_CHANGES
)) {
498 if (GetAPDULogging()) {
499 if (isw
>> 8 == 0x61) {
500 PrintAndLogEx(ERR
, "APDU chaining len: 0x%02x -->", isw
& 0xff);
502 PrintAndLogEx(ERR
, "APDU(%02x%02x) ERROR: [0x%4X] %s", apdu
.CLA
, apdu
.INS
, isw
, GetAPDUCodeDescription(isw
>> 8, isw
& 0xff));
503 return PM3_EAPDU_FAIL
;
506 return PM3_EAPDU_FAIL
;
511 static const char *getstatus(uint16_t *sw
) {
512 if (sw
== NULL
) return "--> sw argument error. This should never happen !";
513 if (((*sw
>> 8) & 0xFF) == 0x91) {
514 switch (*sw
& 0xFF) {
515 case MFDES_E_OUT_OF_EEPROM
:
516 return "Out of Eeprom, insufficient NV-Memory to complete command";
517 case MFDES_E_ILLEGAL_COMMAND_CODE
:
518 return "Command code not supported";
520 case MFDES_E_INTEGRITY_ERROR
:
521 return "CRC or MAC does not match data / Padding bytes invalid";
523 case MFDES_E_NO_SUCH_KEY
:
524 return "Invalid key number specified";
527 return "Length of command string invalid";
529 case MFDES_E_PERMISSION_DENIED
:
530 return "Current configuration/status does not allow the requested command";
532 case MFDES_E_PARAMETER_ERROR
:
533 return "Value of the parameter(s) invalid";
535 case MFDES_E_APPLICATION_NOT_FOUND
:
536 return "Requested AID not present on PICC";
538 case MFDES_E_APPL_INTEGRITY
:
539 return "Application integrity error, application will be disabled";
541 case MFDES_E_AUTHENTIFICATION_ERROR
:
542 return "Current authentication status does not allow the requested command";
544 case MFDES_E_BOUNDARY
:
545 return "Attempted to read/write data from/to beyond the file's/record's limit";
547 case MFDES_E_PICC_INTEGRITY
:
548 return "PICC integrity error, PICC will be disabled";
550 case MFDES_E_COMMAND_ABORTED
:
551 return "Previous command was not fully completed / Not all Frames were requested or provided by the PCD";
553 case MFDES_E_PICC_DISABLED
:
554 return "PICC was disabled by an unrecoverable error";
557 return "Application count is limited to 28, not addition CreateApplication possible";
559 case MFDES_E_DUPLICATE
:
560 return "Duplicate entry: File/Application/ISO Text does already exist";
563 return "Eeprom error due to loss of power, internal backup/rollback mechanism activated";
565 case MFDES_E_FILE_NOT_FOUND
:
566 return "Specified file number does not exist";
568 case MFDES_E_FILE_INTEGRITY
:
569 return "File integrity error, file will be disabled";
572 return "Unknown error";
575 return "Unknown error";
578 static const char *GetErrorString(int res
, uint16_t *sw
) {
581 return getstatus(sw
);
583 return "Undefined error";
585 return "Invalid argument(s)";
586 case PM3_EDEVNOTSUPP
:
587 return "Operation not supported by device";
589 return "Operation timed out";
591 return "Operation aborted (by user)";
593 return "Not (yet) implemented";
595 return "Error while RF transmission";
597 return "Input / output error";
599 return "Buffer overflow";
601 return "Software error";
603 return "Flash error";
605 return "Memory allocation error";
609 return "Generic TTY error";
611 return "Initialization error";
612 case PM3_EWRONGANSWER
:
613 return "Expected a different answer error";
614 case PM3_EOUTOFBOUND
:
615 return "Memory out-of-bounds error";
616 case PM3_ECARDEXCHANGE
:
617 return "Exchange with card error";
618 case PM3_EAPDU_ENCODEFAIL
:
619 return "Failed to create APDU";
623 return "Fatal error";
630 static int send_desfire_cmd(sAPDU
*apdu
, bool select
, uint8_t *dest
, uint32_t *recv_len
, uint16_t *sw
, uint32_t splitbysize
, bool readalldata
) {
632 PrintAndLogEx(DEBUG
, "APDU=NULL");
636 PrintAndLogEx(DEBUG
, "SW=NULL");
639 if (recv_len
== NULL
) {
640 PrintAndLogEx(DEBUG
, "RECV_LEN=NULL");
645 uint8_t data
[255 * 5] = {0x00};
646 uint32_t resplen
= 0;
649 int res
= DESFIRESendApdu(select
, true, *apdu
, data
, sizeof(data
), &resplen
, sw
);
650 if (res
!= PM3_SUCCESS
) {
651 PrintAndLogEx(DEBUG
, "%s", GetErrorString(res
, sw
));
656 memcpy(dest
, data
, resplen
);
661 if (*sw
== status(MFDES_ADDITIONAL_FRAME
)) {
668 while (*sw
== status(MFDES_ADDITIONAL_FRAME
)) {
669 apdu
->INS
= MFDES_ADDITIONAL_FRAME
; //0xAF
674 res
= DESFIRESendApdu(false, true, *apdu
, data
, sizeof(data
), &resplen
, sw
);
675 if (res
!= PM3_SUCCESS
) {
676 PrintAndLogEx(DEBUG
, "%s", GetErrorString(res
, sw
));
683 memcpy(&dest
[i
* splitbysize
], data
, resplen
);
686 memcpy(&dest
[pos
], data
, resplen
);
691 if (*sw
!= status(MFDES_ADDITIONAL_FRAME
)) break;
694 *recv_len
= (splitbysize
) ? i
: pos
;
698 static nxp_cardtype_t
getCardType(uint8_t major
, uint8_t minor
) {
701 return DESFIRE_MF3ICD40
;
702 if (major
== 0x01 && minor
== 0x00)
704 if (major
== 0x12 && minor
== 0x00)
706 if (major
== 0x33 && minor
== 0x00)
708 if (major
== 0x30 && minor
== 0x00)
709 return DESFIRE_LIGHT
;
710 if (major
== 0x11 && minor
== 0x00)
712 if (major
== 0x10 && minor
== 0x00)
714 return DESFIRE_UNKNOWN
;
717 static int mfdes_get_info(mfdes_info_res_t
*info
) {
718 SendCommandNG(CMD_HF_DESFIRE_INFO
, NULL
, 0);
719 PacketResponseNG resp
;
721 if (WaitForResponseTimeout(CMD_HF_DESFIRE_INFO
, &resp
, 1500) == false) {
722 PrintAndLogEx(WARNING
, "Command execute timeout");
727 memcpy(info
, resp
.data
.asBytes
, sizeof(mfdes_info_res_t
));
729 if (resp
.status
!= PM3_SUCCESS
) {
730 switch (info
->isOK
) {
732 PrintAndLogEx(WARNING
, "Can't select card");
735 PrintAndLogEx(WARNING
, "Card is most likely not DESFire. Wrong size UID");
739 PrintAndLogEx(WARNING
, _RED_("Command unsuccessful"));
748 static int handler_desfire_auth(mfdes_authinput_t
*payload
, mfdes_auth_res_t
*rpayload
) {
749 // 3 different way to authenticate AUTH (CRC16) , AUTH_ISO (CRC32) , AUTH_AES (CRC32)
750 // 4 different crypto arg1 DES, 3DES, 3K3DES, AES
751 // 3 different communication modes, PLAIN,MAC,CRYPTO
752 tag
->authenticated_key_no
= NOT_YET_AUTHENTICATED
;
753 tag
->session_key
= NULL
;
755 mbedtls_aes_context ctx
;
757 uint8_t keybytes
[24];
759 uint8_t IV
[16] = {0x00};
760 uint8_t RndA
[16] = {0x00};
761 uint8_t RndB
[16] = {0x00};
762 uint8_t encRndB
[16] = {0x00};
763 uint8_t rotRndB
[16] = {0x00}; //RndB'
764 uint8_t both
[32 + 1] = {0x00}; // ek/dk_keyNo(RndA+RndB')
766 // Generate Random Value
767 uint32_t ng
= msclock();
768 uint32_t value
= prng_successor(ng
, 32);
769 num_to_bytes(value
, 4, &RndA
[0]);
770 value
= prng_successor(ng
, 32);
771 num_to_bytes(value
, 4, &RndA
[4]);
772 value
= prng_successor(ng
, 32);
773 num_to_bytes(value
, 4, &RndA
[8]);
774 value
= prng_successor(ng
, 32);
775 num_to_bytes(value
, 4, &RndA
[12]);
778 memcpy(keybytes
, payload
->key
, payload
->keylen
);
780 struct desfire_key dkey
= {0};
781 desfirekey_t key
= &dkey
;
783 if (payload
->algo
== MFDES_ALGO_AES
) {
784 mbedtls_aes_init(&ctx
);
785 Desfire_aes_key_new(keybytes
, key
);
786 } else if (payload
->algo
== MFDES_ALGO_3DES
) {
787 Desfire_3des_key_new_with_version(keybytes
, key
);
788 } else if (payload
->algo
== MFDES_ALGO_DES
) {
789 Desfire_des_key_new(keybytes
, key
);
790 } else if (payload
->algo
== MFDES_ALGO_3K3DES
) {
791 Desfire_3k3des_key_new_with_version(keybytes
, key
);
794 if (payload
->kdfAlgo
== MFDES_KDF_ALGO_AN10922
) {
795 mifare_kdf_an10922(key
, payload
->kdfInput
, payload
->kdfInputLen
);
796 PrintAndLogEx(DEBUG
, " Derrived key: " _GREEN_("%s"), sprint_hex(key
->data
, key_block_size(key
)));
797 } else if (payload
->kdfAlgo
== MFDES_KDF_ALGO_GALLAGHER
) {
798 // We will overrite any provided KDF input since a gallagher specific KDF was requested.
799 payload
->kdfInputLen
= 11;
801 if (mfdes_kdf_input_gallagher(tag
->info
.uid
, tag
->info
.uidlen
, payload
->keyno
, tag
->selected_application
, payload
->kdfInput
, &payload
->kdfInputLen
) != PM3_SUCCESS
) {
802 PrintAndLogEx(FAILED
, "Could not generate Gallagher KDF input");
805 mifare_kdf_an10922(key
, payload
->kdfInput
, payload
->kdfInputLen
);
806 PrintAndLogEx(DEBUG
, " KDF Input: " _YELLOW_("%s"), sprint_hex(payload
->kdfInput
, payload
->kdfInputLen
));
807 PrintAndLogEx(DEBUG
, " Derrived key: " _GREEN_("%s"), sprint_hex(key
->data
, key_block_size(key
)));
811 uint8_t subcommand
= MFDES_AUTHENTICATE
;
812 tag
->authentication_scheme
= AS_LEGACY
;
814 if (payload
->mode
== MFDES_AUTH_AES
) {
815 subcommand
= MFDES_AUTHENTICATE_AES
;
816 tag
->authentication_scheme
= AS_NEW
;
817 } else if (payload
->mode
== MFDES_AUTH_ISO
) {
818 subcommand
= MFDES_AUTHENTICATE_ISO
;
819 tag
->authentication_scheme
= AS_NEW
;
822 uint32_t recv_len
= 0;
824 uint8_t recv_data
[256] = {0};
826 if (payload
->mode
!= MFDES_AUTH_PICC
) {
827 // Let's send our auth command
828 uint8_t data
[] = {payload
->keyno
};
829 sAPDU apdu
= {0x90, subcommand
, 0x00, 0x00, 0x01, data
};
830 int res
= send_desfire_cmd(&apdu
, false, recv_data
, &recv_len
, &sw
, 0, false);
831 if (res
!= PM3_SUCCESS
) {
837 cmd[0] = AUTHENTICATE;
838 cmd[1] = payload->keyno;
839 len = DesfireAPDU(cmd, 2, resp);
847 if (sw
!= status(MFDES_ADDITIONAL_FRAME
)) {
851 uint32_t expectedlen
= 8;
852 if (payload
->algo
== MFDES_ALGO_AES
|| payload
->algo
== MFDES_ALGO_3K3DES
) {
856 if (recv_len
!= expectedlen
) {
859 uint32_t rndlen
= recv_len
;
862 if (payload
->mode
!= MFDES_AUTH_PICC
) {
863 memcpy(encRndB
, recv_data
, rndlen
);
865 memcpy(encRndB
, recv_data
+ 2, rndlen
);
869 if (payload
->algo
== MFDES_ALGO_AES
) {
870 if (mbedtls_aes_setkey_dec(&ctx
, key
->data
, 128) != 0) {
873 mbedtls_aes_crypt_cbc(&ctx
, MBEDTLS_AES_DECRYPT
, rndlen
, IV
, encRndB
, RndB
);
874 } else if (payload
->algo
== MFDES_ALGO_DES
)
875 des_decrypt(RndB
, encRndB
, key
->data
);
876 else if (payload
->algo
== MFDES_ALGO_3DES
)
877 tdes_nxp_receive(encRndB
, RndB
, rndlen
, key
->data
, IV
, 2);
878 else if (payload
->algo
== MFDES_ALGO_3K3DES
) {
879 tdes_nxp_receive(encRndB
, RndB
, rndlen
, key
->data
, IV
, 3);
882 if (g_debugMode
> 1) {
883 PrintAndLogEx(DEBUG
, "encRndB: %s", sprint_hex(encRndB
, 8));
884 PrintAndLogEx(DEBUG
, "RndB: %s", sprint_hex(RndB
, 8));
887 // - Rotate RndB by 8 bits
888 memcpy(rotRndB
, RndB
, rndlen
);
889 rol(rotRndB
, rndlen
);
891 uint8_t encRndA
[16] = {0x00};
893 // - Encrypt our response
894 if (payload
->mode
== MFDES_AUTH_DES
|| payload
->mode
== MFDES_AUTH_PICC
) {
895 des_decrypt(encRndA
, RndA
, key
->data
);
896 memcpy(both
, encRndA
, rndlen
);
898 for (uint32_t x
= 0; x
< rndlen
; x
++) {
899 rotRndB
[x
] = rotRndB
[x
] ^ encRndA
[x
];
902 des_decrypt(encRndB
, rotRndB
, key
->data
);
903 memcpy(both
+ rndlen
, encRndB
, rndlen
);
904 } else if (payload
->mode
== MFDES_AUTH_ISO
) {
905 if (payload
->algo
== MFDES_ALGO_3DES
) {
906 uint8_t tmp
[16] = {0x00};
907 memcpy(tmp
, RndA
, rndlen
);
908 memcpy(tmp
+ rndlen
, rotRndB
, rndlen
);
909 if (g_debugMode
> 1) {
910 PrintAndLogEx(DEBUG
, "rotRndB: %s", sprint_hex(rotRndB
, rndlen
));
911 PrintAndLogEx(DEBUG
, "Both: %s", sprint_hex(tmp
, 16));
913 tdes_nxp_send(tmp
, both
, 16, key
->data
, IV
, 2);
914 if (g_debugMode
> 1) {
915 PrintAndLogEx(DEBUG
, "EncBoth: %s", sprint_hex(both
, 16));
917 } else if (payload
->algo
== MFDES_ALGO_3K3DES
) {
918 uint8_t tmp
[32] = {0x00};
919 memcpy(tmp
, RndA
, rndlen
);
920 memcpy(tmp
+ rndlen
, rotRndB
, rndlen
);
921 if (g_debugMode
> 1) {
922 PrintAndLogEx(DEBUG
, "rotRndB: %s", sprint_hex(rotRndB
, rndlen
));
923 PrintAndLogEx(DEBUG
, "Both3k3: %s", sprint_hex(tmp
, 32));
925 tdes_nxp_send(tmp
, both
, 32, key
->data
, IV
, 3);
926 if (g_debugMode
> 1) {
927 PrintAndLogEx(DEBUG
, "EncBoth: %s", sprint_hex(both
, 32));
930 } else if (payload
->mode
== MFDES_AUTH_AES
) {
931 uint8_t tmp
[32] = {0x00};
932 memcpy(tmp
, RndA
, rndlen
);
933 memcpy(tmp
+ rndlen
, rotRndB
, rndlen
);
934 if (g_debugMode
> 1) {
935 PrintAndLogEx(DEBUG
, "rotRndB: %s", sprint_hex(rotRndB
, rndlen
));
936 PrintAndLogEx(DEBUG
, "Both3k3: %s", sprint_hex(tmp
, 32));
938 if (payload
->algo
== MFDES_ALGO_AES
) {
939 if (mbedtls_aes_setkey_enc(&ctx
, key
->data
, 128) != 0) {
942 mbedtls_aes_crypt_cbc(&ctx
, MBEDTLS_AES_ENCRYPT
, 32, IV
, tmp
, both
);
943 if (g_debugMode
> 1) {
944 PrintAndLogEx(DEBUG
, "EncBoth: %s", sprint_hex(both
, 32));
949 uint32_t bothlen
= 16;
950 if (payload
->algo
== MFDES_ALGO_AES
|| payload
->algo
== MFDES_ALGO_3K3DES
) {
953 if (payload
->mode
!= MFDES_AUTH_PICC
) {
954 sAPDU apdu
= {0x90, MFDES_ADDITIONAL_FRAME
, 0x00, 0x00, bothlen
, both
};
955 int res
= send_desfire_cmd(&apdu
, false, recv_data
, &recv_len
, &sw
, 0, false);
956 if (res
!= PM3_SUCCESS
) {
960 /*cmd[0] = ADDITIONAL_FRAME;
961 memcpy(cmd + 1, both, 16);
962 len = DesfireAPDU(cmd, 1 + 16, resp);
964 if (res != PM3_SUCCESS) {
965 PrintAndLogEx(SUCCESS, "Sending auth command %02X " _RED_("failed"),subcommand);
974 if (payload
->mode
!= MFDES_AUTH_PICC
) {
975 if (sw
!= status(MFDES_S_OPERATION_OK
)) {
979 /*if (resp[1] != 0x00) {
980 PrintAndLogEx(ERR,"Authentication failed. Card timeout.");
986 // tag->session_key = &default_key;
987 struct desfire_key
*p
= realloc (tag
->session_key
,sizeof(struct desfire_key
));
989 PrintAndLogEx(FAILED
, "Cannot allocate memory for session keys");
990 free(tag
->session_key
);
993 tag
->session_key
= p
;
995 memset (tag
->session_key
, 0x00, sizeof(struct desfire_key
));
997 Desfire_session_key_new(RndA
, RndB
, key
, tag
->session_key
);
999 if (payload
->mode
!= MFDES_AUTH_PICC
) {
1000 memcpy(encRndA
, recv_data
, rndlen
);
1002 memcpy(encRndA
, recv_data
+ 2, rndlen
);
1005 if (payload
->mode
== MFDES_AUTH_DES
|| payload
->mode
== MFDES_AUTH_ISO
|| payload
->mode
== MFDES_AUTH_PICC
) {
1006 if (payload
->algo
== MFDES_ALGO_DES
)
1007 des_decrypt(encRndA
, encRndA
, key
->data
);
1008 else if (payload
->algo
== MFDES_ALGO_3DES
)
1009 tdes_nxp_receive(encRndA
, encRndA
, rndlen
, key
->data
, IV
, 2);
1010 else if (payload
->algo
== MFDES_ALGO_3K3DES
)
1011 tdes_nxp_receive(encRndA
, encRndA
, rndlen
, key
->data
, IV
, 3);
1012 } else if (payload
->mode
== MFDES_AUTH_AES
) {
1013 if (mbedtls_aes_setkey_dec(&ctx
, key
->data
, 128) != 0) {
1016 mbedtls_aes_crypt_cbc(&ctx
, MBEDTLS_AES_DECRYPT
, rndlen
, IV
, encRndA
, encRndA
);
1020 for (uint32_t x
= 0; x
< rndlen
; x
++) {
1021 if (RndA
[x
] != encRndA
[x
]) {
1022 if (g_debugMode
> 1) {
1023 PrintAndLogEx(DEBUG
, "Expected_RndA : %s", sprint_hex(RndA
, rndlen
));
1024 PrintAndLogEx(DEBUG
, "Generated_RndA : %s", sprint_hex(encRndA
, rndlen
));
1030 // If the 3Des key first 8 bytes = 2nd 8 Bytes then we are really using Singe Des
1031 // As such we need to set the session key such that the 2nd 8 bytes = 1st 8 Bytes
1032 if (payload
->algo
== MFDES_ALGO_3DES
) {
1033 if (memcmp(key
->data
,&key
->data
[8],8) == 0)
1034 memcpy(&tag
->session_key
->data
[8], tag
->session_key
->data
, 8);
1037 rpayload
->sessionkeylen
= payload
->keylen
;
1038 memcpy(rpayload
->sessionkey
, tag
->session_key
->data
, rpayload
->sessionkeylen
);
1039 memset(tag
->ivect
, 0, MAX_CRYPTO_BLOCK_SIZE
);
1040 tag
->authenticated_key_no
= payload
->keyno
;
1042 if (tag
->authentication_scheme
== AS_NEW
) {
1043 cmac_generate_subkeys(tag
->session_key
, MCD_RECEIVE
);
1048 static void AuthToError(int error
) {
1051 PrintAndLogEx(SUCCESS
, "Sending auth command failed");
1054 PrintAndLogEx(ERR
, "Authentication failed. No data received");
1057 PrintAndLogEx(ERR
, "Authentication failed. Invalid key number.");
1060 PrintAndLogEx(ERR
, "Authentication failed. Length of answer doesn't match algo length");
1063 PrintAndLogEx(ERR
, "mbedtls_aes_setkey_dec failed");
1066 PrintAndLogEx(ERR
, "mbedtls_aes_setkey_enc failed");
1069 PrintAndLogEx(SUCCESS
, "Sending auth command failed");
1072 PrintAndLogEx(ERR
, "Authentication failed. Card timeout.");
1075 PrintAndLogEx(ERR
, "Authentication failed.");
1078 PrintAndLogEx(ERR
, "mbedtls_aes_setkey_dec failed");
1081 PrintAndLogEx(ERR
, "Authentication failed. Cannot verify Session Key.");
1088 // -- test if card supports 0x0A
1089 static int test_desfire_authenticate(void) {
1090 uint8_t data
[] = {0x00};
1091 sAPDU apdu
= {0x90, MFDES_AUTHENTICATE
, 0x00, 0x00, 0x01, data
}; // 0x0A, KEY 0
1092 uint32_t recv_len
= 0;
1094 int res
= send_desfire_cmd(&apdu
, true, NULL
, &recv_len
, &sw
, 0, false);
1095 if (res
== PM3_SUCCESS
)
1096 if (sw
== status(MFDES_ADDITIONAL_FRAME
)) {
1103 // -- test if card supports 0x1A
1104 static int test_desfire_authenticate_iso(void) {
1105 uint8_t data
[] = {0x00};
1106 sAPDU apdu
= {0x90, MFDES_AUTHENTICATE_ISO
, 0x00, 0x00, 0x01, data
}; // 0x1A, KEY 0
1107 uint32_t recv_len
= 0;
1109 int res
= send_desfire_cmd(&apdu
, true, NULL
, &recv_len
, &sw
, 0, false);
1110 if (res
== PM3_SUCCESS
)
1111 if (sw
== status(MFDES_ADDITIONAL_FRAME
)) {
1118 // -- test if card supports 0xAA
1119 static int test_desfire_authenticate_aes(void) {
1120 uint8_t data
[] = {0x00};
1121 sAPDU apdu
= {0x90, MFDES_AUTHENTICATE_AES
, 0x00, 0x00, 0x01, data
}; // 0xAA, KEY 0
1122 uint32_t recv_len
= 0;
1124 int res
= send_desfire_cmd(&apdu
, true, NULL
, &recv_len
, &sw
, 0, false);
1125 if (res
== PM3_SUCCESS
)
1126 if (sw
== status(MFDES_ADDITIONAL_FRAME
)) {
1134 static int desfire_print_freemem(uint32_t free_mem
) {
1135 PrintAndLogEx(SUCCESS
, " Available free memory on card : " _GREEN_("%d bytes"), free_mem
);
1139 static int handler_desfire_freemem(uint32_t *free_mem
) {
1140 if (free_mem
== NULL
) return PM3_EINVARG
;
1142 uint8_t data
[] = {0x00};
1143 sAPDU apdu
= {0x90, MFDES_GET_FREE_MEMORY
, 0x00, 0x00, 0x00, data
}; // 0x6E
1145 uint32_t recv_len
= 0;
1147 uint8_t fmem
[4] = {0};
1149 size_t plen
= apdu
.Lc
;
1150 uint8_t *p
= mifare_cryto_preprocess_data(tag
, (uint8_t *)apdu
.data
, &plen
, 0, MDCM_PLAIN
| CMAC_COMMAND
);
1151 apdu
.Lc
= (uint8_t)plen
;
1154 int res
= send_desfire_cmd(&apdu
, true, fmem
, &recv_len
, &sw
, 0, true);
1156 if (res
!= PM3_SUCCESS
)
1159 size_t dlen
= recv_len
;
1160 p
= mifare_cryto_postprocess_data(tag
, apdu
.data
, &dlen
, MDCM_PLAIN
| CMAC_COMMAND
| CMAC_VERIFY
);
1162 if (sw
!= status(MFDES_S_OPERATION_OK
))
1165 *free_mem
= le24toh(fmem
);
1169 static int mifare_desfire_change_key(uint8_t key_no
, uint8_t *new_key
, uint8_t new_algo
, uint8_t *old_key
, uint8_t old_algo
, uint8_t aes_version
) {
1171 if (new_key
== NULL
|| old_key
== NULL
) {
1175 // AID == 000000 6bits LSB needs to be 0
1179 Desfire treats Des keys as TDes but with the first half = 2nd half
1180 As such, we should be able to convert the Des to TDes then run the code as TDes
1182 if (new_algo
== MFDES_ALGO_DES
) {
1183 memcpy(&new_key
[8], new_key
, 8);
1184 new_algo
= MFDES_ALGO_3DES
;
1187 if (old_algo
== MFDES_ALGO_DES
) {
1188 memcpy(&old_key
[8], old_key
, 8);
1189 old_algo
= MFDES_ALGO_3DES
;
1193 * Because new crypto methods can be setup only at application creation,
1194 * changing the card master key to one of them require a key_no tweak.
1196 if (0x000000 == tag
->selected_application
) {
1198 // PICC master key, 6bits LSB needs to be 0
1201 // PICC master key, keyalgo specific 2bit MSB
1203 case MFDES_ALGO_DES
:
1204 case MFDES_ALGO_3DES
:
1206 case MFDES_ALGO_3K3DES
:
1207 key_no
|= 0x40; // 01xx xxx
1209 case MFDES_ALGO_AES
:
1210 key_no
|= 0x80; // 10xx xxx
1222 // Variable length ciphered key data 24-42 bytes plus padding..
1223 uint8_t data
[64] = {key_no
};
1224 sAPDU apdu
= {0x90, MFDES_CHANGE_KEY
, 0x00, 0x00, 0x01, data
}; // 0xC4
1227 uint8_t csPkt
[100] = {0x00}; // temp storage for AES/3K3Des packet to calculate checksum (size ????)
1229 uint8_t new_key_length
= 16;
1232 // We have converted the DES to 3DES above,so this will never hit
1233 case MFDES_ALGO_DES:
1234 memcpy(data + cmdcnt + 1, new_key, new_key_length);
1235 memcpy(data + cmdcnt + 1 + new_key_length, new_key, new_key_length);
1238 case MFDES_ALGO_3DES
:
1239 case MFDES_ALGO_AES
:
1240 new_key_length
= 16;
1241 memcpy(data
+ cmdcnt
+ 1, new_key
, new_key_length
);
1243 case MFDES_ALGO_3K3DES
:
1244 new_key_length
= 24;
1245 memcpy(data
+ cmdcnt
+ 1, new_key
, new_key_length
);
1249 if ((tag
->authenticated_key_no
& 0x0f) != (key_no
& 0x0f)) {
1251 for (uint32_t n
= 0; n
< new_key_length
; n
++) {
1252 data
[cmdcnt
+ 1 + n
] ^= old_key
[n
];
1257 cmdcnt
+= new_key_length
;
1259 if (new_algo
== MFDES_ALGO_AES
) {
1260 data
[cmdcnt
+ 1] = aes_version
;
1264 if ((tag
->authenticated_key_no
& 0x0f) != (key_no
& 0x0f)) {
1265 switch (tag
->authentication_scheme
) {
1267 iso14443a_crc_append(data
+ 1, cmdcnt
);
1270 // iso14443a_crc(new_key, new_key_length, data + cmdcnt);
1271 // Add offset + 1 for key no. at start
1272 iso14443a_crc(new_key
, new_key_length
, data
+ 1 + cmdcnt
);
1276 if (new_algo
== MFDES_ALGO_AES
) {
1277 // AES Checksum must cover : C4<KeyNo> <PrevKey XOR Newkey> <NewKeyVer>
1278 // C4 01 A0B08090E0F0C0D02030001060704050 03
1280 //uint8_t csPkt[30] = {0x00};
1281 csPkt
[0] = MFDES_CHANGE_KEY
;
1282 memcpy(&csPkt
[1], data
, 18);
1284 desfire_crc32(csPkt
, 19, data
+ 1 + cmdcnt
);
1285 } else if (new_algo
== MFDES_ALGO_3K3DES
) {
1286 // 3K3Des checksum must cover : C4 <KeyNo> <PrevKey XOR NewKey>
1287 csPkt
[0] = MFDES_CHANGE_KEY
;
1288 memcpy (&csPkt
[1], data
, 25);
1289 desfire_crc32(csPkt
, 26, data
+ 1 + cmdcnt
);
1291 desfire_crc32_append(data
+ 1, cmdcnt
);
1295 desfire_crc32(new_key
, new_key_length
, data
+ 1 + cmdcnt
);
1300 switch (tag
->authentication_scheme
) {
1302 iso14443a_crc_append(data
+ 1, cmdcnt
);
1306 if (new_algo
== MFDES_ALGO_AES
) {
1307 // AES Checksum must cover : C4<KeyNo> <Newkey data> <NewKeyVer>
1308 // C4 01 A0B08090E0F0C0D02030001060704050 03
1309 csPkt
[0] = MFDES_CHANGE_KEY
;
1310 memcpy(&csPkt
[1], data
, 18);
1311 desfire_crc32(csPkt
, 19, data
+ 1 + cmdcnt
);
1312 } else if (new_algo
== MFDES_ALGO_3K3DES
) {
1313 // 3K3Des checksum must cover : C4 <KeyNo> <Newkey Data>
1314 csPkt
[0] = MFDES_CHANGE_KEY
;
1315 memcpy (&csPkt
[1], data
, 25);
1316 desfire_crc32(csPkt
, 26, data
+ 1 + cmdcnt
);
1318 desfire_crc32_append(data
+ 1, cmdcnt
);
1321 // desfire_crc32_append(data, cmdcnt);
1327 uint8_t *p
= mifare_cryto_preprocess_data(tag
, data
+ 1, (size_t *)&cmdcnt
, 0, MDCM_ENCIPHERED
| ENC_COMMAND
| NO_CRC
);
1328 apdu
.Lc
= (uint8_t)cmdcnt
+ 1;
1330 // the above data pointed to from p did not have the key no. at the start, so copy preprocessed data after the key no.
1331 memcpy(&data
[1], p
, cmdcnt
);
1334 uint32_t recv_len
= 0;
1337 // If we call send_desfire with 2nd option (turn field on), it will turn off then on
1338 // leading to loosing the authentication on the aid, so lets not turn on here.
1339 // int res = send_desfire_cmd(&apdu, true, NULL, &recv_len, &sw, 0, true);
1340 int res
= send_desfire_cmd(&apdu
, false, NULL
, &recv_len
, &sw
, 0, true);
1342 if (res
!= PM3_SUCCESS
) {
1343 PrintAndLogEx(WARNING
, _RED_("can't change key -> %s"), GetErrorString(res
, &sw
));
1348 size_t sn
= recv_len
;
1351 if ((new_algo
== MFDES_ALGO_AES
) || (new_algo
== MFDES_ALGO_3K3DES
))
1353 // AES expects us to Calculate CMAC for status byte : OK 0x00 (0x91 00)
1354 // As such if we get this far without an error, we should be good
1355 // Since we are dropping the field, we dont need to maintain the CMAC etc.
1356 // Setting sn = 1 will allow the post process to just exit (as status only)
1358 // Simular 3K3Des has some work to validate, but as long as the reply code was 00
1359 // e.g. 02 fe ec 77 ca 13 e0 c2 06 [91 00 (OK)] 69 67
1364 p
= mifare_cryto_postprocess_data(tag
, data
, &sn
, MDCM_PLAIN
| CMAC_COMMAND
| CMAC_VERIFY
);
1366 // Should be finished processing the changekey so lets ensure the field is dropped.
1371 Note in my testing on an EV1, the AES password did change, with the number of returned bytes was 8, expected 9 <status><8 byte cmac>
1372 As such !p is true and the code reports "Error on changing key"; so comment back to user until its fixed.
1374 Note: as at 19 May 2021, with the sn = 1 patch above, this should no longer be reachable!
1376 if (new_algo
== MFDES_ALGO_AES
) {
1377 PrintAndLogEx(WARNING
, "AES Key may have been changed, please check new password with the auth command.");
1384 * If we changed the current authenticated key, we are not authenticated
1387 if (key_no
== tag
->authenticated_key_no
) {
1388 free(tag
->session_key
);
1389 tag
->session_key
= NULL
;
1395 // --- GET SIGNATURE
1396 static int desfire_print_signature(uint8_t *uid
, uint8_t uidlen
, uint8_t *signature
, size_t signature_len
, nxp_cardtype_t card_type
) {
1400 PrintAndLogEx(DEBUG
, "UID=NULL");
1403 if (signature
== NULL
) {
1404 PrintAndLogEx(DEBUG
, "SIGNATURE=NULL");
1407 // ref: MIFARE Desfire Originality Signature Validation
1408 // See tools/recover_pk.py to recover Pk from UIDs and signatures
1409 #define PUBLIC_DESFIRE_ECDA_KEYLEN 57
1410 const ecdsa_publickey_t nxp_desfire_public_keys
[] = {
1411 {"NTAG424DNA, DESFire EV2", "048A9B380AF2EE1B98DC417FECC263F8449C7625CECE82D9B916C992DA209D68422B81EC20B65A66B5102A61596AF3379200599316A00A1410"},
1412 {"NTAG413DNA, DESFire EV1", "04BB5D514F7050025C7D0F397310360EEC91EAF792E96FC7E0F496CB4E669D414F877B7B27901FE67C2E3B33CD39D1C797715189AC951C2ADD"},
1413 {"DESFire EV2", "04B304DC4C615F5326FE9383DDEC9AA892DF3A57FA7FFB3276192BC0EAA252ED45A865E3B093A3D0DCE5BE29E92F1392CE7DE321E3E5C52B3A"},
1414 {"DESFire EV3", "041DB46C145D0A36539C6544BD6D9B0AA62FF91EC48CBC6ABAE36E0089A46F0D08C8A715EA40A63313B92E90DDC1730230E0458A33276FB743"},
1415 {"NTAG424DNA, NTAG424DNATT, DESFire Light EV2", "04B304DC4C615F5326FE9383DDEC9AA892DF3A57FA7FFB3276192BC0EAA252ED45A865E3B093A3D0DCE5BE29E92F1392CE7DE321E3E5C52B3B"},
1416 {"DESFire Light", "040E98E117AAA36457F43173DC920A8757267F44CE4EC5ADD3C54075571AEBBF7B942A9774A1D94AD02572427E5AE0A2DD36591B1FB34FCF3D"},
1417 {"MIFARE Plus EV1", "044409ADC42F91A8394066BA83D872FB1D16803734E911170412DDF8BAD1A4DADFD0416291AFE1C748253925DA39A5F39A1C557FFACD34C62E"},
1418 {"MIFARE Pluc Evx", "04BB49AE4447E6B1B6D21C098C1538B594A11A4A1DBF3D5E673DEACDEB3CC512D1C08AFA1A2768CE20A200BACD2DC7804CD7523A0131ABF607"},
1423 bool is_valid
= false;
1425 for (i
= 0; i
< ARRAYLEN(nxp_desfire_public_keys
); i
++) {
1428 uint8_t key
[PUBLIC_DESFIRE_ECDA_KEYLEN
];
1429 param_gethex_to_eol(nxp_desfire_public_keys
[i
].value
, 0, key
, PUBLIC_DESFIRE_ECDA_KEYLEN
, &dl
);
1431 int res
= ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP224R1
, key
, uid
, uidlen
, signature
, signature_len
, false);
1432 is_valid
= (res
== 0);
1436 // PrintAndLogEx(NORMAL, "");
1437 // PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature"));
1438 if (is_valid
== false || i
== ARRAYLEN(nxp_desfire_public_keys
)) {
1439 PrintAndLogEx(INFO
, " Elliptic curve parameters: NID_secp224r1");
1440 PrintAndLogEx(INFO
, " TAG IC Signature: %s", sprint_hex_inrow(signature
, 16));
1441 PrintAndLogEx(INFO
, " : %s", sprint_hex_inrow(signature
+ 16, 16));
1442 PrintAndLogEx(INFO
, " : %s", sprint_hex_inrow(signature
+ 32, 16));
1443 PrintAndLogEx(INFO
, " : %s", sprint_hex_inrow(signature
+ 48, signature_len
- 48));
1444 PrintAndLogEx(SUCCESS
, " Signature verification: " _RED_("failed"));
1448 PrintAndLogEx(INFO
, " IC signature public key name: " _GREEN_("%s"), nxp_desfire_public_keys
[i
].desc
);
1449 PrintAndLogEx(INFO
, "IC signature public key value: %.32s", nxp_desfire_public_keys
[i
].value
);
1450 PrintAndLogEx(INFO
, " : %.32s", nxp_desfire_public_keys
[i
].value
+ 32);
1451 PrintAndLogEx(INFO
, " : %.32s", nxp_desfire_public_keys
[i
].value
+ 64);
1452 PrintAndLogEx(INFO
, " : %.32s", nxp_desfire_public_keys
[i
].value
+ 96);
1453 PrintAndLogEx(INFO
, " Elliptic curve parameters: NID_secp224r1");
1454 PrintAndLogEx(INFO
, " TAG IC Signature: %s", sprint_hex_inrow(signature
, 16));
1455 PrintAndLogEx(INFO
, " : %s", sprint_hex_inrow(signature
+ 16, 16));
1456 PrintAndLogEx(INFO
, " : %s", sprint_hex_inrow(signature
+ 32, 16));
1457 PrintAndLogEx(INFO
, " : %s", sprint_hex_inrow(signature
+ 48, signature_len
- 48));
1458 PrintAndLogEx(SUCCESS
, " Signature verification: " _GREEN_("successful"));
1462 static int handler_desfire_signature(uint8_t *signature
, size_t *signature_len
) {
1464 if (signature
== NULL
) {
1465 PrintAndLogEx(DEBUG
, "SIGNATURE=NULL");
1468 if (signature_len
== NULL
) {
1469 PrintAndLogEx(DEBUG
, "SIGNATURE_LEN=NULL");
1473 uint8_t c
[] = {0x00};
1474 sAPDU apdu
= {0x90, MFDES_READSIG
, 0x00, 0x00, sizeof(c
), c
}; // 0x3C
1476 uint32_t recv_len
= 0;
1478 int res
= send_desfire_cmd(&apdu
, true, signature
, &recv_len
, &sw
, 0, true);
1479 if (res
== PM3_SUCCESS
) {
1480 if (recv_len
!= 56) {
1484 *signature_len
= recv_len
;
1492 static int desfire_print_keyversion(uint8_t key_idx
, uint8_t key_version
) {
1493 PrintAndLogEx(SUCCESS
, " Key [%u] Version : %d (0x%02x)", key_idx
, key_version
, key_version
);
1497 static int handler_desfire_keyversion(uint8_t curr_key
, uint8_t *num_versions
) {
1498 if (num_versions
== NULL
) {
1499 PrintAndLogEx(DEBUG
, "NUM_VERSIONS=NULL");
1502 sAPDU apdu
= {0x90, MFDES_GET_KEY_VERSION
, 0x00, 0x00, 0x01, &curr_key
}; //0x64
1503 uint32_t recv_len
= 0;
1505 int res
= send_desfire_cmd(&apdu
, false, num_versions
, &recv_len
, &sw
, 0, true);
1507 if (res
!= PM3_SUCCESS
)
1510 if (sw
!= status(MFDES_S_OPERATION_OK
))
1516 // --- KEY SETTING Application Master Key
1517 static int desfire_print_amk_keysetting(uint8_t key_settings
, uint8_t num_keys
, int algo
) {
1518 PrintAndLogEx(SUCCESS
, " AID Key settings : 0x%02x", key_settings
);
1520 const char *str
= " Max key number and type : %d, " _YELLOW_("%s");
1522 if (algo
== MFDES_ALGO_DES
)
1523 PrintAndLogEx(SUCCESS
, str
, num_keys
& 0x3F, "(3)DES");
1524 else if (algo
== MFDES_ALGO_AES
)
1525 PrintAndLogEx(SUCCESS
, str
, num_keys
& 0x3F, "AES");
1526 else if (algo
== MFDES_ALGO_3K3DES
)
1527 PrintAndLogEx(SUCCESS
, str
, num_keys
& 0x3F, "3K3DES");
1529 //PrintAndLogEx(SUCCESS, " Max number of keys in AID : %d", num_keys & 0x3F);
1530 PrintAndLogEx(INFO
, "-------------------------------------------------------------");
1531 PrintAndLogEx(SUCCESS
, " Changekey Access rights");
1534 uint8_t rights
= ((key_settings
>> 4) & 0x0F);
1537 PrintAndLogEx(SUCCESS
, " -- AMK authentication is necessary to change any key (default)");
1540 PrintAndLogEx(SUCCESS
, " -- Authentication with the key to be changed (same KeyNo) is necessary to change a key");
1543 PrintAndLogEx(SUCCESS
, " -- All keys (except AMK,see Bit0) within this application are frozen");
1546 PrintAndLogEx(SUCCESS
,
1547 " -- Authentication with the specified key is necessary to change any key.\n"
1548 "A change key and a PICC master key (CMK) can only be changed after authentication with the master key.\n"
1549 "For keys other then the master or change key, an authentication with the same key is needed."
1554 PrintAndLogEx(SUCCESS
, " [%c...] AMK Configuration changeable : %s", (key_settings
& (1 << 3)) ? '1' : '0', (key_settings
& (1 << 3)) ? _GREEN_("YES") : "NO (frozen)");
1555 PrintAndLogEx(SUCCESS
, " [.%c..] AMK required for create/delete : %s", (key_settings
& (1 << 2)) ? '1' : '0', (key_settings
& (1 << 2)) ? "NO" : "YES");
1556 PrintAndLogEx(SUCCESS
, " [..%c.] Directory list access with AMK : %s", (key_settings
& (1 << 1)) ? '1' : '0', (key_settings
& (1 << 1)) ? "NO" : "YES");
1557 PrintAndLogEx(SUCCESS
, " [...%c] AMK is changeable : %s", (key_settings
& (1 << 0)) ? '1' : '0', (key_settings
& (1 << 0)) ? _GREEN_("YES") : "NO (frozen)");
1561 // --- KEY SETTING PICC Master Key (CMK)
1562 static int desfire_print_piccmk_keysetting(uint8_t key_settings
, uint8_t num_keys
, int algo
) {
1563 //PrintAndLogEx(INFO, "--- " _CYAN_("PICC Master Key (CMK) settings"));
1564 // number of Master keys (0x01)
1565 PrintAndLogEx(SUCCESS
, " Number of Masterkeys : " _YELLOW_("%u"), (num_keys
& 0x3F));
1566 const char *str
= " Operation of PICC master key : " _YELLOW_("%s");
1568 if (algo
== MFDES_ALGO_DES
)
1569 PrintAndLogEx(SUCCESS
, str
, "(3)DES");
1570 else if (algo
== MFDES_ALGO_AES
)
1571 PrintAndLogEx(SUCCESS
, str
, "AES");
1572 else if (algo
== MFDES_ALGO_3K3DES
)
1573 PrintAndLogEx(SUCCESS
, str
, "3K3DES");
1575 uint8_t cmk_num_versions
= 0;
1576 if (handler_desfire_keyversion(0, &cmk_num_versions
) == PM3_SUCCESS
) {
1577 PrintAndLogEx(SUCCESS
, " PICC Master key Version : " _YELLOW_("%d (0x%02x)"), cmk_num_versions
, cmk_num_versions
);
1580 PrintAndLogEx(INFO
, " ----------------------------------------------------------");
1582 // Authentication tests
1583 int res
= test_desfire_authenticate();
1584 if (res
== PM3_SUCCESS
)
1585 PrintAndLogEx(SUCCESS
, " [0x0A] Authenticate : %s", (res
== PM3_SUCCESS
) ? _YELLOW_("YES") : "NO");
1587 res
= test_desfire_authenticate_iso();
1588 if (res
== PM3_SUCCESS
)
1589 PrintAndLogEx(SUCCESS
, " [0x1A] Authenticate ISO : %s", (res
== PM3_SUCCESS
) ? _YELLOW_("YES") : "NO");
1591 res
= test_desfire_authenticate_aes();
1592 if (res
== PM3_SUCCESS
)
1593 PrintAndLogEx(SUCCESS
, " [0xAA] Authenticate AES : %s", (res
== PM3_SUCCESS
) ? _YELLOW_("YES") : "NO");
1595 PrintAndLogEx(INFO
, "-------------------------------------------------------------");
1596 PrintAndLogEx(INFO
, " Key setting: 0x%02X [%c%c%c%c]",
1598 (key_settings
& (1 << 3)) ? '1' : '0',
1599 (key_settings
& (1 << 2)) ? '1' : '0',
1600 (key_settings
& (1 << 1)) ? '1' : '0',
1601 (key_settings
& (1 << 0)) ? '1' : '0'
1604 PrintAndLogEx(SUCCESS
, " [%c...] CMK Configuration changeable : %s", (key_settings
& (1 << 3)) ? '1' : '0', (key_settings
& (1 << 3)) ? _GREEN_("YES") : "NO (frozen)");
1605 PrintAndLogEx(SUCCESS
, " [.%c..] CMK required for create/delete : %s", (key_settings
& (1 << 2)) ? '1' : '0', (key_settings
& (1 << 2)) ? _GREEN_("NO") : "YES");
1606 PrintAndLogEx(SUCCESS
, " [..%c.] Directory list access with CMK : %s", (key_settings
& (1 << 1)) ? '1' : '0', (key_settings
& (1 << 1)) ? _GREEN_("NO") : "YES");
1607 PrintAndLogEx(SUCCESS
, " [...%c] CMK is changeable : %s", (key_settings
& (1 << 0)) ? '1' : '0', (key_settings
& (1 << 0)) ? _GREEN_("YES") : "NO (frozen)");
1611 static int handler_desfire_getkeysettings(uint8_t *key_settings
, uint8_t *num_keys
) {
1612 if (key_settings
== NULL
) {
1613 PrintAndLogEx(DEBUG
, "KEY_SETTINGS=NULL");
1616 if (num_keys
== NULL
) {
1617 PrintAndLogEx(DEBUG
, "NUM_KEYS=NULL");
1620 sAPDU apdu
= {0x90, MFDES_GET_KEY_SETTINGS
, 0x00, 0x00, 0x00, NULL
}; //0x45
1622 uint32_t recv_len
= 0;
1624 uint8_t data
[2] = {0};
1625 int res
= send_desfire_cmd(&apdu
, false, data
, &recv_len
, &sw
, 0, true);
1627 if (res
!= PM3_SUCCESS
)
1629 if (sw
!= status(MFDES_S_OPERATION_OK
))
1632 *key_settings
= data
[0];
1633 *num_keys
= data
[1];
1637 static int handler_desfire_getuid(uint8_t *uid
) {
1639 PrintAndLogEx(DEBUG
, "UID=NULL");
1642 sAPDU apdu
= {0x90, MFDES_GET_UID
, 0x00, 0x00, 0x00, NULL
}; //0x51
1643 uint32_t recv_len
= 0;
1646 // Setup the pre-process to update the IV etc. (not needed in the apdu to send to card)
1648 uint8_t tmp_data
[100] = { 0x00 }; // Note sure on size, but 100 is more then enough
1649 tmp_data
[0] = MFDES_GET_UID
;
1650 int8_t *p
= mifare_cryto_preprocess_data(tag
, tmp_data
, &plen
, 0, MDCM_PLAIN
| CMAC_COMMAND
);
1653 // Send request/apdu
1654 int res
= send_desfire_cmd(&apdu
, false, uid
, &recv_len
, &sw
, 0, true);
1656 if (res
!= PM3_SUCCESS
)
1659 if (sw
!= status(MFDES_S_OPERATION_OK
))
1663 size_t dlen
= recv_len
;
1664 p
= mifare_cryto_postprocess_data(tag
, uid
, &dlen
, CMAC_COMMAND
| CMAC_VERIFY
| MAC_VERIFY
| MDCM_ENCIPHERED
);
1672 static int handler_desfire_commit_transaction(void) {
1673 sAPDU apdu
= {0x90, MFDES_COMMIT_TRANSACTION
, 0x00, 0x00, 0x00, NULL
}; //0xC7
1674 uint32_t recv_len
= 0;
1676 int res
= send_desfire_cmd(&apdu
, false, NULL
, &recv_len
, &sw
, 0, true);
1678 if (res
!= PM3_SUCCESS
)
1681 if (sw
!= status(MFDES_S_OPERATION_OK
))
1687 /*static int handler_desfire_abort_transaction(void) {
1688 sAPDU apdu = {0x90, MFDES_ABORT_TRANSACTION, 0x00, 0x00, 0x00, NULL}; //0xA7
1689 uint32_t recv_len = 0;
1691 int res = send_desfire_cmd(&apdu, false, NULL, &recv_len, &sw, 0, true);
1693 if (res != PM3_SUCCESS)
1696 if (sw != status(MFDES_S_OPERATION_OK))
1703 static int handler_desfire_appids(uint8_t *dest
, uint32_t *app_ids_len
) {
1705 PrintAndLogEx(DEBUG
, "DEST=NULL");
1708 if (app_ids_len
== NULL
) {
1709 PrintAndLogEx(DEBUG
, "APP_IDS_LEN=NULL");
1713 sAPDU apdu
= {0x90, MFDES_GET_APPLICATION_IDS
, 0x00, 0x00, 0x00, NULL
}; //0x6a
1714 uint32_t recv_len
= 0;
1716 int res
= send_desfire_cmd(&apdu
, true, dest
, &recv_len
, &sw
, 0, true);
1718 if (res
!= PM3_SUCCESS
)
1721 if (sw
!= status(MFDES_S_OPERATION_OK
))
1724 *app_ids_len
= (uint8_t)(recv_len
& 0xFF);
1729 static int handler_desfire_dfnames(dfname_t
*dest
, uint8_t *dfname_count
) {
1731 if (g_debugMode
> 1) {
1732 if (dest
== NULL
) PrintAndLogEx(ERR
, "DEST = NULL");
1733 if (dfname_count
== NULL
) PrintAndLogEx(ERR
, "DFNAME_COUNT = NULL");
1736 if (dest
== NULL
|| dfname_count
== NULL
)
1740 sAPDU apdu
= {0x90, MFDES_GET_DF_NAMES
, 0x00, 0x00, 0x00, NULL
}; //0x6d
1741 uint32_t recv_len
= 0;
1743 int res
= send_desfire_cmd(&apdu
, true, (uint8_t *)dest
, &recv_len
, &sw
, sizeof(dfname_t
), true);
1744 if (res
!= PM3_SUCCESS
) {
1748 if (sw
!= status(MFDES_S_OPERATION_OK
))
1751 *dfname_count
= recv_len
;
1755 static int handler_desfire_select_application(uint8_t *aid
) {
1756 if (g_debugMode
> 1) {
1758 PrintAndLogEx(ERR
, "AID=NULL");
1765 sAPDU apdu
= {0x90, MFDES_SELECT_APPLICATION
, 0x00, 0x00, 0x03, aid
}; //0x5a
1766 uint32_t recv_len
= 0;
1769 int res
= send_desfire_cmd(&apdu
, !tag
->rf_field_on
, NULL
, &recv_len
, &sw
, sizeof(dfname_t
), true);
1770 if (res
!= PM3_SUCCESS
) {
1771 PrintAndLogEx(WARNING
,
1772 _RED_(" Can't select AID 0x%X -> %s"),
1773 (aid
[2] << 16) + (aid
[1] << 8) + aid
[0],
1774 GetErrorString(res
, &sw
)
1779 memcpy(&tag
->selected_application
, aid
, 3);
1783 static int key_setting_to_algo(uint8_t aid
[3], uint8_t *key_setting
, mifare_des_authalgo_t
*algo
, uint8_t *num_keys
) {
1784 int res
= handler_desfire_select_application(aid
);
1785 if (res
!= PM3_SUCCESS
) return res
;
1788 res
= handler_desfire_getkeysettings(key_setting
, num_keys
);
1789 if (res
== PM3_SUCCESS
) {
1790 switch (*num_keys
>> 6) {
1792 *algo
= MFDES_ALGO_DES
;
1795 *algo
= MFDES_ALGO_3K3DES
;
1798 *algo
= MFDES_ALGO_AES
;
1805 static int handler_desfire_fileids(uint8_t *dest
, uint32_t *file_ids_len
) {
1806 if (g_debugMode
> 1) {
1807 if (dest
== NULL
) PrintAndLogEx(ERR
, "DEST=NULL");
1808 if (file_ids_len
== NULL
) PrintAndLogEx(ERR
, "FILE_IDS_LEN=NULL");
1810 if (dest
== NULL
|| file_ids_len
== NULL
) return PM3_EINVARG
;
1811 sAPDU apdu
= {0x90, MFDES_GET_FILE_IDS
, 0x00, 0x00, 0x00, NULL
}; //0x6f
1812 uint32_t recv_len
= 0;
1815 int res
= send_desfire_cmd(&apdu
, false, dest
, &recv_len
, &sw
, 0, true);
1816 if (res
!= PM3_SUCCESS
) {
1817 PrintAndLogEx(WARNING
, _RED_(" Can't get file ids -> %s"), GetErrorString(res
, &sw
));
1821 *file_ids_len
= recv_len
;
1826 static int handler_desfire_filesettings(uint8_t file_id
, uint8_t *dest
, uint32_t *destlen
) {
1827 if (g_debugMode
> 1) {
1828 if (dest
== NULL
) PrintAndLogEx(ERR
, "DEST=NULL");
1829 if (destlen
== NULL
) PrintAndLogEx(ERR
, "DESTLEN=NULL");
1831 if (dest
== NULL
|| destlen
== NULL
) return PM3_EINVARG
;
1832 sAPDU apdu
= {0x90, MFDES_GET_FILE_SETTINGS
, 0x00, 0x00, 0x01, &file_id
}; // 0xF5
1834 int res
= send_desfire_cmd(&apdu
, false, dest
, destlen
, &sw
, 0, true);
1835 if (res
!= PM3_SUCCESS
) {
1836 PrintAndLogEx(WARNING
, _RED_(" Can't get file settings -> %s"), GetErrorString(res
, &sw
));
1843 static int handler_desfire_createapp(aidhdr_t
*aidhdr
, bool usename
, bool usefid
) {
1844 if (aidhdr
== NULL
) return PM3_EINVARG
;
1846 sAPDU apdu
= {0x90, MFDES_CREATE_APPLICATION
, 0x00, 0x00, sizeof(aidhdr_t
), (uint8_t *)aidhdr
}; // 0xCA
1848 if (usename
== false) {
1849 apdu
.Lc
= apdu
.Lc
- sizeof(aidhdr
->name
);
1851 if (usefid
== false) {
1852 apdu
.Lc
= apdu
.Lc
- sizeof(aidhdr
->fid
);
1854 uint8_t *data
= NULL
;
1856 // skip over FID if not used.
1857 if (usefid
== false && usename
) {
1858 data
= calloc(apdu
.Lc
, sizeof(uint8_t));
1861 memcpy(data
, aidhdr
->aid
, sizeof(aidhdr
->aid
));
1862 data
[3] = aidhdr
->keysetting1
;
1863 data
[4] = aidhdr
->keysetting2
;
1864 memcpy(data
+ 5, aidhdr
->name
, sizeof(aidhdr
->name
));
1866 PrintAndLogEx(INFO
, "new data: %s", sprint_hex_inrow(data
, apdu
.Lc
));
1870 uint32_t recvlen
= 0;
1871 int res
= send_desfire_cmd(&apdu
, false, NULL
, &recvlen
, &sw
, 0, true);
1875 if (res
!= PM3_SUCCESS
) {
1876 PrintAndLogEx(WARNING
, _RED_(" Can't create aid -> %s"), GetErrorString(res
, &sw
));
1882 static int handler_desfire_deleteapp(const uint8_t *aid
) {
1886 sAPDU apdu
= {0x90, MFDES_DELETE_APPLICATION
, 0x00, 0x00, 3, (uint8_t *)aid
}; // 0xDA
1888 uint32_t recvlen
= 0;
1889 int res
= send_desfire_cmd(&apdu
, false, NULL
, &recvlen
, &sw
, 0, true);
1890 if (res
!= PM3_SUCCESS
) {
1891 PrintAndLogEx(WARNING
, _RED_(" Can't delete aid -> %s"), GetErrorString(res
, &sw
));
1897 static int handler_desfire_credit(mfdes_value_t
*value
, uint8_t cs
) {
1898 sAPDU apdu
= {0x90, MFDES_CREDIT
, 0x00, 0x00, 1 + 4, (uint8_t *)value
}; // 0x0C
1900 uint32_t recvlen
= 0;
1902 size_t plen
= apdu
.Lc
;
1903 uint8_t *p
= mifare_cryto_preprocess_data(tag
, (uint8_t *)apdu
.data
, &plen
, 0, cs
| MAC_COMMAND
| CMAC_COMMAND
| ENC_COMMAND
);
1904 apdu
.Lc
= (uint8_t)plen
;
1907 int res
= send_desfire_cmd(&apdu
, false, NULL
, &recvlen
, &sw
, 0, true);
1908 if (res
!= PM3_SUCCESS
) {
1909 PrintAndLogEx(WARNING
, _RED_(" Can't credit value -> %s"), GetErrorString(res
, &sw
));
1916 static int handler_desfire_limitedcredit(mfdes_value_t
*value
, uint8_t cs
) {
1917 sAPDU apdu
= {0x90, MFDES_LIMITED_CREDIT
, 0x00, 0x00, 1 + 4, (uint8_t *)value
}; // 0x1C
1919 uint32_t recvlen
= 0;
1921 size_t plen
= apdu
.Lc
;
1922 uint8_t *p
= mifare_cryto_preprocess_data(tag
, (uint8_t *)apdu
.data
, &plen
, 0, cs
| MAC_COMMAND
| CMAC_COMMAND
| ENC_COMMAND
);
1923 apdu
.Lc
= (uint8_t)plen
;
1926 int res
= send_desfire_cmd(&apdu
, false, NULL
, &recvlen
, &sw
, 0, true);
1927 if (res
!= PM3_SUCCESS
) {
1928 PrintAndLogEx(WARNING
, _RED_(" Can't credit limited value -> %s"), GetErrorString(res
, &sw
));
1935 static int handler_desfire_debit(mfdes_value_t
*value
, uint8_t cs
) {
1936 sAPDU apdu
= {0x90, MFDES_DEBIT
, 0x00, 0x00, 1 + 4, (uint8_t *)value
}; // 0xDC
1938 uint32_t recvlen
= 0;
1940 size_t plen
= apdu
.Lc
;
1941 uint8_t *p
= mifare_cryto_preprocess_data(tag
, (uint8_t *)apdu
.data
, &plen
, 0, cs
| MAC_COMMAND
| CMAC_COMMAND
| ENC_COMMAND
);
1942 apdu
.Lc
= (uint8_t)plen
;
1945 int res
= send_desfire_cmd(&apdu
, false, NULL
, &recvlen
, &sw
, 0, true);
1946 if (res
!= PM3_SUCCESS
) {
1947 PrintAndLogEx(WARNING
, _RED_(" Can't debit value -> %s"), GetErrorString(res
, &sw
));
1954 static int handler_desfire_readdata(mfdes_data_t
*data
, MFDES_FILE_TYPE_T type
, uint8_t cs
) {
1955 if (data
->fileno
> 0x1F) {
1959 sAPDU apdu
= {0x90, MFDES_READ_DATA
, 0x00, 0x00, 1 + 3 + 3, (uint8_t *)data
}; // 0xBD
1960 if (type
== MFDES_RECORD_FILE
) {
1961 apdu
.INS
= MFDES_READ_RECORDS
; //0xBB
1964 // we need the CMD 0xBD <data> to calc the CMAC
1965 uint8_t tmp_data
[8]; // Since the APDU is hardcoded to 7 bytes of payload 7+1 = 8 is enough.
1966 tmp_data
[0] = apdu
.INS
;
1967 memcpy(&tmp_data
[1], data
, 7);
1969 // size_t plen = apdu.Lc;
1970 // uint8_t *p = mifare_cryto_preprocess_data(tag, (uint8_t *)data, &plen, 0, MDCM_PLAIN | CMAC_COMMAND);
1971 // apdu.Lc = (uint8_t)plen;
1975 uint8_t *p
= mifare_cryto_preprocess_data(tag
, tmp_data
, &plen
, 0, MDCM_PLAIN
| CMAC_COMMAND
);
1977 // apdu data does not need the cmd, so use the original read command data.
1979 apdu
.data
= (uint8_t *)data
;
1982 uint32_t resplen
= 0;
1983 int res
= send_desfire_cmd(&apdu
, false, data
->data
, &resplen
, &sw
, 0, true);
1984 if (res
!= PM3_SUCCESS
) {
1985 PrintAndLogEx(WARNING
, _RED_(" Can't read data -> %s"), GetErrorString(res
, &sw
));
1990 size_t dlen
= resplen
;
1991 p
= mifare_cryto_postprocess_data(tag
, data
->data
, &dlen
, cs
| CMAC_COMMAND
| CMAC_VERIFY
| MAC_VERIFY
);
1997 memcpy(data
->length
, &resplen
, 3);
2001 static int handler_desfire_getvalue(mfdes_value_t
*value
, uint32_t *resplen
, uint8_t cs
) {
2003 if (value
->fileno
> 0x1F)
2006 sAPDU apdu
= {0x90, MFDES_GET_VALUE
, 0x00, 0x00, 0x01, &value
->fileno
}; // 0xBD
2010 size_t plen
= apdu
.Lc
;
2011 uint8_t *p
= mifare_cryto_preprocess_data(tag
, (uint8_t *)apdu
.data
, &plen
, 0, MDCM_PLAIN
| CMAC_COMMAND
);
2012 apdu
.Lc
= (uint8_t)plen
;
2015 int res
= send_desfire_cmd(&apdu
, false, value
->value
, resplen
, &sw
, 0, true);
2016 if (res
!= PM3_SUCCESS
) {
2017 PrintAndLogEx(WARNING
, _RED_(" Can't read data -> %s"), GetErrorString(res
, &sw
));
2021 size_t dlen
= (size_t) * resplen
;
2022 p
= mifare_cryto_postprocess_data(tag
, value
->value
, &dlen
, cs
| CMAC_COMMAND
| CMAC_VERIFY
| MAC_VERIFY
);
2027 static int handler_desfire_writedata(mfdes_data_t
*data
, MFDES_FILE_TYPE_T type
, uint8_t cs
) {
2028 /* LC FN OF OF OF LN LN LN DD DD DD
2029 90 3d 00 00 16 01 00 00 00 0f 00 00 00 0f 20 00 3b 00 34 04 06 e1 04 0f fe 00 00 00
2030 90 3d 00 00 09 02 00 00 00 02 00 00 00 00 00
2033 if (data
->fileno
> 0x1F) {
2037 uint32_t datatowrite
= le24toh(data
->length
);
2038 uint32_t offset
= le24toh(data
->offset
);
2039 uint32_t datasize
, recvlen
= 0;
2040 int res
= PM3_SUCCESS
;
2044 sAPDU apdu
= {0x90, MFDES_WRITE_DATA
, 0x00, 0x00, 0, (uint8_t *) &sdata
}; // 0x3D
2046 uint8_t tmp
[61] = {0};
2047 tmp
[0] = MFDES_WRITE_DATA
;
2048 tmp
[1] = data
->fileno
;
2049 apdu
.data
= &tmp
[1]; // tmp[0] is holding the OPCODE for macd calc, so we dont want it in the apdu
2051 if (type
== MFDES_RECORD_FILE
) {
2052 apdu
.INS
= MFDES_WRITE_RECORD
;
2055 while (datatowrite
) {
2057 if (datatowrite
> 52)
2060 datasize
= datatowrite
;
2062 // Build packet to pre-process (using CMD FN OFFSET LEN DATA)
2063 tmp
[2] = offset
& 0xFF;
2064 tmp
[3] = (offset
>> 8) & 0xFF;
2065 tmp
[4] = (offset
>> 16) & 0xFF;
2066 tmp
[5] = datasize
& 0xFF;
2067 tmp
[6] = (datasize
>> 8) & 0xFF;
2068 tmp
[7] = (datasize
>> 16) & 0xFF;
2069 memcpy(&tmp
[8], (uint8_t *)&data
->data
[offset
], datasize
);
2071 size_t plen
= datasize
+ 8;
2072 uint8_t *p
= mifare_cryto_preprocess_data(tag
, tmp
, &plen
, 8, cs
| MAC_COMMAND
| CMAC_COMMAND
| ENC_COMMAND
);
2074 // Copy actual data as needed to create APDU Format
2076 memcpy(&tmp
[8], &p
[8], plen
- 8);
2077 // need to drop the OpCode from plen
2082 // we dont want to change the value of datasize, so delt with above without change
2083 // Doing so can create wrong offsets and endless loop.
2084 if (plen != -1) datasize = (uint8_t)plen;
2085 memcpy(&tmp[7], p, datasize);
2087 apdu.Lc = datasize + 1 + 3 + 3;
2090 res
= send_desfire_cmd(&apdu
, false, NULL
, &recvlen
, &sw
, 0, true);
2091 if (res
!= PM3_SUCCESS
) {
2092 PrintAndLogEx(WARNING
, _RED_(" Can't write data -> %s"), GetErrorString(res
, &sw
));
2097 datatowrite
-= datasize
;
2099 if (type
== MFDES_RECORD_FILE
) {
2100 if (handler_desfire_commit_transaction() != PM3_SUCCESS
) {
2101 PrintAndLogEx(WARNING
, _RED_(" Can't commit transaction -> %s"), GetErrorString(res
, &sw
));
2109 static int handler_desfire_deletefile(uint8_t file_no
) {
2113 sAPDU apdu
= {0x90, MFDES_DELETE_FILE
, 0x00, 0x00, 1, &file_no
}; // 0xDF
2115 uint32_t recvlen
= 0;
2116 int res
= send_desfire_cmd(&apdu
, false, NULL
, &recvlen
, &sw
, 0, true);
2117 if (res
!= PM3_SUCCESS
) {
2118 PrintAndLogEx(WARNING
, _RED_(" Can't delete file -> %s"), GetErrorString(res
, &sw
));
2125 static int handler_desfire_clear_record_file(uint8_t file_no
) {
2129 sAPDU apdu
= {0x90, MFDES_CLEAR_RECORD_FILE
, 0x00, 0x00, 1, &file_no
}; // 0xEB
2131 uint32_t recvlen
= 0;
2132 int res
= send_desfire_cmd(&apdu
, false, NULL
, &recvlen
, &sw
, 0, true);
2133 if (res
!= PM3_SUCCESS
) {
2134 PrintAndLogEx(WARNING
, _RED_(" Can't clear record file -> %s"), GetErrorString(res
, &sw
));
2138 res
= handler_desfire_commit_transaction();
2139 if (res
!= PM3_SUCCESS
) {
2140 PrintAndLogEx(WARNING
, _RED_(" Can't commit transaction -> %s"), GetErrorString(res
, &sw
));
2148 static int handler_desfire_create_value_file(mfdes_value_file_t
*value
) {
2149 if (value
->fileno
> 0x1F) return PM3_EINVARG
;
2151 sAPDU apdu
= {0x90, MFDES_CREATE_VALUE_FILE
, 0x00, 0x00, sizeof(mfdes_value_file_t
), (uint8_t *)value
}; // 0xCc
2154 uint32_t recvlen
= 0;
2155 int res
= send_desfire_cmd(&apdu
, false, NULL
, &recvlen
, &sw
, 0, true);
2156 if (res
!= PM3_SUCCESS
) {
2157 PrintAndLogEx(WARNING
, _RED_(" Can't create value -> %s"), GetErrorString(res
, &sw
));
2164 static int handler_desfire_create_std_file(mfdes_file_t
*file
) {
2165 if (file
->fileno
> 0x1F)
2168 sAPDU apdu
= {0x90, MFDES_CREATE_STD_DATA_FILE
, 0x00, 0x00, sizeof(mfdes_file_t
), (uint8_t *)file
}; // 0xCD
2171 uint32_t recvlen
= 0;
2172 int res
= send_desfire_cmd(&apdu
, false, NULL
, &recvlen
, &sw
, 0, true);
2173 if (res
!= PM3_SUCCESS
) {
2174 PrintAndLogEx(WARNING
, _RED_(" Can't create file -> %s"), GetErrorString(res
, &sw
));
2181 static int handler_desfire_create_linearrecordfile(mfdes_linear_t
*file
) {
2182 if (file
->fileno
> 0x1F)
2185 if (memcmp(file
->recordsize
, "\x00\x00\x00", 3) == 0) return PM3_EINVARG
;
2186 sAPDU apdu
= {0x90, MFDES_CREATE_LINEAR_RECORD_FILE
, 0x00, 0x00, sizeof(mfdes_linear_t
), (uint8_t *)file
}; // 0xC1
2189 uint32_t recvlen
= 0;
2190 int res
= send_desfire_cmd(&apdu
, false, NULL
, &recvlen
, &sw
, 0, true);
2191 if (res
!= PM3_SUCCESS
) {
2192 PrintAndLogEx(WARNING
, _RED_(" Can't create linear record file -> %s"), GetErrorString(res
, &sw
));
2199 static int handler_desfire_create_cyclicrecordfile(mfdes_linear_t
*file
) {
2200 if (memcmp(file
->recordsize
, "\x00\x00\x00", 3) == 0)
2203 if (file
->fileno
> 0x1F)
2206 sAPDU apdu
= {0x90, MFDES_CREATE_CYCLIC_RECORD_FILE
, 0x00, 0x00, sizeof(mfdes_linear_t
), (uint8_t *)file
}; // 0xC0
2209 uint32_t recvlen
= 0;
2210 int res
= send_desfire_cmd(&apdu
, false, NULL
, &recvlen
, &sw
, 0, true);
2211 if (res
!= PM3_SUCCESS
) {
2212 PrintAndLogEx(WARNING
, _RED_(" Can't create cyclic record file -> %s"), GetErrorString(res
, &sw
));
2219 static int handler_desfire_create_backup_file(mfdes_file_t
*file
) {
2220 if (file
->fileno
> 0x1F) return PM3_EINVARG
;
2222 sAPDU apdu
= {0x90, MFDES_CREATE_BACKUP_DATA_FILE
, 0x00, 0x00, sizeof(mfdes_file_t
), (uint8_t *)file
}; // 0xCB
2225 uint32_t recvlen
= 0;
2226 int res
= send_desfire_cmd(&apdu
, false, NULL
, &recvlen
, &sw
, 0, true);
2227 if (res
!= PM3_SUCCESS
) {
2228 PrintAndLogEx(WARNING
, _RED_(" Can't create backup file -> %s"), GetErrorString(res
, &sw
));
2235 static int getKeySettings(uint8_t *aid
) {
2236 if (aid
== NULL
) return PM3_EINVARG
;
2238 uint8_t num_keys
= 0;
2239 uint8_t key_setting
= 0;
2241 if (memcmp(aid
, "\x00\x00\x00", 3) == 0) {
2244 //PrintAndLogEx(INFO, "--- " _CYAN_("CMK - PICC, Card Master Key settings"));
2246 // KEY Settings - AMK
2247 mifare_des_authalgo_t algo
= MFDES_ALGO_DES
;
2248 res
= key_setting_to_algo(aid
, &key_setting
, &algo
, &num_keys
);
2250 if (res
== PM3_SUCCESS
) {
2251 desfire_print_piccmk_keysetting(key_setting
, num_keys
, algo
);
2253 PrintAndLogEx(WARNING
, _RED_(" Can't read PICC Master key settings"));
2258 // AID - APPLICATION MASTER KEYS
2259 //PrintAndLogEx(SUCCESS, "--- " _CYAN_("AMK - Application Master Key settings"));
2260 res
= handler_desfire_select_application(aid
);
2261 if (res
!= PM3_SUCCESS
) return res
;
2263 // KEY Settings - AMK
2264 mifare_des_authalgo_t algo
= MFDES_ALGO_DES
;
2265 res
= key_setting_to_algo(aid
, &key_setting
, &algo
, &num_keys
);
2266 if (res
== PM3_SUCCESS
) {
2267 desfire_print_amk_keysetting(key_setting
, num_keys
, algo
);
2269 PrintAndLogEx(WARNING
, _RED_(" Can't read Application Master key settings"));
2272 // KEY VERSION - AMK
2273 uint8_t num_version
= 0;
2274 if (handler_desfire_keyversion(0, &num_version
) == PM3_SUCCESS
) {
2275 PrintAndLogEx(INFO
, "-------------------------------------------------------------");
2276 PrintAndLogEx(INFO
, " Application keys");
2277 desfire_print_keyversion(0, num_version
);
2279 PrintAndLogEx(WARNING
, " Can't read AID master key version. Trying all keys");
2282 // From 0x01 to numOfKeys. We already got 0x00. (AMK)
2285 for (uint8_t i
= 0x01; i
< num_keys
; ++i
) {
2286 if (handler_desfire_keyversion(i
, &num_version
) == PM3_SUCCESS
) {
2287 desfire_print_keyversion(i
, num_version
);
2289 PrintAndLogEx(WARNING
, " Can't read key %d (0x%02x) version", i
, i
);
2299 static void swap32(uint8_t *data
) {
2300 if (data
== NULL
) return;
2301 uint8_t tmp
= data
[0];
2309 static void swap24(uint8_t *data
) {
2310 if (data
== NULL
) return;
2311 uint8_t tmp
= data
[0];
2316 static void swap16(uint8_t *data
) {
2317 if (data
== NULL
) return;
2318 uint8_t tmp
= data
[0];
2323 static int desfire_authenticate(int cmdAuthMode
, int cmdAuthAlgo
, uint8_t *aid
, uint8_t *key
, int cmdKeyNo
, uint8_t cmdKdfAlgo
, uint8_t kdfInputLen
, uint8_t *kdfInput
, mfdes_auth_res_t
*rpayload
) {
2324 switch (cmdAuthMode
) {
2325 case MFDES_AUTH_DES
:
2326 if (cmdAuthAlgo
!= MFDES_ALGO_DES
&& cmdAuthAlgo
!= MFDES_ALGO_3DES
) {
2327 PrintAndLogEx(NORMAL
, "Crypto algo not valid for the auth des mode");
2331 case MFDES_AUTH_ISO
:
2332 if (cmdAuthAlgo
!= MFDES_ALGO_3DES
&& cmdAuthAlgo
!= MFDES_ALGO_3K3DES
) {
2333 PrintAndLogEx(NORMAL
, "Crypto algo not valid for the auth iso mode");
2337 case MFDES_AUTH_AES
:
2338 if (cmdAuthAlgo
!= MFDES_ALGO_AES
) {
2339 PrintAndLogEx(NORMAL
, "Crypto algo not valid for the auth aes mode");
2343 case MFDES_AUTH_PICC
:
2344 if (cmdAuthAlgo
!= MFDES_AUTH_DES
) {
2345 PrintAndLogEx(NORMAL
, "Crypto algo not valid for the auth picc mode");
2350 PrintAndLogEx(WARNING
, "Wrong Auth mode (%d) -> (1=normal, 2=iso, 3=aes)", cmdAuthMode
);
2356 switch (cmdAuthAlgo
) {
2357 case MFDES_ALGO_3DES
:
2360 case MFDES_ALGO_3K3DES
:
2363 case MFDES_ALGO_AES
:
2367 cmdAuthAlgo
= MFDES_ALGO_DES
;
2372 switch (cmdKdfAlgo
) {
2373 case MFDES_KDF_ALGO_AN10922
:
2374 // TODO: 2TDEA and 3TDEA keys use an input length of 1-15 bytes
2375 if (cmdAuthAlgo
!= MFDES_ALGO_AES
) {
2376 PrintAndLogEx(FAILED
, "Crypto algo not valid for the KDF AN10922 algo.");
2379 if (kdfInputLen
< 1 || kdfInputLen
> 31) {
2380 PrintAndLogEx(FAILED
, "KDF AN10922 algo requires an input of length 1-31 bytes.");
2384 case MFDES_KDF_ALGO_GALLAGHER
:
2385 // TODO: 2TDEA and 3TDEA keys use an input length of 1-15 bytes
2386 if (cmdAuthAlgo
!= MFDES_ALGO_AES
) {
2387 PrintAndLogEx(FAILED
, "Crypto algo not valid for the KDF AN10922 algo.");
2391 // KDF input arg is ignored as it'll be generated.
2392 case MFDES_KDF_ALGO_NONE
:
2395 PrintAndLogEx(WARNING
, "KDF algo %d is not supported.", cmdKdfAlgo
);
2400 int res
= handler_desfire_select_application(aid
);
2401 if (res
!= PM3_SUCCESS
) return res
;
2403 if (memcmp(aid
, "\x00\x00\x00", 3) != 0) {
2404 uint8_t file_ids
[33] = {0};
2405 uint32_t file_ids_len
= 0;
2406 res
= handler_desfire_fileids(file_ids
, &file_ids_len
);
2407 if (res
!= PM3_SUCCESS
) return res
;
2410 mfdes_authinput_t payload
;
2411 payload
.keylen
= keylength
;
2412 memcpy(payload
.key
, key
, keylength
);
2413 payload
.mode
= cmdAuthMode
;
2414 payload
.algo
= cmdAuthAlgo
;
2415 payload
.keyno
= cmdKeyNo
;
2416 payload
.kdfAlgo
= cmdKdfAlgo
;
2417 payload
.kdfInputLen
= kdfInputLen
;
2418 memcpy(payload
.kdfInput
, kdfInput
, kdfInputLen
);
2420 int error
= handler_desfire_auth(&payload
, rpayload
);
2421 if (error
== PM3_SUCCESS
) {
2422 memcpy(¤tauth
[payload
.keyno
], &payload
, sizeof(mfdes_authinput_t
));
2428 static int CmdHF14ADesGetUID(const char *Cmd
) {
2429 CLIParserContext
*ctx
;
2430 CLIParserInit(&ctx
, "hf mfdes getuid",
2431 "Get UID from a MIFARE DESfire tag",
2434 void *argtable
[] = {
2438 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
2441 uint8_t uid
[16] = {0};
2442 int res
= handler_desfire_getuid(uid
);
2443 if (res
!= PM3_SUCCESS
) {
2445 PrintAndLogEx(ERR
, "Error on getting uid.");
2449 // This could be done better. by the crc calc checks.
2450 // Extract the Card UID length (needs rework to allow for 10 Byte UID
2451 uint8_t uidlen
= 16;
2453 // Get datalen <uid len> + <crclen> by removing padding.
2454 while ((uidlen
> 0) && (uid
[uidlen
- 1] == 0x00))
2457 if (tag
->authentication_scheme
== AS_LEGACY
)
2458 uidlen
-= 2; // 2 byte crc
2460 uidlen
-= 4; // 4 byte crc
2462 if (uidlen
<= 4) // < incase we trimmed a CRC 00 or more
2467 PrintAndLogEx(SUCCESS
, " UID: " _GREEN_("%s"), sprint_hex(uid
, uidlen
));
2471 static int CmdHF14ADesSelectApp(const char *Cmd
) {
2472 CLIParserContext
*ctx
;
2473 CLIParserInit(&ctx
, "hf mfdes selectaid",
2474 "Select Application ID",
2475 "hf mfdes selectaid -a 123456"
2478 void *argtable
[] = {
2480 arg_strx0("a", "aid", "<hex>", "App ID to select as hex bytes (3 bytes, big endian)"),
2483 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
2485 uint8_t aid
[3] = {0};
2486 CLIGetHexWithReturn(ctx
, 1, aid
, &aidlength
);
2491 if (aidlength
!= 3) {
2492 PrintAndLogEx(ERR
, "AID must have 3 bytes length");
2496 int res
= handler_desfire_select_application(aid
);
2497 if (res
!= PM3_SUCCESS
) {
2498 PrintAndLogEx(ERR
, "Error on selecting aid.");
2501 PrintAndLogEx(SUCCESS
, "Successfully selected aid.");
2506 static int CmdHF14ADesCreateApp(const char *Cmd
) {
2507 CLIParserContext
*ctx
;
2508 CLIParserInit(&ctx
, "hf mfdes createaid",
2509 "Create Application ID",
2510 "hf mfdes createaid -a 123456 -f 1111 -k 0E -l 2E --name Test"
2513 void *argtable
[] = {
2515 arg_strx0("a", "aid", "<hex>", "App ID to create as hex bytes (3 hex bytes)"),
2516 arg_strx0("f", "fid", "<hex>", "File ID to create"),
2517 arg_strx0("k", "ks1", "<hex>", "Key Setting 1 (Application Master Key Settings)"),
2518 arg_strx0("l", "ks2", "<hex>", "Key Setting 2"),
2519 arg_str0(NULL
, "name", "<ascii>", "App ISO-4 Name"),
2522 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
2523 /* KeySetting 1 (AMK Setting):
2524 0: Allow change master key
2525 1: Free Directory list access without master key
2526 0: AMK auth needed for GetFileSettings and GetKeySettings
2527 1: No AMK auth needed for GetFileIDs, GetISOFileIDs, GetFileSettings, GetKeySettings
2528 2: Free create/delete without master key
2529 0: CreateFile/DeleteFile only with AMK auth
2530 1: CreateFile/DeleteFile always
2531 3: Configuration changable
2532 0: Configuration frozen
2533 1: Configuration changable if authenticated with AMK (default)
2534 4-7: ChangeKey Access Rights
2535 0: Application master key needed (default)
2536 0x1..0xD: Auth with specific key needed to change any key
2537 0xE: Auth with the key to be changed (same KeyNo) is necessary to change a key
2538 0xF: All Keys within this application are frozen
2542 0..3: Number of keys stored within the application (max. 14 keys)
2544 5: Use of 2 byte ISO FID, 0: No, 1: Yes
2545 6..7: Crypto Method 00: DES/3DES, 01: 3K3DES, 10: AES
2547 2E = FID, DES, 14 keys
2548 6E = FID, 3K3DES, 14 keys
2549 AE = FID, AES, 14 keys
2552 uint8_t aid
[3] = {0};
2553 CLIGetHexWithReturn(ctx
, 1, aid
, &aidlength
);
2556 uint8_t fid
[2] = {0};
2557 CLIGetHexWithReturn(ctx
, 2, fid
, &fidlength
);
2560 uint8_t keysetting1
[1] = {0};
2561 CLIGetHexWithReturn(ctx
, 3, keysetting1
, &keylen1
);
2564 uint8_t keysetting2
[1] = {0};
2565 CLIGetHexWithReturn(ctx
, 4, keysetting2
, &keylen2
);
2568 uint8_t name
[16] = {0};
2569 CLIGetStrWithReturn(ctx
, 5, name
, &namelen
);
2575 if (aidlength
!= 3) {
2576 PrintAndLogEx(ERR
, "AID must have 3 bytes length");
2580 if (fidlength
!= 2 && fidlength
!= 0) {
2581 PrintAndLogEx(ERR
, "FID must have 2 bytes length");
2585 bool usefid
= (fidlength
!= 0);
2588 PrintAndLogEx(ERR
, "Keysetting1 must have 1 byte length");
2593 PrintAndLogEx(ERR
, "Keysetting2 must have 1 byte length");
2598 PrintAndLogEx(ERR
, "Name has a max. of 16 bytes length");
2601 bool usename
= true;
2602 if (namelen
== 0) usename
= false;
2604 //90 ca 00 00 0e 3cb849 09 22 10e1 d27600 00850101 00
2605 /*char name[]="Test";
2606 uint8_t aid[]={0x12,0x34,0x56};
2607 uint8_t fid[]={0x11,0x22};
2608 uint8_t keysetting1=0xEE;
2609 uint8_t keysetting2=0xEE;*/
2611 if (memcmp(aid
, "\x00\x00\x00", 3) == 0) {
2612 PrintAndLogEx(WARNING
, _RED_(" Creating root aid 000000 is forbidden"));
2617 memcpy(aidhdr
.aid
, aid
, sizeof(aid
));
2618 aidhdr
.keysetting1
= keysetting1
[0];
2619 aidhdr
.keysetting2
= keysetting2
[0];
2622 memcpy(aidhdr
.fid
, fid
, sizeof(aidhdr
.fid
));
2625 memcpy(aidhdr
.name
, name
, sizeof(aidhdr
.name
));
2627 PrintAndLogEx(INFO
, "Creating AID using:");
2628 PrintAndLogEx(INFO
, "AID %s", sprint_hex_inrow(aidhdr
.aid
, sizeof(aidhdr
.aid
)));
2629 PrintAndLogEx(INFO
, "Key set1 0x%02X", aidhdr
.keysetting1
);
2630 PrintAndLogEx(INFO
, "Key Set2 0x%02X", aidhdr
.keysetting2
);
2632 PrintAndLogEx(INFO
, "FID %s", sprint_hex_inrow(aidhdr
.fid
, sizeof(aidhdr
.fid
)));
2634 PrintAndLogEx(INFO
, "DF Name %s", aidhdr
.name
);
2637 uint8_t rootaid[3] = {0x00, 0x00, 0x00};
2638 int res = handler_desfire_select_application(rootaid);
2639 if (res != PM3_SUCCESS) {
2645 int res
= handler_desfire_createapp(&aidhdr
, usename
, usefid
);
2647 if (res
== PM3_SUCCESS
) {
2648 PrintAndLogEx(SUCCESS
, "Successfully created aid.");
2653 static int CmdHF14ADesDeleteApp(const char *Cmd
) {
2654 CLIParserContext
*ctx
;
2655 CLIParserInit(&ctx
, "hf mfdes deleteaid",
2656 "Delete Application ID",
2657 "hf mfdes deleteaid -a 123456"
2660 void *argtable
[] = {
2662 arg_strx0("a", "aid", "<hex>", "App ID to delete (3 hex bytes, big endian)"),
2665 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
2667 uint8_t aid
[3] = {0};
2668 CLIGetHexWithReturn(ctx
, 1, aid
, &aidlength
);
2671 if (aidlength
!= 3) {
2672 PrintAndLogEx(ERR
, "AID must have 3 bytes length.");
2676 if (memcmp(aid
, "\x00\x00\x00", 3) == 0) {
2677 PrintAndLogEx(WARNING
, _RED_(" Deleting root aid 000000 is forbidden."));
2681 int res
= handler_desfire_deleteapp(aid
);
2684 if (res
== PM3_SUCCESS
) {
2685 PrintAndLogEx(SUCCESS
, "Successfully deleted aid.");
2690 static int selectfile(uint8_t *aid
, uint8_t fileno
, uint8_t *cs
) {
2691 if (handler_desfire_select_application(aid
) != PM3_SUCCESS
) {
2692 PrintAndLogEx(ERR
, _RED_(" Couldn't select aid."));
2697 uint8_t filesettings
[20] = {0};
2698 uint32_t fileset_len
= 0;
2699 int res
= handler_desfire_filesettings(fileno
, filesettings
, &fileset_len
);
2700 if (res
!= PM3_SUCCESS
) return res
;
2702 if (tag
->session_key
!= NULL
) {
2704 uint8_t keyno
= tag
->authenticated_key_no
;
2705 if (currentauth
[keyno
].keyno
== keyno
) {
2707 mfdes_auth_res_t rpayload
;
2708 if (handler_desfire_auth(¤tauth
[keyno
], &rpayload
) != PM3_SUCCESS
) {
2709 PrintAndLogEx(ERR
, _RED_(" Couldn't authenticate key."));
2713 } else if (keyno
!= 0xE) {
2714 PrintAndLogEx(ERR
, _RED_(" Please authenticate first."));
2718 *cs
= filesettings
[1];
2722 static int CmdHF14ADesClearRecordFile(const char *Cmd
) {
2723 CLIParserContext
*ctx
;
2724 CLIParserInit(&ctx
, "hf mfdes clearfile",
2725 "Clear record file\nMake sure to select aid or authenticate aid before running this command.",
2726 "hf mfdes clearfile -n 01"
2729 void *argtable
[] = {
2731 arg_int0("n", "fileno", "<dec>", "File Number (0 - 31)"),
2732 arg_strx0("a", "aid", "<hex>", "App ID to select as hex bytes (3 bytes, big endian)"),
2735 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
2736 int fno
= arg_get_int_def(ctx
, 1, 0);
2738 uint8_t aid
[3] = {0};
2739 CLIGetHexWithReturn(ctx
, 2, aid
, &aidlength
);
2744 PrintAndLogEx(ERR
, "File number range is invalid (exp 0 - 31), got %d", fno
);
2748 if (aidlength
!= 3 && aidlength
!= 0) {
2749 PrintAndLogEx(ERR
, _RED_(" The given aid must have 3 bytes (big endian)."));
2751 } else if (aidlength
== 0) {
2752 if (memcmp(&tag
->selected_application
, aid
, 3) == 0) {
2753 PrintAndLogEx(ERR
, _RED_(" You need to select an aid first."));
2756 memcpy(aid
, (uint8_t *)&tag
->selected_application
, 3);
2759 if (selectfile(aid
, fno
, &cs
) != PM3_SUCCESS
) {
2760 PrintAndLogEx(ERR
, _RED_(" Error on selecting file."));
2764 int res
= handler_desfire_clear_record_file(fno
);
2765 if (res
== PM3_SUCCESS
) {
2766 PrintAndLogEx(SUCCESS
, "Successfully cleared record file.");
2768 PrintAndLogEx(ERR
, "Error on deleting file : %d", res
);
2774 static int CmdHF14ADesDeleteFile(const char *Cmd
) {
2775 CLIParserContext
*ctx
;
2776 CLIParserInit(&ctx
, "hf mfdes deletefile",
2778 "hf mfdes deletefile -n 01 -> Make sure to select aid or authenticate aid before running this command."
2781 void *argtable
[] = {
2783 arg_int0("n", "fileno", "<dec>", "File Number (0 - 31)"),
2784 arg_strx0("a", "aid", "<hex>", "App ID to select as hex bytes (3 bytes, big endian)"),
2788 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
2789 int fno
= arg_get_int_def(ctx
, 1, 0);
2792 uint8_t aid
[3] = {0};
2793 CLIGetHexWithReturn(ctx
, 2, aid
, &aidlength
);
2798 PrintAndLogEx(ERR
, "File number range is invalid (exp 0 - 31), got %d", fno
);
2802 if (aidlength
!= 3 && aidlength
!= 0) {
2803 PrintAndLogEx(ERR
, _RED_(" The given aid must have 3 bytes (big endian)."));
2805 } else if (aidlength
== 0) {
2806 if (memcmp(&tag
->selected_application
, aid
, 3) == 0) {
2807 PrintAndLogEx(ERR
, _RED_(" You need to select an aid first."));
2810 memcpy(aid
, (uint8_t *)&tag
->selected_application
, 3);
2813 if (selectfile(aid
, fno
, &cs
) != PM3_SUCCESS
) {
2814 PrintAndLogEx(ERR
, _RED_(" Error on selecting file."));
2818 int res
= handler_desfire_deletefile(fno
);
2819 if (res
== PM3_SUCCESS
) {
2820 PrintAndLogEx(SUCCESS
, "Successfully deleted file..");
2822 PrintAndLogEx(ERR
, "Error on deleting file : %d", res
);
2828 static int CmdHF14ADesCreateFile(const char *Cmd
) {
2829 CLIParserContext
*ctx
;
2830 CLIParserInit(&ctx
, "hf mfdes createfile",
2831 "Create Standard/Backup File",
2832 "hf mfdes createfile -f 0001 -n 01 -c 0 -r EEEE -s 000100 -a 123456"
2835 void *argtable
[] = {
2837 arg_int0("n", "fileno", "<dec>", "File Number (0 - 31)"),
2838 arg_strx0("f", "fileid", "<hex>", "ISO FID (2 hex bytes, big endian)"),
2839 arg_int0("c", "com", "<dec>", "Communication setting (0 = Plain, 1 = Plain + MAC, 3 = Enciphered)"),
2840 arg_strx0("r", "rights", "<hex>", "Access rights (2 hex bytes -> RW/Chg/R/W, 0x0 - 0xD Key, 0xE Free, 0xF Denied)"),
2841 arg_strx0("s", "filesize", "<hex>", "File size (3 hex bytes, big endian)"),
2842 arg_lit0("b", "backup", "Create backupfile instead of standard file"),
2843 arg_strx0("a", "aid", "<hex>", "App ID to select as hex bytes (3 bytes, big endian)"),
2847 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
2848 int fno
= arg_get_int_def(ctx
, 1, 0);
2851 uint8_t fid
[2] = {0};
2852 int res_flen
= CLIParamHexToBuf(arg_get_str(ctx
, 2), fid
, 2, &fidlength
);
2854 uint8_t comset
= arg_get_int(ctx
, 3);
2856 uint8_t ar
[2] = {0};
2857 CLIGetHexWithReturn(ctx
, 4, ar
, &arlength
);
2860 uint8_t filesize
[3] = {0};
2861 CLIGetHexWithReturn(ctx
, 5, filesize
, &fsizelen
);
2863 bool isbackup
= arg_get_lit(ctx
, 6);
2865 uint8_t aid
[3] = {0};
2866 CLIGetHexWithReturn(ctx
, 7, aid
, &aidlength
);
2874 PrintAndLogEx(ERR
, "File number range is invalid (exp 0 - 31), got %d", fno
);
2877 if (comset
!= 0 && comset
!= 1 && comset
!= 3) {
2878 PrintAndLogEx(ERR
, "Communication setting must be either 0=Plain, 1=Plain+MAC or 3=Encrypt.");
2882 if (arlength
!= 2) {
2883 PrintAndLogEx(ERR
, "Access rights must have 2 hex bytes length.");
2887 if (fsizelen
!= 3) {
2888 PrintAndLogEx(ERR
, "Filesize must have 3 hex bytes length.");
2892 if (res_flen
|| fidlength
!= 2) {
2893 PrintAndLogEx(ERR
, "ISO File id must have 2 hex bytes length.");
2898 memcpy(ft
.fid
, fid
, 2);
2899 memcpy(ft
.filesize
, filesize
, 3);
2902 memcpy(ft
.access_rights
, ar
, 2);
2904 if (aidlength
!= 3 && aidlength
!= 0) {
2905 PrintAndLogEx(ERR
, _RED_(" The given aid must have 3 bytes (big endian)."));
2908 } else if (aidlength
== 0) {
2909 if (memcmp(&tag
->selected_application
, aid
, 3) == 0) {
2910 PrintAndLogEx(ERR
, _RED_(" You need to select an aid first."));
2914 memcpy(aid
, (uint8_t *)&tag
->selected_application
, 3);
2918 // a select here seems to invalidate the current authentication with AMK and create file fails if not open access.
2919 // This will be managed when we track Authenticated or Note, so a place holder comment as a reminder.
2920 int res
= handler_desfire_select_application(aid
);
2921 if (res
!= PM3_SUCCESS
) {
2922 PrintAndLogEx(ERR
, "Couldn't select aid. Error %d", res
);
2928 res
= handler_desfire_create_backup_file(&ft
);
2930 res
= handler_desfire_create_std_file(&ft
);
2932 if (res
== PM3_SUCCESS
)
2933 PrintAndLogEx(SUCCESS
, "Successfully created standard / backup file.");
2935 PrintAndLogEx(ERR
, "Couldn't create standard / backup file. Error %d", res
);
2941 static int CmdHF14ADesGetValueData(const char *Cmd
) {
2942 CLIParserContext
*ctx
;
2943 CLIParserInit(&ctx
, "hf mfdes getvalue",
2944 "Get value from value file\n"
2945 "Make sure to select aid or authenticate aid before running this command.",
2946 "hf mfdes getvalue -n 03"
2949 void *argtable
[] = {
2951 arg_int0("n", "fileno", "<dec>", "File Number (0 - 31)"),
2952 arg_strx0("a", "aid", "<hex>", "App ID to select as hex bytes (3 bytes, big endian)"),
2955 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
2957 int fno
= arg_get_int_def(ctx
, 1, 0);
2959 uint8_t aid
[3] = {0};
2960 CLIGetHexWithReturn(ctx
, 2, aid
, &aidlength
);
2966 PrintAndLogEx(ERR
, "File number range is invalid (exp 0 - 31), got %d", fno
);
2970 mfdes_value_t value
= {
2974 if (aidlength
!= 3 && aidlength
!= 0) {
2975 PrintAndLogEx(ERR
, _RED_(" The given aid must have 3 bytes (big endian)."));
2977 } else if (aidlength
== 0) {
2978 if (memcmp(&tag
->selected_application
, aid
, 3) == 0) {
2979 PrintAndLogEx(ERR
, _RED_(" You need to select an aid first."));
2982 memcpy(aid
, (uint8_t *)&tag
->selected_application
, 3);
2985 if (selectfile(aid
, value
.fileno
, &cs
) != PM3_SUCCESS
) {
2986 PrintAndLogEx(ERR
, _RED_(" Error on selecting file."));
2991 int res
= handler_desfire_getvalue(&value
, &len
, cs
);
2992 if (res
== PM3_SUCCESS
) {
2993 PrintAndLogEx(SUCCESS
, "Successfully read value from File %u:", value
.fileno
);
2994 PrintAndLogEx(NORMAL
, "\nOffset | Data | Ascii");
2995 PrintAndLogEx(NORMAL
, "----------------------------------------------------------------------------");
2996 for (uint32_t i
= 0; i
< len
; i
+= 16) {
2997 PrintAndLogEx(NORMAL
, "%02d/0x%02X | %s| %s", i
, i
, sprint_hex(&value
.value
[i
], len
> 16 ? 16 : len
), sprint_ascii(&value
.value
[i
], len
> 16 ? 16 : len
));
3000 PrintAndLogEx(ERR
, "Couldn't read value. Error %d", res
);
3006 static int CmdHF14ADesReadData(const char *Cmd
) {
3007 CLIParserContext
*ctx
;
3008 CLIParserInit(&ctx
, "hf mfdes read",
3009 "Read data from File\n"
3010 "Make sure to select aid or authenticate aid before running this command.",
3011 "hf mfdes read -n 1 -t 0 -o 000000 -l 000000 -a 123456\n"
3012 "hf mfdes read -n 1 -t 0 --> Read all data from standard file, fileno 1"
3015 void *argtable
[] = {
3017 arg_int0("n", "fileno", "<dec>", "File Number (0 - 31)"),
3018 arg_strx0("o", "offset", "<hex>", "File Offset (3 hex bytes, big endian)"),
3019 arg_strx0("l", "length", "<hex>", "Length to read (3 hex bytes, big endian -> 000000 = Read all data)"),
3020 arg_int0("t", "type", "<dec>", "File Type (0 = Standard / Backup, 1 = Record)"),
3021 arg_strx0("a", "aid", "<hex>", "App ID to select (3 hex bytes, big endian)"),
3025 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
3026 int fno
= arg_get_int_def(ctx
, 1, 0);
3028 int offsetlength
= 0;
3029 uint8_t offset
[3] = {0};
3030 int res_offset
= CLIParamHexToBuf(arg_get_str(ctx
, 2), offset
, 3, &offsetlength
);
3033 uint8_t filesize
[3] = {0};
3034 int res_flen
= CLIParamHexToBuf(arg_get_str(ctx
, 3), filesize
, 3, &flength
);
3036 int type
= arg_get_int(ctx
, 4);
3039 uint8_t aid
[3] = {0};
3040 CLIGetHexWithReturn(ctx
, 5, aid
, &aidlength
);
3045 PrintAndLogEx(ERR
, "Invalid file type (0 = Standard/Backup, 1 = Record)");
3049 if (res_offset
|| (offsetlength
!= 3 && offsetlength
!= 0)) {
3050 PrintAndLogEx(ERR
, "Offset needs 3 hex bytes");
3055 PrintAndLogEx(ERR
, "File number range is invalid (exp 0 - 31), got %d", fno
);
3060 PrintAndLogEx(ERR
, "File size input error");
3068 memcpy(ft
.offset
, offset
, 3);
3069 memcpy(ft
.length
, filesize
, 3);
3072 uint32_t bytestoread
= (uint32_t)le24toh(filesize
);
3073 bytestoread
&= 0xFFFFFF;
3075 if (bytestoread
== 0)
3076 bytestoread
= 0xFFFFFF;
3078 if (aidlength
!= 3 && aidlength
!= 0) {
3079 PrintAndLogEx(ERR
, _RED_(" The given aid must have 3 bytes (big endian)."));
3081 } else if (aidlength
== 0) {
3082 if (memcmp(&tag
->selected_application
, aid
, 3) == 0) {
3083 PrintAndLogEx(ERR
, _RED_(" You need to select an aid first."));
3086 memcpy(aid
, (uint8_t *)&tag
->selected_application
, 3);
3089 if (selectfile(aid
, ft
.fileno
, &cs
) != PM3_SUCCESS
) {
3090 PrintAndLogEx(ERR
, _RED_(" Error on selecting file."));
3094 uint8_t *data
= (uint8_t *)calloc(bytestoread
, sizeof(uint8_t));
3095 int res
= PM3_ESOFT
;
3098 res
= handler_desfire_readdata(&ft
, type
, cs
);
3099 if (res
== PM3_SUCCESS
) {
3100 uint32_t len
= le24toh(ft
.length
);
3102 PrintAndLogEx(SUCCESS
, "Read %u bytes from file %d", ft
.fileno
, len
);
3103 PrintAndLogEx(INFO
, "Offset | Data | Ascii");
3104 PrintAndLogEx(INFO
, "----------------------------------------------------------------------------");
3106 for (uint32_t i
= 0; i
< len
; i
+= 16) {
3107 uint32_t l
= len
- i
;
3108 PrintAndLogEx(INFO
, "%3d/0x%02X | %s| %s", i
, i
, sprint_hex(&ft
.data
[i
], l
> 16 ? 16 : l
), sprint_ascii(&ft
.data
[i
], l
> 16 ? 16 : l
));
3111 PrintAndLogEx(ERR
, "Couldn't read data. Error %d", res
);
3121 static int CmdHF14ADesChangeValue(const char *Cmd
) {
3122 CLIParserContext
*ctx
;
3123 CLIParserInit(&ctx
, "hf mfdes changevalue",
3124 "Change value (credit / limitedcredit / debit)\n"
3125 "Make sure to select aid or authenticate aid before running this command.",
3126 "hf mfdes changevalue -n 03 -m 0 -d 00000001"
3129 void *argtable
[] = {
3131 arg_int0("n", "fileno", "<dec>", "File Number (0 - 31)"),
3132 arg_strx0("d", "value", "<hex>", "Value to increase (4 hex bytes, big endian)"),
3133 arg_int0("m", "mode", "<dec>", "Mode (0 = Credit, 1 = Limited Credit, 2 = Debit)"),
3134 arg_strx0("a", "aid", "<hex>", "App ID to select as hex bytes (3 bytes, big endian)"),
3138 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
3140 mfdes_value_t value
;
3141 value
.fileno
= arg_get_int_def(ctx
, 1, 0);
3144 int res_val
= CLIParamHexToBuf(arg_get_str(ctx
, 2), value
.value
, 4, &vlength
);
3146 int mode
= arg_get_int(ctx
, 3);
3148 uint8_t aid
[3] = {0};
3149 CLIGetHexWithReturn(ctx
, 4, aid
, &aidlength
);
3155 PrintAndLogEx(ERR
, "Invalid mode (0 = Credit, 1 = LimitedCredit, 2 = Debit)");
3159 if (res_val
|| vlength
!= 4) {
3160 PrintAndLogEx(ERR
, "Value needs 4 hex bytes.");
3163 swap32(value
.value
);
3165 if (value
.fileno
> 0x1F) {
3166 PrintAndLogEx(ERR
, "File number range is invalid (exp 0 - 31), got %d", value
.fileno
);
3170 if (aidlength
!= 3 && aidlength
!= 0) {
3171 PrintAndLogEx(ERR
, _RED_(" The given aid must have 3 bytes (big endian)."));
3173 } else if (aidlength
== 0) {
3174 if (memcmp(&tag
->selected_application
, aid
, 3) == 0) {
3175 PrintAndLogEx(ERR
, _RED_(" You need to select an aid first."));
3178 memcpy(aid
, (uint8_t *)&tag
->selected_application
, 3);
3181 if (selectfile(aid
, value
.fileno
, &cs
) != PM3_SUCCESS
) {
3182 PrintAndLogEx(ERR
, _RED_(" Error on selecting file."));
3187 int res
= PM3_ESOFT
;
3189 res
= handler_desfire_credit(&value
, cs
);
3190 } else if (mode
== 1) {
3191 res
= handler_desfire_limitedcredit(&value
, cs
);
3192 } else if (mode
== 2) {
3193 res
= handler_desfire_debit(&value
, cs
);
3196 if (res
== PM3_SUCCESS
) {
3197 if (handler_desfire_commit_transaction() == PM3_SUCCESS
) {
3198 PrintAndLogEx(SUCCESS
, "Successfully changed value in value file.");
3200 PrintAndLogEx(ERR
, "Couldn't commit the transaction. Error %d", res
);
3203 PrintAndLogEx(ERR
, "Couldn't change value in value file. Error %d", res
);
3209 static int CmdHF14ADesWriteData(const char *Cmd
) {
3211 CLIParserContext
*ctx
;
3212 CLIParserInit(&ctx
, "hf mfdes write",
3213 "Write data to file\n"
3214 "Make sure to select aid or authenticate aid before running this command.",
3215 "hf mfdes write -n 01 -t 0 -o 000000 -d 3132333435363738"
3218 void *argtable
[] = {
3220 arg_int0("n", "fileno", "<dec>", "File Number (0 - 31)"),
3221 arg_strx0("o", "offset", "<hex>", "File Offset (3 hex bytes, big endian), optional"),
3222 arg_strx0("d", "data", "<hex>", "Data to write (hex bytes, 256 bytes max)"),
3223 arg_int0("t", "type", "<dec>", "File Type (0 = Standard / Backup, 1 = Record)"),
3224 arg_strx0("a", "aid", "<hex>", "App ID to select as hex bytes (3 bytes, big endian)"),
3228 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
3229 int fno
= arg_get_int_def(ctx
, 1, 0);
3231 int offsetlength
= 0;
3232 uint8_t offset
[3] = {0};
3233 int res_offset
= CLIParamHexToBuf(arg_get_str(ctx
, 2), offset
, 3, &offsetlength
);
3235 // iceman: we only have a 1024 byte commandline input array. So this is pointlessly large.
3236 // with 2char hex, 512bytes could be input.
3237 // Instead large binary inputs should be BINARY files and written to card.
3239 uint8_t data
[512] = {0};
3240 int res_data
= CLIParamHexToBuf(arg_get_str(ctx
, 3), data
, 512, &dlength
);
3242 int type
= arg_get_int(ctx
, 4);
3244 uint8_t aid
[3] = {0};
3245 CLIGetHexWithReturn(ctx
, 5, aid
, &aidlength
);
3252 if (type
< 0 || type
> 1) {
3253 PrintAndLogEx(ERR
, "Unknown type (0=Standard/Backup, 1=Record)");
3257 if (res_data
|| dlength
== 0) {
3258 PrintAndLogEx(ERR
, "Data needs some hex bytes to write");
3262 if (res_offset
|| (offsetlength
!= 3 && offsetlength
!= 0)) {
3263 PrintAndLogEx(ERR
, "Offset needs 3 hex bytes");
3268 PrintAndLogEx(ERR
, "File number range is invalid (exp 0 - 31), got %d", fno
);
3274 memcpy(ft
.offset
, offset
, 3);
3275 htole24(dlength
, ft
.length
);
3278 if (aidlength
!= 3 && aidlength
!= 0) {
3279 PrintAndLogEx(ERR
, _RED_(" The given aid must have 3 bytes (big endian)."));
3281 } else if (aidlength
== 0) {
3282 if (memcmp(&tag
->selected_application
, aid
, 3) == 0) {
3283 PrintAndLogEx(ERR
, _RED_(" You need to select an aid first."));
3286 memcpy(aid
, (uint8_t *)&tag
->selected_application
, 3);
3289 if (selectfile(aid
, fno
, &cs
) != PM3_SUCCESS
) {
3290 PrintAndLogEx(ERR
, _RED_(" Error on selecting file."));
3295 int res
= PM3_ESOFT
;
3297 res
= handler_desfire_writedata(&ft
, type
, cs
);
3298 if (res
== PM3_SUCCESS
) {
3299 PrintAndLogEx(SUCCESS
, "Successfully wrote data");
3301 PrintAndLogEx(ERR
, "Couldn't read data. Error %d", res
);
3307 static int CmdHF14ADesCreateRecordFile(const char *Cmd
) {
3308 CLIParserContext
*ctx
;
3309 CLIParserInit(&ctx
, "hf mfdes createrecordfile",
3310 "Create Linear / Cyclic Record File\n"
3311 "Make sure to select aid or authenticate aid before running this command.",
3312 "hf mfdes createrecordfile -f 1122 -n 02 -c 0 -r EEEE -s 000010 -m 000005 -a 123456"
3315 void *argtable
[] = {
3317 arg_int0("n", "fileno", "<dec>", "File Number (0 - 31)"),
3318 arg_strx0("f", "fileid", "<hex>", "ISO FID (2 hex bytes, big endian)"),
3319 arg_int0("c", "com", "<dec>", "Communication setting (0 = Plain, 1 = Plain + MAC, 3 = Enciphered)"),
3320 // arg_strx0("s", "recordsize", "<hex>", "Record size (3 hex bytes, big endian, 000001 to FFFFFF)"),
3321 arg_strx0("r", "rights", "<hex>", "Access rights (2 hex bytes -> RW/Chg/R/W, 0x0 - 0xD Key, 0xE Free, 0xF Denied)"),
3322 arg_strx0("s", "size", "<hex>", "Record size (3 hex bytes, big endian, 000001 to FFFFFF)"),
3323 arg_strx0("m", "maxrecord", "<hex>", "Max. Number of Records (3 hex bytes, big endian)"),
3324 arg_lit0("b", "cyclic", "Create cyclic record file instead of linear record file"),
3325 arg_strx0("a", "aid", "<hex>", "App ID to select as hex bytes (3 bytes, big endian)"),
3329 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
3330 int fno
= arg_get_int_def(ctx
, 1, 0);
3333 uint8_t fid
[2] = {0};
3334 int res_flen
= CLIParamHexToBuf(arg_get_str(ctx
, 2), fid
, 2, &fidlength
);
3336 uint8_t comset
= arg_get_int(ctx
, 3);
3339 uint8_t ar
[2] = {0};
3340 CLIGetHexWithReturn(ctx
, 4, ar
, &arlength
);
3343 uint8_t recordsize
[3] = {0};
3344 CLIGetHexWithReturn(ctx
, 5, recordsize
, &rsizelen
);
3347 uint8_t maxnumrecords
[3] = {0};
3348 CLIGetHexWithReturn(ctx
, 6, maxnumrecords
, &msizelen
);
3350 bool cyclic
= arg_get_lit(ctx
, 7);
3353 uint8_t aid
[3] = {0};
3354 CLIGetHexWithReturn(ctx
, 8, aid
, &aidlength
);
3360 swap24(maxnumrecords
);
3362 if (msizelen
!= 3) {
3363 PrintAndLogEx(ERR
, "Maximum number of records must have 3 hex bytes length.");
3367 if (memcmp("\x00\x00\x00", maxnumrecords
, 3) == 0x0) {
3368 PrintAndLogEx(ERR
, "Maximum number of records is invalid (0x000001-0xFFFFFF).");
3373 PrintAndLogEx(ERR
, "File number range is invalid (exp 0 - 31), got %d", fno
);
3377 if (comset
!= 0 && comset
!= 1 && comset
!= 3) {
3378 PrintAndLogEx(ERR
, "Communication setting must be either 0=Plain, 1=Plain+MAC or 3=Encrypt.");
3382 if (arlength
!= 2) {
3383 PrintAndLogEx(ERR
, "Access rights must have 2 hex bytes length.");
3387 if (rsizelen
!= 3) {
3388 PrintAndLogEx(ERR
, "Recordsize must have 3 hex bytes length.");
3392 if (res_flen
|| fidlength
!= 2) {
3393 PrintAndLogEx(ERR
, "ISO File id must have 2 hex bytes length.");
3397 mfdes_linear_t ft
= {
3401 memcpy(ft
.fid
, fid
, 2);
3402 memcpy(ft
.access_rights
, ar
, 2);
3403 memcpy(ft
.recordsize
, recordsize
, 3);
3404 memcpy(ft
.maxnumrecords
, maxnumrecords
, 3);
3406 if (aidlength
!= 3 && aidlength
!= 0) {
3407 PrintAndLogEx(ERR
, _RED_(" The given aid must have 3 bytes (big endian)."));
3409 } else if (aidlength
== 0) {
3410 if (memcmp(&tag
->selected_application
, aid
, 3) == 0) {
3411 PrintAndLogEx(ERR
, _RED_(" You need to select an aid first."));
3414 memcpy(aid
, (uint8_t *)&tag
->selected_application
, 3);
3416 if (handler_desfire_select_application(aid
) != PM3_SUCCESS
) {
3417 PrintAndLogEx(ERR
, _RED_(" Error on selecting aid."));
3421 int res
= PM3_SUCCESS
;
3423 res
= handler_desfire_create_cyclicrecordfile(&ft
);
3425 res
= handler_desfire_create_linearrecordfile(&ft
);
3428 if (res
== PM3_SUCCESS
) {
3429 PrintAndLogEx(SUCCESS
, "Successfully created linear/cyclic record file.");
3431 PrintAndLogEx(ERR
, "Couldn't create linear/cyclic record file. Error %d", res
);
3437 static int CmdHF14ADesCreateValueFile(const char *Cmd
) {
3438 CLIParserContext
*ctx
;
3439 CLIParserInit(&ctx
, "hf mfdes createvaluefile",
3440 "Create Value File\n"
3441 "Make sure to select aid or authenticate aid before running this command.",
3442 "hf mfdes createvaluefile -n 03 -c 0 -r EEEE -l 00000000 -u 00002000 --val 00000001 -m 02 -a 123456\n"
3445 void *argtable
[] = {
3447 arg_int0("n", "fileno", "<dec>", "File Number (0 - 31)"),
3448 arg_int0("c", "com", "<dec>", "Communication setting (0 = Plain, 1 = Plain + MAC, 3 = Enciphered)"),
3449 arg_strx0("r", "rights", "<hex>", "Access rights (2 hex bytes -> RW/Chg/R/W, 0x0 - 0xD Key, 0xE Free, 0xF Denied)"),
3450 arg_strx0("l", "lower", "<hex>", "Lower limit (4 hex bytes, big endian)"),
3451 arg_strx0("u", "upper", "<hex>", "Upper limit (4 hex bytes, big endian)"),
3452 arg_strx0(NULL
, "val", "<hex>", "Value (4 hex bytes, big endian)"),
3453 arg_int0("m", NULL
, "<dec>", "Limited Credit enabled (Bit 0 = Limited Credit, 1 = FreeValue)"),
3454 arg_strx0("a", "aid", "<hex>", "App ID to select as hex bytes (3 bytes,big endian,optional)"),
3458 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
3459 int fno
= arg_get_int_def(ctx
, 1, 0);
3460 uint8_t comset
= arg_get_int(ctx
, 2);
3463 uint8_t ar
[2] = {0};
3464 CLIGetHexWithReturn(ctx
, 3, ar
, &arlength
);
3467 uint8_t lowerlimit
[4] = {0};
3468 CLIGetHexWithReturn(ctx
, 4, lowerlimit
, &lllen
);
3471 uint8_t upperlimit
[4] = {0};
3472 CLIGetHexWithReturn(ctx
, 5, upperlimit
, &ullen
);
3475 uint8_t value
[4] = {0};
3476 CLIGetHexWithReturn(ctx
, 6, value
, &vllen
);
3478 uint8_t limited
= arg_get_int_def(ctx
, 7, 0);
3481 uint8_t aid
[3] = {0};
3482 CLIGetHexWithReturn(ctx
, 8, aid
, &aidlength
);
3491 PrintAndLogEx(ERR
, "File number range is invalid (exp 0 - 31), got %d", fno
);
3495 if (comset
!= 0 && comset
!= 1 && comset
!= 3) {
3496 PrintAndLogEx(ERR
, "Communication setting must be either 0=Plain, 1=Plain+MAC or 3=Encrypt");
3500 if (arlength
!= 2) {
3501 PrintAndLogEx(ERR
, "Access rights must have 2 hex bytes length");
3506 PrintAndLogEx(ERR
, "Lower limit must have 4 hex bytes length");
3511 PrintAndLogEx(ERR
, "Upper limit must have 4 hex bytes length");
3516 PrintAndLogEx(ERR
, "Value must have 4 hex bytes length");
3520 mfdes_value_file_t ft
= {
3523 .limitedcreditenabled
= limited
,
3526 memcpy(ft
.access_rights
, ar
, 2);
3527 memcpy(ft
.lowerlimit
, lowerlimit
, 4);
3528 memcpy(ft
.upperlimit
, upperlimit
, 4);
3529 memcpy(ft
.value
, value
, 4);
3531 if (aidlength
!= 3 && aidlength
!= 0) {
3532 PrintAndLogEx(ERR
, _RED_(" The given aid must have 3 bytes (big endian)."));
3534 } else if (aidlength
== 0) {
3535 if (memcmp(&tag
->selected_application
, aid
, 3) == 0) {
3536 PrintAndLogEx(ERR
, _RED_(" You need to select an aid first."));
3539 memcpy(aid
, (uint8_t *)&tag
->selected_application
, 3);
3542 if (handler_desfire_select_application(aid
) != PM3_SUCCESS
) {
3543 PrintAndLogEx(ERR
, _RED_(" Error on selecting aid."));
3547 int res
= handler_desfire_create_value_file(&ft
);
3548 if (res
== PM3_SUCCESS
) {
3549 PrintAndLogEx(SUCCESS
, "Successfully created value file.");
3551 PrintAndLogEx(ERR
, "Couldn't create value file. Error %d", res
);
3557 static int CmdHF14ADesFormatPICC(const char *Cmd
) {
3558 CLIParserContext
*ctx
;
3559 CLIParserInit(&ctx
, "hf mfdes formatpicc",
3560 "Formats MIFARE DESFire PICC to factory state\n"
3561 "Make sure to authenticate picc before running this command.",
3562 "hf mfdes formatpicc"
3564 void *argtable
[] = {
3568 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
3570 sAPDU apdu
= {0x90, MFDES_FORMAT_PICC
, 0x00, 0x00, 0, NULL
}; // 0xDF
3572 uint32_t recvlen
= 0;
3573 int res
= send_desfire_cmd(&apdu
, false, NULL
, &recvlen
, &sw
, 0, true);
3574 if (res
!= PM3_SUCCESS
) {
3575 PrintAndLogEx(WARNING
, _RED_(" Can't format picc -> %s"), GetErrorString(res
, &sw
));
3577 PrintAndLogEx(INFO
, "Card successfully reset");
3583 static int CmdHF14ADesInfo(const char *Cmd
) {
3584 CLIParserContext
*ctx
;
3585 CLIParserInit(&ctx
, "hf mfdes info",
3586 "Get info from MIFARE DESfire tags",
3589 void *argtable
[] = {
3593 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
3598 mfdes_info_res_t info
;
3599 int res
= mfdes_get_info(&info
);
3600 if (res
!= PM3_SUCCESS
) {
3604 nxp_cardtype_t cardtype
= getCardType(info
.versionHW
[3], info
.versionHW
[4]);
3605 if (cardtype
== PLUS_EV1
) {
3606 PrintAndLogEx(INFO
, "Card seems to be MIFARE Plus EV1. Try " _YELLOW_("`hf mfp info`"));
3610 PrintAndLogEx(NORMAL
, "");
3611 PrintAndLogEx(INFO
, "--- " _CYAN_("Tag Information") " ---------------------------");
3612 PrintAndLogEx(INFO
, "-------------------------------------------------------------");
3613 PrintAndLogEx(SUCCESS
, " UID: " _GREEN_("%s"), sprint_hex(info
.uid
, info
.uidlen
));
3614 PrintAndLogEx(SUCCESS
, " Batch number: " _GREEN_("%s"), sprint_hex(info
.details
+ 7, 5));
3615 PrintAndLogEx(SUCCESS
, " Production date: week " _GREEN_("%02x") " / " _GREEN_("20%02x"), info
.details
[12], info
.details
[13]);
3616 PrintAndLogEx(NORMAL
, "");
3617 PrintAndLogEx(INFO
, "--- " _CYAN_("Hardware Information"));
3618 PrintAndLogEx(INFO
, " raw: %s", sprint_hex_inrow(info
.versionHW
, sizeof(info
.versionHW
)));
3620 PrintAndLogEx(INFO
, " Vendor Id: " _YELLOW_("%s"), getTagInfo(info
.versionHW
[0]));
3621 PrintAndLogEx(INFO
, " Type: " _YELLOW_("0x%02X"), info
.versionHW
[1]);
3622 PrintAndLogEx(INFO
, " Subtype: " _YELLOW_("0x%02X"), info
.versionHW
[2]);
3623 PrintAndLogEx(INFO
, " Version: %s", getVersionStr(info
.versionHW
[3], info
.versionHW
[4]));
3624 PrintAndLogEx(INFO
, " Storage size: %s", getCardSizeStr(info
.versionHW
[5]));
3625 PrintAndLogEx(INFO
, " Protocol: %s", getProtocolStr(info
.versionHW
[6], true));
3626 PrintAndLogEx(NORMAL
, "");
3627 PrintAndLogEx(INFO
, "--- " _CYAN_("Software Information"));
3628 PrintAndLogEx(INFO
, " raw: %s", sprint_hex_inrow(info
.versionSW
, sizeof(info
.versionSW
)));
3629 PrintAndLogEx(INFO
, " Vendor Id: " _YELLOW_("%s"), getTagInfo(info
.versionSW
[0]));
3630 PrintAndLogEx(INFO
, " Type: " _YELLOW_("0x%02X"), info
.versionSW
[1]);
3631 PrintAndLogEx(INFO
, " Subtype: " _YELLOW_("0x%02X"), info
.versionSW
[2]);
3632 PrintAndLogEx(INFO
, " Version: " _YELLOW_("%d.%d"), info
.versionSW
[3], info
.versionSW
[4]);
3633 PrintAndLogEx(INFO
, " Storage size: %s", getCardSizeStr(info
.versionSW
[5]));
3634 PrintAndLogEx(INFO
, " Protocol: %s", getProtocolStr(info
.versionSW
[6], false));
3636 PrintAndLogEx(NORMAL
, "");
3637 PrintAndLogEx(INFO
, "--- " _CYAN_("Card capabilities"));
3638 uint8_t major
= info
.versionSW
[3];
3639 uint8_t minor
= info
.versionSW
[4];
3640 if (major
== 0 && minor
== 4)
3641 PrintAndLogEx(INFO
, "\t0.4 - DESFire MF3ICD40, No support for APDU (only native commands)");
3642 if (major
== 0 && minor
== 5)
3643 PrintAndLogEx(INFO
, "\t0.5 - DESFire MF3ICD40, Support for wrapping commands inside ISO 7816 style APDUs");
3644 if (major
== 0 && minor
== 6)
3645 PrintAndLogEx(INFO
, "\t0.6 - DESFire MF3ICD40, Add ISO/IEC 7816 command set compatibility");
3646 if (major
== 1 && minor
== 3)
3647 PrintAndLogEx(INFO
, "\t1.3 - DESFire Ev1 MF3ICD21/41/81, Support extended APDU commands, EAL4+");
3648 if (major
== 1 && minor
== 4)
3649 PrintAndLogEx(INFO
, "\t1.4 - DESFire Ev1 MF3ICD21/41/81, EAL4+");
3650 if (major
== 2 && minor
== 0)
3651 PrintAndLogEx(INFO
, "\t2.0 - DESFire Ev2, Originality check, proximity check, EAL5");
3652 if (major
== 3 && minor
== 0)
3653 PrintAndLogEx(INFO
, "\t3.0 - DESFire Ev3, Originality check, proximity check, badass EAL6 ?");
3655 if (major
== 0 && minor
== 2)
3656 PrintAndLogEx(INFO
, "\t0.2 - DESFire Light, Originality check, ");
3658 if (cardtype
== DESFIRE_EV2
||
3659 cardtype
== DESFIRE_LIGHT
||
3660 cardtype
== DESFIRE_EV3
||
3661 cardtype
== NTAG413DNA
) {
3662 // Signature originality check
3663 uint8_t signature
[56] = {0};
3664 size_t signature_len
= 0;
3666 PrintAndLogEx(NORMAL
, "");
3667 PrintAndLogEx(INFO
, "--- " _CYAN_("Tag Signature"));
3668 if (handler_desfire_signature(signature
, &signature_len
) == PM3_SUCCESS
) {
3669 desfire_print_signature(info
.uid
, info
.uidlen
, signature
, signature_len
, cardtype
);
3671 PrintAndLogEx(WARNING
, "--- Card doesn't support GetSignature cmd");
3675 // Master Key settings
3676 uint8_t master_aid
[3] = {0x00, 0x00, 0x00};
3677 getKeySettings(master_aid
);
3679 if (cardtype
!= DESFIRE_LIGHT
) {
3680 // Free memory on card
3681 PrintAndLogEx(NORMAL
, "");
3682 PrintAndLogEx(INFO
, "--- " _CYAN_("Free memory"));
3683 uint32_t free_mem
= 0;
3684 if (handler_desfire_freemem(&free_mem
) == PM3_SUCCESS
) {
3685 desfire_print_freemem(free_mem
);
3687 PrintAndLogEx(SUCCESS
, " Card doesn't support 'free mem' cmd");
3689 PrintAndLogEx(INFO
, "-------------------------------------------------------------");
3693 iso14a_card_select_t card
;
3694 res
= SelectCard14443A_4(true, false, &card
);
3695 if (res
== PM3_SUCCESS
) {
3696 static const char STANDALONE_DESFIRE
[] = { 0x75, 0x77, 0x81, 0x02};
3697 static const char JCOP_DESFIRE
[] = { 0x75, 0xf7, 0xb1, 0x02 };
3698 static const char JCOP3_DESFIRE
[] = { 0x78, 0x77, 0x71, 0x02 };
3700 if (card
.sak
== 0x20) {
3702 if (card
.ats_len
>= 5) {
3703 if (str_startswith((const char *)card
.ats
+ 1, STANDALONE_DESFIRE
)) {
3704 PrintAndLogEx(INFO
, "Standalone DESFire");
3706 if (str_startswith((const char *)card
.ats
+ 1, JCOP_DESFIRE
)) {
3707 PrintAndLogEx(INFO
, "JCOP DESFire");
3710 if (card
.ats_len
== 4) {
3711 if (str_startswith((const char *)card
.ats
+ 1, JCOP3_DESFIRE
)) {
3712 PrintAndLogEx(INFO
, "JCOP3 DESFire");
3719 Card Master key (CMK) 0x00 AID = 00 00 00 (card level)
3720 Application Master Key (AMK) 0x00 AID != 00 00 00
3721 Application keys (APK) 0x01-0x0D
3722 Application free 0x0E
3723 Application never 0x0F
3737 static void DecodeFileType(uint8_t filetype
) {
3740 PrintAndLogEx(INFO
, " File Type: 0x%02X -> Standard Data File", filetype
);
3743 PrintAndLogEx(INFO
, " File Type: 0x%02X -> Backup Data File", filetype
);
3746 PrintAndLogEx(INFO
, " File Type: 0x%02X -> Value Files with Backup", filetype
);
3749 PrintAndLogEx(INFO
, " File Type: 0x%02X -> Linear Record Files with Backup", filetype
);
3752 PrintAndLogEx(INFO
, " File Type: 0x%02X -> Cyclic Record Files with Backup", filetype
);
3755 PrintAndLogEx(INFO
, " File Type: 0x%02X", filetype
);
3760 static void DecodeComSet(uint8_t comset
) {
3763 PrintAndLogEx(INFO
, " Com.Setting: 0x%02X -> Plain", comset
);
3766 PrintAndLogEx(INFO
, " Com.Setting: 0x%02X -> Plain + MAC", comset
);
3769 PrintAndLogEx(INFO
, " Com.Setting: 0x%02X -> Enciphered", comset
);
3772 PrintAndLogEx(INFO
, " Com.Setting: 0x%02X", comset
);
3777 static char *DecodeAccessValue(uint8_t value
) {
3779 char *car
= (char *)calloc(255, sizeof(char));
3785 strcat(car
, "(Free Access)");
3788 strcat(car
, "(Denied Access)");
3791 snprintf(car
, 255, "(Access Key: %d)", value
);
3797 static void DecodeAccessRights(uint16_t accrights
) {
3798 int change_access_rights
= accrights
& 0xF;
3799 int read_write_access
= (accrights
>> 4) & 0xF;
3800 int write_access
= (accrights
>> 8) & 0xF;
3801 int read_access
= (accrights
>> 12) & 0xF;
3802 char *car
= DecodeAccessValue(change_access_rights
);
3803 if (car
== NULL
) return;
3805 char *rwa
= DecodeAccessValue(read_write_access
);
3811 char *wa
= DecodeAccessValue(write_access
);
3818 char *ra
= DecodeAccessValue(read_access
);
3826 PrintAndLogEx(INFO
, " Access Rights: 0x%04X - Change %s - RW %s - W %s - R %s", accrights
, car
, rwa
, wa
, ra
);
3833 static int DecodeFileSettings(uint8_t *src
, int src_len
, int maclen
) {
3834 uint8_t filetype
= src
[0];
3835 uint8_t comset
= src
[1];
3837 uint16_t accrights
= (src
[3] << 8) + src
[2];
3838 if (src_len
== 1 + 1 + 2 + 3 + maclen
) {
3839 int filesize
= (src
[6] << 16) + (src
[5] << 8) + src
[4];
3840 DecodeFileType(filetype
);
3841 DecodeComSet(comset
);
3842 DecodeAccessRights(accrights
);
3843 PrintAndLogEx(INFO
, " Filesize: %d (0x%X)", filesize
, filesize
);
3845 } else if (src_len
== 1 + 1 + 2 + 4 + 4 + 4 + 1 + maclen
) {
3846 int lowerlimit
= (src
[7] << 24) + (src
[6] << 16) + (src
[5] << 8) + src
[4];
3847 int upperlimit
= (src
[11] << 24) + (src
[10] << 16) + (src
[9] << 8) + src
[8];
3848 int limitcredvalue
= (src
[15] << 24) + (src
[14] << 16) + (src
[13] << 8) + src
[12];
3849 uint8_t limited_credit_enabled
= src
[17];
3850 DecodeFileType(filetype
);
3851 DecodeComSet(comset
);
3852 DecodeAccessRights(accrights
);
3853 PrintAndLogEx(INFO
, " Lower limit: %d (0x%X) - Upper limit: %d (0x%X) - limited credit value: %d (0x%X) - limited credit enabled: %d", lowerlimit
, lowerlimit
, upperlimit
, upperlimit
, limitcredvalue
, limitcredvalue
, limited_credit_enabled
);
3855 } else if (src_len
== 1 + 1 + 2 + 3 + 3 + 3 + maclen
) {
3856 uint32_t recordsize
= (src
[6] << 16) + (src
[5] << 8) + src
[4];
3857 uint32_t maxrecords
= (src
[9] << 16) + (src
[8] << 8) + src
[7];
3858 uint32_t currentrecord
= (src
[12] << 16) + (src
[11] << 8) + src
[10];
3859 DecodeFileType(filetype
);
3860 DecodeComSet(comset
);
3861 DecodeAccessRights(accrights
);
3862 PrintAndLogEx(INFO
, " Record size: %d (0x%X) - MaxNumberRecords: %d (0x%X) - Current Number Records: %d (0x%X)", recordsize
, recordsize
, maxrecords
, maxrecords
, currentrecord
, currentrecord
);
3868 static int CmdHF14ADesDump(const char *Cmd
) {
3870 CLIParserContext
*ctx
;
3871 CLIParserInit(&ctx
, "hf mfdes dump",
3872 "Tries to dump all files on a DESFire tag",
3875 void *argtable
[] = {
3877 // arg_strx0("a", "aid", "<aid>", "Use specific AID (3 hex bytes, big endian)"),
3880 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
3883 (void)Cmd
; // Cmd is not used so far
3886 uint8_t aid
[3] = {0};
3887 uint8_t app_ids
[78] = {0};
3888 uint32_t app_ids_len
= 0;
3890 uint8_t file_ids
[33] = {0};
3891 uint32_t file_ids_len
= 0;
3893 dfname_t dfnames
[255];
3894 uint8_t dfname_count
= 0;
3896 if (handler_desfire_appids(app_ids
, &app_ids_len
) != PM3_SUCCESS
) {
3897 PrintAndLogEx(ERR
, "Can't get list of applications on tag");
3902 if (handler_desfire_dfnames(dfnames
, &dfname_count
) != PM3_SUCCESS
) {
3903 PrintAndLogEx(WARNING
, _RED_("Can't get DF Names"));
3906 PrintAndLogEx(NORMAL
, "");
3907 PrintAndLogEx(INFO
, "-- " _CYAN_("MIFARE DESFire Dump") " ----------------------");
3908 PrintAndLogEx(INFO
, "-------------------------------------------------------------");
3910 for (uint32_t i
= 0; i
< app_ids_len
; i
+= 3) {
3912 aid
[0] = app_ids
[i
];
3913 aid
[1] = app_ids
[i
+ 1];
3914 aid
[2] = app_ids
[i
+ 2];
3916 PrintAndLogEx(SUCCESS
, " AID : " _GREEN_("%02X%02X%02X"), aid
[2], aid
[1], aid
[0]);
3917 if ((aid
[2] >> 4) == 0xF) {
3918 uint16_t short_aid
= ((aid
[2] & 0xF) << 12) | (aid
[1] << 4) | (aid
[0] >> 4);
3919 PrintAndLogEx(SUCCESS
, " AID mapped to MIFARE Classic AID (MAD): " _YELLOW_("%02X"), short_aid
);
3920 PrintAndLogEx(SUCCESS
, " MAD AID Cluster 0x%02X : " _YELLOW_("%s"), short_aid
>> 8, cluster_to_text(short_aid
>> 8));
3921 MADDFDecodeAndPrint(short_aid
);
3923 AIDDFDecodeAndPrint(aid
);
3925 for (uint8_t m
= 0; m
< dfname_count
; m
++) {
3926 if (dfnames
[m
].aid
[0] == aid
[0] && dfnames
[m
].aid
[1] == aid
[1] && dfnames
[m
].aid
[2] == aid
[2]) {
3927 PrintAndLogEx(SUCCESS
, " - DF " _YELLOW_("%02X%02X") " Name : " _YELLOW_("%s"), dfnames
[m
].fid
[1], dfnames
[m
].fid
[0], dfnames
[m
].name
);
3931 uint8_t num_keys
= 0;
3932 uint8_t key_setting
= 0;
3933 int res
= handler_desfire_getkeysettings(&key_setting
, &num_keys
);
3934 if (res
!= PM3_SUCCESS
) continue;
3936 res
= handler_desfire_select_application(aid
);
3937 if (res
!= PM3_SUCCESS
) continue;
3939 res
= handler_desfire_fileids(file_ids
, &file_ids_len
);
3940 if (res
!= PM3_SUCCESS
) continue;
3942 for (int j
= (int)file_ids_len
- 1; j
>= 0; j
--) {
3943 PrintAndLogEx(SUCCESS
, "\n\n Fileid %d (0x%02x)", file_ids
[j
], file_ids
[j
]);
3945 uint8_t filesettings
[20] = {0};
3946 uint32_t fileset_len
= 0;
3948 res
= handler_desfire_filesettings(file_ids
[j
], filesettings
, &fileset_len
);
3949 if (res
!= PM3_SUCCESS
) continue;
3951 int maclen
= 0; // To be implemented
3953 if (fileset_len
== 1 + 1 + 2 + 3 + maclen
) {
3954 int filesize
= (filesettings
[6] << 16) + (filesettings
[5] << 8) + filesettings
[4];
3956 fdata
.fileno
= file_ids
[j
];
3957 memset(fdata
.offset
, 0, 3);
3958 memset(fdata
.length
, 0, 3);
3960 uint8_t *data
= (uint8_t *)calloc(filesize
, sizeof(uint8_t));
3967 res
= handler_desfire_readdata(&fdata
, MFDES_DATA_FILE
, filesettings
[1]);
3968 if (res
== PM3_SUCCESS
) {
3969 PrintAndLogEx(NORMAL
, "\nOffset | Data | Ascii");
3970 PrintAndLogEx(NORMAL
, "----------------------------------------------------------------------------");
3971 uint32_t len
= le24toh(fdata
.length
);
3972 for (uint32_t n
= 0; n
< len
; n
+= 16) {
3973 PrintAndLogEx(NORMAL
, "%02d/0x%02X | %s| %s", n
, n
, sprint_hex(&fdata
.data
[n
], len
> 16 ? 16 : len
), sprint_ascii(&fdata
.data
[n
], len
> 16 ? 16 : len
));
3976 PrintAndLogEx(ERR
, "Couldn't read value. Error %d", res
);
3977 res
= handler_desfire_select_application(aid
);
3978 if (res
!= PM3_SUCCESS
) continue;
3983 } else if (fileset_len
== 1 + 1 + 2 + 4 + 4 + 4 + 1 + maclen
) {
3984 PrintAndLogEx(NORMAL
, "\n\nValue file: 0x%0x", file_ids
[j
]);
3985 mfdes_value_t value
;
3986 value
.fileno
= file_ids
[j
];
3988 res
= handler_desfire_getvalue(&value
, &len
, filesettings
[1]);
3989 if (res
== PM3_SUCCESS
) {
3990 PrintAndLogEx(NORMAL
, "\nOffset | Value | Ascii");
3991 PrintAndLogEx(NORMAL
, "----------------------------------------------------------------------------");
3992 for (uint32_t n
= 0; n
< len
; n
+= 16) {
3993 PrintAndLogEx(NORMAL
, "%02d/0x%02X | %s| %s", n
, n
, sprint_hex(&value
.value
[n
], len
> 16 ? 16 : len
), sprint_ascii(&value
.value
[n
], len
> 16 ? 16 : len
));
3996 PrintAndLogEx(ERR
, "Couldn't read value. Error %d", res
);
3997 res
= handler_desfire_select_application(aid
);
3998 if (res
!= PM3_SUCCESS
) continue;
4001 } else if (fileset_len
== 1 + 1 + 2 + 3 + 3 + 3 + maclen
) {
4002 uint32_t maxrecords
= (filesettings
[9] << 16) + (filesettings
[8] << 8) + filesettings
[7];
4003 uint32_t filesize
= (filesettings
[6] << 16) + (filesettings
[5] << 8) + filesettings
[4];
4005 fdata
.fileno
= file_ids
[j
];
4006 memset(fdata
.length
, 0, 3);
4007 uint8_t *data
= (uint8_t *)calloc(filesize
, sizeof(uint8_t));
4014 for (uint32_t offset
= 0; offset
< maxrecords
; offset
++) {
4015 PrintAndLogEx(NORMAL
, "\n\nRecord offset: %024x", offset
);
4016 memset(data
, 0, filesize
);
4017 fdata
.offset
[0] = offset
& 0xFF;
4018 fdata
.offset
[1] = (offset
>> 8) & 0xFF;
4019 fdata
.offset
[2] = (offset
>> 16) & 0xFF;
4020 res
= handler_desfire_readdata(&fdata
, MFDES_RECORD_FILE
, filesettings
[1]);
4021 if (res
== PM3_SUCCESS
) {
4022 PrintAndLogEx(NORMAL
, "\nOffset | Data | Ascii");
4023 PrintAndLogEx(NORMAL
, "----------------------------------------------------------------------------");
4024 uint32_t len
= le24toh(fdata
.length
);
4025 for (uint32_t n
= 0; n
< len
; n
+= 16) {
4026 PrintAndLogEx(NORMAL
, "%02d/0x%02X | %s| %s", n
, n
, sprint_hex(&fdata
.data
[n
], len
> 16 ? 16 : len
), sprint_ascii(&fdata
.data
[n
], len
> 16 ? 16 : len
));
4029 res
= handler_desfire_select_application(aid
);
4030 if (res
!= PM3_SUCCESS
) continue;
4038 PrintAndLogEx(INFO
, "-------------------------------------------------------------");
4043 static int CmdHF14ADesEnumApplications(const char *Cmd
) {
4044 CLIParserContext
*ctx
;
4045 CLIParserInit(&ctx
, "hf mfdes enum",
4046 "Enumerate all AID's on MIFARE DESfire tag",
4049 void *argtable
[] = {
4053 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
4058 uint8_t aid
[3] = {0};
4059 uint8_t app_ids
[78] = {0};
4060 uint32_t app_ids_len
= 0;
4062 uint8_t file_ids
[33] = {0};
4063 uint32_t file_ids_len
= 0;
4065 dfname_t dfnames
[255];
4066 uint8_t dfname_count
= 0;
4068 if (handler_desfire_appids(app_ids
, &app_ids_len
) != PM3_SUCCESS
) {
4069 PrintAndLogEx(ERR
, "Can't get list of applications on tag");
4074 if (handler_desfire_dfnames(dfnames
, &dfname_count
) != PM3_SUCCESS
) {
4075 PrintAndLogEx(WARNING
, _RED_("Can't get DF Names"));
4078 PrintAndLogEx(NORMAL
, "");
4079 PrintAndLogEx(INFO
, "-- MIFARE DESFire Enumerate applications --------------------");
4080 PrintAndLogEx(INFO
, "-------------------------------------------------------------");
4081 PrintAndLogEx(SUCCESS
, " Tag report " _GREEN_("%d") " application%c", app_ids_len
/ 3, (app_ids_len
== 3) ? ' ' : 's');
4083 for (uint32_t i
= 0; i
< app_ids_len
; i
+= 3) {
4085 aid
[0] = app_ids
[i
];
4086 aid
[1] = app_ids
[i
+ 1];
4087 aid
[2] = app_ids
[i
+ 2];
4089 PrintAndLogEx(NORMAL
, "");
4091 if (memcmp(aid
, "\x00\x00\x00", 3) == 0) {
4093 PrintAndLogEx(INFO
, "--- " _CYAN_("CMK - PICC, Card Master Key settings"));
4095 PrintAndLogEx(SUCCESS
, "--- " _CYAN_("AMK - Application Master Key settings"));
4098 PrintAndLogEx(SUCCESS
, " AID : " _GREEN_("%02X%02X%02X"), aid
[2], aid
[1], aid
[0]);
4099 if ((aid
[2] >> 4) == 0xF) {
4100 uint16_t short_aid
= ((aid
[2] & 0xF) << 12) | (aid
[1] << 4) | (aid
[0] >> 4);
4101 PrintAndLogEx(SUCCESS
, " AID mapped to MIFARE Classic AID (MAD): " _YELLOW_("%02X"), short_aid
);
4102 PrintAndLogEx(SUCCESS
, " MAD AID Cluster 0x%02X : " _YELLOW_("%s"), short_aid
>> 8, cluster_to_text(short_aid
>> 8));
4103 MADDFDecodeAndPrint(short_aid
);
4105 AIDDFDecodeAndPrint(aid
);
4107 for (uint8_t m
= 0; m
< dfname_count
; m
++) {
4108 if (dfnames
[m
].aid
[0] == aid
[0] && dfnames
[m
].aid
[1] == aid
[1] && dfnames
[m
].aid
[2] == aid
[2]) {
4109 PrintAndLogEx(SUCCESS
, " - DF " _YELLOW_("%02X%02X") " Name : " _YELLOW_("%s"), dfnames
[m
].fid
[1], dfnames
[m
].fid
[0], dfnames
[m
].name
);
4113 int res
= getKeySettings(aid
);
4114 if (res
!= PM3_SUCCESS
) continue;
4116 res
= handler_desfire_select_application(aid
);
4117 if (res
!= PM3_SUCCESS
) continue;
4119 res
= handler_desfire_fileids(file_ids
, &file_ids_len
);
4120 if (res
!= PM3_SUCCESS
) continue;
4122 PrintAndLogEx(SUCCESS
, " Tag report " _GREEN_("%d") " file%c", file_ids_len
, (file_ids_len
== 1) ? ' ' : 's');
4123 for (int j
= (int)file_ids_len
- 1; j
>= 0; j
--) {
4124 PrintAndLogEx(SUCCESS
, " Fileid %d (0x%02x)", file_ids
[j
], file_ids
[j
]);
4126 uint8_t filesettings
[20] = {0};
4127 uint32_t fileset_len
= 0;
4128 uint32_t maclen
= 0; // To be implemented
4130 res
= handler_desfire_filesettings(file_ids
[j
], filesettings
, &fileset_len
);
4131 if (res
!= PM3_SUCCESS
) continue;
4133 if (DecodeFileSettings(filesettings
, fileset_len
, maclen
) != PM3_SUCCESS
) {
4134 PrintAndLogEx(INFO
, " Settings [%u] %s", fileset_len
, sprint_hex(filesettings
, fileset_len
));
4139 PrintAndLogEx(INFO
, "-------------------------------------------------------------");
4144 static int CmdHF14ADesBruteApps(const char *Cmd
) {
4145 CLIParserContext
*ctx
;
4146 CLIParserInit(&ctx
, "hf mfdes bruteaid",
4147 "Recover AIDs by bruteforce.\n"
4148 "WARNING: This command takes a long time",
4149 "hf mfdes bruteaid -> Search all apps\n"
4150 "hf mfdes bruteaid -s F0000F -i 16 -> Search MAD range manually");
4152 void *argtable
[] = {
4154 arg_strx0("s", "start", "<hex>", "Starting App ID as hex bytes (3 bytes, big endian)"),
4155 arg_strx0("e", "end", "<hex>", "Last App ID as hex bytes (3 bytes, big endian)"),
4156 arg_int0("i", "step", "<dec>", "Increment step when bruteforcing"),
4157 arg_lit0("m", "mad", "Only bruteforce the MAD range"),
4160 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
4161 uint8_t startAid
[3] = {0};
4162 uint8_t endAid
[3] = {0xFF, 0xFF, 0xFF};
4165 CLIGetHexWithReturn(ctx
, 1, startAid
, &startLen
);
4166 CLIGetHexWithReturn(ctx
, 2, endAid
, &endLen
);
4167 uint32_t idIncrement
= arg_get_int_def(ctx
, 3, 1);
4168 bool mad
= arg_get_lit(ctx
, 4);
4170 // TODO: We need to check the tag version, EV1 should stop after 26 apps are found
4177 uint32_t idStart
= le24toh(startAid
);
4178 uint32_t idEnd
= le24toh(endAid
);
4179 PrintAndLogEx(INFO
, "Enumerating through all AIDs manually, this will take a while!");
4180 for (uint32_t id
= idStart
; id
<= idEnd
&& id
>= idStart
; id
+= idIncrement
) {
4181 if (kbd_enter_pressed()) break;
4182 int progress
= ((id
- idStart
) * 100) / ((idEnd
- idStart
));
4183 PrintAndLogEx(INPLACE
, "Progress: %d %%, current AID: %06X", progress
, id
);
4184 uint8_t appId
[3] = {0};
4186 sAPDU apdu
= {0x90, MFDES_SELECT_APPLICATION
, 0x00, 0x00, 0x03, appId
}; //0x5a
4188 uint8_t data
[255 * 5] = {0x00};
4189 uint32_t resplen
= 0;
4190 DESFIRESendApdu(!tag
->rf_field_on
, true, apdu
, data
, sizeof(data
), &resplen
, &sw
);
4191 if (sw
== status(MFDES_S_OPERATION_OK
)) {
4192 printf("\33[2K\r"); // clear current line before printing
4193 PrintAndLogEx(SUCCESS
, "Got new APPID %06X", id
);
4196 PrintAndLogEx(SUCCESS
, "Done");
4201 static int CmdHF14ADesChangeKey(const char *Cmd
) {
4202 CLIParserContext
*ctx
;
4203 CLIParserInit(&ctx
, "hf mfdes changekey",
4204 "Change MIFARE DESFire Key.\n"
4205 "Make sure to select aid or authenticate aid before running this command.",
4206 "hf mfdes changekey -n 0 -t 1 -k 0000000000000000 -u 1 -j 0102030405060708 -> DES, keynumber 0"
4209 void *argtable
[] = {
4211 arg_int0("n", "keyno", "<dec>", "Key number used for authentification"),
4212 arg_int0("t", "algo", "<dec>", "Current key algo (1 = DES, 2 = 3DES(2K2DES), 3 = 3K3DES, 4 = AES)"),
4213 arg_str0("k", "key", "<hex>", "Current Key (HEX 8-24 bytes)"),
4214 arg_int0("u", "newalgo", "<dec>", "New key algo (1 = DES, 2 = 3DES(2K2DES), 3 = 3K3DES, 4 = AES)"),
4215 arg_str0("j", "newkey", "<hex>", "New Key (HEX 8-24 bytes)"),
4216 arg_int0("v", "aesver", "<dec>", "AES version (if AES is used)"),
4219 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
4221 uint8_t cmdKeyNo
= arg_get_int_def(ctx
, 1, 0);
4222 uint8_t cmdAuthAlgo
= arg_get_int_def(ctx
, 2, 0);
4223 uint8_t key
[24] = {0};
4225 int res_klen
= CLIParamHexToBuf(arg_get_str(ctx
, 3), key
, 24, &keylen
);
4227 uint8_t newcmdAuthAlgo
= arg_get_int_def(ctx
, 4, 0);
4228 uint8_t newkey
[24] = {0};
4230 int res_newklen
= CLIParamHexToBuf(arg_get_str(ctx
, 5), newkey
, 24, &newkeylen
);
4232 uint8_t aesversion
= arg_get_int_def(ctx
, 6, 0);
4235 //DropFieldDesfire();
4236 // NR DESC KEYLENGHT
4237 // ------------------------
4242 uint8_t keylength
= 8;
4243 if (cmdAuthAlgo
== MFDES_ALGO_AES
) {
4245 } else if (cmdAuthAlgo
== MFDES_ALGO_3DES
) {
4247 } else if (cmdAuthAlgo
== MFDES_ALGO_DES
) {
4249 } else if (cmdAuthAlgo
== MFDES_ALGO_3K3DES
) {
4253 uint8_t newkeylength
= 8;
4254 if (newcmdAuthAlgo
== MFDES_ALGO_AES
) {
4256 } else if (newcmdAuthAlgo
== MFDES_ALGO_3DES
) {
4258 } else if (newcmdAuthAlgo
== MFDES_ALGO_DES
) {
4260 } else if (newcmdAuthAlgo
== MFDES_ALGO_3K3DES
) {
4264 if (res_klen
|| (keylen
< 8) || (keylen
> 24)) {
4265 PrintAndLogEx(ERR
, "Specified key must have %d bytes length", keylen
);
4269 if (res_newklen
|| (newkeylen
< 8) || (newkeylen
> 24)) {
4270 PrintAndLogEx(ERR
, "Specified new key must have %d bytes length", newkeylen
);
4274 if (keylen
!= keylength
) {
4275 PrintAndLogEx(WARNING
, "Key must include %d hex symbols, got %d", keylength
, keylen
);
4279 if (newkeylen
!= newkeylength
) {
4280 PrintAndLogEx(WARNING
, "New key must include %d hex symbols, got %d", keylength
, newkeylen
);
4284 PrintAndLogEx(INFO
, "changing key number " _YELLOW_("0x%02x"), cmdKeyNo
);
4285 PrintAndLogEx(INFO
, "old key: %s ( %s )", sprint_hex_inrow(key
, keylen
), getEncryptionAlgoStr(cmdAuthAlgo
));
4286 PrintAndLogEx(INFO
, "new key: %s ( %s )", sprint_hex_inrow(newkey
, newkeylen
), getEncryptionAlgoStr(newcmdAuthAlgo
));
4288 int res
= mifare_desfire_change_key(cmdKeyNo
, newkey
, newcmdAuthAlgo
, key
, cmdAuthAlgo
, aesversion
);
4289 if (res
== PM3_SUCCESS
) {
4290 PrintAndLogEx(SUCCESS
, "Change key ( " _GREEN_("ok") " )");
4292 PrintAndLogEx(FAILED
, "Change key ( " _RED_("fail") " )");
4298 // MIAFRE DESFire Authentication
4301 static int CmdHF14ADesAuth(const char *Cmd
) {
4302 //DropFieldDesfire();
4303 // NR DESC KEYLENGHT
4304 // ------------------------
4309 uint8_t keylength
= 8;
4311 CLIParserContext
*ctx
;
4312 CLIParserInit(&ctx
, "hf mfdes auth",
4313 "Authenticates MIFARE DESFire using Key",
4314 "hf mfdes auth -m 3 -t 4 -a 808301 -n 0 -k 00000000000000000000000000000000 -> AES,keynumber 0, aid 0x803201\n"
4315 "hf mfdes auth -m 2 -t 2 -a 000000 -n 1 -k 00000000000000000000000000000000 -> 3DES,keynumber 1, aid 0x000000\n"
4316 "hf mfdes auth -m 1 -t 1 -a 000000 -n 2 -k 0000000000000000 -> DES,keynumber 2, aid 0x000000\n"
4317 "hf mfdes auth -m 1 -t 1 -a 000000 -n 0 -> DES, defaultkey, aid 0x000000\n"
4318 "hf mfdes auth -m 2 -t 2 -a 000000 -n 0 -> 3DES, defaultkey, aid 0x000000\n"
4319 "hf mfdes auth -m 3 -t 4 -a 000000 -n 0 -> 3K3DES, defaultkey, aid 0x000000\n"
4320 "hf mfdes auth -m 3 -t 4 -a 000000 -n 0 -> AES, defaultkey, aid 0x000000"
4323 void *argtable
[] = {
4325 arg_int0("m", "type", "<type>", "Auth type (1=normal, 2=iso, 3=aes)"),
4326 arg_int0("t", "algo", "<algo>", "Crypt algo (1=DES, 2=3DES(2K2DES), 3=3K3DES, 4=AES)"),
4327 arg_strx0("a", "aid", "<aid>", "AID used for authentification (HEX 3 bytes)"),
4328 arg_int0("n", "keyno", "<keyno>", "Key number used for authentification"),
4329 arg_str0("k", "key", "<Key>", "Key for checking (HEX 8-24 bytes)"),
4330 arg_int0("d", "kdf", "<kdf>", "Key Derivation Function (KDF) (0=None, 1=AN10922, 2=Gallagher)"),
4331 arg_str0("i", "kdfi", "<kdfi>", "KDF input (HEX 1-31 bytes)"),
4334 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
4336 uint8_t cmdAuthMode
= arg_get_int_def(ctx
, 1, 0);
4337 uint8_t cmdAuthAlgo
= arg_get_int_def(ctx
, 2, 0);
4340 uint8_t aid
[3] = {0};
4341 CLIGetHexWithReturn(ctx
, 3, aid
, &aidlength
);
4343 uint8_t cmdKeyNo
= arg_get_int_def(ctx
, 4, 0);
4345 uint8_t key
[24] = {0};
4347 CLIGetHexWithReturn(ctx
, 5, key
, &keylen
);
4349 uint8_t cmdKDFAlgo
= arg_get_int_def(ctx
, 6, 0);
4351 uint8_t kdfInput
[31] = {0};
4352 int kdfInputLen
= 0;
4353 CLIGetHexWithReturn(ctx
, 7, kdfInput
, &kdfInputLen
);
4357 if (cmdAuthAlgo
== MFDES_ALGO_AES
) {
4360 memcpy(key
, aesdefaultkeys
[0], keylen
);
4363 } else if (cmdAuthAlgo
== MFDES_ALGO_3DES
) {
4366 memcpy(key
, aesdefaultkeys
[0], keylen
);
4369 } else if (cmdAuthAlgo
== MFDES_ALGO_DES
) {
4372 memcpy(key
, desdefaultkeys
[0], keylen
);
4375 } else if (cmdAuthAlgo
== MFDES_ALGO_3K3DES
) {
4378 memcpy(key
, k3kdefaultkeys
[0], keylen
);
4383 if ((keylen
< 8) || (keylen
> 24)) {
4384 PrintAndLogEx(ERR
, "Specified key must have %d bytes length.", keylen
);
4388 if (keylen
!= keylength
) {
4389 PrintAndLogEx(WARNING
, "Key must include %d HEX symbols", keylength
);
4394 if (aidlength
!= 3) {
4395 PrintAndLogEx(WARNING
, "aid must include %d HEX symbols", 3);
4399 mfdes_auth_res_t rpayload
;
4400 int error
= desfire_authenticate(cmdAuthMode
, cmdAuthAlgo
, aid
, key
, cmdKeyNo
, cmdKDFAlgo
, kdfInputLen
, kdfInput
, &rpayload
);
4401 if (error
== PM3_SUCCESS
) {
4402 PrintAndLogEx(SUCCESS
, " Key : " _GREEN_("%s"), sprint_hex(key
, keylength
));
4403 PrintAndLogEx(SUCCESS
, " SESSION : " _GREEN_("%s"), sprint_hex(rpayload
.sessionkey
, keylength
));
4404 PrintAndLogEx(INFO
, "-------------------------------------------------------------");
4409 PrintAndLogEx(INFO
, "-------------------------------------------------------------");
4413 static void DesFill2bPattern(
4414 uint8_t deskeyList
[MAX_KEYS_LIST_LEN
][8], uint32_t *deskeyListLen
,
4415 uint8_t aeskeyList
[MAX_KEYS_LIST_LEN
][16], uint32_t *aeskeyListLen
,
4416 uint8_t k3kkeyList
[MAX_KEYS_LIST_LEN
][24], uint32_t *k3kkeyListLen
, uint32_t *startPattern
) {
4418 for (uint32_t pt
= *startPattern
; pt
< 0x10000; pt
++) {
4419 if (*deskeyListLen
!= MAX_KEYS_LIST_LEN
) {
4420 deskeyList
[*deskeyListLen
][0] = (pt
>> 8) & 0xff;
4421 deskeyList
[*deskeyListLen
][1] = pt
& 0xff;
4422 memcpy(&deskeyList
[*deskeyListLen
][2], &deskeyList
[*deskeyListLen
][0], 2);
4423 memcpy(&deskeyList
[*deskeyListLen
][4], &deskeyList
[*deskeyListLen
][0], 4);
4426 if (*aeskeyListLen
!= MAX_KEYS_LIST_LEN
) {
4427 aeskeyList
[*aeskeyListLen
][0] = (pt
>> 8) & 0xff;
4428 aeskeyList
[*aeskeyListLen
][1] = pt
& 0xff;
4429 memcpy(&aeskeyList
[*aeskeyListLen
][2], &aeskeyList
[*aeskeyListLen
][0], 2);
4430 memcpy(&aeskeyList
[*aeskeyListLen
][4], &aeskeyList
[*aeskeyListLen
][0], 4);
4431 memcpy(&aeskeyList
[*aeskeyListLen
][8], &aeskeyList
[*aeskeyListLen
][0], 8);
4434 if (*k3kkeyListLen
!= MAX_KEYS_LIST_LEN
) {
4435 k3kkeyList
[*k3kkeyListLen
][0] = (pt
>> 8) & 0xff;
4436 k3kkeyList
[*k3kkeyListLen
][1] = pt
& 0xff;
4437 memcpy(&k3kkeyList
[*k3kkeyListLen
][2], &k3kkeyList
[*k3kkeyListLen
][0], 2);
4438 memcpy(&k3kkeyList
[*k3kkeyListLen
][4], &k3kkeyList
[*k3kkeyListLen
][0], 4);
4439 memcpy(&k3kkeyList
[*k3kkeyListLen
][8], &k3kkeyList
[*k3kkeyListLen
][0], 8);
4440 memcpy(&k3kkeyList
[*k3kkeyListLen
][16], &k3kkeyList
[*k3kkeyListLen
][0], 4);
4445 if ((*deskeyListLen
== MAX_KEYS_LIST_LEN
) &&
4446 (*aeskeyListLen
== MAX_KEYS_LIST_LEN
) &&
4447 (*k3kkeyListLen
== MAX_KEYS_LIST_LEN
)) {
4454 static int AuthCheckDesfire(uint8_t *aid
,
4455 uint8_t deskeyList
[MAX_KEYS_LIST_LEN
][8], uint32_t deskeyListLen
,
4456 uint8_t aeskeyList
[MAX_KEYS_LIST_LEN
][16], uint32_t aeskeyListLen
,
4457 uint8_t k3kkeyList
[MAX_KEYS_LIST_LEN
][24], uint32_t k3kkeyListLen
,
4458 uint8_t cmdKdfAlgo
, uint8_t kdfInputLen
, uint8_t *kdfInput
,
4459 uint8_t foundKeys
[4][0xE][24 + 1], bool *result
) {
4461 uint32_t curaid
= (aid
[0] & 0xFF) + ((aid
[1] & 0xFF) << 8) + ((aid
[2] & 0xFF) << 16);
4463 int res
= handler_desfire_select_application(aid
);
4464 if (res
!= PM3_SUCCESS
) {
4465 PrintAndLogEx(ERR
, "AID 0x%06X does not exist.", curaid
);
4469 int usedkeys
[0xF] = {0};
4473 bool k3kdes
= false;
4475 uint8_t num_keys
= 0;
4476 uint8_t key_setting
= 0;
4477 res
= handler_desfire_getkeysettings(&key_setting
, &num_keys
);
4478 if (res
!= PM3_SUCCESS
) {
4479 PrintAndLogEx(ERR
, "Could not get key settings");
4483 if (memcmp(aid
, "\x00\x00\x00", 3) != 0) {
4484 uint8_t file_ids
[33] = {0};
4485 uint32_t file_ids_len
= 0;
4487 if (handler_desfire_fileids(file_ids
, &file_ids_len
) == PM3_SUCCESS
) {
4489 for (int j
= (int)file_ids_len
- 1; j
>= 0; j
--) {
4491 uint8_t filesettings
[20] = {0};
4492 uint32_t fileset_len
= 0;
4494 res
= handler_desfire_filesettings(file_ids
[j
], filesettings
, &fileset_len
);
4495 if (res
== PM3_SUCCESS
) {
4497 uint16_t accrights
= (filesettings
[3] << 8) + filesettings
[2];
4498 uint8_t change_access_rights
= accrights
& 0xF;
4499 uint8_t read_write_access
= (accrights
>> 4) & 0xF;
4500 uint8_t write_access
= (accrights
>> 8) & 0xF;
4501 uint8_t read_access
= (accrights
>> 12) & 0xF;
4503 if (change_access_rights
== 0xE) change_access_rights
= 0x0;
4504 if (read_write_access
== 0xE) read_write_access
= 0x0;
4505 if (write_access
== 0xE) write_access
= 0x0;
4506 if (read_access
== 0xE) read_access
= 0x0;
4508 usedkeys
[change_access_rights
] = 1;
4509 usedkeys
[read_write_access
] = 1;
4510 usedkeys
[write_access
] = 1;
4511 usedkeys
[read_access
] = 1;
4513 if (res
== PM3_SUCCESS
) {
4514 switch (num_keys
>> 6) {
4532 if (file_ids_len
== 0) {
4533 for (uint8_t z
= 0; z
< 0xE; z
++) {
4547 bool badlen
= false;
4551 for (uint8_t keyno
= 0; keyno
< 0xE; keyno
++) {
4553 if (usedkeys
[keyno
] == 1 && foundKeys
[0][keyno
][0] == 0) {
4554 for (uint32_t curkey
= 0; curkey
< deskeyListLen
; curkey
++) {
4555 mfdes_auth_res_t rpayload
;
4556 error
= desfire_authenticate(MFDES_AUTH_DES
, MFDES_ALGO_DES
, aid
, deskeyList
[curkey
], keyno
, 0, 0, NULL
, &rpayload
);
4557 if (error
== PM3_SUCCESS
) {
4558 PrintAndLogEx(SUCCESS
, "AID 0x%06X, Found DES Key %u : " _GREEN_("%s"), curaid
, keyno
, sprint_hex(deskeyList
[curkey
], 8));
4559 foundKeys
[0][keyno
][0] = 0x01;
4561 memcpy(&foundKeys
[0][keyno
][1], deskeyList
[curkey
], 8);
4563 } else if (error
< 7) {
4566 res
= handler_desfire_select_application(aid
);
4567 if (res
!= PM3_SUCCESS
) {
4573 if (badlen
== true) {
4583 for (uint8_t keyno
= 0; keyno
< 0xE; keyno
++) {
4585 if (usedkeys
[keyno
] == 1 && foundKeys
[1][keyno
][0] == 0) {
4586 for (uint32_t curkey
= 0; curkey
< aeskeyListLen
; curkey
++) {
4587 mfdes_auth_res_t rpayload
;
4588 error
= desfire_authenticate(MFDES_AUTH_DES
, MFDES_ALGO_3DES
, aid
, aeskeyList
[curkey
], keyno
, 0, 0, NULL
, &rpayload
);
4589 if (error
== PM3_SUCCESS
) {
4590 PrintAndLogEx(SUCCESS
, "AID 0x%06X, Found 3DES Key %u : " _GREEN_("%s"), curaid
, keyno
, sprint_hex(aeskeyList
[curkey
], 16));
4591 foundKeys
[1][keyno
][0] = 0x01;
4593 memcpy(&foundKeys
[1][keyno
][1], aeskeyList
[curkey
], 16);
4595 } else if (error
< 7) {
4598 res
= handler_desfire_select_application(aid
);
4599 if (res
!= PM3_SUCCESS
) {
4605 if (badlen
== true) {
4615 for (uint8_t keyno
= 0; keyno
< 0xE; keyno
++) {
4617 if (usedkeys
[keyno
] == 1 && foundKeys
[2][keyno
][0] == 0) {
4618 for (uint32_t curkey
= 0; curkey
< aeskeyListLen
; curkey
++) {
4619 mfdes_auth_res_t rpayload
;
4620 error
= desfire_authenticate(MFDES_AUTH_AES
, MFDES_ALGO_AES
, aid
, aeskeyList
[curkey
], keyno
, cmdKdfAlgo
, kdfInputLen
, kdfInput
, &rpayload
);
4621 if (error
== PM3_SUCCESS
) {
4622 PrintAndLogEx(SUCCESS
, "AID 0x%06X, Found AES Key %u : " _GREEN_("%s"), curaid
, keyno
, sprint_hex(aeskeyList
[curkey
], 16));
4623 foundKeys
[2][keyno
][0] = 0x01;
4625 memcpy(&foundKeys
[2][keyno
][1], aeskeyList
[curkey
], 16);
4627 } else if (error
< 7) {
4630 res
= handler_desfire_select_application(aid
);
4631 if (res
!= PM3_SUCCESS
) {
4637 if (badlen
== true) {
4647 for (uint8_t keyno
= 0; keyno
< 0xE; keyno
++) {
4649 if (usedkeys
[keyno
] == 1 && foundKeys
[3][keyno
][0] == 0) {
4650 for (uint32_t curkey
= 0; curkey
< k3kkeyListLen
; curkey
++) {
4651 mfdes_auth_res_t rpayload
;
4652 error
= desfire_authenticate(MFDES_AUTH_ISO
, MFDES_ALGO_3K3DES
, aid
, k3kkeyList
[curkey
], keyno
, 0, 0, NULL
, &rpayload
);
4653 if (error
== PM3_SUCCESS
) {
4654 PrintAndLogEx(SUCCESS
, "AID 0x%06X, Found 3K3 Key %u : " _GREEN_("%s"), curaid
, keyno
, sprint_hex(k3kkeyList
[curkey
], 24));
4655 foundKeys
[3][keyno
][0] = 0x01;
4657 memcpy(&foundKeys
[3][keyno
][1], k3kkeyList
[curkey
], 16);
4659 } else if (error
< 7) {
4662 res
= handler_desfire_select_application(aid
);
4663 if (res
!= PM3_SUCCESS
) {
4670 if (badlen
== true) {
4680 static int CmdHF14aDesChk(const char *Cmd
) {
4682 uint8_t deskeyList
[MAX_KEYS_LIST_LEN
][8] = {{0}};
4683 uint8_t aeskeyList
[MAX_KEYS_LIST_LEN
][16] = {{0}};
4684 uint8_t k3kkeyList
[MAX_KEYS_LIST_LEN
][MAX_KEY_LEN
] = {{0}};
4685 uint32_t deskeyListLen
= 0;
4686 uint32_t aeskeyListLen
= 0;
4687 uint32_t k3kkeyListLen
= 0;
4688 uint8_t foundKeys
[4][0xE][24 + 1] = {{{0}}};
4690 CLIParserContext
*ctx
;
4691 CLIParserInit(&ctx
, "hf mfdes chk",
4692 "Checks keys with MIFARE DESFire card.",
4693 "hf mfdes chk -a 123456 -k 000102030405060708090a0b0c0d0e0f -> check key on aid 0x123456\n"
4694 "hf mfdes chk -d mfdes_default_keys -> check keys from dictionary against all existing aid on card\n"
4695 "hf mfdes chk -d mfdes_default_keys -a 123456 -> check keys from dictionary against aid 0x123456\n"
4696 "hf mfdes chk -a 123456 --pattern1b -j keys -> check all 1-byte keys pattern on aid 0x123456 and save found keys to json\n"
4697 "hf mfdes chk -a 123456 --pattern2b --startp2b FA00 -> check all 2-byte keys pattern on aid 0x123456. Start from key FA00FA00...FA00");
4699 void *argtable
[] = {
4701 arg_strx0("a", "aid", "<aid>", "Use specific AID (3 hex bytes, big endian)"),
4702 arg_str0("k", "key", "<Key>", "Key for checking (HEX 16 bytes)"),
4703 arg_str0("d", "dict", "<file>", "File with keys dictionary"),
4704 arg_lit0(NULL
, "pattern1b", "Check all 1-byte combinations of key (0000...0000, 0101...0101, 0202...0202, ...)"),
4705 arg_lit0(NULL
, "pattern2b", "Check all 2-byte combinations of key (0000...0000, 0001...0001, 0002...0002, ...)"),
4706 arg_str0(NULL
, "startp2b", "<Pattern>", "Start key (2-byte HEX) for 2-byte search (use with `--pattern2b`)"),
4707 arg_str0("j", "json", "<file>", "Json file to save keys"),
4708 arg_lit0("v", "verbose", "Verbose mode."),
4709 arg_int0("f", "kdf", "<kdf>", "Key Derivation Function (KDF) (0=None, 1=AN10922, 2=Gallagher)"),
4710 arg_str0("i", "kdfi", "<kdfi>", "KDF input (HEX 1-31 bytes)"),
4713 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
4716 uint8_t aid
[3] = {0};
4717 CLIGetHexWithReturn(ctx
, 1, aid
, &aidlength
);
4719 uint8_t vkey
[16] = {0};
4721 CLIGetHexWithReturn(ctx
, 2, vkey
, &vkeylen
);
4725 memcpy(&deskeyList
[deskeyListLen
], vkey
, 8);
4727 } else if (vkeylen
== 16) {
4728 memcpy(&aeskeyList
[aeskeyListLen
], vkey
, 16);
4730 } else if (vkeylen
== 24) {
4731 memcpy(&k3kkeyList
[k3kkeyListLen
], vkey
, 16);
4734 PrintAndLogEx(ERR
, "Specified key must have 8, 16 or 24 bytes length.");
4740 uint8_t dict_filename
[FILE_PATH_SIZE
+ 2] = {0};
4741 int dict_filenamelen
= 0;
4742 if (CLIParamStrToBuf(arg_get_str(ctx
, 3), dict_filename
, FILE_PATH_SIZE
, &dict_filenamelen
)) {
4743 PrintAndLogEx(FAILED
, "File name too long or invalid.");
4748 bool pattern1b
= arg_get_lit(ctx
, 4);
4749 bool pattern2b
= arg_get_lit(ctx
, 5);
4751 if (pattern1b
&& pattern2b
) {
4752 PrintAndLogEx(ERR
, "Pattern search mode must be 2-byte or 1-byte only.");
4757 if (dict_filenamelen
&& (pattern1b
|| pattern2b
)) {
4758 PrintAndLogEx(ERR
, "Pattern search mode and dictionary mode can't be used in one command.");
4763 uint32_t startPattern
= 0x0000;
4764 uint8_t vpattern
[2];
4765 int vpatternlen
= 0;
4766 CLIGetHexWithReturn(ctx
, 6, vpattern
, &vpatternlen
);
4767 if (vpatternlen
> 0) {
4768 if (vpatternlen
<= 2) {
4769 startPattern
= (vpattern
[0] << 8) + vpattern
[1];
4771 PrintAndLogEx(ERR
, "Pattern must be 2-byte length.");
4776 PrintAndLogEx(WARNING
, "Pattern entered, but search mode not is 2-byte search.");
4779 uint8_t jsonname
[250] = {0};
4780 int jsonnamelen
= 0;
4781 if (CLIParamStrToBuf(arg_get_str(ctx
, 7), jsonname
, sizeof(jsonname
), &jsonnamelen
)) {
4782 PrintAndLogEx(ERR
, "Invalid json name.");
4786 jsonname
[jsonnamelen
] = 0;
4788 bool verbose
= arg_get_lit(ctx
, 8);
4791 uint8_t kdfInput
[31] = {0};
4792 int kdfInputLen
= 0;
4793 uint8_t cmdKDFAlgo
= arg_get_int_def(ctx
, 9, 0);
4794 CLIGetHexWithReturn(ctx
, 10, kdfInput
, &kdfInputLen
);
4798 // 1-byte pattern search mode
4800 for (uint32_t i
= 0; i
< 0x100; i
++)
4801 memset(aeskeyList
[i
], i
, 16);
4802 for (uint32_t i
= 0; i
< 0x100; i
++)
4803 memset(deskeyList
[i
], i
, 8);
4804 for (uint32_t i
= 0; i
< 0x100; i
++)
4805 memset(k3kkeyList
[i
], i
, 24);
4806 aeskeyListLen
= 0x100;
4807 deskeyListLen
= 0x100;
4808 k3kkeyListLen
= 0x100;
4811 // 2-byte pattern search mode
4813 DesFill2bPattern(deskeyList
, &deskeyListLen
, aeskeyList
, &aeskeyListLen
, k3kkeyList
, &k3kkeyListLen
, &startPattern
);
4817 size_t endFilePosition
= 0;
4818 if (dict_filenamelen
) {
4820 res
= loadFileDICTIONARYEx((char *)dict_filename
, deskeyList
, sizeof(deskeyList
), NULL
, 8, &deskeyListLen
, 0, &endFilePosition
, true);
4821 if (res
== PM3_SUCCESS
&& endFilePosition
)
4822 PrintAndLogEx(SUCCESS
, "First part of des dictionary successfully loaded.");
4824 endFilePosition
= 0;
4825 res
= loadFileDICTIONARYEx((char *)dict_filename
, aeskeyList
, sizeof(aeskeyList
), NULL
, 16, &aeskeyListLen
, 0, &endFilePosition
, true);
4826 if (res
== PM3_SUCCESS
&& endFilePosition
)
4827 PrintAndLogEx(SUCCESS
, "First part of aes dictionary successfully loaded.");
4829 endFilePosition
= 0;
4830 res
= loadFileDICTIONARYEx((char *)dict_filename
, k3kkeyList
, sizeof(k3kkeyList
), NULL
, 24, &k3kkeyListLen
, 0, &endFilePosition
, true);
4831 if (res
== PM3_SUCCESS
&& endFilePosition
)
4832 PrintAndLogEx(SUCCESS
, "First part of k3kdes dictionary successfully loaded.");
4834 endFilePosition
= 0;
4837 if (aeskeyListLen
== 0 && deskeyListLen
== 0 && k3kkeyListLen
== 0) {
4838 PrintAndLogEx(ERR
, "No keys provided. Nothing to check.");
4842 if (aeskeyListLen
!= 0) {
4843 PrintAndLogEx(INFO
, "Loaded " _YELLOW_("%"PRIu32
) " aes keys", aeskeyListLen
);
4846 if (deskeyListLen
!= 0) {
4847 PrintAndLogEx(INFO
, "Loaded " _YELLOW_("%"PRIu32
) " des keys", deskeyListLen
);
4850 if (k3kkeyListLen
!= 0) {
4851 PrintAndLogEx(INFO
, "Loaded " _YELLOW_("%"PRIu32
) " k3kdes keys", k3kkeyListLen
);
4854 if (verbose
== false)
4855 PrintAndLogEx(INFO
, "Search keys:");
4857 bool result
= false;
4858 uint8_t app_ids
[78] = {0};
4859 uint32_t app_ids_len
= 0;
4861 clearCommandBuffer();
4863 mfdes_info_res_t info
= {0};
4864 res
= mfdes_get_info(&info
);
4865 if (res
!= PM3_SUCCESS
) {
4868 // TODO: Store this UID someowhere not global
4869 memcpy(tag
->info
.uid
, info
.uid
, info
.uidlen
);
4870 tag
->info
.uidlen
= info
.uidlen
;
4872 if (handler_desfire_appids(app_ids
, &app_ids_len
) != PM3_SUCCESS
) {
4873 PrintAndLogEx(ERR
, "Can't get list of applications on tag");
4878 if (aidlength
!= 0) {
4879 memcpy(&app_ids
[0], aid
, 3);
4883 for (uint32_t x
= 0; x
< app_ids_len
/ 3; x
++) {
4885 uint32_t curaid
= (app_ids
[x
* 3] & 0xFF) + ((app_ids
[(x
* 3) + 1] & 0xFF) << 8) + ((app_ids
[(x
* 3) + 2] & 0xFF) << 16);
4886 PrintAndLogEx(ERR
, "Checking aid 0x%06X...", curaid
);
4888 res
= AuthCheckDesfire(&app_ids
[x
* 3], deskeyList
, deskeyListLen
, aeskeyList
, aeskeyListLen
, k3kkeyList
, k3kkeyListLen
, cmdKDFAlgo
, kdfInputLen
, kdfInput
, foundKeys
, &result
);
4889 if (res
== PM3_EOPABORTED
) {
4893 if (pattern2b
&& startPattern
< 0x10000) {
4894 if (verbose
== false)
4895 PrintAndLogEx(NORMAL
, "p" NOLF
);
4900 DesFill2bPattern(deskeyList
, &deskeyListLen
, aeskeyList
, &aeskeyListLen
, k3kkeyList
, &k3kkeyListLen
, &startPattern
);
4904 if (dict_filenamelen
) {
4905 if (verbose
== false)
4906 PrintAndLogEx(NORMAL
, "d" NOLF
);
4908 uint32_t keycnt
= 0;
4909 res
= loadFileDICTIONARYEx((char *)dict_filename
, deskeyList
, sizeof(deskeyList
), NULL
, 16, &keycnt
, endFilePosition
, &endFilePosition
, false);
4910 if (res
== PM3_SUCCESS
&& endFilePosition
)
4911 deskeyListLen
= keycnt
;
4914 res
= loadFileDICTIONARYEx((char *)dict_filename
, aeskeyList
, sizeof(aeskeyList
), NULL
, 16, &keycnt
, endFilePosition
, &endFilePosition
, false);
4915 if (res
== PM3_SUCCESS
&& endFilePosition
)
4916 aeskeyListLen
= keycnt
;
4919 res
= loadFileDICTIONARYEx((char *)dict_filename
, k3kkeyList
, sizeof(k3kkeyList
), NULL
, 16, &keycnt
, endFilePosition
, &endFilePosition
, false);
4920 if (res
== PM3_SUCCESS
&& endFilePosition
)
4921 k3kkeyListLen
= keycnt
;
4926 if (verbose
== false)
4927 PrintAndLogEx(NORMAL
, "");
4929 // save keys to json
4930 if ((jsonnamelen
> 0) && result
) {
4931 // MIFARE DESFire info
4932 SendCommandMIX(CMD_HF_ISO14443A_READER
, ISO14A_CONNECT
, 0, 0, NULL
, 0);
4934 PacketResponseNG resp
;
4935 WaitForResponse(CMD_ACK
, &resp
);
4937 iso14a_card_select_t card
;
4938 memcpy(&card
, (iso14a_card_select_t
*)resp
.data
.asBytes
, sizeof(iso14a_card_select_t
));
4940 uint64_t select_status
= resp
.oldarg
[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision
4942 uint8_t data
[10 + 1 + 2 + 1 + 256 + (4 * 0xE * (24 + 1))] = {0};
4944 if (select_status
== 1 || select_status
== 2) {
4945 memcpy(data
, card
.uid
, card
.uidlen
);
4946 data
[10] = card
.sak
;
4947 data
[11] = card
.atqa
[1];
4948 data
[12] = card
.atqa
[0];
4949 atslen
= card
.ats_len
;
4951 memcpy(&data
[14], card
.ats
, atslen
);
4954 // length: UID(10b)+SAK(1b)+ATQA(2b)+ATSlen(1b)+ATS(atslen)+foundKeys[2][64][AES_KEY_LEN + 1]
4955 memcpy(&data
[14 + atslen
], foundKeys
, 4 * 0xE * (24 + 1));
4956 saveFileJSON((char *)jsonname
, jsfMfDesfireKeys
, data
, 0xE, NULL
);
4962 static int CmdHF14ADesList(const char *Cmd
) {
4963 return CmdTraceListAlias(Cmd
, "hf mfdes", "des");
4967 static int CmdHF14aDesNDEFRead(const char *Cmd) {
4970 CLIParserContext *ctx;
4971 CLIParserInit(&ctx, "hf mfdes ndefread",
4972 "Prints NFC Data Exchange Format (NDEF)",
4973 "hf mfdes ndefread -> shows NDEF data\n"
4974 "hf mfdes ndefread -v -> shows NDEF parsed and raw data\n"
4975 "hf mfdes ndefread -a e103 -k d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7 -> shows NDEF data with custom AID and key");
4977 void *argtable[] = {
4979 arg_litn("v", "verbose", 0, 2, "show technical data"),
4980 arg_str0(NULL, "aid", "<aid>", "replace default aid for NDEF"),
4981 arg_str0("k", "key", "<key>", "replace default key for NDEF"),
4984 CLIExecWithReturn(ctx, Cmd, argtable, true);
4986 bool verbose = arg_get_lit(ctx, 1);
4987 bool verbose2 = arg_get_lit(ctx, 1) > 1;
4988 uint8_t aid[2] = {0};
4990 CLIGetHexWithReturn(ctx, 2, aid, &aidlen);
4991 uint8_t key[16] = {0};
4993 CLIGetHexWithReturn(ctx, 3, key, &keylen);
4997 uint32_t ndefAID = 0xEEEE10;
4999 ndefAID = (aid[0] << 16) | (aid[1] << 8) | aid[2];
5002 // set default NDEF key
5003 uint8_t ndefkey[16] = {0};
5004 memcpy(ndefkey, g_mifarep_ndef_key, 16);
5006 // user supplied key
5008 memcpy(ndefkey, key, 16);
5011 int file_ids_len = 0;
5013 for (int j = (int)file_ids_len - 1; j >= 0; j--) {
5014 PrintAndLogEx(SUCCESS, "\n\n Fileid %d (0x%02x)", file_ids[j], file_ids[j]);
5016 uint8_t filesettings[20] = {0};
5017 uint32_t fileset_len = 0;
5019 int res = handler_desfire_filesettings(file_ids[j], filesettings, &fileset_len);
5020 if (res != PM3_SUCCESS) continue;
5022 int maclen = 0; // To be implemented
5024 if (fileset_len == 1 + 1 + 2 + 3 + maclen) {
5025 int filesize = (filesettings[6] << 16) + (filesettings[5] << 8) + filesettings[4];
5027 fdata.fileno = file_ids[j];
5028 memset(fdata.offset, 0, 3);
5029 memset(fdata.length, 0, 3);
5031 uint8_t *data = (uint8_t *)calloc(filesize, sizeof(uint8_t));
5038 res = handler_desfire_readdata(&fdata, MFDES_DATA_FILE, filesettings[1]);
5039 if (res == PM3_SUCCESS) {
5040 uint32_t len = le24toh(fdata.length);
5041 NDEFDecodeAndPrint(data, datalen, verbose);
5044 PrintAndLogEx(ERR, "Couldn't read value. Error %d", res);
5045 res = handler_desfire_select_application(aid);
5046 if (res != PM3_SUCCESS) continue;
5054 PrintAndLogEx(ERR, "no NDEF data");
5059 PrintAndLogEx(NORMAL, "");
5060 PrintAndLogEx(INFO, "--- " _CYAN_("DESFire NDEF raw") " ----------------");
5061 print_buffer(data, datalen, 1);
5064 PrintAndLogEx(HINT, "Try " _YELLOW_("`hf mfdes ndefread -vv`") " for more details");
5069 static int CmdHF14aDesMAD(const char *Cmd) {
5072 CLIParserContext *ctx;
5073 CLIParserInit(&ctx, "hf mfdes mad",
5074 "Prints MIFARE Application directory (MAD)",
5075 "hf mfdes mad -> shows MAD data\n"
5076 "hf mfdes mad -v -> shows MAD parsed and raw data\n"
5077 "hf mfdes mad -a e103 -k d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7 -> shows MAD data with custom AID and key");
5079 void *argtable[] = {
5081 arg_litn("v", "verbose", 0, 2, "show technical data"),
5082 arg_str0(NULL, "aid", "<aid>", "replace default aid for MAD"),
5083 arg_str0("k", "key", "<key>", "replace default key for MAD"),
5086 CLIExecWithReturn(ctx, Cmd, argtable, true);
5090 PrintAndLogEx(HINT, "Try " _YELLOW_("`hf mfdes mad -v`") " for more details");
5095 /*static int CmdTest(const char *Cmd) {
5096 (void)Cmd; // Cmd is not used so far
5097 uint8_t IV[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
5098 uint8_t key[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
5100 uint8_t encRndB[8] = {0x1A, 0xBE, 0x10, 0x8D, 0x09, 0xE0, 0x18, 0x13};
5101 uint8_t RndB[8] = {0};
5102 uint8_t RndA[8] = {0x6E, 0x6A, 0xEB, 0x86, 0x6E, 0x6A, 0xEB, 0x86};
5103 tdes_nxp_receive(encRndB, RndB, 8, key, IV, 2);
5104 uint8_t rotRndB[8] = {0};
5105 memcpy(rotRndB, RndB, 8);
5107 uint8_t tmp[16] = {0x00};
5108 uint8_t both[16] = {0x00};
5109 memcpy(tmp, RndA, 8);
5110 memcpy(tmp + 8, rotRndB, 8);
5111 PrintAndLogEx(INFO, "3keyenc: %s", sprint_hex(tmp, 16));
5112 PrintAndLogEx(SUCCESS, " Res : " _GREEN_("%s"), sprint_hex(IV, 8));
5113 tdes_nxp_send(tmp, both, 16, key, IV, 2);
5114 PrintAndLogEx(SUCCESS, " Res : " _GREEN_("%s"), sprint_hex(both, 16));
5119 static command_t CommandTable
[] = {
5120 {"help", CmdHelp
, AlwaysAvailable
, "This help"},
5121 {"-----------", CmdHelp
, IfPm3Iso14443a
, "---------------------- " _CYAN_("general") " ----------------------"},
5122 {"auth", CmdHF14ADesAuth
, IfPm3Iso14443a
, "Tries a MIFARE DesFire Authentication"},
5123 {"changekey", CmdHF14ADesChangeKey
, IfPm3Iso14443a
, "Change Key"},
5124 {"chk", CmdHF14aDesChk
, IfPm3Iso14443a
, "Check keys"},
5125 {"enum", CmdHF14ADesEnumApplications
, IfPm3Iso14443a
, "Tries enumerate all applications"},
5126 {"formatpicc", CmdHF14ADesFormatPICC
, IfPm3Iso14443a
, "Format PICC"},
5127 {"getuid", CmdHF14ADesGetUID
, IfPm3Iso14443a
, "Get random uid"},
5128 {"info", CmdHF14ADesInfo
, IfPm3Iso14443a
, "Tag information"},
5129 {"list", CmdHF14ADesList
, AlwaysAvailable
, "List DESFire (ISO 14443A) history"},
5130 // {"ndefread", CmdHF14aDesNDEFRead, IfPm3Iso14443a, "Prints NDEF records from card"},
5131 // {"mad", CmdHF14aDesMAD, IfPm3Iso14443a, "Prints MAD records from card"},
5132 {"-----------", CmdHelp
, IfPm3Iso14443a
, "-------------------- " _CYAN_("Applications") " -------------------"},
5133 {"bruteaid", CmdHF14ADesBruteApps
, IfPm3Iso14443a
, "Recover AIDs by bruteforce"},
5134 {"createaid", CmdHF14ADesCreateApp
, IfPm3Iso14443a
, "Create Application ID"},
5135 {"deleteaid", CmdHF14ADesDeleteApp
, IfPm3Iso14443a
, "Delete Application ID"},
5136 {"selectaid", CmdHF14ADesSelectApp
, IfPm3Iso14443a
, "Select Application ID"},
5137 {"-----------", CmdHelp
, IfPm3Iso14443a
, "----------------------- " _CYAN_("Files") " -----------------------"},
5138 {"changevalue", CmdHF14ADesChangeValue
, IfPm3Iso14443a
, "Write value of a value file (credit/debit/clear)"},
5139 {"clearfile", CmdHF14ADesClearRecordFile
, IfPm3Iso14443a
, "Clear record File"},
5140 {"createfile", CmdHF14ADesCreateFile
, IfPm3Iso14443a
, "Create Standard/Backup File"},
5141 {"createvaluefile", CmdHF14ADesCreateValueFile
, IfPm3Iso14443a
, "Create Value File"},
5142 {"createrecordfile", CmdHF14ADesCreateRecordFile
, IfPm3Iso14443a
, "Create Linear/Cyclic Record File"},
5143 {"deletefile", CmdHF14ADesDeleteFile
, IfPm3Iso14443a
, "Create Delete File"},
5144 {"dump", CmdHF14ADesDump
, IfPm3Iso14443a
, "Dump all files"},
5145 {"getvalue", CmdHF14ADesGetValueData
, IfPm3Iso14443a
, "Get value of file"},
5146 {"read", CmdHF14ADesReadData
, IfPm3Iso14443a
, "Read data from standard/backup/record file"},
5147 {"write", CmdHF14ADesWriteData
, IfPm3Iso14443a
, "Write data to standard/backup/record file"},
5148 {NULL
, NULL
, NULL
, NULL
}
5151 static int CmdHelp(const char *Cmd
) {
5152 (void)Cmd
; // Cmd is not used so far
5153 CmdsHelp(CommandTable
);
5157 int CmdHFMFDes(const char *Cmd
) {
5158 clearCommandBuffer();
5159 return CmdsParse(CommandTable
, Cmd
);
5167 ChangeKeySettings 0x5F
5181 '88' Internal Authenticate
5182 '82' External Authenticate