diff --git a/client/src/mifare/desfire_crypto.c b/client/src/mifare/desfire_crypto.c index fd3cb427d..7ee2f542c 100644 --- a/client/src/mifare/desfire_crypto.c +++ b/client/src/mifare/desfire_crypto.c @@ -53,20 +53,6 @@ static inline void update_key_schedules(desfirekey_t key) { // } } -int desfire_get_key_length(enum DESFIRE_CRYPTOALGO key_type) { - switch (key_type) { - case T_DES: - return 8; - case T_3DES: - return 16; - case T_3K3DES: - return 24; - case T_AES: - return 16; - } - return 0; -} - /******************************************************************************/ void tdes_nxp_receive(const void *in, void *out, size_t length, const void *key, unsigned char iv[8], int keymode) { @@ -334,7 +320,6 @@ void cmac(const desfirekey_t key, uint8_t *ivect, const uint8_t *data, size_t le // This function is almot like cmac(...). but with some key differences. void mifare_kdf_an10922(const desfirekey_t key, const uint8_t *data, size_t len) { int kbs = key_block_size(key); - int kbs2 = kbs * 2; if (key == NULL || kbs == 0 || data == NULL || len < 1 || len > 31) { return; } @@ -342,6 +327,7 @@ void mifare_kdf_an10922(const desfirekey_t key, const uint8_t *data, size_t len) // AES uses 16 byte IV if (kbs < 16) kbs = 16; + int kbs2 = kbs * 2; cmac_generate_subkeys(key, MCD_SEND); @@ -382,21 +368,6 @@ void mifare_kdf_an10922(const desfirekey_t key, const uint8_t *data, size_t len) free(buffer); } -size_t desfire_get_key_block_length(enum DESFIRE_CRYPTOALGO key_type) { - size_t block_size = 8; - switch (key_type) { - case T_DES: - case T_3DES: - case T_3K3DES: - block_size = 8; - break; - case T_AES: - block_size = 16; - break; - } - return block_size; -} - size_t key_block_size(const desfirekey_t key) { if (key == NULL) { return 0; @@ -422,16 +393,6 @@ static size_t key_macing_length(const desfirekey_t key) { return mac_length; } -/* - * Size required to store nbytes of data in a buffer of size n*block_size. - */ -size_t padded_data_length(const size_t nbytes, const size_t block_size) { - if ((!nbytes) || (nbytes % block_size)) - return ((nbytes / block_size) + 1) * block_size; - else - return nbytes; -} - /* * Buffer size required to MAC nbytes of data */ diff --git a/client/src/mifare/desfire_crypto.h b/client/src/mifare/desfire_crypto.h index c4c879ef3..160af81bd 100644 --- a/client/src/mifare/desfire_crypto.h +++ b/client/src/mifare/desfire_crypto.h @@ -74,16 +74,11 @@ typedef enum { /* Error code managed by the library */ #define CRYPTO_ERROR 0x01 -int desfire_get_key_length(enum DESFIRE_CRYPTOALGO key_type); -size_t desfire_get_key_block_length(enum DESFIRE_CRYPTOALGO key_type); - enum DESFIRE_AUTH_SCHEME { AS_LEGACY, AS_NEW }; - - #define DESFIRE_KEY(key) ((struct desfire_key *) key) struct desfire_key { enum DESFIRE_CRYPTOALGO type; @@ -139,7 +134,6 @@ void *mifare_cryto_postprocess_data(desfiretag_t tag, void *data, size_t *nbytes void mifare_cypher_single_block(desfirekey_t key, uint8_t *data, uint8_t *ivect, MifareCryptoDirection direction, MifareCryptoOperation operation, size_t block_size); void mifare_cypher_blocks_chained(desfiretag_t tag, desfirekey_t key, uint8_t *ivect, uint8_t *data, size_t data_size, MifareCryptoDirection direction, MifareCryptoOperation operation); size_t key_block_size(const desfirekey_t key); -size_t padded_data_length(const size_t nbytes, const size_t block_size); size_t maced_data_length(const desfirekey_t key, const size_t nbytes); size_t enciphered_data_length(const desfiretag_t tag, const size_t nbytes, int communication_settings); void cmac_generate_subkeys(desfirekey_t key, MifareCryptoDirection direction); diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 0a2edd8e5..42eb206ba 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -20,6 +20,7 @@ #include #include #include "commonutil.h" +#include "generator.h" #include "aes.h" #include "ui.h" #include "crc.h" @@ -30,7 +31,6 @@ #include "iso7816/apduinfo.h" // APDU manipulation / errorcodes #include "iso7816/iso7816core.h" // APDU logging #include "util_posix.h" // msleep -#include "mifare/desfire_crypto.h" #include "desfiresecurechan.h" #include "mifare/mad.h" #include "mifare/aiddesfire.h" @@ -335,13 +335,16 @@ void DesfirePrintContext(DesfireContext *ctx) { sprint_hex(ctx->key, desfire_get_key_length(ctx->keyType))); - if (ctx->kdfAlgo != MFDES_KDF_ALGO_NONE) + if (ctx->kdfAlgo != MFDES_KDF_ALGO_NONE) { PrintAndLogEx(INFO, "KDF algo: %s KDF input[%d]: %s", CLIGetOptionListStr(DesfireKDFAlgoOpts, ctx->kdfAlgo), ctx->kdfInputLen, sprint_hex(ctx->kdfInput, ctx->kdfInputLen)); + PrintAndLogEx(INFO, "AID: %06x UID[%d]: %s", ctx->selectedAID, ctx->uidlen, sprint_hex(ctx->uid, ctx->uidlen)); + } PrintAndLogEx(INFO, "Secure channel: %s Command set: %s Communication mode: %s", CLIGetOptionListStr(DesfireSecureChannelOpts, ctx->secureChannel), CLIGetOptionListStr(DesfireCommandSetOpts, ctx->cmdSet), CLIGetOptionListStr(DesfireCommunicationModeOpts, ctx->commMode)); + if (DesfireIsAuthenticated(ctx)) { PrintAndLogEx(INFO, "Session key MAC [%d]: %s ", @@ -789,6 +792,7 @@ int DesfireSelectAID(DesfireContext *ctx, uint8_t *aid1, uint8_t *aid2) { DesfireClearSession(ctx); ctx->appSelected = (aid1[0] != 0x00 || aid1[1] != 0x00 || aid1[2] != 0x00); + ctx->selectedAID = DesfireAIDByteToUint(aid1); return PM3_SUCCESS; } @@ -826,6 +830,7 @@ int DesfireSelectAIDHexNoFieldOn(DesfireContext *ctx, uint32_t aid) { DesfireClearSession(ctx); ctx->appSelected = (aid != 0x000000); + ctx->selectedAID = aid; return PM3_SUCCESS; } @@ -845,10 +850,13 @@ void DesfirePrintAIDFunctions(uint32_t appid) { } } - int DesfireSelectAndAuthenticateEx(DesfireContext *dctx, DesfireSecureChannel secureChannel, uint32_t aid, bool noauth, bool verbose) { if (verbose) DesfirePrintContext(dctx); + + // needs card uid for diversification + if (dctx->kdfAlgo == MFDES_KDF_ALGO_GALLAGHER) + DesfireGetCardUID(dctx); bool isosw = false; if (dctx->cmdSet == DCCISO) { @@ -957,8 +965,6 @@ static int DesfireAuthenticateEV1(DesfireContext *dctx, DesfireSecureChannel sec if (secureChannel == DACNone) return PM3_SUCCESS; - mbedtls_aes_context ctx; - uint8_t keybytes[24] = {0}; // Crypt constants uint8_t IV[16] = {0}; @@ -971,37 +977,6 @@ static int DesfireAuthenticateEV1(DesfireContext *dctx, DesfireSecureChannel sec // Part 1 memcpy(keybytes, dctx->key, desfire_get_key_length(dctx->keyType)); - struct desfire_key dkey = {0}; - desfirekey_t key = &dkey; - - if (dctx->keyType == T_AES) { - mbedtls_aes_init(&ctx); - Desfire_aes_key_new(keybytes, key); - } else if (dctx->keyType == T_3DES) { - Desfire_3des_key_new_with_version(keybytes, key); - } else if (dctx->keyType == T_DES) { - Desfire_des_key_new(keybytes, key); - } else if (dctx->keyType == T_3K3DES) { - Desfire_3k3des_key_new_with_version(keybytes, key); - } - - if (dctx->kdfAlgo == MFDES_KDF_ALGO_AN10922) { - mifare_kdf_an10922(key, dctx->kdfInput, dctx->kdfInputLen); - PrintAndLogEx(DEBUG, " Derrived key: " _GREEN_("%s"), sprint_hex(key->data, key_block_size(key))); - } else if (dctx->kdfAlgo == MFDES_KDF_ALGO_GALLAGHER) { - // We will overrite any provided KDF input since a gallagher specific KDF was requested. - dctx->kdfInputLen = 11; - - /*if (mfdes_kdf_input_gallagher(tag->info.uid, tag->info.uidlen, dctx->keyNum, tag->selected_application, dctx->kdfInput, &dctx->kdfInputLen) != PM3_SUCCESS) { - PrintAndLogEx(FAILED, "Could not generate Gallagher KDF input"); - }*/ - - mifare_kdf_an10922(key, dctx->kdfInput, dctx->kdfInputLen); - PrintAndLogEx(DEBUG, " KDF Input: " _YELLOW_("%s"), sprint_hex(dctx->kdfInput, dctx->kdfInputLen)); - PrintAndLogEx(DEBUG, " Derrived key: " _GREEN_("%s"), sprint_hex(key->data, key_block_size(key))); - - } - uint8_t subcommand = MFDES_AUTHENTICATE; if (secureChannel == DACEV1) { if (dctx->keyType == T_AES) @@ -1046,21 +1021,7 @@ static int DesfireAuthenticateEV1(DesfireContext *dctx, DesfireSecureChannel sec // Part 3 - if (dctx->keyType == T_AES) { - if (mbedtls_aes_setkey_dec(&ctx, key->data, 128) != 0) { - return 5; - } - mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_DECRYPT, rndlen, IV, encRndB, RndB); - } else if (dctx->keyType == T_DES) { - if (secureChannel == DACd40) - des_decrypt(RndB, encRndB, key->data); - if (secureChannel == DACEV1) - des_decrypt_cbc(RndB, encRndB, rndlen, key->data, IV); - } else if (dctx->keyType == T_3DES) - tdes_nxp_receive(encRndB, RndB, rndlen, key->data, IV, 2); - else if (dctx->keyType == T_3K3DES) { - tdes_nxp_receive(encRndB, RndB, rndlen, key->data, IV, 3); - } + DesfireCryptoEncDecEx(dctx, DCOMainKey, encRndB, rndlen, RndB, false, false, IV); if (g_debugMode > 1) { PrintAndLogEx(DEBUG, "encRndB: %s", sprint_hex(encRndB, 8)); @@ -1075,82 +1036,25 @@ static int DesfireAuthenticateEV1(DesfireContext *dctx, DesfireSecureChannel sec // - Encrypt our response if (secureChannel == DACd40) { - if (dctx->keyType == T_DES) { - des_decrypt(encRndA, RndA, key->data); - memcpy(both, encRndA, rndlen); - - for (uint32_t x = 0; x < rndlen; x++) { - rotRndB[x] = rotRndB[x] ^ encRndA[x]; - } - - des_decrypt(encRndB, rotRndB, key->data); - memcpy(both + rndlen, encRndB, rndlen); - } else if (dctx->keyType == T_3DES) { - des3_decrypt(encRndA, RndA, key->data, 2); - memcpy(both, encRndA, rndlen); - - for (uint32_t x = 0; x < rndlen; x++) { - rotRndB[x] = rotRndB[x] ^ encRndA[x]; - } - - des3_decrypt(encRndB, rotRndB, key->data, 2); - memcpy(both + rndlen, encRndB, rndlen); - } - } else if (secureChannel == DACEV1 && dctx->keyType != T_AES) { - if (dctx->keyType == T_DES) { - uint8_t tmp[16] = {0x00}; - memcpy(tmp, RndA, rndlen); - memcpy(tmp + rndlen, rotRndB, rndlen); - if (g_debugMode > 1) { - PrintAndLogEx(DEBUG, "rotRndB: %s", sprint_hex(rotRndB, rndlen)); - PrintAndLogEx(DEBUG, "Both: %s", sprint_hex(tmp, 16)); - } - des_encrypt_cbc(both, tmp, 16, key->data, IV); - if (g_debugMode > 1) { - PrintAndLogEx(DEBUG, "EncBoth: %s", sprint_hex(both, 16)); - } - } else if (dctx->keyType == T_3DES) { - uint8_t tmp[16] = {0x00}; - memcpy(tmp, RndA, rndlen); - memcpy(tmp + rndlen, rotRndB, rndlen); - if (g_debugMode > 1) { - PrintAndLogEx(DEBUG, "rotRndB: %s", sprint_hex(rotRndB, rndlen)); - PrintAndLogEx(DEBUG, "Both: %s", sprint_hex(tmp, 16)); - } - tdes_nxp_send(tmp, both, 16, key->data, IV, 2); - if (g_debugMode > 1) { - PrintAndLogEx(DEBUG, "EncBoth: %s", sprint_hex(both, 16)); - } - } else if (dctx->keyType == T_3K3DES) { - uint8_t tmp[32] = {0x00}; - memcpy(tmp, RndA, rndlen); - memcpy(tmp + rndlen, rotRndB, rndlen); - if (g_debugMode > 1) { - PrintAndLogEx(DEBUG, "rotRndB: %s", sprint_hex(rotRndB, rndlen)); - PrintAndLogEx(DEBUG, "Both3k3: %s", sprint_hex(tmp, 32)); - } - tdes_nxp_send(tmp, both, 32, key->data, IV, 3); - if (g_debugMode > 1) { - PrintAndLogEx(DEBUG, "EncBoth: %s", sprint_hex(both, 32)); - } - } - } else if (secureChannel == DACEV1 && dctx->keyType == T_AES) { + memset(IV, 0, DESFIRE_MAX_CRYPTO_BLOCK_SIZE); + DesfireCryptoEncDecEx(dctx, DCOMainKey, RndA, rndlen, encRndA, true, true, IV); + + memcpy(both, encRndA, rndlen); + bin_xor(rotRndB, encRndA, rndlen); + + memset(IV, 0, DESFIRE_MAX_CRYPTO_BLOCK_SIZE); + DesfireCryptoEncDecEx(dctx, DCOMainKey, rotRndB, rndlen, encRndB, true, true, IV); + + memcpy(both + rndlen, encRndB, rndlen); + } else if (secureChannel == DACEV1) { uint8_t tmp[32] = {0x00}; memcpy(tmp, RndA, rndlen); memcpy(tmp + rndlen, rotRndB, rndlen); if (g_debugMode > 1) { PrintAndLogEx(DEBUG, "rotRndB: %s", sprint_hex(rotRndB, rndlen)); - PrintAndLogEx(DEBUG, "Both3k3: %s", sprint_hex(tmp, 32)); - } - if (dctx->keyType == T_AES) { - if (mbedtls_aes_setkey_enc(&ctx, key->data, 128) != 0) { - return 6; - } - mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_ENCRYPT, 32, IV, tmp, both); - if (g_debugMode > 1) { - PrintAndLogEx(DEBUG, "EncBoth: %s", sprint_hex(both, 32)); - } + PrintAndLogEx(DEBUG, "Both : %s", sprint_hex(tmp, 32)); } + DesfireCryptoEncDecEx(dctx, DCOMainKey, tmp, rndlen * 2, both, true, true, IV); } uint32_t bothlen = 16; @@ -1174,31 +1078,15 @@ static int DesfireAuthenticateEV1(DesfireContext *dctx, DesfireSecureChannel sec // Part 4 memcpy(encRndA, recv_data, rndlen); - struct desfire_key sesskey = {0}; - - Desfire_session_key_new(RndA, RndB, key, &sesskey); - memcpy(dctx->sessionKeyEnc, sesskey.data, desfire_get_key_length(dctx->keyType)); - //PrintAndLogEx(INFO, "encRndA : %s", sprint_hex(encRndA, rndlen)); //PrintAndLogEx(INFO, "IV : %s", sprint_hex(IV, rndlen)); - if (dctx->keyType == T_DES) { - if (secureChannel == DACd40) - des_decrypt(encRndA, encRndA, key->data); - if (secureChannel == DACEV1) - des_decrypt_cbc(encRndA, encRndA, rndlen, key->data, IV); - } else if (dctx->keyType == T_3DES) - if (secureChannel == DACd40) - des3_decrypt(encRndA, encRndA, key->data, 2); - else - tdes_nxp_receive(encRndA, encRndA, rndlen, key->data, IV, 2); - else if (dctx->keyType == T_3K3DES) - tdes_nxp_receive(encRndA, encRndA, rndlen, key->data, IV, 3); - else if (dctx->keyType == T_AES) { - if (mbedtls_aes_setkey_dec(&ctx, key->data, 128) != 0) { - return 10; - } - mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_DECRYPT, rndlen, IV, encRndA, encRndA); - } + + if (secureChannel == DACd40) + memset(IV, 0, DESFIRE_MAX_CRYPTO_BLOCK_SIZE); + DesfireCryptoEncDecEx(dctx, DCOMainKey, encRndA, rndlen, encRndA, false, false, IV); + + // generate session key from rnda and rndb. before rol(RndA)! + DesfireGenSessionKeyEV1(RndA, RndB, dctx->keyType, dctx->sessionKeyEnc); rol(RndA, rndlen); //PrintAndLogEx(INFO, "Expected_RndA : %s", sprint_hex(RndA, rndlen)); @@ -1212,20 +1100,14 @@ static int DesfireAuthenticateEV1(DesfireContext *dctx, DesfireSecureChannel sec return 11; } } - + // If the 3Des key first 8 bytes = 2nd 8 Bytes then we are really using Singe Des // As such we need to set the session key such that the 2nd 8 bytes = 1st 8 Bytes if (dctx->keyType == T_3DES) { - if (memcmp(key->data, &key->data[8], 8) == 0) + if (memcmp(dctx->key, &dctx->key[8], 8) == 0) memcpy(&dctx->sessionKeyEnc[8], dctx->sessionKeyEnc, 8); } - if (secureChannel == DACEV1) { - cmac_generate_subkeys(&sesskey, MCD_RECEIVE); - //key->cmac_sk1 and key->cmac_sk2 - //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)); @@ -1420,6 +1302,22 @@ static int DesfireAuthenticateISO(DesfireContext *dctx, DesfireSecureChannel sec } int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel, bool verbose) { + if (dctx->kdfAlgo == MFDES_KDF_ALGO_AN10922) { + MifareKdfAn10922(dctx, DCOMasterKey, dctx->kdfInput, dctx->kdfInputLen); + PrintAndLogEx(DEBUG, " Derrived key: " _GREEN_("%s"), sprint_hex(dctx->key, desfire_get_key_block_length(dctx->keyType))); + } else if (dctx->kdfAlgo == MFDES_KDF_ALGO_GALLAGHER) { + // We will overrite any provided KDF input since a gallagher specific KDF was requested. + dctx->kdfInputLen = 11; + + if (mfdes_kdf_input_gallagher(dctx->uid, dctx->uidlen, dctx->keyNum, dctx->selectedAID, dctx->kdfInput, &dctx->kdfInputLen) != PM3_SUCCESS) { + PrintAndLogEx(FAILED, "Could not generate Gallagher KDF input"); + } + PrintAndLogEx(DEBUG, " KDF Input: " _YELLOW_("%s"), sprint_hex(dctx->kdfInput, dctx->kdfInputLen)); + + MifareKdfAn10922(dctx, DCOMasterKey, dctx->kdfInput, dctx->kdfInputLen); + PrintAndLogEx(DEBUG, " Derrived key: " _GREEN_("%s"), sprint_hex(dctx->key, desfire_get_key_block_length(dctx->keyType))); + } + if (dctx->cmdSet == DCCISO && secureChannel != DACEV2) return DesfireAuthenticateISO(dctx, secureChannel, verbose); @@ -2642,6 +2540,7 @@ int DesfireISOSelectEx(DesfireContext *dctx, bool fieldon, DesfireISOSelectContr DesfireClearSession(dctx); dctx->appSelected = !((cntr == ISSMFDFEF && datalen == 0) || (cntr == ISSEFByFileID && datalen == 2 && data[0] == 0 && data[1] == 0)); + dctx->selectedAID = 0; return res; } @@ -2751,6 +2650,26 @@ int DesfireISOAppendRecord(DesfireContext *dctx, uint8_t fileid, uint8_t *data, return res; } +int DesfireGetCardUID(DesfireContext *ctx) { + iso14a_card_select_t card = {0}; + + SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT, 0, 0, NULL, 0); + PacketResponseNG resp; + WaitForResponse(CMD_ACK, &resp); + + memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t)); + uint64_t select_status = resp.oldarg[0]; + + if (select_status == 0 || select_status == 2 || select_status == 3) { + return PM3_ESOFT; + } + + memcpy(ctx->uid, card.uid, card.uidlen); + ctx->uidlen = card.uidlen; + + return PM3_SUCCESS; +} + int DesfireSelectEx(DesfireContext *ctx, bool fieldon, DesfireISOSelectWay way, uint32_t id, char *dfname) { uint8_t resp[250] = {0}; size_t resplen = 0; diff --git a/client/src/mifare/desfirecore.h b/client/src/mifare/desfirecore.h index a03e489eb..c912f6239 100644 --- a/client/src/mifare/desfirecore.h +++ b/client/src/mifare/desfirecore.h @@ -16,8 +16,6 @@ #include "common.h" #include "cliparser.h" #include "mifare/desfirecrypto.h" -#include "mifare/desfire_crypto.h" -#include "mifare/mifare4.h" #define DESFIRE_TX_FRAME_MAX_LEN 54 @@ -168,6 +166,8 @@ int DesfireSelectAIDHex(DesfireContext *ctx, uint32_t aid1, bool select_two, uin int DesfireSelectAIDHexNoFieldOn(DesfireContext *ctx, uint32_t aid); void DesfirePrintAIDFunctions(uint32_t appid); +int DesfireGetCardUID(DesfireContext *ctx); + int DesfireSelectEx(DesfireContext *ctx, bool fieldon, DesfireISOSelectWay way, uint32_t id, char *dfname); int DesfireSelect(DesfireContext *ctx, DesfireISOSelectWay way, uint32_t id, char *dfname); diff --git a/client/src/mifare/desfirecrypto.c b/client/src/mifare/desfirecrypto.c index 366995a06..db559e850 100644 --- a/client/src/mifare/desfirecrypto.c +++ b/client/src/mifare/desfirecrypto.c @@ -31,7 +31,7 @@ #include "crc16.h" // crc16 ccitt #include "crc32.h" #include "commonutil.h" -#include "mifare/desfire_crypto.h" +#include "crypto/libpcrypto.h" void DesfireClearContext(DesfireContext *ctx) { ctx->keyNum = 0; @@ -43,6 +43,10 @@ void DesfireClearContext(DesfireContext *ctx) { ctx->commMode = DCMNone; ctx->appSelected = false; + ctx->selectedAID = 0; + + memset(ctx->uid, 0, sizeof(ctx->uid)); + ctx->uidlen = 0; ctx->kdfAlgo = 0; ctx->kdfInputLen = 0; @@ -74,6 +78,7 @@ void DesfireSetKey(DesfireContext *ctx, uint8_t keyNum, enum DESFIRE_CRYPTOALGO ctx->keyNum = keyNum; ctx->keyType = keyType; memcpy(ctx->key, key, desfire_get_key_length(keyType)); + memcpy(ctx->masterKey, key, desfire_get_key_length(keyType)); } void DesfireSetCommandSet(DesfireContext *ctx, DesfireCommandSet cmdSet) { @@ -96,7 +101,7 @@ bool DesfireIsAuthenticated(DesfireContext *dctx) { } size_t DesfireGetMACLength(DesfireContext *ctx) { - size_t mac_length = MAC_LENGTH; + size_t mac_length = DESFIRE_MAC_LENGTH; switch (ctx->secureChannel) { case DACNone: mac_length = 0; @@ -151,6 +156,19 @@ size_t DesfireSearchCRCPos(uint8_t *data, size_t datalen, uint8_t respcode, uint return crcposfound; } +uint8_t *DesfireGetKey(DesfireContext *ctx, DesfireCryptoOpKeyType key_type) { + if (key_type == DCOSessionKeyMac) { + return ctx->sessionKeyMAC; + } else if (key_type == DCOSessionKeyEnc) { + return ctx->sessionKeyEnc; + } else if (key_type == DCOMasterKey) { + return ctx->masterKey; + } + + return ctx->key; +} + + 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}; @@ -232,15 +250,14 @@ void DesfireCryptoEncDecEx(DesfireContext *ctx, DesfireCryptoOpKeyType key_type, else memcpy(xiv, iv, block_size); + uint8_t *key = DesfireGetKey(ctx, key_type); + if (key == NULL) + return; + size_t offset = 0; while (offset < srcdatalen) { - if (key_type == DCOSessionKeyMac) { - DesfireCryptoEncDecSingleBlock(ctx->sessionKeyMAC, ctx->keyType, srcdata + offset, data + offset, xiv, dir_to_send, encode); - } else if (key_type == DCOSessionKeyEnc) { - DesfireCryptoEncDecSingleBlock(ctx->sessionKeyEnc, ctx->keyType, srcdata + offset, data + offset, xiv, dir_to_send, encode); - } else { - DesfireCryptoEncDecSingleBlock(ctx->key, ctx->keyType, srcdata + offset, data + offset, xiv, dir_to_send, encode); - } + DesfireCryptoEncDecSingleBlock(key, ctx->keyType, srcdata + offset, data + offset, xiv, dir_to_send, encode); + offset += block_size; } @@ -262,7 +279,7 @@ void DesfireCryptoEncDec(DesfireContext *ctx, DesfireCryptoOpKeyType key_type, u DesfireCryptoEncDecEx(ctx, key_type, srcdata, srcdatalen, dstdata, dir_to_send, xencode, NULL); } -static void DesfireCMACGenerateSubkeys(DesfireContext *ctx, uint8_t *sk1, uint8_t *sk2) { +void DesfireCMACGenerateSubkeys(DesfireContext *ctx, DesfireCryptoOpKeyType key_type, uint8_t *sk1, uint8_t *sk2) { int kbs = desfire_get_key_block_length(ctx->keyType); const uint8_t R = (kbs == 8) ? 0x1B : 0x87; @@ -272,7 +289,7 @@ static void DesfireCMACGenerateSubkeys(DesfireContext *ctx, uint8_t *sk1, uint8_ uint8_t ivect[kbs]; memset(ivect, 0, kbs); - DesfireCryptoEncDecEx(ctx, DCOSessionKeyMac, l, kbs, l, true, true, ivect); + DesfireCryptoEncDecEx(ctx, key_type, l, kbs, l, true, true, ivect); bool txor = false; @@ -293,23 +310,23 @@ static void DesfireCMACGenerateSubkeys(DesfireContext *ctx, uint8_t *sk1, uint8_ } } -void DesfireCryptoCMAC(DesfireContext *ctx, uint8_t *data, size_t len, uint8_t *cmac) { +void DesfireCryptoCMACEx(DesfireContext *ctx, DesfireCryptoOpKeyType key_type, uint8_t *data, size_t len, size_t minlen, uint8_t *cmac) { int kbs = desfire_get_key_block_length(ctx->keyType); if (kbs == 0) return; - uint8_t buffer[padded_data_length(len, kbs)]; + uint8_t buffer[padded_data_length(MAX(minlen, len) + 1, 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); + DesfireCMACGenerateSubkeys(ctx, key_type, sk1, sk2); memcpy(buffer, data, len); - if ((!len) || (len % kbs)) { + if ((!len) || (len % kbs) || (len < minlen)) { buffer[len++] = 0x80; - while (len % kbs) { + while (len % kbs || len < minlen) { buffer[len++] = 0x00; } bin_xor(buffer + len - kbs, sk2, kbs); @@ -317,12 +334,73 @@ void DesfireCryptoCMAC(DesfireContext *ctx, uint8_t *data, size_t len, uint8_t * bin_xor(buffer + len - kbs, sk1, kbs); } - DesfireCryptoEncDec(ctx, DCOSessionKeyMac, buffer, len, NULL, true); + DesfireCryptoEncDec(ctx, key_type, buffer, len, NULL, true); if (cmac != NULL) memcpy(cmac, ctx->IV, kbs); } +void DesfireCryptoCMAC(DesfireContext *ctx, uint8_t *data, size_t len, uint8_t *cmac) { + DesfireCryptoCMACEx(ctx, DCOSessionKeyMac, data, len, 0, cmac); +} + +// This function is almot like cmac(...). but with some key differences. +void MifareKdfAn10922(DesfireContext *ctx, DesfireCryptoOpKeyType key_type, const uint8_t *data, size_t len) { + int kbs = desfire_get_key_block_length(ctx->keyType); // 8 or 16 + if (ctx == NULL || kbs == 0 || data == NULL || len < 1 || len > 31) { + return; + } + + uint8_t cmac[DESFIRE_MAX_CRYPTO_BLOCK_SIZE * 3] = {0}; + uint8_t buffer[DESFIRE_MAX_CRYPTO_BLOCK_SIZE * 3] = {0}; + + if (ctx->keyType == T_AES) { + // AES uses 16 byte IV + if (kbs < CRYPTO_AES_BLOCK_SIZE) + kbs = CRYPTO_AES_BLOCK_SIZE; + + buffer[0] = 0x01; + memcpy(&buffer[1], data, len); + + DesfireCryptoCMACEx(ctx, key_type, buffer, len + 1, kbs * 2, cmac); + memcpy(ctx->key, cmac, kbs); + } else if (ctx->keyType == T_3DES) { + buffer[0] = 0x21; + memcpy(&buffer[1], data, len); + + DesfireClearIV(ctx); + DesfireCryptoCMACEx(ctx, key_type, buffer, len + 1, kbs * 2, cmac); + + buffer[0] = 0x22; + memcpy(&buffer[1], data, len); + + DesfireClearIV(ctx); + DesfireCryptoCMACEx(ctx, key_type, buffer, len + 1, kbs * 2, &cmac[kbs]); + + memcpy(ctx->key, cmac, kbs * 2); + } else if (ctx->keyType == T_3K3DES) { + buffer[0] = 0x31; + memcpy(&buffer[1], data, len); + + DesfireClearIV(ctx); + DesfireCryptoCMACEx(ctx, key_type, buffer, len + 1, kbs * 2, cmac); + + buffer[0] = 0x32; + memcpy(&buffer[1], data, len); + + DesfireClearIV(ctx); + DesfireCryptoCMACEx(ctx, key_type, buffer, len + 1, kbs * 2, &cmac[kbs]); + + buffer[0] = 0x33; + memcpy(&buffer[1], data, len); + + DesfireClearIV(ctx); + DesfireCryptoCMACEx(ctx, key_type, buffer, len + 1, kbs * 2, &cmac[kbs * 2]); + + memcpy(ctx->key, cmac, kbs * 3); + } +} + void DesfireDESKeySetVersion(uint8_t *key, DesfireCryptoAlgorythm keytype, uint8_t version) { if (keytype == T_AES) return; @@ -536,6 +614,45 @@ int DesfireEV2CalcCMAC(DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t d return aes_cmac8(NULL, ctx->sessionKeyMAC, mdata, mac, mdatalen); } +int desfire_get_key_length(DesfireCryptoAlgorythm key_type) { + switch (key_type) { + case T_DES: + return 8; + case T_3DES: + return 16; + case T_3K3DES: + return 24; + case T_AES: + return 16; + } + return 0; +} + +size_t desfire_get_key_block_length(DesfireCryptoAlgorythm key_type) { + size_t block_size = 8; + switch (key_type) { + case T_DES: + case T_3DES: + case T_3K3DES: + block_size = 8; + break; + case T_AES: + block_size = 16; + break; + } + return block_size; +} + +/* + * Size required to store nbytes of data in a buffer of size n*block_size. + */ +size_t padded_data_length(const size_t nbytes, const size_t block_size) { + if ((!nbytes) || (nbytes % block_size)) + return ((nbytes / block_size) + 1) * block_size; + else + return nbytes; +} + void desfire_crc32(const uint8_t *data, const size_t len, uint8_t *crc) { crc32_ex(data, len, crc); } diff --git a/client/src/mifare/desfirecrypto.h b/client/src/mifare/desfirecrypto.h index 9fa379049..e5a7643e8 100644 --- a/client/src/mifare/desfirecrypto.h +++ b/client/src/mifare/desfirecrypto.h @@ -22,12 +22,14 @@ #define __DESFIRECRYPTO_H #include "common.h" -#include "mifare/mifare4.h" +#include "crypto/libpcrypto.h" #define CRYPTO_AES_BLOCK_SIZE 16 #define MAX_CRYPTO_BLOCK_SIZE 16 #define DESFIRE_MAX_CRYPTO_BLOCK_SIZE 16 #define DESFIRE_MAX_KEY_SIZE 24 +#define DESFIRE_MAC_LENGTH 4 +#define DESFIRE_CMAC_LENGTH 8 #define DESFIRE_GET_ISO_STATUS(x) ( ((uint16_t)(0x91<<8)) + (uint16_t)x ) @@ -63,6 +65,7 @@ typedef enum { } DesfireCommunicationMode; typedef enum { + DCOMasterKey, DCOMainKey, DCOSessionKeyMac, DCOSessionKeyEnc @@ -72,6 +75,7 @@ typedef struct DesfireContextS { uint8_t keyNum; DesfireCryptoAlgorythm keyType; // des/2tdea/3tdea/aes uint8_t key[DESFIRE_MAX_KEY_SIZE]; + uint8_t masterKey[DESFIRE_MAX_KEY_SIZE]; // source for kdf // KDF finction uint8_t kdfAlgo; @@ -83,6 +87,10 @@ typedef struct DesfireContextS { DesfireCommunicationMode commMode; // plain/mac/enc bool appSelected; // for iso auth + uint32_t selectedAID; + + uint8_t uid[10]; + uint8_t uidlen; uint8_t IV[DESFIRE_MAX_KEY_SIZE]; uint8_t sessionKeyMAC[DESFIRE_MAX_KEY_SIZE]; @@ -106,10 +114,14 @@ size_t DesfireGetMACLength(DesfireContext *ctx); size_t DesfireSearchCRCPos(uint8_t *data, size_t datalen, uint8_t respcode, uint8_t crclen); +uint8_t *DesfireGetKey(DesfireContext *ctx, DesfireCryptoOpKeyType key_type); void DesfireCryptoEncDec(DesfireContext *ctx, DesfireCryptoOpKeyType key_type, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool encode); void DesfireCryptoEncDecEx(DesfireContext *ctx, DesfireCryptoOpKeyType key_type, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool dir_to_send, bool encode, uint8_t *iv); +void DesfireCMACGenerateSubkeys(DesfireContext *ctx, DesfireCryptoOpKeyType key_type, uint8_t *sk1, uint8_t *sk2); void DesfireCryptoCMAC(DesfireContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t *cmac); - +void DesfireCryptoCMACEx(DesfireContext *ctx, DesfireCryptoOpKeyType key_type, uint8_t *data, size_t len, size_t minlen, uint8_t *cmac); +void MifareKdfAn10922(DesfireContext *ctx, DesfireCryptoOpKeyType key_type, const uint8_t *data, size_t len); + void DesfireDESKeySetVersion(uint8_t *key, DesfireCryptoAlgorythm keytype, uint8_t version); uint8_t DesfireDESKeyGetVersion(uint8_t *key); @@ -125,6 +137,10 @@ void DesfireGenSessionKeyEV2(uint8_t *key, uint8_t *rndA, uint8_t *rndB, bool en void DesfireEV2FillIV(DesfireContext *ctx, bool ivforcommand, uint8_t *iv); int DesfireEV2CalcCMAC(DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *mac); +int desfire_get_key_length(DesfireCryptoAlgorythm key_type); +size_t desfire_get_key_block_length(DesfireCryptoAlgorythm key_type); +size_t padded_data_length(const size_t nbytes, const size_t block_size); + void desfire_crc32(const uint8_t *data, const size_t len, uint8_t *crc); void desfire_crc32_append(uint8_t *data, const size_t len); bool desfire_crc32_check(uint8_t *data, const size_t len, uint8_t *crc); diff --git a/client/src/mifare/desfiresecurechan.c b/client/src/mifare/desfiresecurechan.c index ced1fd073..03106f24e 100644 --- a/client/src/mifare/desfiresecurechan.c +++ b/client/src/mifare/desfiresecurechan.c @@ -21,7 +21,6 @@ #include "crc32.h" #include "commonutil.h" #include "protocols.h" -#include "mifare/desfire_crypto.h" static const uint8_t CommandsCanUseAnyChannel[] = { MFDES_S_ADDITIONAL_FRAME, diff --git a/client/src/mifare/desfiresecurechan.h b/client/src/mifare/desfiresecurechan.h index 235e3a41b..77b84bafc 100644 --- a/client/src/mifare/desfiresecurechan.h +++ b/client/src/mifare/desfiresecurechan.h @@ -16,7 +16,6 @@ #include "common.h" #include "mifare/desfirecore.h" #include "mifare/desfirecrypto.h" -#include "mifare/desfire_crypto.h" #include "mifare/mifare4.h" typedef struct { diff --git a/client/src/mifare/desfiretest.c b/client/src/mifare/desfiretest.c index 9972a6793..1f3425246 100644 --- a/client/src/mifare/desfiretest.c +++ b/client/src/mifare/desfiretest.c @@ -78,6 +78,126 @@ static bool TestCRC32(void) { return res; } +// https://www.nxp.com/docs/en/application-note/AN10922.pdf +static bool TestCMACSubkeys(void) { + bool res = true; + + uint8_t key[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}; + + uint8_t sk1[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0}; + uint8_t sk2[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0}; + DesfireContext dctx; + // AES + DesfireSetKey(&dctx, 0, T_AES, key); + + DesfireCMACGenerateSubkeys(&dctx, DCOMainKey, sk1, sk2); + + uint8_t sk1test[] = {0xFB, 0xC9, 0xF7, 0x5C, 0x94, 0x13, 0xC0, 0x41, 0xDF, 0xEE, 0x45, 0x2D, 0x3F, 0x07, 0x06, 0xD1}; + uint8_t sk2test[] = {0xF7, 0x93, 0xEE, 0xB9, 0x28, 0x27, 0x80, 0x83, 0xBF, 0xDC, 0x8A, 0x5A, 0x7E, 0x0E, 0x0D, 0x25}; + + res = res && (memcmp(sk1, sk1test, sizeof(sk1test)) == 0); + res = res && (memcmp(sk2, sk2test, sizeof(sk2test)) == 0); + + // 2tdea + DesfireSetKey(&dctx, 0, T_3DES, key); + + DesfireCMACGenerateSubkeys(&dctx, DCOMainKey, sk1, sk2); + + uint8_t sk1_2tdea[] = {0xF6, 0x12, 0xEB, 0x32, 0xE4, 0x60, 0x35, 0xF3}; + uint8_t sk2_2tdea[] = {0xEC, 0x25, 0xD6, 0x65, 0xC8, 0xC0, 0x6B, 0xFD}; + + res = res && (memcmp(sk1, sk1_2tdea, sizeof(sk1_2tdea)) == 0); + res = res && (memcmp(sk2, sk2_2tdea, sizeof(sk2_2tdea)) == 0); + + // 3tdea + uint8_t key3[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; + DesfireSetKey(&dctx, 0, T_3K3DES, key3); + + DesfireCMACGenerateSubkeys(&dctx, DCOMainKey, sk1, sk2); + + uint8_t sk1_3tdea[] = {0xA3, 0xED, 0x58, 0xF8, 0xE6, 0x94, 0x1B, 0xCA}; + uint8_t sk2_3tdea[] = {0x47, 0xDA, 0xB1, 0xF1, 0xCD, 0x28, 0x37, 0x8F}; + + res = res && (memcmp(sk1, sk1_3tdea, sizeof(sk1_3tdea)) == 0); + res = res && (memcmp(sk2, sk2_3tdea, sizeof(sk2_3tdea)) == 0); + + if (res) + PrintAndLogEx(INFO, "CMAC subkeys...... " _GREEN_("passed")); + else + PrintAndLogEx(ERR, "CMAC subkeys...... " _RED_("fail")); + + return res; +} + +// https://www.nxp.com/docs/en/application-note/AN10922.pdf +// page 8 +static bool TestAn10922KDFAES(void) { + bool res = true; + + uint8_t key[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}; + + DesfireContext dctx; + DesfireSetKey(&dctx, 0, T_AES, key); + + uint8_t kdfInput[] = {0x04, 0x78, 0x2E, 0x21, 0x80, 0x1D, 0x80, 0x30, 0x42, 0xF5, 0x4E, 0x58, 0x50, 0x20, 0x41, 0x62, 0x75}; + MifareKdfAn10922(&dctx, DCOMainKey, kdfInput, sizeof(kdfInput)); + + uint8_t dkey[] = {0xA8, 0xDD, 0x63, 0xA3, 0xB8, 0x9D, 0x54, 0xB3, 0x7C, 0xA8, 0x02, 0x47, 0x3F, 0xDA, 0x91, 0x75}; + res = res && (memcmp(dctx.key, dkey, sizeof(dkey)) == 0); + + if (res) + PrintAndLogEx(INFO, "An10922 AES....... " _GREEN_("passed")); + else + PrintAndLogEx(ERR, "An10922 AES....... " _RED_("fail")); + + return res; +} + +static bool TestAn10922KDF2TDEA(void) { + bool res = true; + + uint8_t key[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}; + + DesfireContext dctx; + DesfireSetKey(&dctx, 0, T_3DES, key); + + uint8_t kdfInput[] = {0x04, 0x78, 0x2E, 0x21, 0x80, 0x1D, 0x80, 0x30, 0x42, 0xF5, 0x4E, 0x58, 0x50, 0x20, 0x41}; + MifareKdfAn10922(&dctx, DCOMainKey, kdfInput, sizeof(kdfInput)); + + uint8_t dkey[] = {0x16, 0xF8, 0x59, 0x7C, 0x9E, 0x89, 0x10, 0xC8, 0x6B, 0x96, 0x48, 0xD0, 0x06, 0x10, 0x7D, 0xD7}; + res = res && (memcmp(dctx.key, dkey, sizeof(dkey)) == 0); + + if (res) + PrintAndLogEx(INFO, "An10922 2TDEA..... " _GREEN_("passed")); + else + PrintAndLogEx(ERR, "An10922 2TDEA..... " _RED_("fail")); + + return res; +} + +static bool TestAn10922KDF3TDEA(void) { + bool res = true; + + uint8_t key[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; + + DesfireContext dctx; + DesfireSetKey(&dctx, 0, T_3K3DES, key); + + uint8_t kdfInput[] = {0x04, 0x78, 0x2E, 0x21, 0x80, 0x1D, 0x80, 0x30, 0x42, 0xF5, 0x4E, 0x58, 0x50}; + MifareKdfAn10922(&dctx, DCOMainKey, kdfInput, sizeof(kdfInput)); + + uint8_t dkey[] = {0x2F, 0x0D, 0xD0, 0x36, 0x75, 0xD3, 0xFB, 0x9A, 0x57, 0x05, 0xAB, 0x0B, 0xDA, 0x91, 0xCA, 0x0B, + 0x55, 0xB8, 0xE0, 0x7F, 0xCD, 0xBF, 0x10, 0xEC}; + res = res && (memcmp(dctx.key, dkey, sizeof(dkey)) == 0); + + if (res) + PrintAndLogEx(INFO, "An10922 3TDEA..... " _GREEN_("passed")); + else + PrintAndLogEx(ERR, "An10922 3TDEA..... " _RED_("fail")); + + return res; +} + // https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/TDES_CMAC.pdf static bool TestCMAC3TDEA(void) { bool res = true; @@ -336,6 +456,10 @@ bool DesfireTest(bool verbose) { res = res && TestCRC16(); res = res && TestCRC32(); + res = res && TestCMACSubkeys(); + res = res && TestAn10922KDFAES(); + res = res && TestAn10922KDF2TDEA(); + res = res && TestAn10922KDF3TDEA(); res = res && TestCMAC3TDEA(); res = res && TestCMAC2TDEA(); res = res && TestCMACDES();