diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt
index 4879e953b..536464d18 100644
--- a/client/CMakeLists.txt
+++ b/client/CMakeLists.txt
@@ -226,6 +226,7 @@ set (TARGET_SOURCES
${PM3_ROOT}/client/src/mifare/mifarehost.c
${PM3_ROOT}/client/src/nfc/ndef.c
${PM3_ROOT}/client/src/mifare/desfire_crypto.c
+ ${PM3_ROOT}/client/src/mifare/desfirecrypto.c
${PM3_ROOT}/client/src/mifare/desfiresecurechan.c
${PM3_ROOT}/client/src/mifare/desfirecore.c
${PM3_ROOT}/client/src/uart/uart_posix.c
diff --git a/client/Makefile b/client/Makefile
index 45ddffe31..7d09586a0 100644
--- a/client/Makefile
+++ b/client/Makefile
@@ -589,6 +589,7 @@ SRCS = aiddesfire.c \
loclass/elite_crack.c \
loclass/ikeys.c \
mifare/desfire_crypto.c \
+ mifare/desfirecrypto.c \
mifare/desfirecore.c \
mifare/desfiresecurechan.c \
mifare/mad.c \
diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c
index 4204b8a3c..7526207e3 100644
--- a/client/src/cmdhfmfdes.c
+++ b/client/src/cmdhfmfdes.c
@@ -5217,6 +5217,8 @@ static int CmdHF14ADesGetAIDs(const char *Cmd) {
PrintAndLogEx(INFO, "---- " _CYAN_("AID list") " ----");
for (int i = 0; i < buflen; i += 3)
PrintAndLogEx(INFO, "AID: %06x", DesfireAIDByteToUint(&buf[i]));
+ } else {
+ PrintAndLogEx(INFO, "There is no applications on the card");
}
DropField();
@@ -5302,12 +5304,15 @@ static int CmdHF14ADesGetAppNames(const char *Cmd) {
buf[i * 24 + 1 + 3], buf[i * 24 + 1 + 4],
strlen((char *)&buf[i * 24 + 1 + 5]),
&buf[i * 24 + 1 + 5]);
+ } else {
+ PrintAndLogEx(INFO, "There is no applications on the card");
}
DropField();
return PM3_SUCCESS;
}
+
static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"},
{"-----------", CmdHelp, IfPm3Iso14443a, "---------------------- " _CYAN_("general") " ----------------------"},
@@ -5340,6 +5345,8 @@ static command_t CommandTable[] = {
{"getvalue", CmdHF14ADesGetValueData, IfPm3Iso14443a, "Get value of file"},
{"read", CmdHF14ADesReadData, IfPm3Iso14443a, "Read data from standard/backup/record file"},
{"write", CmdHF14ADesWriteData, IfPm3Iso14443a, "Write data to standard/backup/record file"},
+ {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("System") " -----------------------"},
+// {"test", CmdHF14ADesTest, IfPm3Iso14443a, "Test crypto"},
{NULL, NULL, NULL, NULL}
};
diff --git a/client/src/mifare/desfire_crypto.h b/client/src/mifare/desfire_crypto.h
index 71f3acb23..346a7e50c 100644
--- a/client/src/mifare/desfire_crypto.h
+++ b/client/src/mifare/desfire_crypto.h
@@ -25,10 +25,9 @@
#include "mifare.h" // structs
#include "crc32.h"
#include "crypto/libpcrypto.h"
+#include "mifare/desfirecrypto.h"
-#define MAX_CRYPTO_BLOCK_SIZE 16
-#define DESFIRE_MAX_KEY_SIZE 24
/* Mifare DESFire EV1 Application crypto operations */
#define APPLICATION_CRYPTO_DES 0x00
#define APPLICATION_CRYPTO_3K3DES 0x40
@@ -75,13 +74,6 @@ typedef enum {
/* Error code managed by the library */
#define CRYPTO_ERROR 0x01
-enum DESFIRE_CRYPTOALGO {
- T_DES = 0x00,
- T_3DES = 0x01, //aka 2K3DES
- T_3K3DES = 0x02,
- T_AES = 0x03
-};
-
int desfire_get_key_length(enum DESFIRE_CRYPTOALGO key_type);
size_t desfire_get_key_block_length(enum DESFIRE_CRYPTOALGO key_type);
diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c
index 9c4bb721b..862723587 100644
--- a/client/src/mifare/desfirecore.c
+++ b/client/src/mifare/desfirecore.c
@@ -203,34 +203,6 @@ void DesfireAIDUintToByte(uint32_t aid, uint8_t *data) {
data[2] = (aid >> 16) & 0xff;
}
-void DesfireClearContext(DesfireContext *ctx) {
- ctx->keyNum = 0;
- ctx->keyType = T_DES;
- memset(ctx->key, 0, sizeof(ctx->key));
-
- ctx->secureChannel = DACNone;
- ctx->cmdSet = DCCNative;
- ctx->commMode = DCMNone;
-
- ctx->kdfAlgo = 0;
- ctx->kdfInputLen = 0;
- memset(ctx->kdfInput, 0, sizeof(ctx->kdfInput));
-
- DesfireClearSession(ctx);
-}
-
-void DesfireClearSession(DesfireContext *ctx) {
- ctx->secureChannel = DACNone; // here none - not authenticared
-
- memset(ctx->IV, 0, sizeof(ctx->IV));
- memset(ctx->sessionKeyMAC, 0, sizeof(ctx->sessionKeyMAC));
- memset(ctx->sessionKeyEnc, 0, sizeof(ctx->sessionKeyEnc));
- memset(ctx->lastIV, 0, sizeof(ctx->lastIV));
- ctx->cntrTx = 0;
- ctx->cntrRx = 0;
- memset(ctx->TI, 0, sizeof(ctx->TI));
-}
-
void DesfirePrintContext(DesfireContext *ctx) {
PrintAndLogEx(INFO, "Key num: %d Key algo: %s Key[%d]: %s",
ctx->keyNum,
@@ -248,39 +220,18 @@ void DesfirePrintContext(DesfireContext *ctx) {
CLIGetOptionListStr(DesfireCommunicationModeOpts, ctx->commMode));
if (DesfireIsAuthenticated(ctx)) {
- PrintAndLogEx(INFO, "Session key MAC [%d]: %s ENC: %s IV [%d]: %s",
+ PrintAndLogEx(INFO, "Session key MAC [%d]: %s ",
desfire_get_key_length(ctx->keyType),
- sprint_hex(ctx->sessionKeyMAC, desfire_get_key_length(ctx->keyType)),
- sprint_hex(ctx->sessionKeyEnc, desfire_get_key_length(ctx->keyType)),
+ sprint_hex(ctx->sessionKeyMAC, desfire_get_key_length(ctx->keyType)));
+ PrintAndLogEx(INFO, " ENC: %s",
+ sprint_hex(ctx->sessionKeyEnc, desfire_get_key_length(ctx->keyType)));
+ PrintAndLogEx(INFO, " IV [%d]: %s",
desfire_get_key_block_length(ctx->keyType),
- sprint_hex(ctx->sessionKeyEnc, desfire_get_key_block_length(ctx->keyType)));
+ sprint_hex(ctx->IV, desfire_get_key_block_length(ctx->keyType)));
}
}
-void DesfireSetKey(DesfireContext *ctx, uint8_t keyNum, enum DESFIRE_CRYPTOALGO keyType, uint8_t *key) {
- DesfireClearContext(ctx);
-
- ctx->keyNum = keyNum;
- ctx->keyType = keyType;
- memcpy(ctx->key, key, desfire_get_key_length(keyType));
-}
-
-void DesfireSetCommandSet(DesfireContext *ctx, DesfireCommandSet cmdSet) {
- ctx->cmdSet = cmdSet;
-}
-
-void DesfireSetCommMode(DesfireContext *ctx, DesfireCommunicationMode commMode) {
- ctx->commMode = commMode;
-}
-
-void DesfireSetKdf(DesfireContext *ctx, uint8_t kdfAlgo, uint8_t *kdfInput, uint8_t kdfInputLen) {
- ctx->kdfAlgo = kdfAlgo;
- ctx->kdfInputLen = kdfInputLen;
- if (kdfInputLen)
- memcpy(ctx->kdfInput, kdfInput, kdfInputLen);
-}
-
static int DESFIRESendApdu(bool activate_field, sAPDU apdu, uint8_t *result, uint32_t max_result_len, uint32_t *result_len, uint16_t *sw) {
if (result_len) *result_len = 0;
if (sw) *sw = 0;
@@ -648,10 +599,6 @@ int DesfireSelectAIDHex(DesfireContext *ctx, uint32_t aid1, bool select_two, uin
return DesfireSelectAID(ctx, data, (select_two) ? &data[3] : NULL);
}
-bool DesfireIsAuthenticated(DesfireContext *dctx) {
- return dctx->secureChannel != DACNone;
-}
-
int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel) {
// 3 different way to authenticate AUTH (CRC16) , AUTH_ISO (CRC32) , AUTH_AES (CRC32)
// 4 different crypto arg1 DES, 3DES, 3K3DES, AES
@@ -917,6 +864,7 @@ int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel
//memcpy(dctx->sessionKeyEnc, sesskey.data, desfire_get_key_length(dctx->keyType));
}
+ memset(dctx->IV, 0, DESFIRE_MAX_KEY_SIZE);
dctx->secureChannel = secureChannel;
memcpy(dctx->sessionKeyMAC, dctx->sessionKeyEnc, desfire_get_key_length(dctx->keyType));
PrintAndLogEx(INFO, "sessionKeyEnc : %s", sprint_hex(dctx->sessionKeyEnc, desfire_get_key_length(dctx->keyType)));
@@ -943,3 +891,30 @@ int DesfireGetDFList(DesfireContext *dctx, uint8_t *resp, size_t *resplen) {
return PM3_EAPDU_FAIL;
return PM3_SUCCESS;
}
+
+int DesfireCreateApplication(DesfireContext *dctx, uint8_t *appdata, size_t appdatalen) {
+ uint8_t respcode = 0xff;
+ uint8_t resp[257] = {0};
+ size_t resplen = 0;
+ int res = DesfireExchangeEx(false, dctx, MFDES_CREATE_APPLICATION, appdata, appdatalen, &respcode, resp, &resplen, true, 24);
+ if (res != PM3_SUCCESS)
+ return res;
+ if (respcode != MFDES_S_OPERATION_OK || resplen != 0)
+ return PM3_EAPDU_FAIL;
+ return PM3_SUCCESS;
+}
+
+int DesfireDeleteApplication(DesfireContext *dctx, uint32_t aid) {
+ uint8_t respcode = 0xff;
+ uint8_t data[3] = {0};
+ DesfireAIDUintToByte(aid, data);
+ uint8_t resp[257] = {0};
+ size_t resplen = 0;
+ int res = DesfireExchangeEx(false, dctx, MFDES_DELETE_APPLICATION, data, sizeof(data), &respcode, resp, &resplen, true, 24);
+ if (res != PM3_SUCCESS)
+ return res;
+ if (respcode != MFDES_S_OPERATION_OK || resplen != 0)
+ return PM3_EAPDU_FAIL;
+ return PM3_SUCCESS;
+}
+
diff --git a/client/src/mifare/desfirecore.h b/client/src/mifare/desfirecore.h
index f7d9b485c..9eaa74f9a 100644
--- a/client/src/mifare/desfirecore.h
+++ b/client/src/mifare/desfirecore.h
@@ -15,78 +15,22 @@
#include "common.h"
#include "cliparser.h"
+#include "mifare/desfirecrypto.h"
#include "mifare/desfire_crypto.h"
#include "mifare/mifare4.h"
-#define DESF_MAX_KEY_LEN 24
-
-#define DESFIRE_GET_ISO_STATUS(x) ( ((uint16_t)(0x91<<8)) + (uint16_t)x )
-
-typedef enum DESFIRE_CRYPTOALGO DesfireCryptoAlgorythm;
-
-typedef enum {
- DACNone,
- DACd40,
- DACEV1,
- DACEV2
-} DesfireSecureChannel;
-
-typedef enum {
- DCCNative,
- DCCNativeISO,
- DCCISO
-} DesfireCommandSet;
-
-typedef enum {
- DCMNone,
- DCMPlain,
- DCMMACed,
- DCMEncrypted
-} DesfireCommunicationMode;
-
-
-typedef struct DesfireContextS {
- uint8_t keyNum;
- enum DESFIRE_CRYPTOALGO keyType; // des/2tdea/3tdea/aes
- uint8_t key[DESF_MAX_KEY_LEN];
-
- // KDF finction
- uint8_t kdfAlgo;
- uint8_t kdfInputLen;
- uint8_t kdfInput[31];
-
- DesfireSecureChannel secureChannel; // none/d40/ev1/ev2
- DesfireCommandSet cmdSet; // native/nativeiso/iso
- DesfireCommunicationMode commMode; // plain/mac/enc
-
- uint8_t IV[DESF_MAX_KEY_LEN];
- uint8_t sessionKeyMAC[DESF_MAX_KEY_LEN];
- uint8_t sessionKeyEnc[DESF_MAX_KEY_LEN]; // look at mifare4.h - mf4Session_t
- uint8_t lastIV[DESF_MAX_KEY_LEN];
- //mf4Session_t AESSession;
- uint16_t cntrTx; // for AES
- uint16_t cntrRx; // for AES
- uint8_t TI[4]; // for AES
-} DesfireContext;
-
extern const CLIParserOption DesfireAlgoOpts[];
extern const CLIParserOption DesfireKDFAlgoOpts[];
extern const CLIParserOption DesfireCommunicationModeOpts[];
extern const CLIParserOption DesfireCommandSetOpts[];
extern const CLIParserOption DesfireSecureChannelOpts[];
-void DesfireClearContext(DesfireContext *ctx);
-void DesfirePrintContext(DesfireContext *ctx);
-void DesfireClearSession(DesfireContext *ctx);
-void DesfireSetKey(DesfireContext *ctx, uint8_t keyNum, enum DESFIRE_CRYPTOALGO keyType, uint8_t *key);
-void DesfireSetCommandSet(DesfireContext *ctx, DesfireCommandSet cmdSet);
-void DesfireSetCommMode(DesfireContext *ctx, DesfireCommunicationMode commMode);
-void DesfireSetKdf(DesfireContext *ctx, uint8_t kdfAlgo, uint8_t *kdfInput, uint8_t kdfInputLen);
-
const char *DesfireGetErrorString(int res, uint16_t *sw);
uint32_t DesfireAIDByteToUint(uint8_t *data);
void DesfireAIDUintToByte(uint32_t aid, uint8_t *data);
+void DesfirePrintContext(DesfireContext *ctx);
+
int DesfireExchange(DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen);
int DesfireExchangeEx(bool activate_field, DesfireContext *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);
@@ -94,10 +38,11 @@ int DesfireSelectAID(DesfireContext *ctx, uint8_t *aid1, uint8_t *aid2);
int DesfireSelectAIDHex(DesfireContext *ctx, uint32_t aid1, bool select_two, uint32_t aid2);
int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel);
-bool DesfireIsAuthenticated(DesfireContext *dctx);
int DesfireGetAIDList(DesfireContext *dctx, uint8_t *resp, size_t *resplen);
int DesfireGetDFList(DesfireContext *dctx, uint8_t *resp, size_t *resplen);
+int DesfireCreateApplication(DesfireContext *dctx, uint8_t *appdata, size_t appdatalen);
+int DesfireDeleteApplication(DesfireContext *dctx, uint32_t aid);
#endif // __DESFIRECORE_H
diff --git a/client/src/mifare/desfirecrypto.c b/client/src/mifare/desfirecrypto.c
new file mode 100644
index 000000000..187744ec7
--- /dev/null
+++ b/client/src/mifare/desfirecrypto.c
@@ -0,0 +1,270 @@
+/*-
+ * Copyright (C) 2010, Romain Tartiere.
+ * Copyright (C) 2021 Merlok
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see
+ *
+ * $Id$
+ */
+
+#include "desfirecrypto.h"
+
+#include
+#include
+#include
+#include "ui.h"
+#include "aes.h"
+#include "des.h"
+#include
+#include "crc.h"
+#include "crc16.h" // crc16 ccitt
+#include "crc32.h"
+#include "commonutil.h"
+#include "mifare/desfire_crypto.h"
+
+void DesfireClearContext(DesfireContext *ctx) {
+ ctx->keyNum = 0;
+ ctx->keyType = T_DES;
+ memset(ctx->key, 0, sizeof(ctx->key));
+
+ ctx->secureChannel = DACNone;
+ ctx->cmdSet = DCCNative;
+ ctx->commMode = DCMNone;
+
+ ctx->kdfAlgo = 0;
+ ctx->kdfInputLen = 0;
+ memset(ctx->kdfInput, 0, sizeof(ctx->kdfInput));
+
+ DesfireClearSession(ctx);
+}
+
+void DesfireClearSession(DesfireContext *ctx) {
+ ctx->secureChannel = DACNone; // here none - not authenticared
+
+ memset(ctx->IV, 0, sizeof(ctx->IV));
+ memset(ctx->sessionKeyMAC, 0, sizeof(ctx->sessionKeyMAC));
+ memset(ctx->sessionKeyEnc, 0, sizeof(ctx->sessionKeyEnc));
+ memset(ctx->lastIV, 0, sizeof(ctx->lastIV));
+ ctx->cntrTx = 0;
+ ctx->cntrRx = 0;
+ memset(ctx->TI, 0, sizeof(ctx->TI));
+}
+
+void DesfireSetKey(DesfireContext *ctx, uint8_t keyNum, enum DESFIRE_CRYPTOALGO keyType, uint8_t *key) {
+ DesfireClearContext(ctx);
+
+ ctx->keyNum = keyNum;
+ ctx->keyType = keyType;
+ memcpy(ctx->key, key, desfire_get_key_length(keyType));
+}
+
+void DesfireSetCommandSet(DesfireContext *ctx, DesfireCommandSet cmdSet) {
+ ctx->cmdSet = cmdSet;
+}
+
+void DesfireSetCommMode(DesfireContext *ctx, DesfireCommunicationMode commMode) {
+ ctx->commMode = commMode;
+}
+
+void DesfireSetKdf(DesfireContext *ctx, uint8_t kdfAlgo, uint8_t *kdfInput, uint8_t kdfInputLen) {
+ ctx->kdfAlgo = kdfAlgo;
+ ctx->kdfInputLen = kdfInputLen;
+ if (kdfInputLen)
+ memcpy(ctx->kdfInput, kdfInput, kdfInputLen);
+}
+
+bool DesfireIsAuthenticated(DesfireContext *dctx) {
+ return dctx->secureChannel != DACNone;
+}
+
+size_t DesfireGetMACLength(DesfireContext *ctx) {
+ size_t mac_length = MAC_LENGTH;
+ switch (ctx->secureChannel) {
+ case DACNone:
+ mac_length = 0;
+ break;
+ case DACd40:
+ mac_length = 4;
+ break;
+ case DACEV1:
+ mac_length = 8;
+ break;
+ case DACEV2:
+ mac_length = 8;
+ break;
+ }
+ return mac_length;
+}
+
+static void DesfireCryptoEncDecSingleBlock(uint8_t *key, DesfireCryptoAlgorythm keyType, uint8_t *data, uint8_t *dstdata, uint8_t *ivect, bool dir_to_send, bool encode) {
+ size_t block_size = desfire_get_key_block_length(keyType);
+ uint8_t sdata[MAX_CRYPTO_BLOCK_SIZE] = {0};
+ memcpy(sdata, data, block_size);
+ if (dir_to_send) {
+ bin_xor(sdata, ivect, block_size);
+ }
+
+ uint8_t edata[MAX_CRYPTO_BLOCK_SIZE] = {0};
+
+ switch (keyType) {
+ case T_DES:
+ if (encode)
+ des_encrypt(edata, sdata, key);
+ else
+ des_decrypt(edata, sdata, key);
+ break;
+ case T_3DES:
+ if (encode) {
+ mbedtls_des3_context ctx3;
+ mbedtls_des3_set2key_enc(&ctx3, key);
+ mbedtls_des3_crypt_ecb(&ctx3, sdata, edata);
+ } else {
+ mbedtls_des3_context ctx3;
+ mbedtls_des3_set2key_dec(&ctx3, key);
+ mbedtls_des3_crypt_ecb(&ctx3, sdata, edata);
+ }
+ break;
+ case T_3K3DES:
+ if (encode) {
+ mbedtls_des3_context ctx3;
+ mbedtls_des3_set3key_enc(&ctx3, key);
+ mbedtls_des3_crypt_ecb(&ctx3, sdata, edata);
+ } else {
+ mbedtls_des3_context ctx3;
+ mbedtls_des3_set3key_dec(&ctx3, key);
+ mbedtls_des3_crypt_ecb(&ctx3, sdata, edata);
+ }
+ break;
+ case T_AES:
+ if (encode) {
+ mbedtls_aes_context actx;
+ mbedtls_aes_init(&actx);
+ mbedtls_aes_setkey_enc(&actx, key, 128);
+ mbedtls_aes_crypt_ecb(&actx, MBEDTLS_AES_ENCRYPT, sdata, edata);
+ mbedtls_aes_free(&actx);
+ } else {
+ mbedtls_aes_context actx;
+ mbedtls_aes_init(&actx);
+ mbedtls_aes_setkey_dec(&actx, key, 128);
+ mbedtls_aes_crypt_ecb(&actx, MBEDTLS_AES_DECRYPT, sdata, edata);
+ mbedtls_aes_free(&actx);
+ }
+ break;
+ }
+
+ memcpy(dstdata, edata, block_size);
+
+ if (dir_to_send) {
+ memcpy(ivect, edata, block_size);
+ } else {
+ memcpy(ivect, data, block_size);
+ }
+}
+
+void DesfireCryptoEncDecEx(DesfireContext *ctx, bool use_session_key, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool encode, uint8_t *iv) {
+ uint8_t data[1024] = {0};
+ uint8_t xiv[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0};
+
+ if (ctx->secureChannel == DACd40)
+ memset(ctx->IV, 0, DESFIRE_MAX_CRYPTO_BLOCK_SIZE);
+
+ size_t block_size = desfire_get_key_block_length(ctx->keyType);
+
+ if (iv == NULL)
+ memcpy(xiv, ctx->IV, block_size);
+ else
+ memcpy(xiv, iv, block_size);
+
+ size_t offset = 0;
+ while (offset < srcdatalen) {
+ if (use_session_key)
+ DesfireCryptoEncDecSingleBlock(ctx->sessionKeyMAC, ctx->keyType, srcdata + offset, data, xiv, encode, encode);
+ else
+ DesfireCryptoEncDecSingleBlock(ctx->key, ctx->keyType, srcdata + offset, data, xiv, encode, encode);
+ offset += block_size;
+ }
+
+ if (iv == NULL)
+ memcpy(ctx->IV, xiv, block_size);
+ else
+ memcpy(iv, xiv, block_size);
+
+ if (dstdata)
+ memcpy(dstdata, data, srcdatalen);
+}
+
+void DesfireCryptoEncDec(DesfireContext *ctx, bool use_session_key, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool encode) {
+ DesfireCryptoEncDecEx(ctx, use_session_key, srcdata, srcdatalen, dstdata, encode, NULL);
+}
+
+static void DesfireCMACGenerateSubkeys(DesfireContext *ctx, uint8_t *sk1, uint8_t *sk2) {
+ int kbs = desfire_get_key_block_length(ctx->keyType);
+ const uint8_t R = (kbs == 8) ? 0x1B : 0x87;
+
+ uint8_t l[kbs];
+ memset(l, 0, kbs);
+
+ uint8_t ivect[kbs];
+ memset(ivect, 0, kbs);
+
+ DesfireCryptoEncDecEx(ctx, true, l, kbs, l, true, ivect);
+
+ bool txor = false;
+
+ // Used to compute CMAC on complete blocks
+ memcpy(sk1, l, kbs);
+ txor = l[0] & 0x80;
+ lsl(sk1, kbs);
+ if (txor) {
+ sk1[kbs - 1] ^= R;
+ }
+
+ // Used to compute CMAC on the last block if non-complete
+ memcpy(sk2, sk1, kbs);
+ txor = sk1[0] & 0x80;
+ lsl(sk2, kbs);
+ if (txor) {
+ sk2[kbs - 1] ^= R;
+ }
+}
+
+void DesfireCryptoCMAC(DesfireContext *ctx, uint8_t *data, size_t len, uint8_t *cmac) {
+ int kbs = desfire_get_key_block_length(ctx->keyType);
+ if (kbs == 0)
+ return;
+
+ uint8_t buffer[padded_data_length(len, kbs)];
+ memset(buffer, 0, sizeof(buffer));
+
+ uint8_t sk1[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0};
+ uint8_t sk2[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0};
+ DesfireCMACGenerateSubkeys(ctx, sk1, sk2);
+
+ memcpy(buffer, data, len);
+
+ if ((!len) || (len % kbs)) {
+ buffer[len++] = 0x80;
+ while (len % kbs) {
+ buffer[len++] = 0x00;
+ }
+ bin_xor(buffer + len - kbs, sk2, kbs);
+ } else {
+ bin_xor(buffer + len - kbs, sk1, kbs);
+ }
+
+ DesfireCryptoEncDec(ctx, true, buffer, len, NULL, true);
+
+ memcpy(cmac, ctx->IV, kbs);
+}
+
diff --git a/client/src/mifare/desfirecrypto.h b/client/src/mifare/desfirecrypto.h
new file mode 100644
index 000000000..b9f28f31a
--- /dev/null
+++ b/client/src/mifare/desfirecrypto.h
@@ -0,0 +1,102 @@
+/*-
+ * Copyright (C) 2010, Romain Tartiere.
+ * Copyright (C) 2021 Merlok
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see
+ *
+ * $Id$
+ */
+
+#ifndef __DESFIRECRYPTO_H
+#define __DESFIRECRYPTO_H
+
+#include "common.h"
+#include "mifare/mifare4.h"
+
+#define MAX_CRYPTO_BLOCK_SIZE 16
+#define DESFIRE_MAX_CRYPTO_BLOCK_SIZE 16
+#define DESFIRE_MAX_KEY_SIZE 24
+
+#define DESFIRE_GET_ISO_STATUS(x) ( ((uint16_t)(0x91<<8)) + (uint16_t)x )
+
+enum DESFIRE_CRYPTOALGO {
+ T_DES = 0x00,
+ T_3DES = 0x01, //aka 2K3DES
+ T_3K3DES = 0x02,
+ T_AES = 0x03
+};
+
+typedef enum DESFIRE_CRYPTOALGO DesfireCryptoAlgorythm;
+
+typedef enum {
+ DACNone,
+ DACd40,
+ DACEV1,
+ DACEV2
+} DesfireSecureChannel;
+
+typedef enum {
+ DCCNative,
+ DCCNativeISO,
+ DCCISO
+} DesfireCommandSet;
+
+typedef enum {
+ DCMNone,
+ DCMPlain,
+ DCMMACed,
+ DCMEncrypted
+} DesfireCommunicationMode;
+
+
+typedef struct DesfireContextS {
+ uint8_t keyNum;
+ DesfireCryptoAlgorythm keyType; // des/2tdea/3tdea/aes
+ uint8_t key[DESFIRE_MAX_KEY_SIZE];
+
+ // KDF finction
+ uint8_t kdfAlgo;
+ uint8_t kdfInputLen;
+ uint8_t kdfInput[31];
+
+ DesfireSecureChannel secureChannel; // none/d40/ev1/ev2
+ DesfireCommandSet cmdSet; // native/nativeiso/iso
+ DesfireCommunicationMode commMode; // plain/mac/enc
+
+ uint8_t IV[DESFIRE_MAX_KEY_SIZE];
+ uint8_t sessionKeyMAC[DESFIRE_MAX_KEY_SIZE];
+ uint8_t sessionKeyEnc[DESFIRE_MAX_KEY_SIZE]; // look at mifare4.h - mf4Session_t
+ uint8_t lastIV[DESFIRE_MAX_KEY_SIZE];
+ //mf4Session_t AESSession;
+ uint16_t cntrTx; // for AES
+ uint16_t cntrRx; // for AES
+ uint8_t TI[4]; // for AES
+} DesfireContext;
+
+void DesfireClearContext(DesfireContext *ctx);
+void DesfireClearSession(DesfireContext *ctx);
+void DesfireSetKey(DesfireContext *ctx, uint8_t keyNum, enum DESFIRE_CRYPTOALGO keyType, uint8_t *key);
+void DesfireSetCommandSet(DesfireContext *ctx, DesfireCommandSet cmdSet);
+void DesfireSetCommMode(DesfireContext *ctx, DesfireCommunicationMode commMode);
+void DesfireSetKdf(DesfireContext *ctx, uint8_t kdfAlgo, uint8_t *kdfInput, uint8_t kdfInputLen);
+bool DesfireIsAuthenticated(DesfireContext *dctx);
+size_t DesfireGetMACLength(DesfireContext *ctx);
+
+
+void DesfireCryptoEncDec(DesfireContext *ctx, bool use_session_key, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool encode);
+void DesfireCryptoEncDecEx(DesfireContext *ctx, bool use_session_key, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool encode, uint8_t *iv);
+void DesfireCryptoCMAC(DesfireContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t *cmac);
+
+
+#endif // __DESFIRECRYPTO_H
diff --git a/client/src/mifare/desfiresecurechan.c b/client/src/mifare/desfiresecurechan.c
index 49e3e6b05..b437ebc07 100644
--- a/client/src/mifare/desfiresecurechan.c
+++ b/client/src/mifare/desfiresecurechan.c
@@ -22,42 +22,6 @@
#include "commonutil.h"
#include "mifare/desfire_crypto.h"
-void DesfireCryptoEncDec(DesfireContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool encode) {
- uint8_t data[1024] = {0};
-
- switch (ctx->keyType) {
- case T_DES:
- if (ctx->secureChannel == DACd40) {
- if (encode)
- des_encrypt_ecb(data, srcdata, srcdatalen, ctx->key);
- else
- des_decrypt_ecb(data, srcdata, srcdatalen, ctx->key);
- }
- if (ctx->secureChannel == DACEV1) {
- if (encode)
- des_encrypt_cbc(data, srcdata, srcdatalen, ctx->key, ctx->IV);
- else
- des_decrypt_cbc(data, srcdata, srcdatalen, ctx->key, ctx->IV);
- }
-
- if (dstdata)
- memcpy(dstdata, data, srcdatalen);
- break;
- case T_3DES:
- break;
- case T_3K3DES:
- break;
- case T_AES:
- if (encode)
- aes_encode(ctx->IV, ctx->key, srcdata, data, srcdatalen);
- else
- aes_decode(ctx->IV, ctx->key, srcdata, data, srcdatalen);
- if (dstdata)
- memcpy(dstdata, data, srcdatalen);
- break;
- }
-}
-
static void DesfireSecureChannelEncodeD40(DesfireContext *ctx, uint8_t cmd, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen) {
memcpy(dstdata, srcdata, srcdatalen);
*dstdatalen = srcdatalen;
@@ -76,7 +40,7 @@ static void DesfireSecureChannelEncodeD40(DesfireContext *ctx, uint8_t cmd, uint
rlen = padded_data_length(srcdatalen, desfire_get_key_block_length(ctx->keyType));
memcpy(data, srcdata, srcdatalen);
- DesfireCryptoEncDec(ctx, data, rlen, NULL, true);
+ DesfireCryptoEncDec(ctx, true, data, rlen, NULL, true);
memcpy(dstdata, srcdata, srcdatalen);
memcpy(&dstdata[srcdatalen], ctx->IV, 4);
*dstdatalen = rlen;
@@ -85,7 +49,7 @@ static void DesfireSecureChannelEncodeD40(DesfireContext *ctx, uint8_t cmd, uint
rlen = padded_data_length(srcdatalen + 2, desfire_get_key_block_length(ctx->keyType)); // 2 - crc16
memcpy(data, srcdata, srcdatalen);
compute_crc(CRC_14443_A, data, srcdatalen, &data[srcdatalen], &data[srcdatalen + 1]);
- DesfireCryptoEncDec(ctx, data, rlen, dstdata, true);
+ DesfireCryptoEncDec(ctx, true, data, rlen, dstdata, true);
*dstdatalen = rlen;
break;
case DCMNone:
@@ -95,7 +59,6 @@ static void DesfireSecureChannelEncodeD40(DesfireContext *ctx, uint8_t cmd, uint
static void DesfireSecureChannelEncodeEV1(DesfireContext *ctx, uint8_t cmd, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen) {
uint8_t data[1024] = {0};
- size_t rlen = 0;
memcpy(dstdata, srcdata, srcdatalen);
*dstdatalen = srcdatalen;
@@ -104,14 +67,14 @@ static void DesfireSecureChannelEncodeEV1(DesfireContext *ctx, uint8_t cmd, uint
case DCMPlain:
case DCMMACed:
data[0] = cmd;
- rlen = padded_data_length(srcdatalen + 1, desfire_get_key_block_length(ctx->keyType));
memcpy(&data[1], srcdata, srcdatalen);
- DesfireCryptoEncDec(ctx, data, rlen, NULL, true);
+ uint8_t cmac[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0};
+ DesfireCryptoCMAC(ctx, data, srcdatalen + 1, cmac);
memcpy(dstdata, srcdata, srcdatalen);
if (srcdatalen != 0 && ctx->commMode == DCMMACed) {
- memcpy(&dstdata[srcdatalen], ctx->IV, 4);
- *dstdatalen = rlen;
+ memcpy(&dstdata[srcdatalen], cmac, DesfireGetMACLength(ctx));
+ *dstdatalen = srcdatalen + DesfireGetMACLength(ctx);
}
break;
case DCMEncrypted:
@@ -157,14 +120,30 @@ static void DesfireSecureChannelDecodeD40(DesfireContext *ctx, uint8_t *srcdata,
}
static void DesfireSecureChannelDecodeEV1(DesfireContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t respcode, uint8_t *dstdata, size_t *dstdatalen) {
+ uint8_t data[1024] = {0};
+
memcpy(dstdata, srcdata, srcdatalen);
*dstdatalen = srcdatalen;
switch (ctx->commMode) {
case DCMPlain:
case DCMMACed:
- memcpy(dstdata, srcdata, srcdatalen - 8);
- *dstdatalen = srcdatalen - 8;
+ if (srcdatalen < DesfireGetMACLength(ctx))
+ break;
+
+ memcpy(dstdata, srcdata, srcdatalen - DesfireGetMACLength(ctx));
+ *dstdatalen = srcdatalen - DesfireGetMACLength(ctx);
+
+ memcpy(data, srcdata, *dstdatalen);
+ data[*dstdatalen] = respcode;
+
+ uint8_t cmac[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0};
+ DesfireCryptoCMAC(ctx, data, *dstdatalen + 1, cmac);
+ if (memcmp(&srcdata[*dstdatalen], cmac, DesfireGetMACLength(ctx)) != 0) {
+ PrintAndLogEx(WARNING, "Received MAC is not match with calculated");
+ PrintAndLogEx(INFO, " received MAC: %s", sprint_hex(&srcdata[*dstdatalen], desfire_get_key_block_length(ctx->keyType)));
+ PrintAndLogEx(INFO, " calculated MAC: %s", sprint_hex(cmac, desfire_get_key_block_length(ctx->keyType)));
+ }
break;
case DCMEncrypted:
diff --git a/client/src/mifare/desfiresecurechan.h b/client/src/mifare/desfiresecurechan.h
index df997eb54..23810c791 100644
--- a/client/src/mifare/desfiresecurechan.h
+++ b/client/src/mifare/desfiresecurechan.h
@@ -15,11 +15,10 @@
#include "common.h"
#include "mifare/desfirecore.h"
+#include "mifare/desfirecrypto.h"
#include "mifare/desfire_crypto.h"
#include "mifare/mifare4.h"
-void DesfireCryptoEncDec(DesfireContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool encode);
-
void DesfireSecureChannelEncode(DesfireContext *ctx, uint8_t cmd, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen);
void DesfireSecureChannelDecode(DesfireContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t respcode, uint8_t *dstdata, size_t *dstdatalen);