1 //-----------------------------------------------------------------------------
2 // Borrowed initially from https://github.com/nfc-tools/libfreefare
3 // Copyright (C) 2010, Romain Tartiere.
4 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
6 // This program is free software: you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation, either version 3 of the License, or
9 // (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // See LICENSE.txt for the text of the license.
17 //-----------------------------------------------------------------------------
18 // High frequency Desfire core functions
19 //-----------------------------------------------------------------------------
20 // Info from here and many other sources from the public internet sites
21 // https://github.com/revk/DESFireAES
22 // https://github.com/step21/desfire_rfid
23 // https://github.com/patsys/desfire-python/blob/master/Desfire/DESFire.py
24 //-----------------------------------------------------------------------------
26 #include "desfirecore.h"
30 #include "commonutil.h"
31 #include "generator.h"
35 #include "crc16.h" // crc16 ccitt
37 #include "protocols.h" // ISO7816 APDU return codes
39 #include "iso7816/apduinfo.h" // APDU manipulation / errorcodes
40 #include "iso7816/iso7816core.h" // APDU logging
41 #include "util_posix.h" // msleep
42 #include "desfiresecurechan.h"
43 #include "mifare/mad.h"
44 #include "mifare/aiddesfire.h"
47 const CLIParserOption DesfireAlgoOpts
[] = {
54 const size_t DesfireAlgoOptsLen
= ARRAYLEN(DesfireAlgoOpts
);
56 const CLIParserOption DesfireKDFAlgoOpts
[] = {
57 {MFDES_KDF_ALGO_NONE
, "none"},
58 {MFDES_KDF_ALGO_AN10922
, "an10922"},
59 {MFDES_KDF_ALGO_GALLAGHER
, "gallagher"},
62 const size_t DesfireKDFAlgoOptsLen
= ARRAYLEN(DesfireKDFAlgoOpts
);
64 const CLIParserOption DesfireCommunicationModeOpts
[] = {
67 {DCMEncrypted
, "encrypt"},
70 const size_t DesfireCommunicationModeOptsLen
= ARRAYLEN(DesfireCommunicationModeOpts
);
72 const CLIParserOption DesfireCommandSetOpts
[] = {
73 {DCCNative
, "native"},
74 {DCCNativeISO
, "niso"},
78 const size_t DesfireCommandSetOptsLen
= ARRAYLEN(DesfireCommandSetOpts
);
80 const CLIParserOption DesfireSecureChannelOpts
[] = {
87 const size_t DesfireSecureChannelOptsLen
= ARRAYLEN(DesfireSecureChannelOpts
);
89 const CLIParserOption DesfireFileAccessModeOpts
[] = {
109 const CLIParserOption DesfireValueFileOperOpts
[] = {
110 {MFDES_GET_VALUE
, "get"},
111 {MFDES_CREDIT
, "credit"},
112 {MFDES_LIMITED_CREDIT
, "limcredit"},
113 {MFDES_DEBIT
, "debit"},
118 const CLIParserOption DesfireReadFileTypeOpts
[] = {
122 {RFTRecord
, "record"},
127 static const char *getstatus(const uint16_t *sw
) {
128 if (sw
== NULL
) return "--> sw argument error. This should never happen !";
129 if (((*sw
>> 8) & 0xFF) == 0x91) {
130 switch (*sw
& 0xFF) {
131 case MFDES_E_OUT_OF_EEPROM
:
132 return "Out of Eeprom, insufficient NV-Memory to complete command";
133 case MFDES_E_ILLEGAL_COMMAND_CODE
:
134 return "Command code not supported";
136 case MFDES_E_INTEGRITY_ERROR
:
137 return "CRC or MAC does not match data / Padding bytes invalid";
139 case MFDES_E_NO_SUCH_KEY
:
140 return "Invalid key number specified";
143 return "Length of command string invalid";
145 case MFDES_E_PERMISSION_DENIED
:
146 return "Current configuration/status does not allow the requested command";
148 case MFDES_E_PARAMETER_ERROR
:
149 return "Value of the parameter(s) invalid";
151 case MFDES_E_APPLICATION_NOT_FOUND
:
152 return "Requested AID not present on PICC";
154 case MFDES_E_APPL_INTEGRITY
:
155 return "Application integrity error, application will be disabled";
157 case MFDES_E_AUTHENTICATION_ERROR
:
158 return "Current authentication status does not allow the requested command";
160 case MFDES_E_BOUNDARY
:
161 return "Attempted to read/write data from/to beyond the file's/record's limit";
163 case MFDES_E_PICC_INTEGRITY
:
164 return "PICC integrity error, PICC will be disabled";
166 case MFDES_E_COMMAND_ABORTED
:
167 return "Previous command was not fully completed / Not all Frames were requested or provided by the PCD";
169 case MFDES_E_PICC_DISABLED
:
170 return "PICC was disabled by an unrecoverable error";
173 return "Application count is limited to 28, not addition CreateApplication possible";
175 case MFDES_E_DUPLICATE
:
176 return "Duplicate entry: File/Application/ISO Text does already exist";
179 return "Eeprom error due to loss of power, internal backup/rollback mechanism activated";
181 case MFDES_E_FILE_NOT_FOUND
:
182 return "Specified file number does not exist";
184 case MFDES_E_FILE_INTEGRITY
:
185 return "File integrity error, file will be disabled";
188 return "Unknown error";
191 return "Unknown error";
194 const char *DesfireGetErrorString(int res
, uint16_t *sw
) {
197 return getstatus(sw
);
199 return "Undefined error";
201 return "Invalid argument(s)";
202 case PM3_EDEVNOTSUPP
:
203 return "Operation not supported by device";
205 return "Operation timed out";
207 return "Operation aborted (by user)";
209 return "Not (yet) implemented";
211 return "Error while RF transmission";
213 return "Input / output error";
215 return "Buffer overflow";
217 return "Software error";
219 return "Flash error";
221 return "Memory allocation error";
225 return "Generic TTY error";
227 return "Initialization error";
228 case PM3_EWRONGANSWER
:
229 return "Expected a different answer error";
230 case PM3_EOUTOFBOUND
:
231 return "Memory out-of-bounds error";
232 case PM3_ECARDEXCHANGE
:
233 return "Exchange with card error";
234 case PM3_EAPDU_ENCODEFAIL
:
235 return "Failed to create APDU";
239 return "Fatal error";
246 const char *DesfireAuthErrorToStr(int error
) {
249 return "Sending auth command failed";
251 return "Authentication failed. No data received";
253 return "Authentication failed. Invalid key number.";
255 return "Authentication failed. Length of answer doesn't match algo length";
257 return "mbedtls_aes_setkey_dec failed";
259 return "mbedtls_aes_setkey_enc failed";
261 return "Sending auth command failed";
263 return "Authentication failed. Card timeout.";
265 return "Authentication failed.";
267 return "mbedtls_aes_setkey_dec failed";
269 return "Authentication failed. Cannot verify Session Key.";
271 return "Authentication failed. Cannot verify CMAC.";
273 return "PICC returned not an AES answer";
275 return "PICC returned not an LRP answer";
277 return "Can't find auth method for provided channel parameters.";
279 return "Can't select application.";
281 return "Authentication returned no error but channel not authenticated.";
283 return "Can't select application by ISO ID.";
285 return "Can't select file by ISO ID.";
287 return "ISO Get challenge error.";
289 return "ISO Get challenge returned wrong length.";
291 return "Crypto encode piccrnd1 error.";
293 return "External authenticate error.";
295 return "Internal authenticate error.";
297 return "Internal authenticate returned wrong length.";
299 return "Crypto decode piccrnd2 error.";
301 return "Random numbers don't match. Authentication failed.";
308 const char *DesfireSelectWayToStr(DesfireISOSelectWay way
) {
324 char *DesfireWayIDStr(DesfireISOSelectWay way
, uint32_t id
) {
325 static char str
[200] = {0};
327 if (way
== ISWMF
|| way
== ISWDFName
)
328 snprintf(str
, sizeof(str
), "%s", DesfireSelectWayToStr(way
));
330 snprintf(str
, sizeof(str
), "%s %0*x", DesfireSelectWayToStr(way
), (way
== ISW6bAID
) ? 6 : 4, id
);
335 bool DesfireMFSelected(DesfireISOSelectWay way
, uint32_t id
) {
338 return (id
== 0x000000);
342 return (id
== 0x3f00);
351 // iceman todo: use commonutil.c instead
352 uint32_t DesfireAIDByteToUint(const uint8_t *data
) {
353 return data
[0] + (data
[1] << 8) + (data
[2] << 16);
356 void DesfireAIDUintToByte(uint32_t aid
, uint8_t *data
) {
357 data
[0] = aid
& 0xff;
358 data
[1] = (aid
>> 8) & 0xff;
359 data
[2] = (aid
>> 16) & 0xff;
362 static uint8_t DesfireKeyToISOKey(DesfireCryptoAlgorithm keytype
) {
376 static uint8_t DesfireGetRndLenForKey(DesfireCryptoAlgorithm keytype
) {
390 void DesfirePrintContext(DesfireContext_t
*ctx
) {
391 PrintAndLogEx(INFO
, "Key num: %d Key algo: %s Key[%d]: %s",
393 CLIGetOptionListStr(DesfireAlgoOpts
, ctx
->keyType
),
394 desfire_get_key_length(ctx
->keyType
),
396 desfire_get_key_length(ctx
->keyType
)));
398 if (ctx
->kdfAlgo
!= MFDES_KDF_ALGO_NONE
) {
399 PrintAndLogEx(INFO
, "KDF algo: %s KDF input[%d]: %s", CLIGetOptionListStr(DesfireKDFAlgoOpts
, ctx
->kdfAlgo
), ctx
->kdfInputLen
, sprint_hex(ctx
->kdfInput
, ctx
->kdfInputLen
));
400 PrintAndLogEx(INFO
, "AID: %06x UID[%d]: %s", ctx
->selectedAID
, ctx
->uidlen
, sprint_hex(ctx
->uid
, ctx
->uidlen
));
403 PrintAndLogEx(INFO
, "Secure channel: %s Command set: %s Communication mode: %s",
404 CLIGetOptionListStr(DesfireSecureChannelOpts
, ctx
->secureChannel
),
405 CLIGetOptionListStr(DesfireCommandSetOpts
, ctx
->cmdSet
),
406 CLIGetOptionListStr(DesfireCommunicationModeOpts
, ctx
->commMode
));
409 if (DesfireIsAuthenticated(ctx
)) {
410 if (memcmp(ctx
->sessionKeyMAC
, ctx
->sessionKeyEnc
, desfire_get_key_length(ctx
->keyType
)) == 0) {
411 PrintAndLogEx(INFO
, "Session key [%d]: %s ",
412 desfire_get_key_length(ctx
->keyType
),
413 sprint_hex(ctx
->sessionKeyEnc
, desfire_get_key_length(ctx
->keyType
)));
415 PrintAndLogEx(INFO
, "Session key MAC [%d]: %s ",
416 desfire_get_key_length(ctx
->keyType
),
417 sprint_hex(ctx
->sessionKeyMAC
, desfire_get_key_length(ctx
->keyType
)));
418 PrintAndLogEx(INFO
, " ENC: %s",
419 sprint_hex(ctx
->sessionKeyEnc
, desfire_get_key_length(ctx
->keyType
)));
421 PrintAndLogEx(INFO
, " IV [%zu]: %s",
422 desfire_get_key_block_length(ctx
->keyType
),
423 sprint_hex(ctx
->IV
, desfire_get_key_block_length(ctx
->keyType
)));
424 if (ctx
->secureChannel
== DACEV2
) {
425 PrintAndLogEx(INFO
, " TI: %s cmdCntr: 0x%04x",
426 sprint_hex(ctx
->TI
, 4),
433 static int DESFIRESendApduEx(bool activate_field
, sAPDU_t apdu
, uint16_t le
, uint8_t *result
, uint32_t max_result_len
, uint32_t *result_len
, uint16_t *sw
) {
434 if (result_len
) *result_len
= 0;
440 if (activate_field
) {
445 uint8_t data
[APDU_RES_LEN
] = {0};
449 if (APDUEncodeS(&apdu
, false, le
, data
, &datalen
)) { // 100 == with Le
450 PrintAndLogEx(ERR
, "APDU encoding error.");
451 return PM3_EAPDU_ENCODEFAIL
;
454 if (GetAPDULogging())
455 PrintAndLogEx(SUCCESS
, ">>>> %s", sprint_hex(data
, datalen
));
457 res
= ExchangeAPDU14a(data
, datalen
, activate_field
, true, result
, max_result_len
, (int *)result_len
);
458 if (res
!= PM3_SUCCESS
) {
462 if (GetAPDULogging())
463 PrintAndLogEx(SUCCESS
, "<<<< %s", sprint_hex(result
, *result_len
));
465 if (*result_len
< 2) {
470 isw
= (result
[*result_len
] << 8) + result
[*result_len
+ 1];
474 if (isw
!= ISO7816_OK
&&
475 isw
!= DESFIRE_GET_ISO_STATUS(MFDES_S_OPERATION_OK
) &&
476 isw
!= DESFIRE_GET_ISO_STATUS(MFDES_S_SIGNATURE
) &&
477 isw
!= DESFIRE_GET_ISO_STATUS(MFDES_S_ADDITIONAL_FRAME
) &&
478 isw
!= DESFIRE_GET_ISO_STATUS(MFDES_S_NO_CHANGES
)) {
479 if (GetAPDULogging()) {
480 if (isw
>> 8 == 0x61) {
481 PrintAndLogEx(ERR
, "APDU chaining len: 0x%02x -->", isw
& 0xff);
483 PrintAndLogEx(ERR
, "APDU(%02x%02x) ERROR: [0x%4X] %s", apdu
.CLA
, apdu
.INS
, isw
, GetAPDUCodeDescription(isw
>> 8, isw
& 0xff));
484 return PM3_EAPDU_FAIL
;
487 return PM3_EAPDU_FAIL
;
492 static int DESFIRESendApdu(bool activate_field
, sAPDU_t apdu
, uint8_t *result
, uint32_t max_result_len
, uint32_t *result_len
, uint16_t *sw
) {
493 return DESFIRESendApduEx(activate_field
, apdu
, APDU_INCLUDE_LE_00
, result
, max_result_len
, result_len
, sw
);
496 static int DESFIRESendRaw(bool activate_field
, uint8_t *data
, size_t datalen
, uint8_t *result
, uint32_t max_result_len
, uint32_t *result_len
, uint8_t *respcode
) {
502 if (activate_field
) {
507 if (GetAPDULogging()) {
508 PrintAndLogEx(SUCCESS
, "raw>> %s", sprint_hex(data
, datalen
));
511 int res
= ExchangeRAW14a(data
, datalen
, activate_field
, true, result
, max_result_len
, (int *)result_len
, true);
512 if (res
!= PM3_SUCCESS
) {
516 if (GetAPDULogging()) {
517 PrintAndLogEx(SUCCESS
, "raw<< %s", sprint_hex(result
, *result_len
));
520 if (*result_len
< 1) {
524 *result_len
-= (1 + 2);
526 uint8_t rcode
= result
[0];
531 memmove(&result
[0], &result
[1], *result_len
);
533 if (rcode
!= MFDES_S_OPERATION_OK
&&
534 rcode
!= MFDES_S_SIGNATURE
&&
535 rcode
!= MFDES_S_ADDITIONAL_FRAME
&&
536 rcode
!= MFDES_S_NO_CHANGES
) {
538 if (GetAPDULogging()) {
539 PrintAndLogEx(ERR
, "Command (%02x) ERROR: 0x%02x", data
[0], rcode
);
541 return PM3_EAPDU_FAIL
;
546 static int DesfireExchangeNative(bool activate_field
, DesfireContext_t
*ctx
, uint8_t cmd
, uint8_t *data
, size_t datalen
, uint8_t *respcode
, uint8_t *resp
, size_t *resplen
, bool enable_chaining
, size_t splitbysize
) {
555 uint8_t *buf
= calloc(DESFIRE_BUFFER_SIZE
, 1);
564 uint8_t rcode
= 0xff;
565 uint8_t cdata
[1024] = {0};
566 uint32_t cdatalen
= 0;
568 memcpy(&cdata
[1], data
, datalen
);
569 cdatalen
= datalen
+ 1;
574 size_t sentdatalen
= 0;
575 while (cdatalen
>= sentdatalen
) {
577 if ((cdatalen
- sentdatalen
) > DESFIRE_TX_FRAME_MAX_LEN
)
578 len
= DESFIRE_TX_FRAME_MAX_LEN
;
580 len
= cdatalen
- sentdatalen
;
582 size_t sendindx
= sentdatalen
;
583 size_t sendlen
= len
;
584 if (sentdatalen
> 0) {
587 cdata
[sendindx
] = MFDES_ADDITIONAL_FRAME
;
590 res
= DESFIRESendRaw(activate_field
, &cdata
[sendindx
], sendlen
, buf
, DESFIRE_BUFFER_SIZE
, &buflen
, &rcode
);
591 if (res
!= PM3_SUCCESS
) {
592 uint16_t ssw
= DESFIRE_GET_ISO_STATUS(rcode
);
593 PrintAndLogEx(DEBUG
, "error DESFIRESendRaw %s", DesfireGetErrorString(res
, &ssw
));
599 if ((rcode
!= MFDES_ADDITIONAL_FRAME
) || (buflen
> 0)) {
600 if (sentdatalen
!= cdatalen
) {
601 PrintAndLogEx(WARNING
, "Tx chaining error. Needs to send: %d but sent: %zu", cdatalen
, sentdatalen
);
611 memcpy(&resp
[1], buf
, buflen
);
613 memcpy(resp
, buf
, buflen
);
616 if (respcode
!= NULL
) {
622 if (enable_chaining
== false) {
623 if (rcode
== MFDES_S_OPERATION_OK
||
624 rcode
== MFDES_ADDITIONAL_FRAME
) {
634 while (rcode
== MFDES_ADDITIONAL_FRAME
) {
635 cdata
[0] = MFDES_ADDITIONAL_FRAME
; //0xAF
637 res
= DESFIRESendRaw(false, cdata
, 1, buf
, DESFIRE_BUFFER_SIZE
, &buflen
, &rcode
);
638 if (res
!= PM3_SUCCESS
) {
639 uint16_t ssw
= DESFIRE_GET_ISO_STATUS(rcode
);
640 PrintAndLogEx(DEBUG
, "error DESFIRESendRaw %s", DesfireGetErrorString(res
, &ssw
));
644 if (respcode
!= NULL
) {
650 resp
[i
* splitbysize
] = buflen
;
651 memcpy(&resp
[i
* splitbysize
+ 1], buf
, buflen
);
654 memcpy(&resp
[pos
], buf
, buflen
);
659 if (rcode
!= MFDES_ADDITIONAL_FRAME
)
664 *resplen
= (splitbysize
) ? i
: pos
;
671 static int DesfireExchangeISONative(bool activate_field
, DesfireContext_t
*ctx
, uint8_t cmd
, uint8_t *data
, size_t datalen
, uint8_t *respcode
, uint8_t *resp
, size_t *resplen
, bool enable_chaining
, size_t splitbysize
) {
681 uint8_t *buf
= calloc(DESFIRE_BUFFER_SIZE
, 1);
691 .CLA
= MFDES_NATIVE_ISO7816_WRAP_CLA
, //0x90
699 size_t sentdatalen
= 0;
700 while (datalen
>= sentdatalen
) {
701 if (datalen
- sentdatalen
> DESFIRE_TX_FRAME_MAX_LEN
) {
702 apdu
.Lc
= DESFIRE_TX_FRAME_MAX_LEN
;
704 apdu
.Lc
= datalen
- sentdatalen
;
707 apdu
.data
= &data
[sentdatalen
];
709 if (sentdatalen
> 0) {
710 apdu
.INS
= MFDES_ADDITIONAL_FRAME
;
713 res
= DESFIRESendApdu(activate_field
, apdu
, buf
, DESFIRE_BUFFER_SIZE
, &buflen
, &sw
);
714 if (res
!= PM3_SUCCESS
) {
715 PrintAndLogEx(DEBUG
, "error DESFIRESendApdu %s", DesfireGetErrorString(res
, &sw
));
720 sentdatalen
+= apdu
.Lc
;
721 if (sw
!= DESFIRE_GET_ISO_STATUS(MFDES_ADDITIONAL_FRAME
) || buflen
> 0) {
722 if (sentdatalen
!= datalen
) {
723 PrintAndLogEx(WARNING
, "Tx chaining error. Needs to send: %zu but sent: %zu", datalen
, sentdatalen
);
729 if (respcode
!= NULL
&& ((sw
& 0xFF00) == 0x9100)) {
730 *respcode
= sw
& 0xFF;
736 memcpy(&resp
[1], buf
, buflen
);
738 memcpy(resp
, buf
, buflen
);
743 if (enable_chaining
== false) {
744 if (sw
== DESFIRE_GET_ISO_STATUS(MFDES_S_OPERATION_OK
) ||
745 sw
== DESFIRE_GET_ISO_STATUS(MFDES_ADDITIONAL_FRAME
)) {
755 while (sw
== DESFIRE_GET_ISO_STATUS(MFDES_ADDITIONAL_FRAME
)) {
756 apdu
.CLA
= MFDES_NATIVE_ISO7816_WRAP_CLA
; //0x90
757 apdu
.INS
= MFDES_ADDITIONAL_FRAME
; //0xAF
765 res
= DESFIRESendApdu(false, apdu
, buf
, DESFIRE_BUFFER_SIZE
, &buflen
, &sw
);
766 if (res
!= PM3_SUCCESS
) {
767 PrintAndLogEx(DEBUG
, "error DESFIRESendApdu %s", DesfireGetErrorString(res
, &sw
));
772 if (respcode
!= NULL
&& ((sw
& 0xFF00) == 0x9100)) {
773 *respcode
= sw
& 0xFF;
778 resp
[i
* splitbysize
] = buflen
;
779 memcpy(&resp
[i
* splitbysize
+ 1], buf
, buflen
);
782 memcpy(resp
+ (pos
), buf
, buflen
);
788 if (sw
!= DESFIRE_GET_ISO_STATUS(MFDES_ADDITIONAL_FRAME
)) {
795 *resplen
= (splitbysize
) ? i
: pos
;
802 static int DesfireExchangeISO(bool activate_field
, DesfireContext_t
*ctx
, sAPDU_t apdu
, uint16_t le
, uint8_t *resp
, size_t *resplen
, uint16_t *sw
) {
803 uint8_t *data
= calloc(DESFIRE_BUFFER_SIZE
, 1);
808 uint32_t datalen
= 0;
809 int res
= DESFIRESendApduEx(activate_field
, apdu
, le
, data
, DESFIRE_BUFFER_SIZE
, &datalen
, sw
);
811 if (res
== PM3_SUCCESS
) {
812 DesfireSecureChannelDecode(ctx
, data
, datalen
, 0, resp
, resplen
);
819 // move data from blockdata [format: <length, data><length, data>...] to single data block
820 static void DesfireJoinBlockToBytes(uint8_t *blockdata
, size_t blockdatacount
, size_t blockdatasize
, uint8_t *dstdata
, size_t *dstdatalen
) {
822 for (int i
= 0; i
< blockdatacount
; i
++) {
823 memcpy(&dstdata
[*dstdatalen
], &blockdata
[i
* blockdatasize
+ 1], blockdata
[i
* blockdatasize
]);
824 *dstdatalen
+= blockdata
[i
* blockdatasize
];
828 // move data from single data block to blockdata [format: <length, data><length, data>...]
829 // lengths in the blockdata is not changed. result - in the blockdata
830 static void DesfireSplitBytesToBlock(uint8_t *blockdata
, size_t *blockdatacount
, size_t blockdatasize
, uint8_t *dstdata
, size_t dstdatalen
) {
832 for (int i
= 0; i
< *blockdatacount
; i
++) {
833 memset(&blockdata
[i
* blockdatasize
+ 1], 0, blockdatasize
- 1);
834 size_t tlen
= len
+ blockdata
[i
* blockdatasize
];
835 if (tlen
> dstdatalen
) {
839 blockdata
[i
* blockdatasize
] = tlen
- len
;
841 blockdata
[i
* blockdatasize
] = 0;
849 memcpy(&blockdata
[i
* blockdatasize
+ 1], &dstdata
[len
], tlen
- len
);
854 int DesfireExchangeEx(bool activate_field
, DesfireContext_t
*ctx
, uint8_t cmd
, uint8_t *data
, size_t datalen
, uint8_t *respcode
,
855 uint8_t *resp
, size_t *resplen
, bool enable_chaining
, size_t splitbysize
) {
856 int res
= PM3_SUCCESS
;
858 if (PrintChannelModeWarning(cmd
, ctx
->secureChannel
, ctx
->cmdSet
, ctx
->commMode
) == false) {
859 DesfirePrintContext(ctx
);
862 uint8_t *databuf
= calloc(DESFIRE_BUFFER_SIZE
, 1);
863 if (databuf
== NULL
) {
867 size_t databuflen
= 0;
869 switch (ctx
->cmdSet
) {
872 DesfireSecureChannelEncode(ctx
, cmd
, data
, datalen
, databuf
, &databuflen
);
874 if (ctx
->cmdSet
== DCCNative
) {
875 res
= DesfireExchangeNative(activate_field
, ctx
, cmd
, databuf
, databuflen
, respcode
, databuf
, &databuflen
, enable_chaining
, splitbysize
);
877 res
= DesfireExchangeISONative(activate_field
, ctx
, cmd
, databuf
, databuflen
, respcode
, databuf
, &databuflen
, enable_chaining
, splitbysize
);
881 uint8_t sdata
[DESFIRE_BUFFER_SIZE
] = {0};
883 DesfireJoinBlockToBytes(databuf
, databuflen
, splitbysize
, sdata
, &sdatalen
);
885 //PrintAndLogEx(INFO, "block : %s", sprint_hex(sdata, sdatalen));
886 DesfireSecureChannelDecode(ctx
, sdata
, sdatalen
, *respcode
, resp
, resplen
);
888 DesfireSplitBytesToBlock(databuf
, &databuflen
, splitbysize
, resp
, *resplen
);
889 memcpy(resp
, databuf
, databuflen
* splitbysize
);
890 *resplen
= databuflen
;
892 DesfireSecureChannelDecode(ctx
, databuf
, databuflen
, *respcode
, resp
, resplen
);
897 return PM3_EAPDU_FAIL
;
905 int DesfireExchange(DesfireContext_t
*ctx
, uint8_t cmd
, uint8_t *data
, size_t datalen
, uint8_t *respcode
, uint8_t *resp
, size_t *resplen
) {
906 return DesfireExchangeEx(false, ctx
, cmd
, data
, datalen
, respcode
, resp
, resplen
, true, 0);
909 int DesfireSelectAID(DesfireContext_t
*ctx
, uint8_t *aid1
, uint8_t *aid2
) {
914 uint8_t data
[6] = {0};
915 memcpy(data
, aid1
, 3);
917 memcpy(&data
[3], aid2
, 3);
920 uint8_t resp
[257] = {0};
922 uint8_t respcode
= 0;
924 ctx
->secureChannel
= DACNone
;
925 int res
= DesfireExchangeEx(true, ctx
, MFDES_SELECT_APPLICATION
, data
, (aid2
== NULL
) ? 3 : 6, &respcode
, resp
, &resplen
, true, 0);
926 if (res
== PM3_SUCCESS
) {
928 return PM3_ECARDEXCHANGE
;
931 // select operation fail
932 if (respcode
!= MFDES_S_OPERATION_OK
) {
933 return PM3_EAPDU_FAIL
;
936 DesfireClearSession(ctx
);
937 ctx
->appSelected
= (aid1
[0] != 0x00 || aid1
[1] != 0x00 || aid1
[2] != 0x00);
938 ctx
->selectedAID
= DesfireAIDByteToUint(aid1
);
946 int DesfireSelectAIDHex(DesfireContext_t
*ctx
, uint32_t aid1
, bool select_two
, uint32_t aid2
) {
947 uint8_t data
[6] = {0};
949 DesfireAIDUintToByte(aid1
, data
);
950 DesfireAIDUintToByte(aid2
, &data
[3]);
952 return DesfireSelectAID(ctx
, data
, (select_two
) ? &data
[3] : NULL
);
955 int DesfireSelectAIDHexNoFieldOn(DesfireContext_t
*ctx
, uint32_t aid
) {
956 uint8_t data
[3] = {0};
958 DesfireAIDUintToByte(aid
, data
);
960 uint8_t resp
[257] = {0};
962 uint8_t respcode
= 0;
964 ctx
->secureChannel
= DACNone
;
965 int res
= DesfireExchangeEx(false, ctx
, MFDES_SELECT_APPLICATION
, data
, 3, &respcode
, resp
, &resplen
, true, 0);
966 if (res
== PM3_SUCCESS
) {
968 return PM3_ECARDEXCHANGE
;
970 // select operation fail
971 if (respcode
!= MFDES_S_OPERATION_OK
)
972 return PM3_EAPDU_FAIL
;
974 DesfireClearSession(ctx
);
975 ctx
->appSelected
= (aid
!= 0x000000);
976 ctx
->selectedAID
= aid
;
983 void DesfirePrintMADAID(uint32_t appid
, bool verbose
) {
984 uint8_t aid
[3] = {0};
985 DesfireAIDUintToByte(appid
, aid
);
986 if ((aid
[2] >> 4) != 0xF)
989 uint16_t short_aid
= ((aid
[2] & 0xF) << 12) | (aid
[1] << 4) | (aid
[0] >> 4);
991 PrintAndLogEx(SUCCESS
, "MIFARE Classic ID (MAD): " _YELLOW_("%04X") " ver: " _YELLOW_("%01X") " AID: " _YELLOW_("%06x") " MAD AID Cluster[0x%02X]: " _YELLOW_("%s"),
996 nxp_cluster_to_text(short_aid
>> 8));
998 if (appid
== 0xffffff)
999 PrintAndLogEx(SUCCESS
, " Card issuer information application");
1001 MADDFDecodeAndPrint(short_aid
, verbose
);
1005 void DesfirePrintAIDFunctions(uint32_t appid
) {
1006 uint8_t aid
[3] = {0};
1007 DesfireAIDUintToByte(appid
, aid
);
1008 if ((aid
[2] >> 4) == 0xF) {
1009 uint16_t short_aid
= ((aid
[2] & 0xF) << 12) | (aid
[1] << 4) | (aid
[0] >> 4);
1010 PrintAndLogEx(SUCCESS
, " AID mapped to MIFARE Classic AID (MAD): " _YELLOW_("%02X"), short_aid
);
1011 PrintAndLogEx(SUCCESS
, " MAD AID Cluster 0x%02X : " _YELLOW_("%s"), short_aid
>> 8, nxp_cluster_to_text(short_aid
>> 8));
1012 MADDFDecodeAndPrint(short_aid
, false);
1014 AIDDFDecodeAndPrint(aid
);
1018 int DesfireSelectAndAuthenticateEx(DesfireContext_t
*dctx
, DesfireSecureChannel secureChannel
, uint32_t aid
, bool noauth
, bool verbose
) {
1020 DesfirePrintContext(dctx
);
1022 // needs card uid for diversification
1023 if (dctx
->kdfAlgo
== MFDES_KDF_ALGO_GALLAGHER
)
1024 DesfireGetCardUID(dctx
);
1027 if (dctx
->cmdSet
== DCCISO
) {
1028 dctx
->cmdSet
= DCCNativeISO
;
1031 PrintAndLogEx(INFO
, "Switch to " _CYAN_("native") " for select");
1035 if (aid
== 0x000000) {
1036 res
= DesfireAnticollision(verbose
);
1037 if (res
!= PM3_SUCCESS
) {
1038 PrintAndLogEx(ERR
, "Desfire anticollision " _RED_("error") ".");
1042 PrintAndLogEx(INFO
, "Anticollision " _GREEN_("ok"));
1044 res
= DesfireSelectAIDHex(dctx
, aid
, false, 0);
1045 if (res
!= PM3_SUCCESS
) {
1046 PrintAndLogEx(ERR
, "Desfire select " _RED_("error") ".");
1050 PrintAndLogEx(INFO
, "App %06x " _GREEN_("selected"), aid
);
1054 dctx
->cmdSet
= DCCISO
;
1056 if (noauth
== false) {
1057 res
= DesfireAuthenticate(dctx
, secureChannel
, verbose
);
1058 if (res
!= PM3_SUCCESS
) {
1059 PrintAndLogEx(ERR
, "Desfire authenticate " _RED_("error") ". Result: [%d] %s", res
, DesfireAuthErrorToStr(res
));
1063 if (DesfireIsAuthenticated(dctx
)) {
1065 PrintAndLogEx(INFO
, "Desfire " _GREEN_("authenticated"));
1074 int DesfireSelectAndAuthenticate(DesfireContext_t
*dctx
, DesfireSecureChannel secureChannel
, uint32_t aid
, bool verbose
) {
1075 return DesfireSelectAndAuthenticateEx(dctx
, secureChannel
, aid
, false, verbose
);
1078 int DesfireSelectAndAuthenticateW(DesfireContext_t
*dctx
, DesfireSecureChannel secureChannel
, DesfireISOSelectWay way
, uint32_t id
, bool selectfile
, uint16_t isofileid
, bool noauth
, bool verbose
) {
1080 DesfirePrintContext(dctx
);
1083 if (way
== ISW6bAID
&& dctx
->cmdSet
== DCCISO
) {
1084 dctx
->cmdSet
= DCCNativeISO
;
1086 PrintAndLogEx(INFO
, "Select via " _CYAN_("native iso wrapping") " interface");
1088 res
= DesfireSelectAIDHex(dctx
, id
, false, 0);
1089 if (res
!= PM3_SUCCESS
) {
1090 PrintAndLogEx(ERR
, "Desfire select " _RED_("error") ".");
1094 PrintAndLogEx(INFO
, "App %06x via native iso channel is " _GREEN_("selected"), id
);
1096 dctx
->cmdSet
= DCCISO
;
1098 res
= DesfireSelectEx(dctx
, true, way
, id
, NULL
);
1099 if (res
!= PM3_SUCCESS
) {
1100 PrintAndLogEx(ERR
, "Desfire %s select " _RED_("error") ".", DesfireSelectWayToStr(way
));
1104 PrintAndLogEx(INFO
, "%s is " _GREEN_("selected"), DesfireWayIDStr(way
, id
));
1108 res
= DesfireSelectEx(dctx
, false, ISWIsoID
, isofileid
, NULL
);
1109 if (res
!= PM3_SUCCESS
) {
1110 PrintAndLogEx(ERR
, "Desfire iso file select " _RED_("error") ".");
1115 PrintAndLogEx(INFO
, "Application %s file iso id %04x is " _GREEN_("selected"), DesfireWayIDStr(way
, id
), isofileid
);
1119 res
= DesfireAuthenticate(dctx
, secureChannel
, verbose
);
1120 if (res
!= PM3_SUCCESS
) {
1121 PrintAndLogEx(ERR
, "Desfire authenticate " _RED_("error") ". Result: [%d] %s", res
, DesfireAuthErrorToStr(res
));
1125 if (DesfireIsAuthenticated(dctx
)) {
1127 PrintAndLogEx(INFO
, "Desfire " _GREEN_("authenticated"));
1136 int DesfireSelectAndAuthenticateAppW(DesfireContext_t
*dctx
, DesfireSecureChannel secureChannel
, DesfireISOSelectWay way
, uint32_t id
, bool noauth
, bool verbose
) {
1137 return DesfireSelectAndAuthenticateW(dctx
, secureChannel
, way
, id
, false, 0, noauth
, verbose
);
1140 int DesfireSelectAndAuthenticateISO(DesfireContext_t
*dctx
, DesfireSecureChannel secureChannel
, bool useaid
, uint32_t aid
, uint16_t isoappid
, bool selectfile
, uint16_t isofileid
, bool noauth
, bool verbose
) {
1141 return DesfireSelectAndAuthenticateW(dctx
, secureChannel
, useaid
? ISW6bAID
: ISWIsoID
, useaid
? aid
: isoappid
, selectfile
, isofileid
, noauth
, verbose
);
1144 static int DesfireAuthenticateEV1(DesfireContext_t
*dctx
, DesfireSecureChannel secureChannel
, bool verbose
) {
1145 // 3 different way to authenticate AUTH (CRC16) , AUTH_ISO (CRC32) , AUTH_AES (CRC32)
1146 // 4 different crypto arg1 DES, 3DES, 3K3DES, AES
1147 // 3 different communication modes, PLAIN,MAC,CRYPTO
1149 DesfireClearSession(dctx
);
1151 if (secureChannel
== DACNone
)
1154 uint8_t keybytes
[24] = {0};
1156 uint8_t IV
[16] = {0};
1157 uint8_t RndA
[16] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16};
1158 uint8_t RndB
[16] = {0};
1159 uint8_t encRndB
[16] = {0};
1160 uint8_t rotRndB
[16] = {0}; //RndB'
1161 uint8_t both
[32 + 1] = {0}; // ek/dk_keyNo(RndA+RndB')
1164 memcpy(keybytes
, dctx
->key
, desfire_get_key_length(dctx
->keyType
));
1166 uint8_t subcommand
= MFDES_AUTHENTICATE
;
1167 if (secureChannel
== DACEV1
) {
1168 if (dctx
->keyType
== T_AES
)
1169 subcommand
= MFDES_AUTHENTICATE_AES
;
1171 subcommand
= MFDES_AUTHENTICATE_ISO
;
1174 size_t recv_len
= 0;
1175 uint8_t respcode
= 0;
1176 uint8_t recv_data
[256] = {0};
1179 PrintAndLogEx(INFO
, _CYAN_("Auth:") " cmd: 0x%02x keynum: 0x%02x", subcommand
, dctx
->keyNum
);
1181 // Let's send our auth command
1182 int res
= DesfireExchangeEx(false, dctx
, subcommand
, &dctx
->keyNum
, 1, &respcode
, recv_data
, &recv_len
, false, 0);
1183 if (res
!= PM3_SUCCESS
) {
1191 if (respcode
!= MFDES_ADDITIONAL_FRAME
) {
1195 uint32_t expectedlen
= 8;
1196 if (dctx
->keyType
== T_AES
|| dctx
->keyType
== T_3K3DES
) {
1200 if (recv_len
!= expectedlen
) {
1205 uint32_t rndlen
= recv_len
;
1206 memcpy(encRndB
, recv_data
, rndlen
);
1210 DesfireCryptoEncDecEx(dctx
, DCOMainKey
, encRndB
, rndlen
, RndB
, false, false, IV
);
1212 if (g_debugMode
> 1) {
1213 PrintAndLogEx(DEBUG
, "encRndB: %s", sprint_hex(encRndB
, 8));
1214 PrintAndLogEx(DEBUG
, "RndB: %s", sprint_hex(RndB
, 8));
1217 // - Rotate RndB by 8 bits
1218 memcpy(rotRndB
, RndB
, rndlen
);
1219 rol(rotRndB
, rndlen
);
1221 uint8_t encRndA
[16] = {0x00};
1223 // - Encrypt our response
1224 if (secureChannel
== DACd40
) {
1225 memset(IV
, 0, DESFIRE_MAX_CRYPTO_BLOCK_SIZE
);
1226 DesfireCryptoEncDecEx(dctx
, DCOMainKey
, RndA
, rndlen
, encRndA
, true, true, IV
);
1228 memcpy(both
, encRndA
, rndlen
);
1229 bin_xor(rotRndB
, encRndA
, rndlen
);
1231 memset(IV
, 0, DESFIRE_MAX_CRYPTO_BLOCK_SIZE
);
1232 DesfireCryptoEncDecEx(dctx
, DCOMainKey
, rotRndB
, rndlen
, encRndB
, true, true, IV
);
1234 memcpy(both
+ rndlen
, encRndB
, rndlen
);
1235 } else if (secureChannel
== DACEV1
) {
1236 uint8_t tmp
[32] = {0x00};
1237 memcpy(tmp
, RndA
, rndlen
);
1238 memcpy(tmp
+ rndlen
, rotRndB
, rndlen
);
1239 if (g_debugMode
> 1) {
1240 PrintAndLogEx(DEBUG
, "rotRndB: %s", sprint_hex(rotRndB
, rndlen
));
1241 PrintAndLogEx(DEBUG
, "Both : %s", sprint_hex(tmp
, 32));
1243 DesfireCryptoEncDecEx(dctx
, DCOMainKey
, tmp
, rndlen
* 2, both
, true, true, IV
);
1246 uint32_t bothlen
= 16;
1247 if (dctx
->keyType
== T_AES
|| dctx
->keyType
== T_3K3DES
) {
1251 res
= DesfireExchangeEx(false, dctx
, MFDES_ADDITIONAL_FRAME
, both
, bothlen
, &respcode
, recv_data
, &recv_len
, false, 0);
1252 if (res
!= PM3_SUCCESS
) {
1260 if (respcode
!= MFDES_S_OPERATION_OK
) {
1265 memcpy(encRndA
, recv_data
, rndlen
);
1267 //PrintAndLogEx(INFO, "encRndA : %s", sprint_hex(encRndA, rndlen));
1268 //PrintAndLogEx(INFO, "IV : %s", sprint_hex(IV, rndlen));
1270 if (secureChannel
== DACd40
)
1271 memset(IV
, 0, DESFIRE_MAX_CRYPTO_BLOCK_SIZE
);
1272 DesfireCryptoEncDecEx(dctx
, DCOMainKey
, encRndA
, rndlen
, encRndA
, false, false, IV
);
1274 // generate session key from rnda and rndb. before rol(RndA)!
1275 DesfireGenSessionKeyEV1(RndA
, RndB
, dctx
->keyType
, dctx
->sessionKeyEnc
);
1278 //PrintAndLogEx(INFO, "Expected_RndA : %s", sprint_hex(RndA, rndlen));
1279 //PrintAndLogEx(INFO, "Generated_RndA : %s", sprint_hex(encRndA, rndlen));
1280 for (uint32_t x
= 0; x
< rndlen
; x
++) {
1281 if (RndA
[x
] != encRndA
[x
]) {
1282 if (g_debugMode
> 1) {
1283 PrintAndLogEx(DEBUG
, "Expected_RndA : %s", sprint_hex(RndA
, rndlen
));
1284 PrintAndLogEx(DEBUG
, "Generated_RndA : %s", sprint_hex(encRndA
, rndlen
));
1290 // If the 3Des key first 8 bytes = 2nd 8 Bytes then we are really using Singe Des
1291 // As such we need to set the session key such that the 2nd 8 bytes = 1st 8 Bytes
1292 if (dctx
->keyType
== T_3DES
) {
1293 if (memcmp(dctx
->key
, &dctx
->key
[8], 8) == 0)
1294 memcpy(&dctx
->sessionKeyEnc
[8], dctx
->sessionKeyEnc
, 8);
1297 memset(dctx
->IV
, 0, DESFIRE_MAX_KEY_SIZE
);
1298 dctx
->secureChannel
= secureChannel
;
1299 memcpy(dctx
->sessionKeyMAC
, dctx
->sessionKeyEnc
, desfire_get_key_length(dctx
->keyType
));
1301 PrintAndLogEx(INFO
, _GREEN_("Session key") " : %s", sprint_hex(dctx
->sessionKeyEnc
, desfire_get_key_length(dctx
->keyType
)));
1306 static int DesfireAuthenticateEV2(DesfireContext_t
*dctx
, DesfireSecureChannel secureChannel
, bool firstauth
, bool verbose
) {
1308 uint8_t IV
[16] = {0};
1309 uint8_t RndA
[CRYPTO_AES_BLOCK_SIZE
] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16};
1310 uint8_t RndB
[CRYPTO_AES_BLOCK_SIZE
] = {0};
1311 uint8_t encRndB
[CRYPTO_AES_BLOCK_SIZE
] = {0};
1312 uint8_t rotRndA
[CRYPTO_AES_BLOCK_SIZE
] = {0}; //RndA'
1313 uint8_t rotRndB
[CRYPTO_AES_BLOCK_SIZE
] = {0}; //RndB'
1314 uint8_t both
[CRYPTO_AES_BLOCK_SIZE
* 2 + 1] = {0}; // ek/dk_keyNo(RndA+RndB')
1316 uint8_t subcommand
= firstauth
? MFDES_AUTHENTICATE_EV2F
: MFDES_AUTHENTICATE_EV2NF
;
1317 uint8_t *key
= dctx
->key
;
1319 size_t recv_len
= 0;
1320 uint8_t respcode
= 0;
1321 uint8_t recv_data
[256] = {0};
1324 PrintAndLogEx(INFO
, _CYAN_("Auth %s:") " cmd: 0x%02x keynum: 0x%02x key: %s", (firstauth
) ? "first" : "non-first", subcommand
, dctx
->keyNum
, sprint_hex(key
, 16));
1326 // Let's send our auth command
1327 uint8_t cdata
[] = {dctx
->keyNum
, 0x00};
1328 int res
= DesfireExchangeEx(false, dctx
, subcommand
, cdata
, (firstauth
) ? sizeof(cdata
) : 1, &respcode
, recv_data
, &recv_len
, false, 0);
1329 if (res
!= PM3_SUCCESS
) {
1337 if (respcode
!= MFDES_ADDITIONAL_FRAME
) {
1341 size_t rdataindx
= 0;
1342 if (recv_len
!= CRYPTO_AES_BLOCK_SIZE
) {
1343 if (recv_len
== CRYPTO_AES_BLOCK_SIZE
+ 1) {
1344 if (recv_data
[0] != 0x00)
1353 memcpy(encRndB
, &recv_data
[rdataindx
], 16);
1356 if (aes_decode(IV
, key
, encRndB
, RndB
, CRYPTO_AES_BLOCK_SIZE
))
1359 if (g_debugMode
> 1) {
1360 PrintAndLogEx(DEBUG
, "encRndB: %s", sprint_hex(encRndB
, CRYPTO_AES_BLOCK_SIZE
));
1361 PrintAndLogEx(DEBUG
, "RndB: %s", sprint_hex(RndB
, CRYPTO_AES_BLOCK_SIZE
));
1364 // - Rotate RndB by 8 bits
1365 memcpy(rotRndB
, RndB
, CRYPTO_AES_BLOCK_SIZE
);
1366 rol(rotRndB
, CRYPTO_AES_BLOCK_SIZE
);
1368 // - Encrypt our response
1369 uint8_t tmp
[32] = {0x00};
1370 memcpy(tmp
, RndA
, CRYPTO_AES_BLOCK_SIZE
);
1371 memcpy(tmp
+ CRYPTO_AES_BLOCK_SIZE
, rotRndB
, CRYPTO_AES_BLOCK_SIZE
);
1372 if (g_debugMode
> 1) {
1373 PrintAndLogEx(DEBUG
, "rotRndB: %s", sprint_hex(rotRndB
, CRYPTO_AES_BLOCK_SIZE
));
1374 PrintAndLogEx(DEBUG
, "Both: %s", sprint_hex(tmp
, CRYPTO_AES_BLOCK_SIZE
* 2));
1377 if (aes_encode(IV
, key
, tmp
, both
, CRYPTO_AES_BLOCK_SIZE
* 2))
1379 if (g_debugMode
> 1) {
1380 PrintAndLogEx(DEBUG
, "EncBoth: %s", sprint_hex(both
, CRYPTO_AES_BLOCK_SIZE
* 2));
1383 res
= DesfireExchangeEx(false, dctx
, MFDES_ADDITIONAL_FRAME
, both
, CRYPTO_AES_BLOCK_SIZE
* 2, &respcode
, recv_data
, &recv_len
, false, 0);
1384 if (res
!= PM3_SUCCESS
) {
1392 if (respcode
!= MFDES_S_OPERATION_OK
) {
1397 uint8_t data
[32] = {0};
1399 if (aes_decode(IV
, key
, recv_data
, data
, recv_len
))
1402 // rotate rndA to check
1403 memcpy(rotRndA
, RndA
, CRYPTO_AES_BLOCK_SIZE
);
1404 rol(rotRndA
, CRYPTO_AES_BLOCK_SIZE
);
1406 uint8_t *recRndA
= (firstauth
) ? &data
[4] : data
;
1408 if (memcmp(rotRndA
, recRndA
, CRYPTO_AES_BLOCK_SIZE
) != 0) {
1409 if (g_debugMode
> 1) {
1410 PrintAndLogEx(DEBUG
, "Expected_RndA' : %s", sprint_hex(rotRndA
, CRYPTO_AES_BLOCK_SIZE
));
1411 PrintAndLogEx(DEBUG
, "Generated_RndA' : %s", sprint_hex(recRndA
, CRYPTO_AES_BLOCK_SIZE
));
1418 memcpy(dctx
->TI
, data
, 4);
1420 DesfireClearIV(dctx
);
1421 DesfireGenSessionKeyEV2(dctx
->key
, RndA
, RndB
, true, dctx
->sessionKeyEnc
);
1422 DesfireGenSessionKeyEV2(dctx
->key
, RndA
, RndB
, false, dctx
->sessionKeyMAC
);
1423 dctx
->secureChannel
= secureChannel
;
1427 PrintAndLogEx(INFO
, "TI : %s", sprint_hex(data
, 4));
1428 PrintAndLogEx(INFO
, "pic : %s", sprint_hex(&data
[20], 6));
1429 PrintAndLogEx(INFO
, "pcd : %s", sprint_hex(&data
[26], 6));
1431 PrintAndLogEx(INFO
, "TI : %s", sprint_hex(dctx
->TI
, 4));
1433 PrintAndLogEx(INFO
, "session key ENC: %s", sprint_hex(dctx
->sessionKeyEnc
, 16));
1434 PrintAndLogEx(INFO
, "session key MAC: %s", sprint_hex(dctx
->sessionKeyMAC
, 16));
1440 static int DesfireAuthenticateISO(DesfireContext_t
*dctx
, DesfireSecureChannel secureChannel
, bool verbose
) {
1441 uint8_t rndlen
= DesfireGetRndLenForKey(dctx
->keyType
);
1443 uint8_t hostrnd
[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16};
1444 uint8_t hostrnd2
[] = {0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01};
1446 uint8_t piccrnd
[64];
1448 int res
= DesfireISOGetChallenge(dctx
, dctx
->keyType
, piccrnd
, &xlen
);
1449 if (res
!= PM3_SUCCESS
)
1455 uint8_t both
[32] = {0};
1456 memcpy(both
, hostrnd
, rndlen
);
1457 memcpy(&both
[rndlen
], piccrnd
, rndlen
);
1460 DesfireClearIV(dctx
);
1461 DesfireCryptoEncDec(dctx
, DCOMainKey
, both
, rndlen
* 2, both
, true); // error 303
1463 // external authenticate
1464 res
= DesfireISOExternalAuth(dctx
, dctx
->appSelected
, dctx
->keyNum
, dctx
->keyType
, both
);
1465 if (res
!= PM3_SUCCESS
)
1468 // internal authenticate
1469 uint8_t rnddata
[64] = {0};
1471 res
= DesfireISOInternalAuth(dctx
, dctx
->appSelected
, dctx
->keyNum
, dctx
->keyType
, hostrnd2
, rnddata
, &xlen
);
1472 if (res
!= PM3_SUCCESS
)
1475 if (xlen
!= rndlen
* 2)
1479 uint8_t piccrnd2
[64] = {0};
1480 DesfireCryptoEncDec(dctx
, DCOMainKey
, rnddata
, rndlen
* 2, piccrnd2
, false); // error 307
1483 if (memcmp(hostrnd2
, &piccrnd2
[rndlen
], rndlen
) != 0)
1486 DesfireGenSessionKeyEV1(hostrnd
, piccrnd2
, dctx
->keyType
, dctx
->sessionKeyEnc
);
1487 DesfireClearIV(dctx
);
1488 memcpy(dctx
->sessionKeyMAC
, dctx
->sessionKeyEnc
, desfire_get_key_length(dctx
->keyType
));
1489 dctx
->secureChannel
= secureChannel
;
1492 PrintAndLogEx(INFO
, "session key: %s", sprint_hex(dctx
->sessionKeyEnc
, desfire_get_key_length(dctx
->keyType
)));
1497 static int DesfireAuthenticateLRP(DesfireContext_t
*dctx
, DesfireSecureChannel secureChannel
, bool firstauth
, bool verbose
) {
1499 uint8_t RndA
[CRYPTO_AES_BLOCK_SIZE
] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16};
1500 uint8_t RndB
[CRYPTO_AES_BLOCK_SIZE
] = {0};
1501 uint8_t both
[CRYPTO_AES_BLOCK_SIZE
* 2 + 1] = {0};
1503 uint8_t subcommand
= firstauth
? MFDES_AUTHENTICATE_EV2F
: MFDES_AUTHENTICATE_EV2NF
;
1504 uint8_t *key
= dctx
->key
;
1506 size_t recv_len
= 0;
1507 uint8_t respcode
= 0;
1508 uint8_t recv_data
[256] = {0};
1511 PrintAndLogEx(INFO
, _CYAN_("Auth %s:") " cmd: 0x%02x keynum: 0x%02x key: %s", (firstauth
) ? "first" : "non-first", subcommand
, dctx
->keyNum
, sprint_hex(key
, 16));
1513 // Let's send our auth command
1514 uint8_t cdata
[] = {dctx
->keyNum
, 0x01, 0x02};
1515 int res
= DesfireExchangeEx(false, dctx
, subcommand
, cdata
, (firstauth
) ? sizeof(cdata
) : 1, &respcode
, recv_data
, &recv_len
, false, 0);
1516 if (res
!= PM3_SUCCESS
) {
1524 if (respcode
!= MFDES_ADDITIONAL_FRAME
) {
1528 if (recv_len
!= CRYPTO_AES_BLOCK_SIZE
+ 1) {
1532 if (recv_data
[0] != 0x01)
1535 // PICC return RndB in plain
1536 memcpy(RndB
, &recv_data
[1], 16);
1538 if (g_debugMode
> 1) {
1539 PrintAndLogEx(DEBUG
, "RndB: %s", sprint_hex(RndB
, CRYPTO_AES_BLOCK_SIZE
));
1542 // cmac(sessionkey, rnda+rndb)
1543 uint8_t sessionkey
[32] = {0};
1544 DesfireGenSessionKeyLRP(key
, RndA
, RndB
, false, sessionkey
);
1546 uint8_t tmp
[CRYPTO_AES_BLOCK_SIZE
* 4] = {0};
1547 memcpy(tmp
, RndA
, CRYPTO_AES_BLOCK_SIZE
);
1548 memcpy(tmp
+ CRYPTO_AES_BLOCK_SIZE
, RndB
, CRYPTO_AES_BLOCK_SIZE
);
1550 uint8_t cmac
[CRYPTO_AES_BLOCK_SIZE
] = {0};
1551 LRPContext_t ctx
= {0};
1552 LRPSetKey(&ctx
, sessionkey
, 0, true);
1553 LRPCMAC(&ctx
, tmp
, 32, cmac
);
1555 // response = rnda + cmac(sessionkey, rnda+rndb)
1556 memcpy(both
, RndA
, CRYPTO_AES_BLOCK_SIZE
);
1557 memcpy(both
+ CRYPTO_AES_BLOCK_SIZE
, cmac
, CRYPTO_AES_BLOCK_SIZE
);
1558 if (g_debugMode
> 1) {
1559 PrintAndLogEx(DEBUG
, "Both: %s", sprint_hex(tmp
, CRYPTO_AES_BLOCK_SIZE
* 2));
1562 res
= DesfireExchangeEx(false, dctx
, MFDES_ADDITIONAL_FRAME
, both
, CRYPTO_AES_BLOCK_SIZE
* 2, &respcode
, recv_data
, &recv_len
, false, 0);
1563 if (res
!= PM3_SUCCESS
) {
1571 if (respcode
!= MFDES_S_OPERATION_OK
) {
1576 uint8_t data
[64] = {0};
1579 DesfireClearIV(dctx
);
1582 memcpy(tmp
, RndB
, CRYPTO_AES_BLOCK_SIZE
);
1583 memcpy(tmp
+ CRYPTO_AES_BLOCK_SIZE
, RndA
, CRYPTO_AES_BLOCK_SIZE
);
1585 memcpy(tmp
+ CRYPTO_AES_BLOCK_SIZE
* 2, recv_data
, CRYPTO_AES_BLOCK_SIZE
);
1587 LRPSetKey(&ctx
, sessionkey
, 0, true);
1588 LRPCMAC(&ctx
, tmp
, (firstauth
) ? CRYPTO_AES_BLOCK_SIZE
* 3 : CRYPTO_AES_BLOCK_SIZE
* 2, cmac
);
1589 uint8_t *recCMAC
= &recv_data
[(firstauth
) ? CRYPTO_AES_BLOCK_SIZE
: 0];
1590 if (memcmp(recCMAC
, cmac
, CRYPTO_AES_BLOCK_SIZE
) != 0) {
1591 if (g_debugMode
> 1) {
1592 PrintAndLogEx(DEBUG
, "Expected cmac : %s", sprint_hex(recCMAC
, CRYPTO_AES_BLOCK_SIZE
));
1593 PrintAndLogEx(DEBUG
, "Generated cmac : %s", sprint_hex(cmac
, CRYPTO_AES_BLOCK_SIZE
));
1600 LRPSetKeyEx(&ctx
, sessionkey
, dctx
->IV
, 4 * 2, 1, false);
1602 LRPDecode(&ctx
, recv_data
, 16, data
, &declen
);
1603 memcpy(dctx
->IV
, ctx
.counter
, 4);
1606 memcpy(dctx
->TI
, data
, 4);
1609 memcpy(dctx
->sessionKeyEnc
, sessionkey
, CRYPTO_AES_BLOCK_SIZE
);
1610 memcpy(dctx
->sessionKeyMAC
, sessionkey
, CRYPTO_AES_BLOCK_SIZE
);
1611 dctx
->secureChannel
= secureChannel
;
1615 PrintAndLogEx(INFO
, "TI : %s", sprint_hex(data
, 4));
1616 PrintAndLogEx(INFO
, "pic : %s", sprint_hex(&data
[4], 6));
1617 PrintAndLogEx(INFO
, "pcd : %s", sprint_hex(&data
[10], 6));
1619 PrintAndLogEx(INFO
, "TI : %s", sprint_hex(dctx
->TI
, 4));
1621 PrintAndLogEx(INFO
, "session key : %s", sprint_hex(dctx
->sessionKeyEnc
, 16));
1628 int DesfireAuthenticate(DesfireContext_t
*dctx
, DesfireSecureChannel secureChannel
, bool verbose
) {
1629 if (dctx
->kdfAlgo
== MFDES_KDF_ALGO_AN10922
) {
1630 MifareKdfAn10922(dctx
, DCOMasterKey
, dctx
->kdfInput
, dctx
->kdfInputLen
);
1631 PrintAndLogEx(DEBUG
, " Derrived key: " _GREEN_("%s"), sprint_hex(dctx
->key
, desfire_get_key_block_length(dctx
->keyType
)));
1632 } else if (dctx
->kdfAlgo
== MFDES_KDF_ALGO_GALLAGHER
) {
1633 // We will overrite any provided KDF input since a gallagher specific KDF was requested.
1634 dctx
->kdfInputLen
= 11;
1636 if (mfdes_kdf_input_gallagher(dctx
->uid
, dctx
->uidlen
, dctx
->keyNum
, dctx
->selectedAID
, dctx
->kdfInput
, &dctx
->kdfInputLen
) != PM3_SUCCESS
) {
1637 PrintAndLogEx(FAILED
, "Could not generate Gallagher KDF input");
1639 PrintAndLogEx(DEBUG
, " KDF Input: " _YELLOW_("%s"), sprint_hex(dctx
->kdfInput
, dctx
->kdfInputLen
));
1641 MifareKdfAn10922(dctx
, DCOMasterKey
, dctx
->kdfInput
, dctx
->kdfInputLen
);
1642 PrintAndLogEx(DEBUG
, " Derrived key: " _GREEN_("%s"), sprint_hex(dctx
->key
, desfire_get_key_block_length(dctx
->keyType
)));
1645 if (dctx
->cmdSet
== DCCISO
&& secureChannel
!= DACEV2
)
1646 return DesfireAuthenticateISO(dctx
, secureChannel
, verbose
);
1648 if (secureChannel
== DACd40
|| secureChannel
== DACEV1
)
1649 return DesfireAuthenticateEV1(dctx
, secureChannel
, verbose
);
1651 if (secureChannel
== DACEV2
)
1652 return DesfireAuthenticateEV2(dctx
, secureChannel
, (DesfireIsAuthenticated(dctx
) == false), verbose
); // non first auth if there is a working secure channel
1654 if (secureChannel
== DACLRP
)
1655 return DesfireAuthenticateLRP(dctx
, secureChannel
, (DesfireIsAuthenticated(dctx
) == false), verbose
);
1660 bool DesfireCheckAuthCmd(DesfireISOSelectWay way
, uint32_t appID
, uint8_t keyNum
, uint8_t authcmd
, bool checklrp
) {
1661 size_t recv_len
= 0;
1662 uint8_t respcode
= 0;
1663 uint8_t recv_data
[256] = {0};
1665 DesfireContext_t dctx
= {0};
1666 dctx
.keyNum
= keyNum
;
1667 dctx
.commMode
= DCMPlain
;
1668 dctx
.cmdSet
= DCCNativeISO
;
1670 // if cant select - return false
1671 int res
= DesfireSelect(&dctx
, way
, appID
, NULL
);
1672 if (res
!= PM3_SUCCESS
)
1675 uint8_t data
[] = {keyNum
, 0x01, (checklrp
) ? 0x02 : 0x00};
1676 uint8_t datalen
= (authcmd
== MFDES_AUTHENTICATE_EV2F
) ? 3 : 1;
1677 res
= DesfireExchangeEx(false, &dctx
, authcmd
, data
, datalen
, &respcode
, recv_data
, &recv_len
, false, 0);
1681 return (res
== PM3_SUCCESS
&& respcode
== 0xaf && recv_len
== 17 && recv_data
[0] == 0x01);
1683 return (res
== PM3_SUCCESS
&& respcode
== 0xaf);
1686 static bool DesfireCheckISOAuthCmd(DesfireISOSelectWay way
, uint32_t appID
, char *dfname
, uint8_t keyNum
, DesfireCryptoAlgorithm keytype
) {
1688 DesfireContext_t dctx
= {0};
1689 dctx
.keyNum
= keyNum
;
1690 dctx
.commMode
= DCMPlain
;
1691 dctx
.cmdSet
= DCCISO
;
1693 int res
= DesfireSelect(&dctx
, way
, appID
, dfname
);
1694 if (res
!= PM3_SUCCESS
)
1697 bool app_level
= !DesfireMFSelected(way
, appID
);
1698 uint8_t rndlen
= DesfireGetRndLenForKey(keytype
);
1700 uint8_t piccrnd
[64] = {0};
1702 res
= DesfireISOGetChallenge(&dctx
, keytype
, piccrnd
, &xlen
);
1703 if (res
!= PM3_SUCCESS
|| xlen
!= rndlen
)
1706 uint8_t resp
[250] = {0};
1710 uint8_t p1
= DesfireKeyToISOKey(keytype
);
1711 uint8_t p2
= ((app_level
) ? 0x80 : 0x00) | keyNum
;
1712 res
= DesfireExchangeISO(false, &dctx
, (sAPDU_t
) {0x00, ISO7816_EXTERNAL_AUTHENTICATION
, p1
, p2
, rndlen
* 2, piccrnd
}, 0, resp
, &resplen
, &sw
);
1714 return (sw
== ISO7816_OK
|| sw
== ISO7816_SECURITY_STATUS_NOT_SATISFIED
);
1717 void DesfireCheckAuthCommands(DesfireISOSelectWay way
, uint32_t appID
, char *dfname
, uint8_t keyNum
, AuthCommandsChk_t
*authCmdCheck
) {
1718 memset(authCmdCheck
, 0, sizeof(AuthCommandsChk_t
));
1720 authCmdCheck
->auth
= DesfireCheckAuthCmd(way
, appID
, keyNum
, MFDES_AUTHENTICATE
, false);
1721 authCmdCheck
->authISO
= DesfireCheckAuthCmd(way
, appID
, keyNum
, MFDES_AUTHENTICATE_ISO
, false);
1722 authCmdCheck
->authAES
= DesfireCheckAuthCmd(way
, appID
, keyNum
, MFDES_AUTHENTICATE_AES
, false);
1723 authCmdCheck
->authEV2
= DesfireCheckAuthCmd(way
, appID
, keyNum
, MFDES_AUTHENTICATE_EV2F
, false);
1724 authCmdCheck
->authISONative
= DesfireCheckISOAuthCmd(way
, appID
, dfname
, keyNum
, T_DES
);
1725 authCmdCheck
->authLRP
= DesfireCheckAuthCmd(way
, appID
, keyNum
, MFDES_AUTHENTICATE_EV2F
, true);
1726 authCmdCheck
->checked
= true;
1729 void DesfireCheckAuthCommandsPrint(AuthCommandsChk_t
*authCmdCheck
) {
1730 PrintAndLogEx(SUCCESS
, " Auth.............. %s", authCmdCheck
->auth
? _GREEN_("YES") : _RED_("NO"));
1731 PrintAndLogEx(SUCCESS
, " Auth ISO.......... %s", authCmdCheck
->authISO
? _GREEN_("YES") : _RED_("NO"));
1732 PrintAndLogEx(SUCCESS
, " Auth AES.......... %s", authCmdCheck
->authAES
? _GREEN_("YES") : _RED_("NO"));
1733 PrintAndLogEx(SUCCESS
, " Auth Ev2.......... %s", authCmdCheck
->authEV2
? _GREEN_("YES") : _RED_("NO"));
1734 PrintAndLogEx(SUCCESS
, " Auth ISO Native... %s", authCmdCheck
->authISONative
? _GREEN_("YES") : _RED_("NO"));
1735 PrintAndLogEx(SUCCESS
, " Auth LRP.......... %s", authCmdCheck
->authLRP
? _GREEN_("YES") : _RED_("NO"));
1738 int DesfireFillPICCInfo(DesfireContext_t
*dctx
, PICCInfo_t
*PICCInfo
, bool deepmode
) {
1739 uint8_t buf
[250] = {0};
1742 uint32_t freemem
= 0;
1743 int res
= DesfireGetFreeMem(dctx
, &freemem
);
1744 if (res
== PM3_SUCCESS
)
1745 PICCInfo
->freemem
= freemem
;
1747 PICCInfo
->freemem
= 0xffffffff;
1749 PICCInfo
->keySettings
= 0;
1750 PICCInfo
->numKeysRaw
= 0;
1751 PICCInfo
->keyVersion0
= 0;
1752 res
= DesfireGetKeySettings(dctx
, buf
, &buflen
);
1753 if (res
== PM3_SUCCESS
&& buflen
>= 2) {
1754 PICCInfo
->keySettings
= buf
[0];
1755 PICCInfo
->numKeysRaw
= buf
[1];
1756 PICCInfo
->numberOfKeys
= PICCInfo
->numKeysRaw
& 0x1f;
1757 if (PICCInfo
->numKeysRaw
> 0) {
1758 uint8_t keyNum0
= 0;
1759 res
= DesfireGetKeyVersion(dctx
, &keyNum0
, 1, buf
, &buflen
);
1760 if (res
== PM3_SUCCESS
&& buflen
> 0) {
1761 PICCInfo
->keyVersion0
= buf
[0];
1766 // field on-off zone
1768 DesfireCheckAuthCommands(ISW6bAID
, 0x000000, NULL
, 0, &PICCInfo
->authCmdCheck
);
1773 static int AppListSearchAID(uint32_t appNum
, AppListS AppList
, size_t appcount
) {
1774 for (int i
= 0; i
< appcount
; i
++)
1775 if (AppList
[i
].appNum
== appNum
)
1781 int DesfireFillAppList(DesfireContext_t
*dctx
, PICCInfo_t
*PICCInfo
, AppListS appList
, bool deepmode
, bool readFiles
, bool fillAppSettings
) {
1782 uint8_t buf
[250] = {0};
1785 int res
= DesfireGetAIDList(dctx
, buf
, &buflen
);
1786 if (res
!= PM3_SUCCESS
) {
1787 PrintAndLogEx(ERR
, "Desfire GetAIDList command " _RED_("error") ". Result: %d", res
);
1792 PICCInfo
->appCount
= buflen
/ 3;
1793 for (int i
= 0; i
< buflen
; i
+= 3)
1794 appList
[i
/ 3].appNum
= DesfireAIDByteToUint(&buf
[i
]);
1796 // result bytes: 3, 2, 1-16. total record size = 24
1797 res
= DesfireGetDFList(dctx
, buf
, &buflen
);
1798 if (res
!= PM3_SUCCESS
) {
1799 PrintAndLogEx(WARNING
, "Desfire GetDFList command " _RED_("error") ". Result: %d", res
);
1800 } else if (buflen
> 0) {
1801 for (int i
= 0; i
< buflen
; i
++) {
1802 int indx
= AppListSearchAID(DesfireAIDByteToUint(&buf
[i
* 24 + 1]), appList
, PICCInfo
->appCount
);
1804 appList
[indx
].appISONum
= MemLeToUint2byte(&buf
[i
* 24 + 1 + 3]);
1806 appList
[indx
].appDFName
,
1807 &buf
[i
* 24 + 1 + 5],
1808 // str_nlen((char *)&buf[i * 24 + 1 + 5], 16)
1815 // field on-off zone
1816 DesfireFillPICCInfo(dctx
, PICCInfo
, deepmode
);
1818 if (fillAppSettings
&& PICCInfo
->appCount
> 0) {
1819 for (int i
= 0; i
< PICCInfo
->appCount
; i
++) {
1821 res
= DesfireSelectAIDHex(dctx
, appList
[i
].appNum
, false, 0);
1823 res
= DesfireSelectAIDHexNoFieldOn(dctx
, appList
[i
].appNum
);
1824 if (res
!= PM3_SUCCESS
)
1827 DesfireGetKeySettings(dctx
, buf
, &buflen
);
1828 if (res
== PM3_SUCCESS
&& buflen
>= 2) {
1829 appList
[i
].keySettings
= buf
[0];
1830 appList
[i
].numKeysRaw
= buf
[1];
1831 appList
[i
].numberOfKeys
= appList
[i
].numKeysRaw
& 0x1f;
1832 appList
[i
].isoFileIDEnabled
= ((appList
[i
].numKeysRaw
& 0x20) != 0);
1833 appList
[i
].keyType
= DesfireKeyTypeToAlgo(appList
[i
].numKeysRaw
>> 6);
1835 if (appList
[i
].numberOfKeys
> 0)
1836 for (uint8_t keyn
= 0; keyn
< appList
[i
].numberOfKeys
; keyn
++) {
1837 res
= DesfireGetKeyVersion(dctx
, &keyn
, 1, buf
, &buflen
);
1838 if (res
== PM3_SUCCESS
&& buflen
> 0) {
1839 appList
[i
].keyVersions
[keyn
] = buf
[0];
1843 appList
[i
].filesReaded
= false;
1845 res
= DesfireFillFileList(dctx
, appList
[i
].fileList
, &appList
[i
].filesCount
, &appList
[i
].isoPresent
);
1846 appList
[i
].filesReaded
= (res
== PM3_SUCCESS
);
1852 // field on-off zone
1853 if (fillAppSettings
&& PICCInfo
->appCount
> 0 && deepmode
) {
1854 for (int i
= 0; i
< PICCInfo
->appCount
; i
++) {
1855 DesfireCheckAuthCommands(ISW6bAID
, appList
[i
].appNum
, appList
[i
].appDFName
, 0, &appList
[i
].authCmdCheck
);
1862 void DesfirePrintPICCInfo(DesfireContext_t
*dctx
, PICCInfo_t
*PICCInfo
) {
1863 PrintAndLogEx(SUCCESS
, "------------------------------------ " _CYAN_("PICC level") " -------------------------------------");
1864 if (PICCInfo
->freemem
== 0xffffffff)
1865 PrintAndLogEx(SUCCESS
, "Applications count: " _GREEN_("%zu") " free memory " _YELLOW_("n/a"), PICCInfo
->appCount
);
1867 PrintAndLogEx(SUCCESS
, "Applications count: " _GREEN_("%zu") " free memory " _GREEN_("%d") " bytes", PICCInfo
->appCount
, PICCInfo
->freemem
);
1868 if (PICCInfo
->authCmdCheck
.checked
) {
1869 PrintAndLogEx(SUCCESS
, "PICC level auth commands: ");
1870 DesfireCheckAuthCommandsPrint(&PICCInfo
->authCmdCheck
);
1872 if (PICCInfo
->numberOfKeys
> 0) {
1873 PrintKeySettings(PICCInfo
->keySettings
, PICCInfo
->numKeysRaw
, false, true);
1874 PrintAndLogEx(SUCCESS
, "PICC key 0 version: %d (0x%02x)", PICCInfo
->keyVersion0
, PICCInfo
->keyVersion0
);
1878 void DesfirePrintAppList(DesfireContext_t
*dctx
, PICCInfo_t
*PICCInfo
, AppListS appList
) {
1879 if (PICCInfo
->appCount
== 0)
1882 PrintAndLogEx(NORMAL
, "");
1883 PrintAndLogEx(SUCCESS
, "--------------------------------- " _CYAN_("Applications list") " ---------------------------------");
1885 for (int i
= 0; i
< PICCInfo
->appCount
; i
++) {
1886 PrintAndLogEx(SUCCESS
, _CYAN_("Application number: 0x%02X"), appList
[i
].appNum
);
1887 PrintAndLogEx(SUCCESS
, " ISO id.... " _GREEN_("0x%04X"), appList
[i
].appISONum
);
1888 PrintAndLogEx(SUCCESS
, " DF name... " _GREEN_("%s") " ( %s)", appList
[i
].appDFName
, sprint_hex((uint8_t *)appList
[i
].appDFName
, sizeof(appList
[i
].appDFName
)));
1890 DesfirePrintAIDFunctions(appList
[i
].appNum
);
1892 if (PICCInfo
->authCmdCheck
.checked
) {
1893 PrintAndLogEx(SUCCESS
, "Auth commands: ");
1894 DesfireCheckAuthCommandsPrint(&appList
[i
].authCmdCheck
);
1895 PrintAndLogEx(SUCCESS
, "");
1898 if (appList
[i
].numberOfKeys
> 0) {
1899 PrintKeySettings(appList
[i
].keySettings
, appList
[i
].numKeysRaw
, true, true);
1901 if (appList
[i
].numberOfKeys
> 0) {
1902 PrintAndLogEx(SUCCESS
, "Key versions [0..%d]: " NOLF
, appList
[i
].numberOfKeys
- 1);
1903 for (uint8_t keyn
= 0; keyn
< appList
[i
].numberOfKeys
; keyn
++) {
1904 PrintAndLogEx(NORMAL
, "%s %02x" NOLF
, (keyn
== 0) ? "" : ",", appList
[i
].keyVersions
[keyn
]);
1906 PrintAndLogEx(NORMAL
, "\n");
1909 if (appList
[i
].filesReaded
) {
1910 PrintAndLogEx(SUCCESS
, "Application have " _GREEN_("%zu") " files", appList
[i
].filesCount
);
1912 if (appList
[i
].filesCount
> 0) {
1913 for (int fnum
= 0; fnum
< appList
[i
].filesCount
; fnum
++) {
1914 PrintAndLogEx(NORMAL
, "");
1915 PrintAndLogEx(SUCCESS
, "--------------------------------- " _CYAN_("File %02x") " ----------------------------------", appList
[i
].fileList
[fnum
].fileNum
);
1916 PrintAndLogEx(SUCCESS
, "File ID : " _GREEN_("%02x"), appList
[i
].fileList
[fnum
].fileNum
);
1917 if (appList
[i
].isoPresent
) {
1918 if (appList
[i
].fileList
[fnum
].fileISONum
!= 0)
1919 PrintAndLogEx(SUCCESS
, "File ISO ID : %04x", appList
[i
].fileList
[fnum
].fileISONum
);
1921 PrintAndLogEx(SUCCESS
, "File ISO ID : " _YELLOW_("n/a"));
1923 DesfirePrintFileSettingsExtended(&appList
[i
].fileList
[fnum
].fileSettings
);
1926 PrintAndLogEx(NORMAL
, "");
1932 static int DesfireCommandEx(DesfireContext_t
*dctx
, uint8_t cmd
, uint8_t *data
, size_t datalen
, uint8_t *resp
, size_t *resplen
, int checklength
, size_t splitbysize
) {
1937 uint8_t respcode
= 0xFF;
1939 uint8_t *xresp
= calloc(DESFIRE_BUFFER_SIZE
, 1);
1940 if (xresp
== NULL
) {
1944 size_t xresplen
= 0;
1945 int res
= DesfireExchangeEx(false, dctx
, cmd
, data
, datalen
, &respcode
, xresp
, &xresplen
, true, splitbysize
);
1946 if (res
!= PM3_SUCCESS
) {
1951 if (respcode
!= MFDES_S_OPERATION_OK
) {
1953 return PM3_EAPDU_FAIL
;
1956 if (checklength
>= 0 && xresplen
!= checklength
) {
1958 return PM3_EAPDU_FAIL
;
1962 *resplen
= xresplen
;
1966 memcpy(resp
, xresp
, (splitbysize
== 0) ? xresplen
: xresplen
* splitbysize
);
1973 static int DesfireCommand(DesfireContext_t
*dctx
, uint8_t cmd
, uint8_t *data
, size_t datalen
, uint8_t *resp
, size_t *resplen
, int checklength
) {
1974 return DesfireCommandEx(dctx
, cmd
, data
, datalen
, resp
, resplen
, checklength
, 0);
1977 static int DesfireCommandNoData(DesfireContext_t
*dctx
, uint8_t cmd
) {
1978 return DesfireCommand(dctx
, cmd
, NULL
, 0, NULL
, NULL
, 0);
1981 static int DesfireCommandTxData(DesfireContext_t
*dctx
, uint8_t cmd
, uint8_t *data
, size_t datalen
) {
1982 return DesfireCommand(dctx
, cmd
, data
, datalen
, NULL
, NULL
, 0);
1985 static int DesfireCommandRxData(DesfireContext_t
*dctx
, uint8_t cmd
, uint8_t *resp
, size_t *resplen
, int checklength
) {
1986 return DesfireCommand(dctx
, cmd
, NULL
, 0, resp
, resplen
, checklength
);
1989 int DesfireFormatPICC(DesfireContext_t
*dctx
) {
1990 return DesfireCommandNoData(dctx
, MFDES_FORMAT_PICC
);
1993 int DesfireGetFreeMem(DesfireContext_t
*dctx
, uint32_t *freemem
) {
1996 uint8_t resp
[257] = {0};
1998 int res
= DesfireCommandRxData(dctx
, MFDES_GET_FREE_MEMORY
, resp
, &resplen
, 3);
1999 if (res
== PM3_SUCCESS
) {
2000 *freemem
= DesfireAIDByteToUint(resp
);
2005 int DesfireReadSignature(DesfireContext_t
*dctx
, uint8_t sid
, uint8_t *resp
, size_t *resplen
) {
2008 uint8_t xresp
[257] = {0};
2009 size_t xresplen
= 0;
2010 uint8_t respcode
= 0xff;
2012 int res
= DesfireExchange(dctx
, MFDES_READSIG
, &sid
, 1, &respcode
, xresp
, &xresplen
);
2013 if (res
!= PM3_SUCCESS
) {
2017 if (respcode
!= 0x90) {
2018 return PM3_EAPDU_FAIL
;
2021 memcpy(resp
, xresp
, xresplen
);
2023 *resplen
= xresplen
;
2028 int DesfireGetUID(DesfireContext_t
*dctx
, uint8_t *resp
, size_t *resplen
) {
2029 return DesfireCommandRxData(dctx
, MFDES_GET_UID
, resp
, resplen
, -1);
2032 int DesfireGetAIDList(DesfireContext_t
*dctx
, uint8_t *resp
, size_t *resplen
) {
2033 return DesfireCommandRxData(dctx
, MFDES_GET_APPLICATION_IDS
, resp
, resplen
, -1);
2036 int DesfireGetDFList(DesfireContext_t
*dctx
, uint8_t *resp
, size_t *resplen
) {
2037 return DesfireCommandEx(dctx
, MFDES_GET_DF_NAMES
, NULL
, 0, resp
, resplen
, -1, 24);
2040 int DesfireCreateApplication(DesfireContext_t
*dctx
, uint8_t *appdata
, size_t appdatalen
) {
2041 return DesfireCommandTxData(dctx
, MFDES_CREATE_APPLICATION
, appdata
, appdatalen
);
2044 int DesfireDeleteApplication(DesfireContext_t
*dctx
, uint32_t aid
) {
2045 uint8_t data
[3] = {0};
2046 DesfireAIDUintToByte(aid
, data
);
2047 return DesfireCommandTxData(dctx
, MFDES_DELETE_APPLICATION
, data
, sizeof(data
));
2050 int DesfireGetKeySettings(DesfireContext_t
*dctx
, uint8_t *resp
, size_t *resplen
) {
2051 return DesfireCommandRxData(dctx
, MFDES_GET_KEY_SETTINGS
, resp
, resplen
, -1);
2054 int DesfireGetKeyVersion(DesfireContext_t
*dctx
, uint8_t *data
, size_t len
, uint8_t *resp
, size_t *resplen
) {
2055 return DesfireCommand(dctx
, MFDES_GET_KEY_VERSION
, data
, len
, resp
, resplen
, -1);
2058 int DesfireChangeKeySettings(DesfireContext_t
*dctx
, uint8_t *data
, size_t len
) {
2059 return DesfireCommandTxData(dctx
, MFDES_CHANGE_KEY_SETTINGS
, data
, len
);
2062 int DesfireChangeKeyCmd(DesfireContext_t
*dctx
, uint8_t *data
, size_t datalen
, uint8_t *resp
, size_t *resplen
) {
2063 return DesfireCommand(dctx
, MFDES_CHANGE_KEY
, data
, datalen
, resp
, resplen
, -1);
2066 int DesfireSetConfigurationCmd(DesfireContext_t
*dctx
, uint8_t *data
, size_t len
, uint8_t *resp
, size_t *resplen
) {
2067 return DesfireCommand(dctx
, MFDES_CHANGE_CONFIGURATION
, data
, len
, resp
, resplen
, -1);
2070 int DesfireChangeFileSettings(DesfireContext_t
*dctx
, uint8_t *data
, size_t datalen
) {
2071 return DesfireCommandTxData(dctx
, MFDES_CHANGE_FILE_SETTINGS
, data
, datalen
);
2074 int DesfireGetFileIDList(DesfireContext_t
*dctx
, uint8_t *resp
, size_t *resplen
) {
2075 return DesfireCommandRxData(dctx
, MFDES_GET_FILE_IDS
, resp
, resplen
, -1);
2078 int DesfireGetFileISOIDList(DesfireContext_t
*dctx
, uint8_t *resp
, size_t *resplen
) {
2079 return DesfireCommandRxData(dctx
, MFDES_GET_ISOFILE_IDS
, resp
, resplen
, -1);
2082 int DesfireGetFileSettings(DesfireContext_t
*dctx
, uint8_t fileid
, uint8_t *resp
, size_t *resplen
) {
2083 return DesfireCommand(dctx
, MFDES_GET_FILE_SETTINGS
, &fileid
, 1, resp
, resplen
, -1);
2086 int DesfireFileSettingsStruct(DesfireContext_t
*dctx
, uint8_t fileid
, FileSettings_t
*fsettings
) {
2087 uint8_t resp
[250] = {0};
2089 int res
= DesfireGetFileSettings(dctx
, fileid
, resp
, &resplen
);
2090 if (res
== PM3_SUCCESS
&& resplen
> 0 && fsettings
!= NULL
)
2091 DesfireFillFileSettings(resp
, resplen
, fsettings
);
2096 int DesfireFillFileList(DesfireContext_t
*dctx
, FileList_t FileList
, size_t *filescount
, bool *isopresent
) {
2097 uint8_t buf
[APDU_RES_LEN
] = {0};
2101 *isopresent
= false;
2102 memset(FileList
, 0, sizeof(FileList_t
));
2104 int res
= DesfireGetFileIDList(dctx
, buf
, &buflen
);
2105 if (res
!= PM3_SUCCESS
) {
2106 PrintAndLogEx(ERR
, "Desfire GetFileIDList command " _RED_("error") ". Result: %d", res
);
2113 for (int i
= 0; i
< buflen
; i
++) {
2114 FileList
[i
].fileNum
= buf
[i
];
2115 DesfireFileSettingsStruct(dctx
, FileList
[i
].fileNum
, &FileList
[i
].fileSettings
);
2117 *filescount
= buflen
;
2120 res
= DesfireGetFileISOIDList(dctx
, buf
, &buflen
);
2121 if (res
!= PM3_SUCCESS
) {
2122 PrintAndLogEx(ERR
, "Desfire GetFileISOIDList command " _RED_("error") ". Result: %d", res
);
2127 for (int i
= 0; i
< *filescount
; i
++) {
2128 if (FileList
[i
].fileSettings
.fileType
!= 0x02 && FileList
[i
].fileSettings
.fileType
!= 0x05) {
2129 FileList
[i
].fileISONum
= MemLeToUint2byte(&buf
[isoindx
* 2]);
2134 if (isoindx
* 2 != buflen
)
2135 PrintAndLogEx(WARNING
, "Wrong ISO ID list length. must be %zu but %zu", buflen
, isoindx
* 2);
2137 PrintAndLogEx(WARNING
, "ISO ID list returned no data");
2140 *isopresent
= (isoindx
> 0);
2145 int DesfireCreateFile(DesfireContext_t
*dctx
, uint8_t ftype
, uint8_t *fdata
, size_t fdatalen
, bool checklen
) {
2146 const DesfireCreateFileCommands_t
*rcmd
= GetDesfireFileCmdRec(ftype
);
2149 if (checklen
&& fdatalen
!= (rcmd
->createlen
+ 1) && fdatalen
!= (rcmd
->createlen
+ 1 + (rcmd
->mayHaveISOfid
? 2 : 0)))
2152 return DesfireCommandTxData(dctx
, rcmd
->cmd
, fdata
, fdatalen
);
2155 int DesfireDeleteFile(DesfireContext_t
*dctx
, uint8_t fnum
) {
2156 return DesfireCommandTxData(dctx
, MFDES_DELETE_FILE
, &fnum
, 1);
2159 int DesfireClearRecordFile(DesfireContext_t
*dctx
, uint8_t fnum
) {
2160 return DesfireCommandTxData(dctx
, MFDES_CLEAR_RECORD_FILE
, &fnum
, 1);
2163 int DesfireCommitReaderID(DesfireContext_t
*dctx
, uint8_t *readerid
, size_t readeridlen
, uint8_t *resp
, size_t *resplen
) {
2164 uint8_t rid
[16] = {0};
2165 // command use 16b reader id only
2166 memcpy(rid
, readerid
, MIN(readeridlen
, 16));
2167 return DesfireCommand(dctx
, MFDES_COMMIT_READER_ID
, rid
, 16, resp
, resplen
, -1);
2170 int DesfireCommitTransactionEx(DesfireContext_t
*dctx
, bool enable_options
, uint8_t options
, uint8_t *resp
, size_t *resplen
) {
2172 return DesfireCommand(dctx
, MFDES_COMMIT_TRANSACTION
, &options
, 1, resp
, resplen
, -1);
2174 return DesfireCommandNoData(dctx
, MFDES_COMMIT_TRANSACTION
);
2177 int DesfireCommitTransaction(DesfireContext_t
*dctx
, bool enable_options
, uint8_t options
) {
2178 uint8_t resp
[250] = {0};
2180 return DesfireCommitTransactionEx(dctx
, enable_options
, options
, resp
, &resplen
);
2183 int DesfireAbortTransaction(DesfireContext_t
*dctx
) {
2184 return DesfireCommandNoData(dctx
, MFDES_ABORT_TRANSACTION
);
2187 int DesfireReadFile(DesfireContext_t
*dctx
, uint8_t fnum
, uint32_t offset
, uint32_t len
, uint8_t *resp
, size_t *resplen
) {
2188 uint8_t data
[10] = {0};
2190 Uint3byteToMemLe(&data
[1], offset
);
2191 Uint3byteToMemLe(&data
[4], len
);
2192 return DesfireCommand(dctx
, (dctx
->isoChaining
) ? MFDES_READ_DATA2
: MFDES_READ_DATA
, data
, 7, resp
, resplen
, -1);
2195 int DesfireWriteFile(DesfireContext_t
*dctx
, uint8_t fnum
, uint32_t offset
, uint32_t len
, uint8_t *data
) {
2196 uint8_t xdata
[1024] = {0};
2198 Uint3byteToMemLe(&xdata
[1], offset
);
2199 Uint3byteToMemLe(&xdata
[4], len
);
2200 memcpy(&xdata
[7], data
, len
);
2202 return DesfireCommandTxData(dctx
, (dctx
->isoChaining
) ? MFDES_WRITE_DATA2
: MFDES_WRITE_DATA
, xdata
, 7 + len
);
2205 int DesfireValueFileOperations(DesfireContext_t
*dctx
, uint8_t fid
, uint8_t operation
, uint32_t *value
) {
2206 uint8_t data
[10] = {0};
2208 size_t datalen
= (operation
== MFDES_GET_VALUE
) ? 1 : 5;
2210 Uint4byteToMemLe(&data
[1], *value
);
2212 uint8_t resp
[250] = {0};
2215 int res
= DesfireCommand(dctx
, operation
, data
, datalen
, resp
, &resplen
, -1);
2217 if (resplen
== 4 && value
) {
2218 *value
= MemLeToUint4byte(resp
);
2223 int DesfireReadRecords(DesfireContext_t
*dctx
, uint8_t fnum
, uint32_t recnum
, uint32_t reccount
, uint8_t *resp
, size_t *resplen
) {
2224 uint8_t data
[10] = {0};
2226 Uint3byteToMemLe(&data
[1], recnum
);
2227 Uint3byteToMemLe(&data
[4], reccount
);
2229 return DesfireCommand(dctx
, (dctx
->isoChaining
) ? MFDES_READ_RECORDS2
: MFDES_READ_RECORDS
, data
, 7, resp
, resplen
, -1);
2232 int DesfireWriteRecord(DesfireContext_t
*dctx
, uint8_t fnum
, uint32_t offset
, uint32_t len
, uint8_t *data
) {
2233 uint8_t xdata
[1024] = {0};
2235 Uint3byteToMemLe(&xdata
[1], offset
);
2236 Uint3byteToMemLe(&xdata
[4], len
);
2237 memcpy(&xdata
[7], data
, len
);
2239 return DesfireCommandTxData(dctx
, (dctx
->isoChaining
) ? MFDES_WRITE_RECORD2
: MFDES_WRITE_RECORD
, xdata
, 7 + len
);
2242 int DesfireUpdateRecord(DesfireContext_t
*dctx
, uint8_t fnum
, uint32_t recnum
, uint32_t offset
, uint32_t len
, uint8_t *data
) {
2243 uint8_t xdata
[1024] = {0};
2245 Uint3byteToMemLe(&xdata
[1], recnum
);
2246 Uint3byteToMemLe(&xdata
[4], offset
);
2247 Uint3byteToMemLe(&xdata
[7], len
);
2248 memcpy(&xdata
[10], data
, len
);
2250 return DesfireCommandTxData(dctx
, (dctx
->isoChaining
) ? MFDES_UPDATE_RECORD2
: MFDES_UPDATE_RECORD
, xdata
, 10 + len
);
2253 static void PrintKeySettingsPICC(uint8_t keysettings
, uint8_t numkeys
, bool print2ndbyte
) {
2254 PrintAndLogEx(SUCCESS
, "PICC level rights:");
2255 PrintAndLogEx(SUCCESS
, "[%c...] CMK Configuration changeable : %s", (keysettings
& (1 << 3)) ? '1' : '0', (keysettings
& (1 << 3)) ? _GREEN_("YES") : _RED_("NO (frozen)"));
2256 PrintAndLogEx(SUCCESS
, "[.%c..] CMK required for create/delete : %s", (keysettings
& (1 << 2)) ? '1' : '0', (keysettings
& (1 << 2)) ? _GREEN_("NO") : "YES");
2257 PrintAndLogEx(SUCCESS
, "[..%c.] Directory list access with CMK : %s", (keysettings
& (1 << 1)) ? '1' : '0', (keysettings
& (1 << 1)) ? _GREEN_("NO") : "YES");
2258 PrintAndLogEx(SUCCESS
, "[...%c] CMK is changeable : %s", (keysettings
& (1 << 0)) ? '1' : '0', (keysettings
& (1 << 0)) ? _GREEN_("YES") : _RED_("NO (frozen)"));
2259 PrintAndLogEx(SUCCESS
, "");
2262 DesfirePrintCardKeyType(numkeys
>> 6);
2263 PrintAndLogEx(SUCCESS
, "key count: %d", numkeys
& 0x0f);
2267 static void PrintKeySettingsApp(uint8_t keysettings
, uint8_t numkeys
, bool print2ndbyte
) {
2269 PrintAndLogEx(SUCCESS
, "Application level rights:");
2270 uint8_t rights
= ((keysettings
>> 4) & 0x0F);
2273 PrintAndLogEx(SUCCESS
, "-- AMK authentication is necessary to change any key (default)");
2276 PrintAndLogEx(SUCCESS
, "-- Authentication with the key to be changed (same KeyNo) is necessary to change a key");
2279 PrintAndLogEx(SUCCESS
, "-- All keys (except AMK,see Bit0) within this application are frozen");
2282 PrintAndLogEx(SUCCESS
,
2283 "-- Authentication with the specified key " _YELLOW_("(0x%02x)") " is necessary to change any key.\n"
2284 "A change key and a PICC master key (CMK) can only be changed after authentication with the master key.\n"
2285 "For keys other then the master or change key, an authentication with the same key is needed.",
2291 PrintAndLogEx(SUCCESS
, "[%c...] AMK Configuration changeable : %s", (keysettings
& (1 << 3)) ? '1' : '0', (keysettings
& (1 << 3)) ? _GREEN_("YES") : _RED_("NO (frozen)"));
2292 PrintAndLogEx(SUCCESS
, "[.%c..] AMK required for create/delete : %s", (keysettings
& (1 << 2)) ? '1' : '0', (keysettings
& (1 << 2)) ? _GREEN_("NO") : "YES");
2293 PrintAndLogEx(SUCCESS
, "[..%c.] Directory list access with AMK : %s", (keysettings
& (1 << 1)) ? '1' : '0', (keysettings
& (1 << 1)) ? _GREEN_("NO") : "YES");
2294 PrintAndLogEx(SUCCESS
, "[...%c] AMK is changeable : %s", (keysettings
& (1 << 0)) ? '1' : '0', (keysettings
& (1 << 0)) ? _GREEN_("YES") : _RED_("NO (frozen)"));
2295 PrintAndLogEx(SUCCESS
, "");
2298 DesfirePrintCardKeyType(numkeys
>> 6);
2299 PrintAndLogEx(SUCCESS
, "key count: %d", numkeys
& 0x0f);
2301 PrintAndLogEx(SUCCESS
, "iso file id: enabled");
2302 PrintAndLogEx(SUCCESS
, "");
2306 void PrintKeySettings(uint8_t keysettings
, uint8_t numkeys
, bool applevel
, bool print2ndbyte
) {
2308 PrintKeySettingsApp(keysettings
, numkeys
, print2ndbyte
);
2310 PrintKeySettingsPICC(keysettings
, numkeys
, print2ndbyte
);
2313 static const char *DesfireUnknownStr
= "unknown";
2314 static const char *DesfireDisabledStr
= "disabled";
2315 static const char *DesfireFreeStr
= "free";
2316 static const char *DesfireNAStr
= "n/a";
2317 static const DesfireCreateFileCommands_t DesfireFileCommands
[] = {
2318 {0x00, "Standard data", MFDES_CREATE_STD_DATA_FILE
, 6, 6, true},
2319 {0x01, "Backup data", MFDES_CREATE_BACKUP_DATA_FILE
, 6, 6, true},
2320 {0x02, "Value", MFDES_CREATE_VALUE_FILE
, 16, 16, false},
2321 {0x03, "Linear Record", MFDES_CREATE_LINEAR_RECORD_FILE
, 12, 9, true},
2322 {0x04, "Cyclic Record", MFDES_CREATE_CYCLIC_RECORD_FILE
, 12, 9, true},
2323 {0x05, "Transaction MAC", MFDES_CREATE_TRANS_MAC_FILE
, 5, 21, false},
2326 const DesfireCreateFileCommands_t
*GetDesfireFileCmdRec(uint8_t type
) {
2327 for (int i
= 0; i
< ARRAYLEN(DesfireFileCommands
); i
++) {
2328 if (DesfireFileCommands
[i
].id
== type
) {
2329 return &DesfireFileCommands
[i
];
2335 const char *GetDesfireFileType(uint8_t type
) {
2336 const DesfireCreateFileCommands_t
*res
= GetDesfireFileCmdRec(type
);
2340 return DesfireUnknownStr
;
2343 static const char *DesfireCommunicationModes
[] = {
2350 static const char *GetDesfireCommunicationMode(uint8_t mode
) {
2351 if (mode
< ARRAYLEN(DesfireCommunicationModes
))
2352 return DesfireCommunicationModes
[mode
];
2354 return DesfireUnknownStr
;
2357 static const char *DesfireKeyTypeStr
[] = {
2364 static const char *GetDesfireKeyType(uint8_t keytype
) {
2365 if (keytype
< ARRAYLEN(DesfireKeyTypeStr
))
2366 return DesfireKeyTypeStr
[keytype
];
2368 return DesfireUnknownStr
;
2371 const char *GetDesfireAccessRightStr(uint8_t right
) {
2373 if (right
<= 0x0d) {
2374 static char int_access_str
[200];
2375 snprintf(int_access_str
, sizeof(int_access_str
), "key 0x%02x", right
);
2376 return int_access_str
;
2380 return DesfireFreeStr
;
2383 return DesfireDisabledStr
;
2385 return DesfireUnknownStr
;
2388 const char *AccessRightShortStr
[] = {
2407 const char *GetDesfireAccessRightShortStr(uint8_t right
) {
2409 return DesfireNAStr
;
2412 return AccessRightShortStr
[right
];
2415 void DesfireEncodeFileAcessMode(uint8_t *mode
, uint8_t r
, uint8_t w
, uint8_t rw
, uint8_t ch
) {
2416 mode
[0] = (ch
& 0x0f) | ((rw
<< 4) & 0xf0);
2417 mode
[1] = (w
& 0x0f) | ((r
<< 4) & 0xf0);
2420 void DesfireDecodeFileAcessMode(const uint8_t *mode
, uint8_t *r
, uint8_t *w
, uint8_t *rw
, uint8_t *ch
) {
2423 *r
= (mode
[1] >> 4) & 0x0F; // hi 2b
2426 *w
= mode
[1] & 0x0F;
2429 *rw
= (mode
[0] >> 4) & 0x0F; // low 2b
2432 *ch
= mode
[0] & 0x0F;
2435 void DesfirePrintAccessRight(uint8_t *data
) {
2436 uint8_t r
= 0, w
= 0, rw
= 0, ch
= 0;
2437 DesfireDecodeFileAcessMode(data
, &r
, &w
, &rw
, &ch
);
2438 PrintAndLogEx(SUCCESS
, " read......... %s", GetDesfireAccessRightStr(r
));
2439 PrintAndLogEx(SUCCESS
, " write........ %s", GetDesfireAccessRightStr(w
));
2440 PrintAndLogEx(SUCCESS
, " read/write... %s", GetDesfireAccessRightStr(rw
));
2441 PrintAndLogEx(SUCCESS
, " change....... %s", GetDesfireAccessRightStr(ch
));
2444 void DesfireFillFileSettings(uint8_t *data
, size_t datalen
, FileSettings_t
*fsettings
) {
2445 if (fsettings
== NULL
)
2448 memset(fsettings
, 0, sizeof(FileSettings_t
));
2453 fsettings
->fileType
= data
[0];
2454 fsettings
->fileOption
= data
[1];
2455 fsettings
->fileCommMode
= data
[1] & 0x03;
2456 fsettings
->commMode
= DesfireFileCommModeToCommMode(fsettings
->fileCommMode
);
2457 fsettings
->additionalAccessRightsEn
= ((data
[1] & 0x80) != 0);
2458 fsettings
->rawAccessRights
= MemLeToUint2byte(&data
[2]);
2459 DesfireDecodeFileAcessMode(&data
[2], &fsettings
->rAccess
, &fsettings
->wAccess
, &fsettings
->rwAccess
, &fsettings
->chAccess
);
2462 switch (fsettings
->fileType
) {
2465 fsettings
->fileSize
= MemLeToUint3byte(&data
[4]);
2470 fsettings
->lowerLimit
= MemLeToUint4byte(&data
[4]);
2471 fsettings
->upperLimit
= MemLeToUint4byte(&data
[8]);
2472 fsettings
->value
= MemLeToUint4byte(&data
[12]);
2473 fsettings
->limitedCredit
= data
[16];
2479 fsettings
->recordSize
= MemLeToUint3byte(&data
[4]);
2480 fsettings
->maxRecordCount
= MemLeToUint3byte(&data
[7]);
2481 fsettings
->curRecordCount
= MemLeToUint3byte(&data
[10]);
2486 fsettings
->keyType
= data
[4];
2487 fsettings
->keyVersion
= data
[5];
2495 if (fsettings
->additionalAccessRightsEn
&& reclen
> 0 && datalen
> reclen
&& datalen
== reclen
+ data
[reclen
] * 2) {
2496 fsettings
->additionalAccessRightsLength
= data
[reclen
];
2498 for (int i
= 0; i
< fsettings
->additionalAccessRightsLength
; i
++) {
2499 fsettings
->additionalAccessRights
[i
] = MemLeToUint2byte(&data
[reclen
+ 1 + i
* 2]);
2504 static void DesfirePrintShortFileTypeSettings(FileSettings_t
*fsettings
) {
2505 switch (fsettings
->fileType
) {
2508 PrintAndLogEx(NORMAL
, "Size " _YELLOW_("%d") " / " _YELLOW_("0x%X") NOLF
, fsettings
->fileSize
, fsettings
->fileSize
);
2512 PrintAndLogEx(NORMAL
, "Value [%d .. %d] lim cred: 0x%02x (%d [0x%x]) " NOLF
,
2513 fsettings
->lowerLimit
,
2514 fsettings
->upperLimit
,
2515 fsettings
->limitedCredit
,
2523 PrintAndLogEx(NORMAL
, "Rec cnt %d/%d size: %d [0x%x]b " NOLF
,
2524 fsettings
->curRecordCount
,
2525 fsettings
->maxRecordCount
,
2526 fsettings
->recordSize
,
2527 fsettings
->recordSize
2532 PrintAndLogEx(NORMAL
, "Key type: 0x%02x ver: 0x%02x " NOLF
, fsettings
->keyType
, fsettings
->keyVersion
);
2541 void DesfirePrintFileSettingsOneLine(FileSettings_t
*fsettings
) {
2542 PrintAndLogEx(NORMAL
, "(%-5s) " NOLF
, GetDesfireCommunicationMode(fsettings
->fileCommMode
));
2543 PrintAndLogEx(NORMAL
, "[0x%02x] " _CYAN_("%-13s ") NOLF
, fsettings
->fileType
, GetDesfireFileType(fsettings
->fileType
));
2545 DesfirePrintShortFileTypeSettings(fsettings
);
2547 PrintAndLogEx(NORMAL
, "(%s %s %s %s)",
2548 GetDesfireAccessRightShortStr(fsettings
->rAccess
),
2549 GetDesfireAccessRightShortStr(fsettings
->wAccess
),
2550 GetDesfireAccessRightShortStr(fsettings
->rwAccess
),
2551 GetDesfireAccessRightShortStr(fsettings
->chAccess
));
2554 void DesfirePrintFileSettingsTable(bool printheader
, uint8_t id
, bool isoidavail
, uint16_t isoid
, FileSettings_t
*fsettings
) {
2556 PrintAndLogEx(SUCCESS
, " ID |ISO ID| File type | Mode | Rights: raw, r w rw ch | File settings");
2557 PrintAndLogEx(SUCCESS
, "----------------------------------------------------------------------------------------------------------");
2559 PrintAndLogEx(SUCCESS
, " " _GREEN_("%02x") " |" NOLF
, id
);
2562 PrintAndLogEx(NORMAL
, " " _CYAN_("%04x") " |" NOLF
, isoid
);
2564 PrintAndLogEx(NORMAL
, " " _YELLOW_("n/a ") " |" NOLF
);
2566 PrintAndLogEx(NORMAL
, " |" NOLF
);
2569 PrintAndLogEx(NORMAL
, " 0x%02x " _CYAN_("%-15s") " |" NOLF
, fsettings
->fileType
, GetDesfireFileType(fsettings
->fileType
));
2570 PrintAndLogEx(NORMAL
, " %-5s |" NOLF
, GetDesfireCommunicationMode(fsettings
->fileCommMode
));
2572 PrintAndLogEx(NORMAL
, " %04x, %-4s %-4s %-4s %-4s |" NOLF
,
2573 fsettings
->rawAccessRights
,
2574 GetDesfireAccessRightShortStr(fsettings
->rAccess
),
2575 GetDesfireAccessRightShortStr(fsettings
->wAccess
),
2576 GetDesfireAccessRightShortStr(fsettings
->rwAccess
),
2577 GetDesfireAccessRightShortStr(fsettings
->chAccess
));
2579 PrintAndLogEx(NORMAL
, " " NOLF
);
2580 DesfirePrintShortFileTypeSettings(fsettings
);
2581 PrintAndLogEx(NORMAL
, "");
2584 void DesfirePrintFileSettingsExtended(FileSettings_t
*fsettings
) {
2585 PrintAndLogEx(SUCCESS
, "File type : " _CYAN_("%s") " [0x%02x]", GetDesfireFileType(fsettings
->fileType
), fsettings
->fileType
);
2586 PrintAndLogEx(SUCCESS
, "Comm mode : %s", GetDesfireCommunicationMode(fsettings
->fileCommMode
));
2588 switch (fsettings
->fileType
) {
2591 PrintAndLogEx(SUCCESS
, "File size : %d [0x%x] bytes", fsettings
->fileSize
, fsettings
->fileSize
);
2595 PrintAndLogEx(SUCCESS
, "Lower limit : %d [0x%x]", fsettings
->lowerLimit
, fsettings
->lowerLimit
);
2596 PrintAndLogEx(SUCCESS
, "Upper limit : %d [0x%x]", fsettings
->upperLimit
, fsettings
->upperLimit
);
2597 bool limited_credit_enabled
= ((fsettings
->limitedCredit
& 0x01) != 0);
2598 PrintAndLogEx(SUCCESS
, "Limited credit : [%d - %s] %d (0x%08X)", fsettings
->limitedCredit
, (limited_credit_enabled
) ? "enabled" : "disabled", fsettings
->value
, fsettings
->value
);
2599 PrintAndLogEx(SUCCESS
, "GetValue access : %s", ((fsettings
->limitedCredit
& 0x02) != 0) ? "Free" : "Not Free");
2604 PrintAndLogEx(SUCCESS
, "Record count : %d [0x%x]", fsettings
->curRecordCount
, fsettings
->curRecordCount
);
2605 PrintAndLogEx(SUCCESS
, "Max record count: %d [0x%x]", fsettings
->maxRecordCount
, fsettings
->maxRecordCount
);
2606 PrintAndLogEx(SUCCESS
, "Record size : %d [0x%x] bytes", fsettings
->recordSize
, fsettings
->recordSize
);
2610 PrintAndLogEx(SUCCESS
, "Key type : 0x%02x", fsettings
->keyType
);
2611 PrintAndLogEx(SUCCESS
, "Key version : 0x%02x ", fsettings
->keyVersion
);
2619 PrintAndLogEx(SUCCESS
, "Access rights : %04x (" NOLF
, fsettings
->rawAccessRights
);
2620 PrintAndLogEx(NORMAL
, "r: %s " NOLF
, GetDesfireAccessRightStr(fsettings
->rAccess
));
2621 PrintAndLogEx(NORMAL
, "w: %s " NOLF
, GetDesfireAccessRightStr(fsettings
->wAccess
));
2622 PrintAndLogEx(NORMAL
, "rw: %s " NOLF
, GetDesfireAccessRightStr(fsettings
->rwAccess
));
2623 PrintAndLogEx(NORMAL
, "change: %s)", GetDesfireAccessRightStr(fsettings
->chAccess
));
2626 static void DesfirePrintFileSettDynPart(uint8_t filetype
, uint8_t *data
, size_t datalen
, uint8_t *dynlen
, bool create
) {
2630 int filesize
= MemLeToUint3byte(&data
[0]);
2631 PrintAndLogEx(INFO
, "File size (bytes)... " _YELLOW_("%d") " / " _YELLOW_("0x%X"), filesize
, filesize
);
2636 int lowerlimit
= MemLeToUint4byte(&data
[0]);
2637 int upperlimit
= MemLeToUint4byte(&data
[4]);
2638 int value
= MemLeToUint4byte(&data
[8]);
2639 uint8_t limited_credit_enabled
= data
[12];
2641 PrintAndLogEx(INFO
, "Lower limit... %d / 0x%08X", lowerlimit
, lowerlimit
);
2642 PrintAndLogEx(INFO
, "Upper limit... %d / 0x%08X", upperlimit
, upperlimit
);
2644 PrintAndLogEx(INFO
, "Value............ %d / 0x%08X", value
, value
);
2645 PrintAndLogEx(INFO
, "Limited credit... %d - %s"
2646 , limited_credit_enabled
2647 , ((limited_credit_enabled
& 1) != 0) ? "enabled" : "disabled"
2650 PrintAndLogEx(INFO
, "Limited credit... %d - %s %d (0x%08X)"
2651 , limited_credit_enabled
2652 , ((limited_credit_enabled
& 1) != 0) ? "enabled" : "disabled"
2657 PrintAndLogEx(INFO
, "GetValue access... %s", ((limited_credit_enabled
& 0x02) != 0) ? "Free" : "Not Free");
2664 uint32_t recordsize
= MemLeToUint3byte(&data
[0]);
2665 uint32_t maxrecords
= MemLeToUint3byte(&data
[3]);
2666 uint32_t currentrecord
= 0;
2667 if (create
== false)
2668 currentrecord
= MemLeToUint3byte(&data
[6]);
2670 PrintAndLogEx(INFO
, "Record size....... %d / 0x%X bytes", recordsize
, recordsize
);
2671 PrintAndLogEx(INFO
, "Max num records... %d / 0x%X", maxrecords
, maxrecords
);
2672 PrintAndLogEx(INFO
, "Total size........ %d / 0x%X bytes", recordsize
* maxrecords
, recordsize
* maxrecords
);
2673 if (create
== false)
2674 PrintAndLogEx(INFO
, "Curr num records... %d / 0x%X", currentrecord
, currentrecord
);
2676 *dynlen
= (create
) ? 6 : 9;
2680 PrintAndLogEx(INFO
, "Key type [0x%02x] ... %s", data
[0], GetDesfireKeyType(data
[0]));
2684 PrintAndLogEx(INFO
, "Key... %s", sprint_hex(&data
[1], 16));
2688 PrintAndLogEx(INFO
, "Key version... %d / 0x%X", data
[*dynlen
], data
[*dynlen
]);
2698 void DesfirePrintFileSettings(uint8_t *data
, size_t len
) {
2700 PrintAndLogEx(ERR
, "Wrong file settings length, expected 6> got %zu ", len
);
2704 uint8_t filetype
= data
[0];
2705 PrintAndLogEx(INFO
, "---- " _CYAN_("File settings") " ----");
2706 PrintAndLogEx(SUCCESS
, "File type " _YELLOW_("0x%02x") " ..... %s file", filetype
, GetDesfireFileType(filetype
));
2707 PrintAndLogEx(SUCCESS
, "File comm mode...... %s", GetDesfireCommunicationMode(data
[1] & 0x03));
2708 bool addaccess
= false;
2709 if (filetype
!= 0x05) {
2710 addaccess
= ((data
[1] & 0x80) != 0);
2711 PrintAndLogEx(SUCCESS
, "Additional access... %s", (addaccess
) ? "Yes" : "No");
2714 PrintAndLogEx(SUCCESS
, "Access rights....... %04x", MemLeToUint2byte(&data
[2]));
2715 DesfirePrintAccessRight(&data
[2]); // 2 bytes
2718 DesfirePrintFileSettDynPart(filetype
, &data
[4], len
- 4, &reclen
, false);
2719 reclen
+= 4; // static part
2721 if (addaccess
&& filetype
!= 0x05 && reclen
> 0 && len
> reclen
&& len
== reclen
+ data
[reclen
] * 2) {
2722 PrintAndLogEx(SUCCESS
, "Add access records... %d", data
[reclen
]);
2723 for (int i
= 0; i
< data
[reclen
] * 2; i
+= 2) {
2724 PrintAndLogEx(SUCCESS
, "Add access rights : [%d] %04x", i
/ 2, MemLeToUint2byte(&data
[reclen
+ 1 + i
]));
2725 DesfirePrintAccessRight(&data
[reclen
+ 1 + i
]);
2730 void DesfirePrintSetFileSettings(uint8_t *data
, size_t len
) {
2731 PrintAndLogEx(INFO
, "---- " _CYAN_("Set file settings") " ----");
2732 PrintAndLogEx(SUCCESS
, "File comm mode : %s", GetDesfireCommunicationMode(data
[0] & 0x03));
2734 bool addaccess
= ((data
[0] & 0x80) != 0);
2735 PrintAndLogEx(SUCCESS
, "Additional access: %s", (addaccess
) ? "Yes" : "No");
2737 PrintAndLogEx(SUCCESS
, "Access rights : %04x", MemLeToUint2byte(&data
[1]));
2738 DesfirePrintAccessRight(&data
[1]); //2 bytes
2740 if (addaccess
&& len
> 3 && len
== 4 + data
[3] * 2) {
2741 PrintAndLogEx(SUCCESS
, "Add access records: %d", data
[3]);
2742 for (int i
= 0; i
< data
[3] * 2; i
+= 2) {
2743 PrintAndLogEx(SUCCESS
, "Add access rights : [%d] %04x", i
/ 2, MemLeToUint2byte(&data
[4 + i
]));
2744 DesfirePrintAccessRight(&data
[4 + i
]);
2749 void DesfirePrintCreateFileSettings(uint8_t filetype
, uint8_t *data
, size_t len
) {
2750 const DesfireCreateFileCommands_t
*ftyperec
= GetDesfireFileCmdRec(filetype
);
2751 if (ftyperec
== NULL
) {
2752 PrintAndLogEx(WARNING
, "Unknown file type 0x%02x", filetype
);
2756 bool isoidpresent
= ftyperec
->mayHaveISOfid
&& (len
== ftyperec
->createlen
+ 2 + 1);
2758 PrintAndLogEx(INFO
, "---- " _CYAN_("Create file settings") " ----");
2759 PrintAndLogEx(SUCCESS
, "File type : %s", ftyperec
->text
);
2760 PrintAndLogEx(SUCCESS
, "File number : 0x%02X (%d)", data
[0], data
[0]);
2762 if (ftyperec
->mayHaveISOfid
) {
2764 PrintAndLogEx(SUCCESS
, "File ISO number : 0x%04X", MemLeToUint2byte(&data
[xlen
]));
2767 PrintAndLogEx(SUCCESS
, "File ISO number : n/a");
2771 PrintAndLogEx(SUCCESS
, "File comm mode : %s", GetDesfireCommunicationMode(data
[xlen
] & 0x03));
2772 bool addaccess
= ((data
[xlen
] & 0x80) != 0);
2773 PrintAndLogEx(SUCCESS
, "Additional access: %s", (addaccess
) ? "Yes" : "No");
2776 PrintAndLogEx(SUCCESS
, "Access rights : %04X", MemLeToUint2byte(&data
[xlen
]));
2777 DesfirePrintAccessRight(&data
[xlen
]);
2780 // https://www.nxp.com/docs/en/data-sheet/MF2DLHX0.pdf
2782 // TransactionMAC file
2783 if (filetype
== 0x05) {
2786 uint8_t readwrite
= 0;
2788 DesfireDecodeFileAcessMode(&data
[xlen
- 2], &read
, &write
, &readwrite
, &change
);
2790 PrintAndLogEx(WARNING
, "descr. : Write right should be set to F because write " _RED_("not allowed") ".");
2792 if (readwrite
== 0x0f)
2793 PrintAndLogEx(SUCCESS
, "descr. : ReadWrite right is %01X, CommitReaderID command disabled", readwrite
);
2794 else if (readwrite
== 0x0e)
2795 PrintAndLogEx(SUCCESS
, "descr. : ReadWrite right is %01X, CommitReaderID command enabled with free access", readwrite
);
2796 else if (readwrite
<= 0x04)
2797 PrintAndLogEx(SUCCESS
, "descr. : ReadWrite right is %01X, CommitReaderID command enabled with key 0x0%01x", readwrite
, readwrite
);
2799 PrintAndLogEx(WARNING
, "descr. : ReadWrite right must me 0..4,E,F instead of is %01X.", readwrite
);
2803 DesfirePrintFileSettDynPart(filetype
, &data
[xlen
], len
- xlen
, &reclen
, true);
2807 int DesfireChangeKey(DesfireContext_t
*dctx
, bool change_master_key
, uint8_t newkeynum
, DesfireCryptoAlgorithm newkeytype
, uint32_t newkeyver
, uint8_t *newkey
, DesfireCryptoAlgorithm oldkeytype
, uint8_t *oldkey
, bool verbose
) {
2809 uint8_t okeybuf
[DESFIRE_MAX_KEY_SIZE
] = {0};
2810 uint8_t nkeybuf
[DESFIRE_MAX_KEY_SIZE
] = {0};
2811 uint8_t pckcdata
[DESFIRE_MAX_KEY_SIZE
+ 10] = {0};
2812 uint8_t *cdata
= &pckcdata
[2];
2813 uint8_t keynodata
= newkeynum
& 0x3f;
2816 * Because new crypto methods can be setup only at application creation,
2817 * changing the card master key to one of them require a key_no tweak.
2819 if (change_master_key
) {
2820 keynodata
|= (DesfireKeyAlgoToType(newkeytype
) & 0x03) << 6;
2823 pckcdata
[0] = MFDES_CHANGE_KEY
; // TODO
2824 pckcdata
[1] = keynodata
;
2827 memcpy(okeybuf
, oldkey
, desfire_get_key_length(oldkeytype
));
2828 if (oldkeytype
== T_DES
) {
2829 memcpy(&okeybuf
[8], oldkey
, 8);
2832 memcpy(nkeybuf
, newkey
, desfire_get_key_length(newkeytype
));
2833 size_t nkeylen
= desfire_get_key_length(newkeytype
);
2834 if (newkeytype
== T_DES
) {
2835 memcpy(&nkeybuf
[8], newkey
, 8);
2836 nkeylen
= desfire_get_key_length(T_3DES
);
2839 // set key version for DES. if newkeyver > 0xff - setting key version is disabled
2840 if (newkeytype
!= T_AES
&& newkeyver
< 0x100) {
2841 DesfireDESKeySetVersion(nkeybuf
, newkeytype
, newkeyver
);
2843 PrintAndLogEx(INFO
, "changed new key: %s [%d] %s", CLIGetOptionListStr(DesfireAlgoOpts
, newkeytype
), desfire_get_key_length(newkeytype
), sprint_hex(nkeybuf
, desfire_get_key_length(newkeytype
)));
2846 // xor if we change current auth key
2847 if (newkeynum
== dctx
->keyNum
) {
2848 memcpy(cdata
, nkeybuf
, nkeylen
);
2850 memcpy(cdata
, nkeybuf
, nkeylen
);
2851 bin_xor(cdata
, okeybuf
, nkeylen
);
2854 // add key version for AES
2855 size_t cdatalen
= nkeylen
;
2856 if (newkeytype
== T_AES
) {
2857 cdata
[cdatalen
] = newkeyver
;
2861 // add crc||crc_new_key
2862 if (dctx
->secureChannel
== DACd40
) {
2863 iso14443a_crc_append(cdata
, cdatalen
);
2865 if (newkeynum
!= dctx
->keyNum
) {
2866 iso14443a_crc(nkeybuf
, nkeylen
, &cdata
[cdatalen
]);
2869 } else if (dctx
->secureChannel
== DACEV1
) {
2870 // EV1 Checksum must cover : <KeyNo> <PrevKey XOR Newkey> [<AES NewKeyVer>]
2871 desfire_crc32_append(pckcdata
, cdatalen
+ 2);
2873 if (newkeynum
!= dctx
->keyNum
) {
2874 desfire_crc32(nkeybuf
, nkeylen
, &cdata
[cdatalen
]);
2877 } else if (dctx
->secureChannel
== DACEV2
|| dctx
->secureChannel
== DACLRP
) {
2878 // EV2 : <PrevKey XOR Newkey> [<AES NewKeyVer>]
2879 if (newkeynum
!= dctx
->keyNum
) {
2880 desfire_crc32(nkeybuf
, nkeylen
, &cdata
[cdatalen
]);
2886 uint8_t resp
[257] = {0};
2888 int res
= DesfireChangeKeyCmd(dctx
, &pckcdata
[1], cdatalen
+ 1, resp
, &resplen
);
2891 if (res
== 0 && resplen
> 0)
2895 if (newkeynum
== dctx
->keyNum
)
2896 DesfireClearSession(dctx
);
2901 int DesfireSetConfiguration(DesfireContext_t
*dctx
, uint8_t paramid
, uint8_t *param
, size_t paramlen
) {
2902 uint8_t cdata
[200] = {0};
2903 cdata
[0] = MFDES_CHANGE_CONFIGURATION
;
2904 uint8_t *data
= &cdata
[1];
2906 memcpy(&data
[1], param
, paramlen
);
2907 size_t datalen
= 1 + paramlen
;
2910 if (paramid
== 0x02 && dctx
->commMode
== DCMEncrypted
)
2911 dctx
->commMode
= DCMEncryptedWithPadding
;
2914 uint8_t resp
[257] = {0};
2916 int res
= DesfireSetConfigurationCmd(dctx
, data
, datalen
, resp
, &resplen
);
2919 if (res
== 0 && resplen
> 0)
2925 int DesfireISOSelectEx(DesfireContext_t
*dctx
, bool fieldon
, DesfireISOSelectControl cntr
, uint8_t *data
, uint8_t datalen
, uint8_t *resp
, size_t *resplen
) {
2926 uint8_t xresp
[250] = {0};
2927 size_t xresplen
= 0;
2929 int res
= DesfireExchangeISO(fieldon
, dctx
, (sAPDU_t
) {0x00, ISO7816_SELECT_FILE
, cntr
, ((resp
== NULL
) ? 0x0C : 0x00), datalen
, data
}, APDU_INCLUDE_LE_00
, xresp
, &xresplen
, &sw
);
2930 if (res
== PM3_SUCCESS
&& sw
!= ISO7816_OK
)
2933 if (resp
!= NULL
&& resplen
!= NULL
) {
2934 *resplen
= xresplen
;
2935 memcpy(resp
, xresp
, xresplen
);
2938 DesfireClearSession(dctx
);
2939 dctx
->appSelected
= !((cntr
== ISSMFDFEF
&& datalen
== 0) || (cntr
== ISSEFByFileID
&& datalen
== 2 && data
[0] == 0 && data
[1] == 0));
2940 dctx
->selectedAID
= 0;
2945 int DesfireISOSelect(DesfireContext_t
*dctx
, DesfireISOSelectControl cntr
, uint8_t *data
, uint8_t datalen
, uint8_t *resp
, size_t *resplen
) {
2946 return DesfireISOSelectEx(dctx
, true, cntr
, data
, datalen
, resp
, resplen
);
2949 int DesfireISOSelectDF(DesfireContext_t
*dctx
, char *dfname
, uint8_t *resp
, size_t *resplen
) {
2950 return DesfireISOSelect(dctx
, ISSDFName
, (uint8_t *)dfname
, str_nlen(dfname
, 16), resp
, resplen
);
2953 int DesfireISOGetChallenge(DesfireContext_t
*dctx
, DesfireCryptoAlgorithm keytype
, uint8_t *resp
, size_t *resplen
) {
2955 int res
= DesfireExchangeISO(false, dctx
, (sAPDU_t
) {0x00, ISO7816_GET_CHALLENGE
, 0x00, 0x00, 0x00, NULL
}, DesfireGetRndLenForKey(keytype
), resp
, resplen
, &sw
);
2956 if (res
== PM3_SUCCESS
&& sw
!= ISO7816_OK
)
2962 int DesfireISOExternalAuth(DesfireContext_t
*dctx
, bool app_level
, uint8_t keynum
, DesfireCryptoAlgorithm keytype
, uint8_t *data
) {
2963 uint8_t p1
= DesfireKeyToISOKey(keytype
);
2964 uint8_t p2
= ((app_level
) ? 0x80 : 0x00) | keynum
;
2966 uint8_t resp
[250] = {0};
2970 int res
= DesfireExchangeISO(false, dctx
, (sAPDU_t
) {0x00, ISO7816_EXTERNAL_AUTHENTICATION
, p1
, p2
, DesfireGetRndLenForKey(keytype
) * 2, data
}, 0, resp
, &resplen
, &sw
);
2971 if (res
== PM3_SUCCESS
&& sw
!= ISO7816_OK
)
2977 int DesfireISOInternalAuth(DesfireContext_t
*dctx
, bool app_level
, uint8_t keynum
, DesfireCryptoAlgorithm keytype
, uint8_t *data
, uint8_t *resp
, size_t *resplen
) {
2978 uint8_t keylen
= DesfireGetRndLenForKey(keytype
);
2979 uint8_t p1
= DesfireKeyToISOKey(keytype
);
2980 uint8_t p2
= ((app_level
) ? 0x80 : 0x00) | keynum
;
2983 int res
= DesfireExchangeISO(false, dctx
, (sAPDU_t
) {0x00, ISO7816_INTERNAL_AUTHENTICATION
, p1
, p2
, keylen
, data
}, keylen
* 2, resp
, resplen
, &sw
);
2984 if (res
== PM3_SUCCESS
&& sw
!= ISO7816_OK
)
2990 int DesfireISOReadBinary(DesfireContext_t
*dctx
, bool use_file_id
, uint8_t fileid
, uint16_t offset
, uint8_t length
, uint8_t *resp
, size_t *resplen
) {
2993 p1
= 0x80 | (fileid
& 0x1f);
2995 p1
= (offset
>> 8) & 0x7f;
2996 uint8_t p2
= offset
& 0xff;
2999 int res
= DesfireExchangeISO(false, dctx
, (sAPDU_t
) {0x00, ISO7816_READ_BINARY
, p1
, p2
, 0, NULL
}, (length
== 0) ? APDU_INCLUDE_LE_00
: length
, resp
, resplen
, &sw
);
3000 if (res
== PM3_SUCCESS
&& sw
!= ISO7816_OK
)
3006 int DesfireISOUpdateBinary(DesfireContext_t
*dctx
, bool use_file_id
, uint8_t fileid
, uint16_t offset
, uint8_t *data
, size_t datalen
) {
3009 p1
= 0x80 | (fileid
& 0x1f);
3011 p1
= (offset
>> 8) & 0x7f;
3012 uint8_t p2
= offset
& 0xff;
3014 uint8_t resp
[250] = {0};
3018 int res
= DesfireExchangeISO(false, dctx
, (sAPDU_t
) {0x00, ISO7816_UPDATE_BINARY
, p1
, p2
, datalen
, data
}, 0, resp
, &resplen
, &sw
);
3019 if (res
== PM3_SUCCESS
&& sw
!= ISO7816_OK
)
3025 int DesfireISOReadRecords(DesfireContext_t
*dctx
, uint8_t recordnum
, bool read_all_records
, uint8_t fileid
, uint8_t length
, uint8_t *resp
, size_t *resplen
) {
3026 uint8_t p2
= ((fileid
& 0x1f) << 3) | ((read_all_records
) ? 0x05 : 0x04);
3029 int res
= DesfireExchangeISO(false, dctx
, (sAPDU_t
) {0x00, ISO7816_READ_RECORDS
, recordnum
, p2
, 0, NULL
}, (length
== 0) ? APDU_INCLUDE_LE_00
: length
, resp
, resplen
, &sw
);
3030 if (res
== PM3_SUCCESS
&& sw
!= ISO7816_OK
)
3036 int DesfireISOAppendRecord(DesfireContext_t
*dctx
, uint8_t fileid
, uint8_t *data
, size_t datalen
) {
3037 uint8_t p2
= ((fileid
& 0x1f) << 3);
3039 uint8_t resp
[250] = {0};
3043 int res
= DesfireExchangeISO(false, dctx
, (sAPDU_t
) {0x00, ISO7816_APPEND_RECORD
, 0x00, p2
, datalen
, data
}, 0, resp
, &resplen
, &sw
);
3044 if (res
== PM3_SUCCESS
&& sw
!= ISO7816_OK
)
3050 int DesfireGetCardUID(DesfireContext_t
*ctx
) {
3051 iso14a_card_select_t card
= {0};
3053 SendCommandMIX(CMD_HF_ISO14443A_READER
, ISO14A_CONNECT
, 0, 0, NULL
, 0);
3054 PacketResponseNG resp
;
3055 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 2500) == false) {
3056 PrintAndLogEx(WARNING
, "timeout while waiting for reply.");
3057 return PM3_ETIMEOUT
;
3060 memcpy(&card
, (iso14a_card_select_t
*)resp
.data
.asBytes
, sizeof(iso14a_card_select_t
));
3061 uint64_t select_status
= resp
.oldarg
[0];
3063 if (select_status
== 0 || select_status
== 2 || select_status
== 3) {
3067 memcpy(ctx
->uid
, card
.uid
, card
.uidlen
);
3068 ctx
->uidlen
= card
.uidlen
;
3073 int DesfireAnticollision(bool verbose
) {
3074 return SelectCard14443A_4(false, verbose
, NULL
);
3077 int DesfireSelectEx(DesfireContext_t
*ctx
, bool fieldon
, DesfireISOSelectWay way
, uint32_t id
, const char *dfname
) {
3078 uint8_t resp
[250] = {0};
3081 if (way
== ISWMF
|| (way
== ISWDFName
&& dfname
== NULL
)) {
3082 return DesfireISOSelectEx(ctx
, fieldon
, ISSMFDFEF
, NULL
, 0, resp
, &resplen
);
3083 } else if (way
== ISW6bAID
) {
3084 if (id
== 0x000000 && fieldon
)
3085 return DesfireAnticollision(false);
3087 DesfireCommandSet cmdset
= ctx
->cmdSet
;
3090 // if we try to select 6b AID via ISO channel - we can only switch the channel via the over channel because there is no equivalent command in the iso commands
3091 if (ctx
->cmdSet
== DCCISO
)
3092 ctx
->cmdSet
= DCCNativeISO
;
3095 res
= DesfireSelectAIDHex(ctx
, id
, false, 0);
3097 res
= DesfireSelectAIDHexNoFieldOn(ctx
, id
);
3099 ctx
->cmdSet
= cmdset
;
3101 } else if (way
== ISWIsoID
) {
3102 uint8_t data
[2] = {0};
3103 Uint2byteToMemBe(data
, id
);
3104 return DesfireISOSelectEx(ctx
, fieldon
, ISSMFDFEF
, data
, 2, resp
, &resplen
);
3105 } else if (way
== ISWDFName
) {
3106 return DesfireISOSelectEx(ctx
, fieldon
, ISSMFDFEF
, NULL
, 0, resp
, &resplen
);
3111 int DesfireSelect(DesfireContext_t
*ctx
, DesfireISOSelectWay way
, uint32_t id
, char *dfname
) {
3112 return DesfireSelectEx(ctx
, true, way
, id
, dfname
);