diff --git a/client/src/mifare/desfire_crypto.c b/client/src/mifare/desfire_crypto.c index 935083ab4..23c8b1fd9 100644 --- a/client/src/mifare/desfire_crypto.c +++ b/client/src/mifare/desfire_crypto.c @@ -976,6 +976,12 @@ void desfire_crc32_append(uint8_t *data, const size_t len) { crc32_ex(data, len, data + len); } +bool desfire_crc32_check(uint8_t *data, const size_t len, uint8_t *crc) { + uint8_t ccrc[4] = {0}; + desfire_crc32(data, len, ccrc); + return (memcmp(ccrc, crc, 4) == 0); +} + void iso14443a_crc_append(uint8_t *data, size_t len) { return compute_crc(CRC_14443_A, data, len, data + len, data + len + 1); } @@ -983,3 +989,9 @@ void iso14443a_crc_append(uint8_t *data, size_t len) { void iso14443a_crc(uint8_t *data, size_t len, uint8_t *pbtCrc) { return compute_crc(CRC_14443_A, data, len, pbtCrc, pbtCrc + 1); } + +bool iso14443a_crc_check(uint8_t *data, const size_t len, uint8_t *crc) { + uint8_t ccrc[2] = {0}; + iso14443a_crc(data, len, ccrc); + return (memcmp(ccrc, crc, 2) == 0); +} diff --git a/client/src/mifare/desfire_crypto.h b/client/src/mifare/desfire_crypto.h index 346a7e50c..689c0d56c 100644 --- a/client/src/mifare/desfire_crypto.h +++ b/client/src/mifare/desfire_crypto.h @@ -149,6 +149,8 @@ void mifare_kdf_an10922(const desfirekey_t key, const uint8_t *data, size_t len) 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); void iso14443a_crc_append(uint8_t *data, size_t len); void iso14443a_crc(uint8_t *data, size_t len, uint8_t *pbtCrc); +bool iso14443a_crc_check(uint8_t *data, const size_t len, uint8_t *crc); #endif diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 862723587..ad4c6c545 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -872,6 +872,16 @@ int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel return PM3_SUCCESS; } +int DesfireGetUID(DesfireContext *dctx, uint8_t *resp, size_t *resplen) { + uint8_t respcode = 0xff; + int res = DesfireExchange(dctx, MFDES_GET_UID, NULL, 0, &respcode, resp, resplen); + if (res != PM3_SUCCESS) + return res; + if (respcode != MFDES_S_OPERATION_OK) + return PM3_EAPDU_FAIL; + return PM3_SUCCESS; +} + int DesfireGetAIDList(DesfireContext *dctx, uint8_t *resp, size_t *resplen) { uint8_t respcode = 0xff; int res = DesfireExchange(dctx, MFDES_GET_APPLICATION_IDS, NULL, 0, &respcode, resp, resplen); diff --git a/client/src/mifare/desfirecore.h b/client/src/mifare/desfirecore.h index 9eaa74f9a..080fed18d 100644 --- a/client/src/mifare/desfirecore.h +++ b/client/src/mifare/desfirecore.h @@ -39,6 +39,7 @@ int DesfireSelectAIDHex(DesfireContext *ctx, uint32_t aid1, bool select_two, uin int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel); +int DesfireGetUID(DesfireContext *dctx, uint8_t *resp, size_t *resplen); int DesfireGetAIDList(DesfireContext *dctx, uint8_t *resp, size_t *resplen); int DesfireGetDFList(DesfireContext *dctx, uint8_t *resp, size_t *resplen); diff --git a/client/src/mifare/desfirecrypto.c b/client/src/mifare/desfirecrypto.c index c3fa5b67e..87fb4e1a1 100644 --- a/client/src/mifare/desfirecrypto.c +++ b/client/src/mifare/desfirecrypto.c @@ -56,6 +56,8 @@ void DesfireClearSession(DesfireContext *ctx) { memset(ctx->sessionKeyMAC, 0, sizeof(ctx->sessionKeyMAC)); memset(ctx->sessionKeyEnc, 0, sizeof(ctx->sessionKeyEnc)); memset(ctx->lastIV, 0, sizeof(ctx->lastIV)); + ctx->lastCommand = 0; + ctx->lastRequestZeroLen = false; ctx->cntrTx = 0; ctx->cntrRx = 0; memset(ctx->TI, 0, sizeof(ctx->TI)); @@ -107,6 +109,42 @@ size_t DesfireGetMACLength(DesfireContext *ctx) { return mac_length; } +size_t DesfireSearchCRCPos(uint8_t *data, size_t datalen, uint8_t respcode, uint8_t crclen) { + size_t crcpos = datalen - 1; + while (crcpos > 0) + if (data[crcpos] == 0) + crcpos--; + else + break; + crcpos++; // crc may be 0x00000000 or 0x0000 + if (crcpos < crclen) { + PrintAndLogEx(WARNING, "No space for crc. pos: %d", crcpos); + return 0; + } + + uint8_t crcdata[1024] = {0}; + size_t crcposfound = 0; + for (int i = 0; i < crclen + 1; i++) { + if (crcpos - i == 0) + break; + if (crcpos - i + crclen > datalen) + continue; + + memcpy(crcdata, data, crcpos - i); + crcdata[crcpos - i] = respcode; + bool res; + if (crclen == 4) + res = desfire_crc32_check(crcdata, crcpos - i + 1, &data[crcpos - i]); + else + res = iso14443a_crc_check(data, crcpos - i, &data[crcpos - i]); + if (res) { + crcposfound = crcpos - i; + } + } + + return crcposfound; +} + 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}; @@ -163,13 +201,14 @@ static void DesfireCryptoEncDecSingleBlock(uint8_t *key, DesfireCryptoAlgorythm break; } - memcpy(dstdata, edata, block_size); - if (dir_to_send) { memcpy(ivect, edata, block_size); } else { + bin_xor(edata, ivect, block_size); memcpy(ivect, data, block_size); } + + memcpy(dstdata, edata, block_size); } void DesfireCryptoEncDecEx(DesfireContext *ctx, bool use_session_key, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool encode, uint8_t *iv) { @@ -189,9 +228,9 @@ void DesfireCryptoEncDecEx(DesfireContext *ctx, bool use_session_key, uint8_t *s size_t offset = 0; while (offset < srcdatalen) { if (use_session_key) - DesfireCryptoEncDecSingleBlock(ctx->sessionKeyMAC, ctx->keyType, srcdata + offset, data, xiv, encode, encode); + DesfireCryptoEncDecSingleBlock(ctx->sessionKeyMAC, ctx->keyType, srcdata + offset, data + offset, xiv, encode, encode); else - DesfireCryptoEncDecSingleBlock(ctx->key, ctx->keyType, srcdata + offset, data, xiv, encode, encode); + DesfireCryptoEncDecSingleBlock(ctx->key, ctx->keyType, srcdata + offset, data + offset, xiv, encode, encode); offset += block_size; } @@ -265,6 +304,7 @@ void DesfireCryptoCMAC(DesfireContext *ctx, uint8_t *data, size_t len, uint8_t * DesfireCryptoEncDec(ctx, true, buffer, len, NULL, true); - memcpy(cmac, ctx->IV, kbs); + if (cmac != NULL) + memcpy(cmac, ctx->IV, kbs); } diff --git a/client/src/mifare/desfirecrypto.h b/client/src/mifare/desfirecrypto.h index 8ff77c377..824225b39 100644 --- a/client/src/mifare/desfirecrypto.h +++ b/client/src/mifare/desfirecrypto.h @@ -78,6 +78,8 @@ typedef struct DesfireContextS { 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]; + uint8_t lastCommand; + bool lastRequestZeroLen; //mf4Session_t AESSession; uint16_t cntrTx; // for AES uint16_t cntrRx; // for AES @@ -93,6 +95,7 @@ void DesfireSetKdf(DesfireContext *ctx, uint8_t kdfAlgo, uint8_t *kdfInput, uint bool DesfireIsAuthenticated(DesfireContext *dctx); size_t DesfireGetMACLength(DesfireContext *ctx); +size_t DesfireSearchCRCPos(uint8_t *data, size_t datalen, uint8_t respcode, uint8_t crclen); 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); diff --git a/client/src/mifare/desfiresecurechan.c b/client/src/mifare/desfiresecurechan.c index 9e440fad4..c2001bdf0 100644 --- a/client/src/mifare/desfiresecurechan.c +++ b/client/src/mifare/desfiresecurechan.c @@ -40,15 +40,20 @@ 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); + memset(ctx->IV, 0, sizeof(ctx->IV)); DesfireCryptoEncDec(ctx, true, data, rlen, NULL, true); memcpy(dstdata, srcdata, srcdatalen); memcpy(&dstdata[srcdatalen], ctx->IV, 4); *dstdatalen = rlen; break; case DCMEncrypted: + if (srcdatalen == 0) + break; + 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]); + memset(ctx->IV, 0, sizeof(ctx->IV)); DesfireCryptoEncDec(ctx, true, data, rlen, dstdata, true); *dstdatalen = rlen; break; @@ -60,31 +65,33 @@ 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}; - memcpy(dstdata, srcdata, srcdatalen); - *dstdatalen = srcdatalen; + // we calc MAC anyway + // if encypted channel and no data - we only calc MAC + if (ctx->commMode == DCMPlain || ctx->commMode == DCMMACed || (ctx->commMode == DCMEncrypted && srcdatalen == 0)) { + data[0] = cmd; + memcpy(&data[1], srcdata, srcdatalen); + uint8_t cmac[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0}; + DesfireCryptoCMAC(ctx, data, srcdatalen + 1, cmac); - switch (ctx->commMode) { - case DCMPlain: - case DCMMACed: - data[0] = cmd; - memcpy(&data[1], srcdata, srcdatalen); - 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], cmac, DesfireGetMACLength(ctx)); - *dstdatalen = srcdatalen + DesfireGetMACLength(ctx); - } - break; - case DCMEncrypted: - break; - case DCMNone: - ; + memcpy(dstdata, srcdata, srcdatalen); + if (srcdatalen != 0 && ctx->commMode == DCMMACed) { + memcpy(&dstdata[srcdatalen], cmac, DesfireGetMACLength(ctx)); + *dstdatalen = srcdatalen + DesfireGetMACLength(ctx); + } + } else if (ctx->commMode == DCMEncrypted) { + + + + } else { + memcpy(dstdata, srcdata, srcdatalen); + *dstdatalen = srcdatalen; } } void DesfireSecureChannelEncode(DesfireContext *ctx, uint8_t cmd, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen) { + ctx->lastCommand = cmd; + ctx->lastRequestZeroLen = (srcdatalen == 0); + switch (ctx->secureChannel) { case DACd40: DesfireSecureChannelEncodeD40(ctx, cmd, srcdata, srcdatalen, dstdata, dstdatalen); @@ -110,6 +117,22 @@ static void DesfireSecureChannelDecodeD40(DesfireContext *ctx, uint8_t *srcdata, break; case DCMEncrypted: + if (srcdatalen < desfire_get_key_block_length(ctx->keyType)) { + memcpy(dstdata, srcdata, srcdatalen); + *dstdatalen = srcdatalen; + return; + } + + DesfireCryptoEncDec(ctx, true, srcdata, srcdatalen, dstdata, false); + //PrintAndLogEx(INFO, "decoded[%d]: %s", srcdatalen, sprint_hex(dstdata, srcdatalen)); + + size_t puredatalen = DesfireSearchCRCPos(dstdata, srcdatalen, respcode, 2); + if (puredatalen != 0) { + *dstdatalen = puredatalen; + } else { + PrintAndLogEx(WARNING, "CRC16 error."); + *dstdatalen = srcdatalen; + } break; case DCMPlain: case DACNone: @@ -122,36 +145,49 @@ 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: - 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: - break; - case DACNone: + // if comm mode = plain --> response with MAC + // if request is not zero length --> response MAC + if (ctx->commMode == DCMPlain || ctx->commMode == DCMMACed || (ctx->commMode == DCMEncrypted && !ctx->lastRequestZeroLen)) { + if (srcdatalen < DesfireGetMACLength(ctx)) { memcpy(dstdata, srcdata, srcdatalen); *dstdatalen = srcdatalen; - break; + return; + } + + 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))); + } + } else if (ctx->commMode == DCMEncrypted) { + if (srcdatalen < desfire_get_key_block_length(ctx->keyType)) { + memcpy(dstdata, srcdata, srcdatalen); + *dstdatalen = srcdatalen; + return; + } + + DesfireCryptoEncDec(ctx, true, srcdata, srcdatalen, dstdata, false); + //PrintAndLogEx(INFO, "decoded[%d]: %s", srcdatalen, sprint_hex(dstdata, srcdatalen)); + + size_t puredatalen = DesfireSearchCRCPos(dstdata, srcdatalen, respcode, 4); + if (puredatalen != 0) { + *dstdatalen = puredatalen; + } else { + PrintAndLogEx(WARNING, "CRC32 error."); + *dstdatalen = srcdatalen; + } + + } else { + memcpy(dstdata, srcdata, srcdatalen); + *dstdatalen = srcdatalen; } }