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 secure channel functions
19 //-----------------------------------------------------------------------------
21 #include "desfiresecurechan.h"
28 #include "crc16.h" // crc16 ccitt
30 #include "commonutil.h"
31 #include "protocols.h"
33 static const uint8_t CommandsCanUseAnyChannel
[] = {
34 MFDES_S_ADDITIONAL_FRAME
,
51 static bool CommandCanUseAnyChannel(uint8_t cmd
) {
52 for (int i
= 0; i
< ARRAYLEN(CommandsCanUseAnyChannel
); i
++) {
53 if (CommandsCanUseAnyChannel
[i
] == cmd
) {
60 static const AllowedChannelModes_t AllowedChannelModes
[] = {
62 {MFDES_SELECT_APPLICATION
, DACd40
, DCCNative
, DCMPlain
},
64 {MFDES_CREATE_APPLICATION
, DACd40
, DCCNative
, DCMMACed
},
65 {MFDES_DELETE_APPLICATION
, DACd40
, DCCNative
, DCMMACed
},
66 {MFDES_GET_APPLICATION_IDS
, DACd40
, DCCNative
, DCMMACed
},
67 {MFDES_GET_DF_NAMES
, DACd40
, DCCNative
, DCMMACed
},
68 {MFDES_GET_KEY_SETTINGS
, DACd40
, DCCNative
, DCMMACed
},
69 {MFDES_GET_KEY_VERSION
, DACd40
, DCCNative
, DCMMACed
},
70 {MFDES_GET_FREE_MEMORY
, DACd40
, DCCNative
, DCMMACed
},
71 {MFDES_CREATE_STD_DATA_FILE
, DACd40
, DCCNative
, DCMMACed
},
72 {MFDES_CREATE_BACKUP_DATA_FILE
, DACd40
, DCCNative
, DCMMACed
},
73 {MFDES_CREATE_VALUE_FILE
, DACd40
, DCCNative
, DCMMACed
},
74 {MFDES_CREATE_LINEAR_RECORD_FILE
, DACd40
, DCCNative
, DCMMACed
},
75 {MFDES_CREATE_CYCLIC_RECORD_FILE
, DACd40
, DCCNative
, DCMMACed
},
76 {MFDES_DELETE_FILE
, DACd40
, DCCNative
, DCMMACed
},
77 {MFDES_COMMIT_TRANSACTION
, DACd40
, DCCNative
, DCMMACed
},
78 {MFDES_CLEAR_RECORD_FILE
, DACd40
, DCCNative
, DCMMACed
},
79 {MFDES_GET_FILE_SETTINGS
, DACd40
, DCCNative
, DCMMACed
},
80 {MFDES_GET_VALUE
, DACd40
, DCCNative
, DCMMACed
},
81 {MFDES_CREDIT
, DACd40
, DCCNative
, DCMMACed
},
82 {MFDES_DEBIT
, DACd40
, DCCNative
, DCMMACed
},
83 {MFDES_LIMITED_CREDIT
, DACd40
, DCCNative
, DCMMACed
},
84 {MFDES_READ_RECORDS
, DACd40
, DCCNative
, DCMMACed
},
85 {MFDES_WRITE_RECORD
, DACd40
, DCCNative
, DCMMACed
},
86 {MFDES_UPDATE_RECORD
, DACd40
, DCCNative
, DCMMACed
},
87 {MFDES_UPDATE_RECORD2
, DACd40
, DCCNativeISO
, DCMMACed
},
88 {MFDES_INIT_KEY_SETTINGS
, DACd40
, DCCNative
, DCMMACed
},
89 {MFDES_FINALIZE_KEY_SETTINGS
, DACd40
, DCCNative
, DCMMACed
},
90 {MFDES_ROLL_KEY_SETTINGS
, DACd40
, DCCNative
, DCMMACed
},
91 {MFDES_COMMIT_READER_ID
, DACd40
, DCCNative
, DCMMACed
},
92 {MFDES_FORMAT_PICC
, DACd40
, DCCNative
, DCMMACed
},
93 {MFDES_GET_FILE_IDS
, DACd40
, DCCNative
, DCMMACed
},
94 {MFDES_GET_ISOFILE_IDS
, DACd40
, DCCNative
, DCMMACed
},
95 {MFDES_ABORT_TRANSACTION
, DACd40
, DCCNative
, DCMMACed
},
97 {MFDES_GET_UID
, DACd40
, DCCNative
, DCMEncrypted
},
98 {MFDES_CHANGE_KEY_SETTINGS
, DACd40
, DCCNative
, DCMEncrypted
},
99 {MFDES_CHANGE_FILE_SETTINGS
, DACd40
, DCCNative
, DCMEncrypted
},
100 {MFDES_CHANGE_CONFIGURATION
, DACd40
, DCCNative
, DCMEncrypted
},
102 {MFDES_CHANGE_KEY
, DACd40
, DCCNative
, DCMEncryptedPlain
},
103 {MFDES_CHANGE_KEY_EV2
, DACd40
, DCCNative
, DCMEncryptedPlain
},
105 // EV1 and EV2 channel
106 {MFDES_SELECT_APPLICATION
, DACEV1
, DCCNative
, DCMPlain
},
108 {MFDES_GET_KEY_VERSION
, DACEV1
, DCCNative
, DCMMACed
},
109 {MFDES_GET_FREE_MEMORY
, DACEV1
, DCCNative
, DCMMACed
},
110 {MFDES_CREATE_APPLICATION
, DACEV1
, DCCNative
, DCMMACed
},
111 {MFDES_DELETE_APPLICATION
, DACEV1
, DCCNative
, DCMMACed
},
112 {MFDES_GET_APPLICATION_IDS
, DACEV1
, DCCNative
, DCMMACed
},
113 {MFDES_GET_DF_NAMES
, DACEV1
, DCCNative
, DCMMACed
},
114 {MFDES_GET_KEY_SETTINGS
, DACEV1
, DCCNative
, DCMMACed
},
115 {MFDES_FORMAT_PICC
, DACEV1
, DCCNative
, DCMMACed
},
116 {MFDES_GET_FILE_IDS
, DACEV1
, DCCNative
, DCMMACed
},
117 {MFDES_GET_ISOFILE_IDS
, DACEV1
, DCCNative
, DCMMACed
},
118 {MFDES_GET_FILE_SETTINGS
, DACEV1
, DCCNative
, DCMMACed
},
119 {MFDES_CREATE_STD_DATA_FILE
, DACEV1
, DCCNative
, DCMMACed
},
120 {MFDES_CREATE_BACKUP_DATA_FILE
, DACEV1
, DCCNative
, DCMMACed
},
121 {MFDES_CREATE_VALUE_FILE
, DACEV1
, DCCNative
, DCMMACed
},
122 {MFDES_CREATE_LINEAR_RECORD_FILE
, DACEV1
, DCCNative
, DCMMACed
},
123 {MFDES_CREATE_CYCLIC_RECORD_FILE
, DACEV1
, DCCNative
, DCMMACed
},
124 {MFDES_DELETE_FILE
, DACEV1
, DCCNative
, DCMMACed
},
125 {MFDES_GET_VALUE
, DACEV1
, DCCNative
, DCMMACed
},
126 {MFDES_CREDIT
, DACEV1
, DCCNative
, DCMMACed
},
127 {MFDES_LIMITED_CREDIT
, DACEV1
, DCCNative
, DCMMACed
},
128 {MFDES_DEBIT
, DACEV1
, DCCNative
, DCMMACed
},
129 {MFDES_COMMIT_TRANSACTION
, DACEV1
, DCCNative
, DCMMACed
},
130 {MFDES_CLEAR_RECORD_FILE
, DACEV1
, DCCNative
, DCMMACed
},
131 {MFDES_COMMIT_READER_ID
, DACEV1
, DCCNative
, DCMMACed
},
132 {MFDES_ABORT_TRANSACTION
, DACEV1
, DCCNative
, DCMMACed
},
134 {MFDES_GET_UID
, DACEV1
, DCCNative
, DCMEncrypted
},
135 {MFDES_CHANGE_KEY_SETTINGS
, DACEV1
, DCCNative
, DCMEncrypted
},
136 {MFDES_CHANGE_FILE_SETTINGS
, DACEV1
, DCCNative
, DCMEncrypted
},
137 {MFDES_CREATE_TRANS_MAC_FILE
, DACEV1
, DCCNative
, DCMEncrypted
},
138 {MFDES_CHANGE_CONFIGURATION
, DACEV1
, DCCNative
, DCMEncrypted
},
140 {MFDES_CHANGE_KEY
, DACEV1
, DCCNative
, DCMEncryptedPlain
},
141 {MFDES_CHANGE_KEY_EV2
, DACEV1
, DCCNative
, DCMEncryptedPlain
},
143 // EV2 channel separately
144 {MFDES_AUTHENTICATE_EV2F
, DACEV2
, DCCNative
, DCMPlain
},
145 {MFDES_AUTHENTICATE_EV2NF
, DACEV2
, DCCNative
, DCMPlain
},
148 {ISO7816_READ_BINARY
, DACd40
, DCCISO
, DCMPlain
},
149 {ISO7816_UPDATE_BINARY
, DACd40
, DCCISO
, DCMPlain
},
150 {ISO7816_READ_RECORDS
, DACd40
, DCCISO
, DCMPlain
},
151 {ISO7816_APPEND_RECORD
, DACd40
, DCCISO
, DCMPlain
},
153 {ISO7816_READ_BINARY
, DACd40
, DCCISO
, DCMMACed
},
154 {ISO7816_READ_RECORDS
, DACd40
, DCCISO
, DCMMACed
},
156 {ISO7816_READ_BINARY
, DACEV1
, DCCISO
, DCMPlain
},
157 {ISO7816_UPDATE_BINARY
, DACEV1
, DCCISO
, DCMPlain
},
158 {ISO7816_READ_RECORDS
, DACEV1
, DCCISO
, DCMPlain
},
159 {ISO7816_APPEND_RECORD
, DACEV1
, DCCISO
, DCMPlain
},
161 {ISO7816_READ_BINARY
, DACEV1
, DCCISO
, DCMMACed
},
162 {ISO7816_READ_RECORDS
, DACEV1
, DCCISO
, DCMMACed
},
164 // LRP channel separately
165 {MFDES_AUTHENTICATE_EV2F
, DACLRP
, DCCNative
, DCMPlain
},
166 {MFDES_AUTHENTICATE_EV2NF
, DACLRP
, DCCNative
, DCMPlain
},
168 {MFDES_GET_FILE_IDS
, DACLRP
, DCCNative
, DCMMACed
},
169 {MFDES_GET_ISOFILE_IDS
, DACLRP
, DCCNative
, DCMMACed
},
170 {MFDES_GET_FILE_SETTINGS
, DACLRP
, DCCNative
, DCMMACed
},
171 {MFDES_GET_KEY_VERSION
, DACLRP
, DCCNative
, DCMMACed
},
172 {MFDES_CLEAR_RECORD_FILE
, DACLRP
, DCCNative
, DCMMACed
},
173 {MFDES_COMMIT_TRANSACTION
, DACLRP
, DCCNative
, DCMMACed
},
174 {MFDES_ABORT_TRANSACTION
, DACLRP
, DCCNative
, DCMMACed
},
175 {MFDES_COMMIT_READER_ID
, DACLRP
, DCCNative
, DCMMACed
},
177 {MFDES_GET_UID
, DACLRP
, DCCNative
, DCMEncrypted
},
178 {MFDES_CHANGE_FILE_SETTINGS
, DACLRP
, DCCNative
, DCMEncrypted
},
179 {MFDES_CHANGE_CONFIGURATION
, DACLRP
, DCCNative
, DCMEncrypted
},
180 {MFDES_CREATE_TRANS_MAC_FILE
, DACLRP
, DCCNative
, DCMEncrypted
},
182 {MFDES_CHANGE_KEY
, DACLRP
, DCCNative
, DCMEncryptedPlain
},
185 #define CMD_HEADER_LEN_ALL 0xffff
186 static const CmdHeaderLengths_t CmdHeaderLengths
[] = {
187 {MFDES_CREATE_APPLICATION
, CMD_HEADER_LEN_ALL
},
188 {MFDES_DELETE_APPLICATION
, CMD_HEADER_LEN_ALL
},
189 {MFDES_CHANGE_KEY
, 1},
190 {MFDES_CHANGE_KEY_EV2
, 2},
191 {MFDES_CHANGE_CONFIGURATION
, 1},
192 {MFDES_GET_FILE_SETTINGS
, 1},
193 {MFDES_CHANGE_FILE_SETTINGS
, 1},
194 {MFDES_CREATE_TRANS_MAC_FILE
, 5},
195 {MFDES_READ_DATA
, 7},
196 {MFDES_READ_DATA2
, 7},
197 {MFDES_WRITE_DATA
, 7},
198 {MFDES_WRITE_DATA2
, 7},
199 {MFDES_READ_RECORDS
, 7},
200 {MFDES_READ_RECORDS2
, 7},
201 {MFDES_WRITE_RECORD
, 7},
202 {MFDES_WRITE_RECORD2
, 7},
203 {MFDES_UPDATE_RECORD
, 10},
204 {MFDES_UPDATE_RECORD2
, 10},
205 {MFDES_GET_VALUE
, 1},
208 {MFDES_LIMITED_CREDIT
, 1},
211 static uint8_t DesfireGetCmdHeaderLen(uint8_t cmd
) {
212 for (int i
= 0; i
< ARRAYLEN(CmdHeaderLengths
); i
++) {
213 if (CmdHeaderLengths
[i
].cmd
== cmd
) {
214 return CmdHeaderLengths
[i
].len
;
220 static const uint8_t EV1D40TransmitMAC
[] = {
223 MFDES_LIMITED_CREDIT
,
227 MFDES_COMMIT_READER_ID
,
228 MFDES_INIT_KEY_SETTINGS
,
229 MFDES_ROLL_KEY_SETTINGS
,
230 MFDES_FINALIZE_KEY_SETTINGS
,
233 static bool DesfireEV1D40TransmitMAC(DesfireContext_t
*ctx
, uint8_t cmd
) {
234 if (ctx
->secureChannel
!= DACd40
&& ctx
->secureChannel
!= DACEV1
) {
238 for (int i
= 0; i
< ARRAYLEN(EV1D40TransmitMAC
); i
++) {
239 if (EV1D40TransmitMAC
[i
] == cmd
) {
247 static const uint8_t D40ReceiveMAC
[] = {
255 static bool DesfireEV1D40ReceiveMAC(DesfireContext_t
*ctx
, uint8_t cmd
) {
256 if (ctx
->secureChannel
!= DACd40
) {
260 for (int i
= 0; i
< ARRAYLEN(D40ReceiveMAC
); i
++) {
261 if (D40ReceiveMAC
[i
] == cmd
) {
269 static const uint8_t ISOChannelValidCmd
[] = {
272 ISO7816_UPDATE_BINARY
,
273 ISO7816_READ_RECORDS
,
274 ISO7816_APPEND_RECORD
,
275 ISO7816_GET_CHALLENGE
,
276 ISO7816_EXTERNAL_AUTHENTICATION
,
277 ISO7816_INTERNAL_AUTHENTICATION
280 static bool DesfireISOChannelValidCmd(uint8_t cmd
) {
281 for (int i
= 0; i
< ARRAYLEN(ISOChannelValidCmd
); i
++) {
282 if (ISOChannelValidCmd
[i
] == cmd
) {
289 static void DesfireSecureChannelEncodeD40(DesfireContext_t
*ctx
, uint8_t cmd
, uint8_t *srcdata
, size_t srcdatalen
, uint8_t *dstdata
, size_t *dstdatalen
) {
291 uint8_t *data
= calloc(DESFIRE_BUFFER_SIZE
, sizeof(uint8_t));
295 memcpy(dstdata
, srcdata
, srcdatalen
);
296 *dstdatalen
= srcdatalen
;
298 uint8_t hdrlen
= DesfireGetCmdHeaderLen(cmd
);
299 if (srcdatalen
< hdrlen
)
304 if (ctx
->commMode
== DCMMACed
|| (ctx
->commMode
== DCMEncrypted
&& srcdatalen
<= hdrlen
)) {
305 if (srcdatalen
== 0) {
310 rlen
= srcdatalen
+ DesfireGetMACLength(ctx
);
312 memcpy(data
, &srcdata
[hdrlen
], srcdatalen
- hdrlen
);
313 size_t srcmaclen
= padded_data_length(srcdatalen
- hdrlen
, desfire_get_key_block_length(ctx
->keyType
));
315 uint8_t mac
[32] = {0};
316 DesfireCryptoEncDecEx(ctx
, DCOSessionKeyMac
, data
, srcmaclen
, NULL
, true, true, mac
);
318 if (DesfireEV1D40TransmitMAC(ctx
, cmd
)) {
319 memcpy(&dstdata
[srcdatalen
], mac
, DesfireGetMACLength(ctx
));
322 } else if (ctx
->commMode
== DCMEncrypted
|| ctx
->commMode
== DCMEncryptedWithPadding
) {
323 if (srcdatalen
<= hdrlen
) {
328 uint8_t paddinglen
= (ctx
->commMode
== DCMEncryptedWithPadding
) ? 1 : 0;
329 rlen
= padded_data_length(srcdatalen
+ 2 + paddinglen
- hdrlen
, desfire_get_key_block_length(ctx
->keyType
)) + hdrlen
; // 2 - crc16
330 memcpy(data
, &srcdata
[hdrlen
], srcdatalen
- hdrlen
);
331 iso14443a_crc_append(data
, srcdatalen
- hdrlen
);
335 data
[srcdatalen
- hdrlen
+ 2] = 0x80;
337 memcpy(dstdata
, srcdata
, hdrlen
);
338 //PrintAndLogEx(INFO, "src[%d]: %s", srcdatalen - hdrlen + 2, sprint_hex(data, srcdatalen - hdrlen + 2));
339 DesfireCryptoEncDec(ctx
, DCOSessionKeyEnc
, data
, rlen
- hdrlen
, &dstdata
[hdrlen
], true);
342 } else if (ctx
->commMode
== DCMEncryptedPlain
) {
343 if (srcdatalen
== 0 || srcdatalen
<= hdrlen
) {
348 rlen
= padded_data_length(srcdatalen
- hdrlen
, desfire_get_key_block_length(ctx
->keyType
)) + hdrlen
;
349 memcpy(data
, srcdata
, srcdatalen
);
350 memcpy(dstdata
, srcdata
, hdrlen
);
351 DesfireCryptoEncDec(ctx
, DCOSessionKeyEnc
, &data
[hdrlen
], rlen
- hdrlen
, &dstdata
[hdrlen
], true);
353 ctx
->commMode
= DCMEncrypted
;
359 static void DesfireSecureChannelEncodeEV1(DesfireContext_t
*ctx
, uint8_t cmd
, uint8_t *srcdata
, size_t srcdatalen
, uint8_t *dstdata
, size_t *dstdatalen
) {
361 uint8_t *data
= calloc(DESFIRE_BUFFER_SIZE
, sizeof(uint8_t));
366 memcpy(dstdata
, srcdata
, srcdatalen
);
367 *dstdatalen
= srcdatalen
;
369 uint8_t hdrlen
= DesfireGetCmdHeaderLen(cmd
);
370 if (srcdatalen
< hdrlen
) {
376 // we calc MAC anyway
377 // if encypted channel and no data - we only calc MAC
378 if (ctx
->commMode
== DCMPlain
|| ctx
->commMode
== DCMMACed
|| (ctx
->commMode
== DCMEncrypted
&& srcdatalen
<= hdrlen
)) {
380 memcpy(&data
[1], srcdata
, srcdatalen
);
381 uint8_t cmac
[DESFIRE_MAX_CRYPTO_BLOCK_SIZE
] = {0};
382 DesfireCryptoCMAC(ctx
, data
, srcdatalen
+ 1, cmac
);
384 memcpy(dstdata
, srcdata
, srcdatalen
);
385 *dstdatalen
= srcdatalen
;
386 if (ctx
->commMode
== DCMMACed
&& DesfireEV1D40TransmitMAC(ctx
, cmd
)) {
387 memcpy(&dstdata
[srcdatalen
], cmac
, DesfireGetMACLength(ctx
));
388 *dstdatalen
= srcdatalen
+ DesfireGetMACLength(ctx
);
391 } else if (ctx
->commMode
== DCMEncrypted
|| ctx
->commMode
== DCMEncryptedWithPadding
) {
392 uint8_t paddinglen
= (ctx
->commMode
== DCMEncryptedWithPadding
) ? 1 : 0;
393 rlen
= padded_data_length(srcdatalen
+ 4 + paddinglen
- hdrlen
, desfire_get_key_block_length(ctx
->keyType
));
397 memcpy(&data
[1], srcdata
, srcdatalen
);
398 desfire_crc32_append(data
, srcdatalen
+ 1);
402 data
[srcdatalen
+ 1 + 4] = 0x80;
404 memcpy(dstdata
, srcdata
, hdrlen
);
405 DesfireCryptoEncDec(ctx
, DCOSessionKeyEnc
, &data
[1 + hdrlen
], rlen
, &dstdata
[hdrlen
], true);
407 *dstdatalen
= hdrlen
+ rlen
;
408 ctx
->commMode
= DCMEncrypted
;
409 } else if (ctx
->commMode
== DCMEncryptedPlain
) {
410 if (srcdatalen
<= hdrlen
) {
415 memcpy(dstdata
, srcdata
, hdrlen
);
416 memcpy(data
, &srcdata
[hdrlen
], srcdatalen
);
417 rlen
= padded_data_length(srcdatalen
- hdrlen
, desfire_get_key_block_length(ctx
->keyType
));
418 DesfireCryptoEncDec(ctx
, DCOSessionKeyEnc
, data
, rlen
, &dstdata
[hdrlen
], true);
419 *dstdatalen
= hdrlen
+ rlen
;
420 ctx
->commMode
= DCMEncrypted
;
425 static void DesfireSecureChannelEncodeEV2(DesfireContext_t
*ctx
, uint8_t cmd
, uint8_t *srcdata
, size_t srcdatalen
, uint8_t *dstdata
, size_t *dstdatalen
) {
427 uint8_t *data
= calloc(DESFIRE_BUFFER_SIZE
, sizeof(uint8_t));
431 memcpy(dstdata
, srcdata
, srcdatalen
);
432 *dstdatalen
= srcdatalen
;
434 uint8_t hdrlen
= DesfireGetCmdHeaderLen(cmd
);
435 if (srcdatalen
< hdrlen
)
438 if (ctx
->commMode
== DCMMACed
) {
439 uint8_t cmac
[DESFIRE_MAX_CRYPTO_BLOCK_SIZE
] = {0};
440 DesfireEV2CalcCMAC(ctx
, cmd
, srcdata
, srcdatalen
, cmac
);
442 memcpy(&dstdata
[srcdatalen
], cmac
, DesfireGetMACLength(ctx
));
443 *dstdatalen
= srcdatalen
+ DesfireGetMACLength(ctx
);
444 } else if (ctx
->commMode
== DCMEncrypted
|| ctx
->commMode
== DCMEncryptedWithPadding
|| ctx
->commMode
== DCMEncryptedPlain
) {
445 memcpy(dstdata
, srcdata
, hdrlen
);
448 if (srcdatalen
> hdrlen
) {
449 rlen
= padded_data_length(srcdatalen
+ 1 - hdrlen
, desfire_get_key_block_length(ctx
->keyType
));
450 memcpy(data
, &srcdata
[hdrlen
], srcdatalen
- hdrlen
);
451 data
[srcdatalen
- hdrlen
] = 0x80; // padding
453 DesfireEV2FillIV(ctx
, true, NULL
); // fill IV to ctx
454 DesfireCryptoEncDec(ctx
, DCOSessionKeyEnc
, data
, rlen
, &dstdata
[hdrlen
], true);
457 uint8_t cmac
[DESFIRE_MAX_CRYPTO_BLOCK_SIZE
] = {0};
458 DesfireEV2CalcCMAC(ctx
, cmd
, dstdata
, hdrlen
+ rlen
, cmac
);
460 memcpy(&dstdata
[hdrlen
+ rlen
], cmac
, DesfireGetMACLength(ctx
));
462 *dstdatalen
= hdrlen
+ rlen
+ DesfireGetMACLength(ctx
);
463 ctx
->commMode
= DCMEncrypted
;
468 static void DesfireSecureChannelEncodeLRP(DesfireContext_t
*ctx
, uint8_t cmd
, uint8_t *srcdata
, size_t srcdatalen
, uint8_t *dstdata
, size_t *dstdatalen
) {
470 uint8_t *data
= calloc(DESFIRE_BUFFER_SIZE
, sizeof(uint8_t));
474 memcpy(dstdata
, srcdata
, srcdatalen
);
475 *dstdatalen
= srcdatalen
;
477 uint8_t hdrlen
= DesfireGetCmdHeaderLen(cmd
);
478 if (srcdatalen
< hdrlen
)
481 if (ctx
->commMode
== DCMMACed
) {
482 uint8_t cmac
[DESFIRE_MAX_CRYPTO_BLOCK_SIZE
] = {0};
483 DesfireLRPCalcCMAC(ctx
, cmd
, srcdata
, srcdatalen
, cmac
);
485 memcpy(&dstdata
[srcdatalen
], cmac
, DesfireGetMACLength(ctx
));
486 *dstdatalen
= srcdatalen
+ DesfireGetMACLength(ctx
);
487 } else if (ctx
->commMode
== DCMEncrypted
|| ctx
->commMode
== DCMEncryptedWithPadding
|| ctx
->commMode
== DCMEncryptedPlain
) {
488 memcpy(dstdata
, srcdata
, hdrlen
);
491 if (srcdatalen
> hdrlen
) {
492 rlen
= padded_data_length(srcdatalen
+ 1 - hdrlen
, desfire_get_key_block_length(ctx
->keyType
));
493 memcpy(data
, &srcdata
[hdrlen
], srcdatalen
- hdrlen
);
494 data
[srcdatalen
- hdrlen
] = 0x80; // padding
496 DesfireCryptoEncDec(ctx
, DCOSessionKeyEnc
, data
, rlen
, &dstdata
[hdrlen
], true);
499 uint8_t cmac
[DESFIRE_MAX_CRYPTO_BLOCK_SIZE
] = {0};
500 DesfireLRPCalcCMAC(ctx
, cmd
, dstdata
, hdrlen
+ rlen
, cmac
);
502 memcpy(&dstdata
[hdrlen
+ rlen
], cmac
, DesfireGetMACLength(ctx
));
504 *dstdatalen
= hdrlen
+ rlen
+ DesfireGetMACLength(ctx
);
505 ctx
->commMode
= DCMEncrypted
;
510 void DesfireSecureChannelEncode(DesfireContext_t
*ctx
, uint8_t cmd
, uint8_t *srcdata
, size_t srcdatalen
, uint8_t *dstdata
, size_t *dstdatalen
) {
511 ctx
->lastCommand
= cmd
;
512 ctx
->lastRequestZeroLen
= (srcdatalen
<= DesfireGetCmdHeaderLen(cmd
));
514 switch (ctx
->secureChannel
) {
516 DesfireSecureChannelEncodeD40(ctx
, cmd
, srcdata
, srcdatalen
, dstdata
, dstdatalen
);
519 DesfireSecureChannelEncodeEV1(ctx
, cmd
, srcdata
, srcdatalen
, dstdata
, dstdatalen
);
522 DesfireSecureChannelEncodeEV2(ctx
, cmd
, srcdata
, srcdatalen
, dstdata
, dstdatalen
);
525 DesfireSecureChannelEncodeLRP(ctx
, cmd
, srcdata
, srcdatalen
, dstdata
, dstdatalen
);
528 memcpy(dstdata
, srcdata
, srcdatalen
);
529 *dstdatalen
= srcdatalen
;
534 static void DesfireSecureChannelDecodeD40(DesfireContext_t
*ctx
, uint8_t *srcdata
, size_t srcdatalen
, uint8_t respcode
, uint8_t *dstdata
, size_t *dstdatalen
) {
536 uint8_t *data
= calloc(DESFIRE_BUFFER_SIZE
, sizeof(uint8_t));
540 memcpy(dstdata
, srcdata
, srcdatalen
);
541 *dstdatalen
= srcdatalen
;
543 switch (ctx
->commMode
) {
545 size_t maclen
= DesfireGetMACLength(ctx
);
546 if (srcdatalen
> maclen
&& DesfireEV1D40ReceiveMAC(ctx
, ctx
->lastCommand
)) {
547 uint8_t mac
[16] = {0};
548 size_t rlen
= padded_data_length(srcdatalen
- maclen
, desfire_get_key_block_length(ctx
->keyType
));
549 memcpy(data
, srcdata
, srcdatalen
- maclen
);
550 DesfireCryptoEncDecEx(ctx
, DCOSessionKeyMac
, data
, rlen
, NULL
, true, true, mac
);
552 if (memcmp(mac
, &srcdata
[srcdatalen
- maclen
], maclen
) == 0) {
553 *dstdatalen
= srcdatalen
- maclen
;
554 if (GetAPDULogging())
555 PrintAndLogEx(INFO
, "Received MAC OK");
557 PrintAndLogEx(WARNING
, "Received MAC is not match with calculated");
558 PrintAndLogEx(INFO
, " received MAC: %s", sprint_hex(&srcdata
[srcdatalen
- maclen
], maclen
));
559 PrintAndLogEx(INFO
, " calculated MAC: %s", sprint_hex(mac
, maclen
));
565 case DCMEncryptedWithPadding
:
566 if (srcdatalen
< desfire_get_key_block_length(ctx
->keyType
)) {
567 memcpy(dstdata
, srcdata
, srcdatalen
);
568 *dstdatalen
= srcdatalen
;
573 DesfireCryptoEncDec(ctx
, DCOSessionKeyEnc
, srcdata
, srcdatalen
, dstdata
, false);
574 //PrintAndLogEx(INFO, "decoded[%d]: %s", srcdatalen, sprint_hex(dstdata, srcdatalen));
576 size_t puredatalen
= DesfireSearchCRCPos(dstdata
, srcdatalen
, respcode
, 2);
577 if (puredatalen
!= 0) {
578 *dstdatalen
= puredatalen
;
580 PrintAndLogEx(WARNING
, "CRC16 error.");
581 *dstdatalen
= srcdatalen
;
586 case DCMEncryptedPlain
:
587 memcpy(dstdata
, srcdata
, srcdatalen
);
588 *dstdatalen
= srcdatalen
;
594 static void DesfireSecureChannelDecodeEV1(DesfireContext_t
*ctx
, uint8_t *srcdata
, size_t srcdatalen
, uint8_t respcode
, uint8_t *dstdata
, size_t *dstdatalen
) {
596 uint8_t *data
= calloc(DESFIRE_BUFFER_SIZE
, sizeof(uint8_t));
601 // if comm mode = plain --> response with MAC
602 // if request is not zero length --> response MAC
603 if (ctx
->commMode
== DCMPlain
|| ctx
->commMode
== DCMMACed
|| (ctx
->commMode
== DCMEncrypted
&& !ctx
->lastRequestZeroLen
)) {
605 if (srcdatalen
< DesfireGetMACLength(ctx
)) {
606 memcpy(dstdata
, srcdata
, srcdatalen
);
607 *dstdatalen
= srcdatalen
;
612 memcpy(dstdata
, srcdata
, srcdatalen
- DesfireGetMACLength(ctx
));
614 *dstdatalen
= srcdatalen
- DesfireGetMACLength(ctx
);
616 memcpy(data
, srcdata
, *dstdatalen
);
617 data
[*dstdatalen
] = respcode
;
619 uint8_t cmac
[DESFIRE_MAX_CRYPTO_BLOCK_SIZE
] = {0};
620 DesfireCryptoCMAC(ctx
, data
, *dstdatalen
+ 1, cmac
);
622 if (memcmp(&srcdata
[*dstdatalen
], cmac
, DesfireGetMACLength(ctx
)) != 0) {
624 PrintAndLogEx(WARNING
, "Received MAC is not match with calculated");
625 PrintAndLogEx(INFO
, " received MAC: %s", sprint_hex(&srcdata
[*dstdatalen
], DesfireGetMACLength(ctx
)));
626 PrintAndLogEx(INFO
, " calculated MAC: %s", sprint_hex(cmac
, DesfireGetMACLength(ctx
)));
630 if (GetAPDULogging()) {
631 PrintAndLogEx(INFO
, "Received MAC OK");
635 } else if (ctx
->commMode
== DCMEncrypted
|| ctx
->commMode
== DCMEncryptedWithPadding
) {
637 if (srcdatalen
< desfire_get_key_block_length(ctx
->keyType
)) {
638 memcpy(dstdata
, srcdata
, srcdatalen
);
639 *dstdatalen
= srcdatalen
;
644 DesfireCryptoEncDec(ctx
, DCOSessionKeyEnc
, srcdata
, srcdatalen
, dstdata
, false);
645 // PrintAndLogEx(INFO, "decoded[%d]: %s", srcdatalen, sprint_hex(dstdata, srcdatalen));
647 size_t puredatalen
= DesfireSearchCRCPos(dstdata
, srcdatalen
, respcode
, 4);
648 if (puredatalen
!= 0) {
649 *dstdatalen
= puredatalen
;
651 PrintAndLogEx(WARNING
, "CRC32 error.");
652 *dstdatalen
= srcdatalen
;
656 memcpy(dstdata
, srcdata
, srcdatalen
);
657 *dstdatalen
= srcdatalen
;
662 static void DesfireSecureChannelDecodeEV2(DesfireContext_t
*ctx
, uint8_t *srcdata
, size_t srcdatalen
, uint8_t respcode
, uint8_t *dstdata
, size_t *dstdatalen
) {
665 memcpy(dstdata
, srcdata
, srcdatalen
);
666 *dstdatalen
= srcdatalen
;
667 uint8_t cmac
[DESFIRE_MAX_CRYPTO_BLOCK_SIZE
] = {0};
669 if (ctx
->commMode
== DCMMACed
) {
670 if (srcdatalen
< DesfireGetMACLength(ctx
)) {
671 memcpy(dstdata
, srcdata
, srcdatalen
);
672 *dstdatalen
= srcdatalen
;
676 memcpy(dstdata
, srcdata
, srcdatalen
- DesfireGetMACLength(ctx
));
677 *dstdatalen
= srcdatalen
- DesfireGetMACLength(ctx
);
679 DesfireEV2CalcCMAC(ctx
, 0x00, srcdata
, *dstdatalen
, cmac
);
680 if (memcmp(&srcdata
[*dstdatalen
], cmac
, DesfireGetMACLength(ctx
)) != 0) {
681 PrintAndLogEx(WARNING
, "Received MAC is not match with calculated");
682 PrintAndLogEx(INFO
, " received MAC: %s", sprint_hex(&srcdata
[*dstdatalen
], DesfireGetMACLength(ctx
)));
683 PrintAndLogEx(INFO
, " calculated MAC: %s", sprint_hex(cmac
, DesfireGetMACLength(ctx
)));
685 if (GetAPDULogging())
686 PrintAndLogEx(INFO
, "Received MAC OK");
688 } else if (ctx
->commMode
== DCMEncrypted
|| ctx
->commMode
== DCMEncryptedWithPadding
) {
689 if (srcdatalen
< DesfireGetMACLength(ctx
)) {
690 memcpy(dstdata
, srcdata
, srcdatalen
);
691 *dstdatalen
= srcdatalen
;
695 *dstdatalen
= srcdatalen
- DesfireGetMACLength(ctx
);
696 DesfireEV2CalcCMAC(ctx
, 0x00, srcdata
, *dstdatalen
, cmac
);
697 if (memcmp(&srcdata
[*dstdatalen
], cmac
, DesfireGetMACLength(ctx
)) != 0) {
698 PrintAndLogEx(WARNING
, "Received MAC is not match with calculated");
699 PrintAndLogEx(INFO
, " received MAC: %s", sprint_hex(&srcdata
[*dstdatalen
], DesfireGetMACLength(ctx
)));
700 PrintAndLogEx(INFO
, " calculated MAC: %s", sprint_hex(cmac
, DesfireGetMACLength(ctx
)));
702 if (GetAPDULogging())
703 PrintAndLogEx(INFO
, "Received MAC OK");
706 if (*dstdatalen
>= desfire_get_key_block_length(ctx
->keyType
)) {
707 DesfireEV2FillIV(ctx
, false, NULL
); // fill response IV to ctx
708 DesfireCryptoEncDec(ctx
, DCOSessionKeyEnc
, srcdata
, *dstdatalen
, dstdata
, false);
710 size_t puredatalen
= FindISO9797M2PaddingDataLen(dstdata
, *dstdatalen
);
711 if (puredatalen
!= 0) {
712 *dstdatalen
= puredatalen
;
714 PrintAndLogEx(WARNING
, "Padding search error.");
720 static void DesfireSecureChannelDecodeLRP(DesfireContext_t
*ctx
, uint8_t *srcdata
, size_t srcdatalen
, uint8_t respcode
, uint8_t *dstdata
, size_t *dstdatalen
) {
723 memcpy(dstdata
, srcdata
, srcdatalen
);
724 *dstdatalen
= srcdatalen
;
725 uint8_t cmac
[DESFIRE_MAX_CRYPTO_BLOCK_SIZE
] = {0};
727 if (ctx
->commMode
== DCMMACed
) {
728 if (srcdatalen
< DesfireGetMACLength(ctx
)) {
729 memcpy(dstdata
, srcdata
, srcdatalen
);
730 *dstdatalen
= srcdatalen
;
734 memcpy(dstdata
, srcdata
, srcdatalen
- DesfireGetMACLength(ctx
));
735 *dstdatalen
= srcdatalen
- DesfireGetMACLength(ctx
);
737 DesfireLRPCalcCMAC(ctx
, 0x00, srcdata
, *dstdatalen
, cmac
);
738 if (memcmp(&srcdata
[*dstdatalen
], cmac
, DesfireGetMACLength(ctx
)) != 0) {
739 PrintAndLogEx(WARNING
, "Received MAC is not match with calculated");
740 PrintAndLogEx(INFO
, " received MAC: %s", sprint_hex(&srcdata
[*dstdatalen
], DesfireGetMACLength(ctx
)));
741 PrintAndLogEx(INFO
, " calculated MAC: %s", sprint_hex(cmac
, DesfireGetMACLength(ctx
)));
743 if (GetAPDULogging())
744 PrintAndLogEx(INFO
, "Received MAC OK");
746 } else if (ctx
->commMode
== DCMEncrypted
|| ctx
->commMode
== DCMEncryptedWithPadding
) {
747 if (srcdatalen
< DesfireGetMACLength(ctx
)) {
748 memcpy(dstdata
, srcdata
, srcdatalen
);
749 *dstdatalen
= srcdatalen
;
753 *dstdatalen
= srcdatalen
- DesfireGetMACLength(ctx
);
754 DesfireLRPCalcCMAC(ctx
, 0x00, srcdata
, *dstdatalen
, cmac
);
755 if (memcmp(&srcdata
[*dstdatalen
], cmac
, DesfireGetMACLength(ctx
)) != 0) {
756 PrintAndLogEx(WARNING
, "Received MAC is not match with calculated");
757 PrintAndLogEx(INFO
, " received MAC: %s", sprint_hex(&srcdata
[*dstdatalen
], DesfireGetMACLength(ctx
)));
758 PrintAndLogEx(INFO
, " calculated MAC: %s", sprint_hex(cmac
, DesfireGetMACLength(ctx
)));
760 if (GetAPDULogging())
761 PrintAndLogEx(INFO
, "Received MAC OK");
764 if (*dstdatalen
>= desfire_get_key_block_length(ctx
->keyType
)) {
765 DesfireCryptoEncDec(ctx
, DCOSessionKeyEnc
, srcdata
, *dstdatalen
, dstdata
, false);
767 size_t puredatalen
= FindISO9797M2PaddingDataLen(dstdata
, *dstdatalen
);
768 if (puredatalen
!= 0) {
769 *dstdatalen
= puredatalen
;
771 PrintAndLogEx(WARNING
, "Padding search error.");
777 static void DesfireISODecode(DesfireContext_t
*ctx
, uint8_t *srcdata
, size_t srcdatalen
, uint8_t *dstdata
, size_t *dstdatalen
) {
778 memcpy(dstdata
, srcdata
, srcdatalen
);
779 *dstdatalen
= srcdatalen
;
781 if (srcdatalen
< DesfireGetMACLength(ctx
))
784 uint8_t *data
= calloc(DESFIRE_BUFFER_SIZE
, 1);
788 uint8_t maclen
= DesfireGetMACLength(ctx
);
789 if (DesfireIsAuthenticated(ctx
)) {
790 memcpy(data
, srcdata
, srcdatalen
- maclen
);
791 data
[*dstdatalen
] = 0x00; // respcode
793 uint8_t cmac
[DESFIRE_MAX_CRYPTO_BLOCK_SIZE
] = {0};
794 DesfireCryptoCMAC(ctx
, data
, srcdatalen
- maclen
+ 1, cmac
);
795 if (memcmp(&srcdata
[srcdatalen
- maclen
], cmac
, maclen
) != 0) {
796 PrintAndLogEx(WARNING
, "Received MAC is not match with calculated");
797 PrintAndLogEx(INFO
, " received MAC: %s", sprint_hex(&srcdata
[srcdatalen
- maclen
], maclen
));
798 PrintAndLogEx(INFO
, " calculated MAC: %s", sprint_hex(cmac
, maclen
));
800 *dstdatalen
= srcdatalen
- maclen
;
801 if (GetAPDULogging())
802 PrintAndLogEx(INFO
, "Received MAC OK");
808 void DesfireSecureChannelDecode(DesfireContext_t
*ctx
, uint8_t *srcdata
, size_t srcdatalen
, uint8_t respcode
, uint8_t *dstdata
, size_t *dstdatalen
) {
809 if (ctx
->cmdSet
== DCCISO
) {
810 DesfireISODecode(ctx
, srcdata
, srcdatalen
, dstdata
, dstdatalen
);
814 switch (ctx
->secureChannel
) {
816 DesfireSecureChannelDecodeD40(ctx
, srcdata
, srcdatalen
, respcode
, dstdata
, dstdatalen
);
819 DesfireSecureChannelDecodeEV1(ctx
, srcdata
, srcdatalen
, respcode
, dstdata
, dstdatalen
);
822 DesfireSecureChannelDecodeEV2(ctx
, srcdata
, srcdatalen
, respcode
, dstdata
, dstdatalen
);
825 DesfireSecureChannelDecodeLRP(ctx
, srcdata
, srcdatalen
, respcode
, dstdata
, dstdatalen
);
828 memcpy(dstdata
, srcdata
, srcdatalen
);
829 *dstdatalen
= srcdatalen
;
834 bool PrintChannelModeWarning(uint8_t cmd
, DesfireSecureChannel secureChannel
, DesfireCommandSet cmdSet
, DesfireCommunicationMode commMode
) {
835 if (commMode
== DCMNone
) {
836 PrintAndLogEx(WARNING
, "Communication mode can't be NONE. command: %02x", cmd
);
841 if (secureChannel
== DACNone
)
844 if (CommandCanUseAnyChannel(cmd
))
848 if (cmdSet
== DCCISO
) {
849 bool res
= DesfireISOChannelValidCmd(cmd
);
855 for (int i
= 0; i
< ARRAYLEN(AllowedChannelModes
); i
++)
856 if (AllowedChannelModes
[i
].cmd
== cmd
) {
858 if (AllowedChannelModes
[i
].secureChannel
== secureChannel
&&
859 (AllowedChannelModes
[i
].cmdSet
== cmdSet
|| (AllowedChannelModes
[i
].cmdSet
== DCCNative
&& cmdSet
== DCCNativeISO
)) &&
860 AllowedChannelModes
[i
].commMode
== commMode
) {
866 // ev1 plain and mac are the same
867 if (AllowedChannelModes
[i
].secureChannel
== secureChannel
&&
868 AllowedChannelModes
[i
].secureChannel
== DACEV1
&&
869 (AllowedChannelModes
[i
].cmdSet
== cmdSet
|| (AllowedChannelModes
[i
].cmdSet
== DCCNative
&& cmdSet
== DCCNativeISO
)) &&
870 (commMode
== DCMPlain
|| commMode
== DCMMACed
)) {
877 if (secureChannel
== DACEV2
&&
878 AllowedChannelModes
[i
].secureChannel
== DACEV1
&&
879 (AllowedChannelModes
[i
].cmdSet
== cmdSet
|| (AllowedChannelModes
[i
].cmdSet
== DCCNative
&& cmdSet
== DCCNativeISO
)) &&
880 AllowedChannelModes
[i
].commMode
== commMode
) {
888 PrintAndLogEx(WARNING
, "Wrong communication mode. Check settings. command: %02x", cmd
);