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);