style
[RRG-proxmark3.git] / client / src / mifare / desfiresecurechan.c
blobd35833b4d7f7d310c65619ad39f689b1cbcec6d4
1 //-----------------------------------------------------------------------------
2 // Borrowed initially from https://github.com/nfc-tools/libfreefare
3 // Copyright (C) 2010, Romain Tartiere.
4 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
5 //
6 // This program is free software: you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation, either version 3 of the License, or
9 // (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // See LICENSE.txt for the text of the license.
17 //-----------------------------------------------------------------------------
18 // High frequency Desfire secure channel functions
19 //-----------------------------------------------------------------------------
21 #include "desfiresecurechan.h"
23 #include <stdlib.h>
24 #include <string.h>
25 #include <util.h>
26 #include "ui.h"
27 #include "crc.h"
28 #include "crc16.h" // crc16 ccitt
29 #include "crc32.h"
30 #include "commonutil.h"
31 #include "protocols.h"
33 static const uint8_t CommandsCanUseAnyChannel[] = {
34 MFDES_S_ADDITIONAL_FRAME,
35 MFDES_READ_DATA,
36 MFDES_READ_DATA2,
37 MFDES_WRITE_DATA,
38 MFDES_WRITE_DATA2,
39 MFDES_READ_RECORDS,
40 MFDES_READ_RECORDS2,
41 MFDES_WRITE_RECORD,
42 MFDES_WRITE_RECORD2,
43 MFDES_UPDATE_RECORD,
44 MFDES_UPDATE_RECORD2,
45 MFDES_GET_VALUE,
46 MFDES_CREDIT,
47 MFDES_DEBIT,
48 MFDES_LIMITED_CREDIT,
51 static bool CommandCanUseAnyChannel(uint8_t cmd) {
52 for (int i = 0; i < ARRAYLEN(CommandsCanUseAnyChannel); i++) {
53 if (CommandsCanUseAnyChannel[i] == cmd) {
54 return true;
57 return false;
60 static const AllowedChannelModes_t AllowedChannelModes[] = {
61 // D40 channel
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},
147 // ISO channel
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},
206 {MFDES_CREDIT, 1},
207 {MFDES_DEBIT, 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;
217 return 0;
220 static const uint8_t EV1D40TransmitMAC[] = {
221 MFDES_WRITE_DATA,
222 MFDES_CREDIT,
223 MFDES_LIMITED_CREDIT,
224 MFDES_DEBIT,
225 MFDES_WRITE_RECORD,
226 MFDES_UPDATE_RECORD,
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) {
235 return true;
238 for (int i = 0; i < ARRAYLEN(EV1D40TransmitMAC); i++) {
239 if (EV1D40TransmitMAC[i] == cmd) {
240 return true;
244 return false;
247 static const uint8_t D40ReceiveMAC[] = {
248 MFDES_READ_DATA,
249 MFDES_READ_DATA2,
250 MFDES_READ_RECORDS,
251 MFDES_READ_RECORDS2,
252 MFDES_GET_VALUE,
255 static bool DesfireEV1D40ReceiveMAC(DesfireContext_t *ctx, uint8_t cmd) {
256 if (ctx->secureChannel != DACd40) {
257 return true;
260 for (int i = 0; i < ARRAYLEN(D40ReceiveMAC); i++) {
261 if (D40ReceiveMAC[i] == cmd) {
262 return true;
266 return false;
269 static const uint8_t ISOChannelValidCmd[] = {
270 ISO7816_SELECT_FILE,
271 ISO7816_READ_BINARY,
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) {
283 return true;
286 return false;
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));
292 if (data == NULL)
293 return;
295 memcpy(dstdata, srcdata, srcdatalen);
296 *dstdatalen = srcdatalen;
298 uint8_t hdrlen = DesfireGetCmdHeaderLen(cmd);
299 if (srcdatalen < hdrlen)
300 hdrlen = srcdatalen;
302 size_t rlen;
304 if (ctx->commMode == DCMMACed || (ctx->commMode == DCMEncrypted && srcdatalen <= hdrlen)) {
305 if (srcdatalen == 0) {
306 free(data);
307 return;
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));
320 *dstdatalen = rlen;
322 } else if (ctx->commMode == DCMEncrypted || ctx->commMode == DCMEncryptedWithPadding) {
323 if (srcdatalen <= hdrlen) {
324 free(data);
325 return;
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);
333 // add padding
334 if (paddinglen > 0)
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);
341 *dstdatalen = rlen;
342 } else if (ctx->commMode == DCMEncryptedPlain) {
343 if (srcdatalen == 0 || srcdatalen <= hdrlen) {
344 free(data);
345 return;
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);
352 *dstdatalen = rlen;
353 ctx->commMode = DCMEncrypted;
356 free(data);
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));
362 if (data == NULL) {
363 return;
366 memcpy(dstdata, srcdata, srcdatalen);
367 *dstdatalen = srcdatalen;
369 uint8_t hdrlen = DesfireGetCmdHeaderLen(cmd);
370 if (srcdatalen < hdrlen) {
371 hdrlen = srcdatalen;
374 size_t rlen;
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)) {
379 data[0] = cmd;
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));
394 data[0] = cmd;
396 // crc
397 memcpy(&data[1], srcdata, srcdatalen);
398 desfire_crc32_append(data, srcdatalen + 1);
400 // add padding
401 if (paddinglen > 0)
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) {
411 free(data);
412 return;
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;
422 free(data);
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));
428 if (data == NULL)
429 return;
431 memcpy(dstdata, srcdata, srcdatalen);
432 *dstdatalen = srcdatalen;
434 uint8_t hdrlen = DesfireGetCmdHeaderLen(cmd);
435 if (srcdatalen < hdrlen)
436 hdrlen = srcdatalen;
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);
447 size_t rlen = 0;
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;
465 free(data);
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));
471 if (data == NULL)
472 return;
474 memcpy(dstdata, srcdata, srcdatalen);
475 *dstdatalen = srcdatalen;
477 uint8_t hdrlen = DesfireGetCmdHeaderLen(cmd);
478 if (srcdatalen < hdrlen)
479 hdrlen = srcdatalen;
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);
490 size_t rlen = 0;
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;
507 free(data);
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) {
515 case DACd40:
516 DesfireSecureChannelEncodeD40(ctx, cmd, srcdata, srcdatalen, dstdata, dstdatalen);
517 break;
518 case DACEV1:
519 DesfireSecureChannelEncodeEV1(ctx, cmd, srcdata, srcdatalen, dstdata, dstdatalen);
520 break;
521 case DACEV2:
522 DesfireSecureChannelEncodeEV2(ctx, cmd, srcdata, srcdatalen, dstdata, dstdatalen);
523 break;
524 case DACLRP:
525 DesfireSecureChannelEncodeLRP(ctx, cmd, srcdata, srcdatalen, dstdata, dstdatalen);
526 break;
527 case DACNone:
528 memcpy(dstdata, srcdata, srcdatalen);
529 *dstdatalen = srcdatalen;
530 break;
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));
537 if (data == NULL)
538 return;
540 memcpy(dstdata, srcdata, srcdatalen);
541 *dstdatalen = srcdatalen;
543 switch (ctx->commMode) {
544 case DCMMACed: {
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");
556 } else {
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));
562 break;
564 case DCMEncrypted:
565 case DCMEncryptedWithPadding:
566 if (srcdatalen < desfire_get_key_block_length(ctx->keyType)) {
567 memcpy(dstdata, srcdata, srcdatalen);
568 *dstdatalen = srcdatalen;
569 free(data);
570 return;
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;
579 } else {
580 PrintAndLogEx(WARNING, "CRC16 error.");
581 *dstdatalen = srcdatalen;
583 break;
584 case DCMPlain:
585 case DACNone:
586 case DCMEncryptedPlain:
587 memcpy(dstdata, srcdata, srcdatalen);
588 *dstdatalen = srcdatalen;
589 break;
591 free(data);
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));
597 if (data == NULL) {
598 return;
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;
608 free(data);
609 return;
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)));
628 } else {
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;
640 free(data);
641 return;
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;
650 } else {
651 PrintAndLogEx(WARNING, "CRC32 error.");
652 *dstdatalen = srcdatalen;
655 } else {
656 memcpy(dstdata, srcdata, srcdatalen);
657 *dstdatalen = srcdatalen;
659 free(data);
662 static void DesfireSecureChannelDecodeEV2(DesfireContext_t *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t respcode, uint8_t *dstdata, size_t *dstdatalen) {
663 ctx->cmdCntr++;
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;
673 return;
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)));
684 } else {
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;
692 return;
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)));
701 } else {
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;
713 } else {
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) {
721 ctx->cmdCntr++;
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;
731 return;
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)));
742 } else {
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;
750 return;
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)));
759 } else {
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;
770 } else {
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))
782 return;
784 uint8_t *data = calloc(DESFIRE_BUFFER_SIZE, 1);
785 if (data == NULL)
786 return;
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));
799 } else {
800 *dstdatalen = srcdatalen - maclen;
801 if (GetAPDULogging())
802 PrintAndLogEx(INFO, "Received MAC OK");
805 free(data);
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);
811 return;
814 switch (ctx->secureChannel) {
815 case DACd40:
816 DesfireSecureChannelDecodeD40(ctx, srcdata, srcdatalen, respcode, dstdata, dstdatalen);
817 break;
818 case DACEV1:
819 DesfireSecureChannelDecodeEV1(ctx, srcdata, srcdatalen, respcode, dstdata, dstdatalen);
820 break;
821 case DACEV2:
822 DesfireSecureChannelDecodeEV2(ctx, srcdata, srcdatalen, respcode, dstdata, dstdatalen);
823 break;
824 case DACLRP:
825 DesfireSecureChannelDecodeLRP(ctx, srcdata, srcdatalen, respcode, dstdata, dstdatalen);
826 break;
827 case DACNone:
828 memcpy(dstdata, srcdata, srcdatalen);
829 *dstdatalen = srcdatalen;
830 break;
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);
837 return false;
840 // no security set
841 if (secureChannel == DACNone)
842 return true;
844 if (CommandCanUseAnyChannel(cmd))
845 return true;
847 // ISO commands
848 if (cmdSet == DCCISO) {
849 bool res = DesfireISOChannelValidCmd(cmd);
850 if (!res)
851 return false;
854 bool found = false;
855 for (int i = 0; i < ARRAYLEN(AllowedChannelModes); i++)
856 if (AllowedChannelModes[i].cmd == cmd) {
857 // full compare
858 if (AllowedChannelModes[i].secureChannel == secureChannel &&
859 (AllowedChannelModes[i].cmdSet == cmdSet || (AllowedChannelModes[i].cmdSet == DCCNative && cmdSet == DCCNativeISO)) &&
860 AllowedChannelModes[i].commMode == commMode) {
862 found = true;
863 break;
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)) {
872 found = true;
873 break;
876 // ev2 like ev1
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) {
882 found = true;
883 break;
887 if (!found)
888 PrintAndLogEx(WARNING, "Wrong communication mode. Check settings. command: %02x", cmd);
890 return found;