From cc699d288dad316019c70474c7c828d5dadac424 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 30 Jul 2021 00:04:10 +0300 Subject: [PATCH 1/9] ev2 auth sketch --- client/src/mifare/desfirecore.c | 150 +++++++++++++++++++++++++++++- client/src/mifare/desfirecrypto.h | 1 + 2 files changed, 150 insertions(+), 1 deletion(-) diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index ce7f8298f..c3ec93c1f 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -745,7 +745,7 @@ int DesfireSelectAndAuthenticate(DesfireContext *dctx, DesfireSecureChannel secu return DesfireSelectAndAuthenticateEx(dctx, secureChannel, aid, false, verbose); } -int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel, bool verbose) { +static int DesfireAuthenticateEV1(DesfireContext *dctx, DesfireSecureChannel secureChannel, bool verbose) { // 3 different way to authenticate AUTH (CRC16) , AUTH_ISO (CRC32) , AUTH_AES (CRC32) // 4 different crypto arg1 DES, 3DES, 3K3DES, AES // 3 different communication modes, PLAIN,MAC,CRYPTO @@ -1033,6 +1033,154 @@ int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel return PM3_SUCCESS; } +static int DesfireAuthenticateEV2(DesfireContext *dctx, DesfireSecureChannel secureChannel, bool firstauth, bool verbose) { + // Crypt constants + uint8_t IV[16] = {0}; + uint8_t RndA[CRYPTO_AES_BLOCK_SIZE] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16}; + uint8_t RndB[CRYPTO_AES_BLOCK_SIZE] = {0}; + uint8_t encRndB[CRYPTO_AES_BLOCK_SIZE] = {0}; + uint8_t rotRndB[CRYPTO_AES_BLOCK_SIZE] = {0}; //RndB' + uint8_t both[CRYPTO_AES_BLOCK_SIZE * 2 + 1] = {0}; // ek/dk_keyNo(RndA+RndB') + + uint8_t subcommand = firstauth ? MFDES_AUTHENTICATE_EV2F : MFDES_AUTHENTICATE_EV2NF; + + size_t recv_len = 0; + uint8_t respcode = 0; + uint8_t recv_data[256] = {0}; + + //mbedtls_aes_context ctx; + + if (verbose) + PrintAndLogEx(INFO, _CYAN_("Auth:") " cmd: 0x%02x keynum: 0x%02x", subcommand, dctx->keyNum); + + // Let's send our auth command + uint8_t cdata[2] = {dctx->keyNum, 0x00}; + int res = DesfireExchangeEx(false, dctx, subcommand, cdata, sizeof(cdata), &respcode, recv_data, &recv_len, false, 0); + if (res != PM3_SUCCESS) { + return 1; + } + + if (!recv_len) { + return 2; + } + + if (respcode != MFDES_ADDITIONAL_FRAME) { + return 3; + } + + if (recv_len != CRYPTO_AES_BLOCK_SIZE) { + return 4; + } + + // Part 2 + memcpy(encRndB, recv_data, 16); + + // Part 3 + //if (mbedtls_aes_setkey_dec(&ctx, dctx->key, 128) != 0) { + // return 5; + //} + //mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_DECRYPT, CRYPTO_AES_BLOCK_SIZE, IV, encRndB, RndB); + //aes_decode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length) + if (aes_decode(IV, dctx->key, encRndB, RndB, CRYPTO_AES_BLOCK_SIZE)) + return 5; + + if (g_debugMode > 1) { + PrintAndLogEx(DEBUG, "encRndB: %s", sprint_hex(encRndB, CRYPTO_AES_BLOCK_SIZE)); + PrintAndLogEx(DEBUG, "RndB: %s", sprint_hex(RndB, CRYPTO_AES_BLOCK_SIZE)); + } +PrintAndLogEx(INFO, "encRndB: %s", sprint_hex(encRndB, 16)); +PrintAndLogEx(INFO, "RndB: %s", sprint_hex(RndB, 16)); + + // - Rotate RndB by 8 bits + memcpy(rotRndB, RndB, CRYPTO_AES_BLOCK_SIZE); + rol(rotRndB, CRYPTO_AES_BLOCK_SIZE); + + uint8_t encRndA[16] = {0x00}; + + // - Encrypt our response + uint8_t tmp[32] = {0x00}; + memcpy(tmp, RndA, CRYPTO_AES_BLOCK_SIZE); + memcpy(tmp + CRYPTO_AES_BLOCK_SIZE, rotRndB, CRYPTO_AES_BLOCK_SIZE); + if (g_debugMode > 1) { + PrintAndLogEx(DEBUG, "rotRndB: %s", sprint_hex(rotRndB, CRYPTO_AES_BLOCK_SIZE)); + PrintAndLogEx(DEBUG, "Both: %s", sprint_hex(tmp, CRYPTO_AES_BLOCK_SIZE * 2)); + } + +PrintAndLogEx(INFO, "rotRndB: %s", sprint_hex(rotRndB, CRYPTO_AES_BLOCK_SIZE)); +PrintAndLogEx(INFO, "Both: %s", sprint_hex(tmp, CRYPTO_AES_BLOCK_SIZE * 2)); + + //if (mbedtls_aes_setkey_enc(&ctx, dctx->key, 128) != 0) { + // return 6; + //} + //mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_ENCRYPT, CRYPTO_AES_BLOCK_SIZE * 2, IV, tmp, both); + if (aes_encode(IV, dctx->key, tmp, both, CRYPTO_AES_BLOCK_SIZE * 2)) + return 6; + if (g_debugMode > 1) { + PrintAndLogEx(DEBUG, "EncBoth: %s", sprint_hex(both, CRYPTO_AES_BLOCK_SIZE * 2)); + } + +PrintAndLogEx(INFO, "EncBoth: %s", sprint_hex(both, CRYPTO_AES_BLOCK_SIZE * 2)); + + res = DesfireExchangeEx(false, dctx, MFDES_ADDITIONAL_FRAME, both, CRYPTO_AES_BLOCK_SIZE * 2, &respcode, recv_data, &recv_len, false, 0); + if (res != PM3_SUCCESS) { + return 7; + } + + if (!recv_len) { + return 8; + } + + if (respcode != MFDES_S_OPERATION_OK) { + return 9; + } + + // Part 4 + memcpy(encRndA, recv_data, CRYPTO_AES_BLOCK_SIZE); + + //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, CRYPTO_AES_BLOCK_SIZE)); +PrintAndLogEx(INFO, "IV : %s", sprint_hex(IV, CRYPTO_AES_BLOCK_SIZE)); + + uint8_t data[32] = {0}; + + if (aes_decode(IV, dctx->key, recv_data, data, CRYPTO_AES_BLOCK_SIZE)) + return 10; + //if (mbedtls_aes_setkey_dec(&ctx, dctx->key, 128) != 0) { + // return 10; + //} + //mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_DECRYPT, CRYPTO_AES_BLOCK_SIZE, IV, recv_data, data); +PrintAndLogEx(INFO, "data : %s", sprint_hex(data, CRYPTO_AES_BLOCK_SIZE * 2)); + + + rol(RndA, CRYPTO_AES_BLOCK_SIZE); +PrintAndLogEx(INFO, "Expected_RndA : %s", sprint_hex(RndA, CRYPTO_AES_BLOCK_SIZE)); +PrintAndLogEx(INFO, "Generated_RndA : %s", sprint_hex(encRndA, CRYPTO_AES_BLOCK_SIZE)); + for (uint32_t x = 0; x < CRYPTO_AES_BLOCK_SIZE; x++) { + if (RndA[x] != encRndA[x]) { + if (g_debugMode > 1) { + PrintAndLogEx(DEBUG, "Expected_RndA : %s", sprint_hex(RndA, CRYPTO_AES_BLOCK_SIZE)); + PrintAndLogEx(DEBUG, "Generated_RndA : %s", sprint_hex(encRndA, CRYPTO_AES_BLOCK_SIZE)); + } + return 11; + } + } + + return PM3_SUCCESS; +} + +int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel, bool verbose) { + if (secureChannel == DACd40 || secureChannel == DACEV1) + return DesfireAuthenticateEV1(dctx, secureChannel, verbose); + + if (secureChannel == DACEV2) + return DesfireAuthenticateEV2(dctx, secureChannel, true, verbose); // TODO make 2nd auth if there is working secure channel + + return PM3_SUCCESS; +} + static int DesfireCommandEx(DesfireContext *dctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *resp, size_t *resplen, int checklength, size_t splitbysize) { if (resplen) *resplen = 0; diff --git a/client/src/mifare/desfirecrypto.h b/client/src/mifare/desfirecrypto.h index fddef64c9..b992a7f83 100644 --- a/client/src/mifare/desfirecrypto.h +++ b/client/src/mifare/desfirecrypto.h @@ -24,6 +24,7 @@ #include "common.h" #include "mifare/mifare4.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 From 319607f014419db8c3af45c05077b1f289240af6 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 30 Jul 2021 00:14:30 +0300 Subject: [PATCH 2/9] auth works --- client/src/mifare/desfirecore.c | 37 +++++++++++++-------------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index c3ec93c1f..9476825b7 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -1076,11 +1076,6 @@ static int DesfireAuthenticateEV2(DesfireContext *dctx, DesfireSecureChannel sec memcpy(encRndB, recv_data, 16); // Part 3 - //if (mbedtls_aes_setkey_dec(&ctx, dctx->key, 128) != 0) { - // return 5; - //} - //mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_DECRYPT, CRYPTO_AES_BLOCK_SIZE, IV, encRndB, RndB); - //aes_decode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length) if (aes_decode(IV, dctx->key, encRndB, RndB, CRYPTO_AES_BLOCK_SIZE)) return 5; @@ -1109,10 +1104,7 @@ PrintAndLogEx(INFO, "RndB: %s", sprint_hex(RndB, 16)); PrintAndLogEx(INFO, "rotRndB: %s", sprint_hex(rotRndB, CRYPTO_AES_BLOCK_SIZE)); PrintAndLogEx(INFO, "Both: %s", sprint_hex(tmp, CRYPTO_AES_BLOCK_SIZE * 2)); - //if (mbedtls_aes_setkey_enc(&ctx, dctx->key, 128) != 0) { - // return 6; - //} - //mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_ENCRYPT, CRYPTO_AES_BLOCK_SIZE * 2, IV, tmp, both); + if (aes_encode(IV, dctx->key, tmp, both, CRYPTO_AES_BLOCK_SIZE * 2)) return 6; if (g_debugMode > 1) { @@ -1146,28 +1138,29 @@ PrintAndLogEx(INFO, "IV : %s", sprint_hex(IV, CRYPTO_AES_BLOCK_SIZE)); uint8_t data[32] = {0}; - if (aes_decode(IV, dctx->key, recv_data, data, CRYPTO_AES_BLOCK_SIZE)) + if (aes_decode(IV, dctx->key, recv_data, data, CRYPTO_AES_BLOCK_SIZE * 2)) return 10; - //if (mbedtls_aes_setkey_dec(&ctx, dctx->key, 128) != 0) { - // return 10; - //} - //mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_DECRYPT, CRYPTO_AES_BLOCK_SIZE, IV, recv_data, data); + PrintAndLogEx(INFO, "data : %s", sprint_hex(data, CRYPTO_AES_BLOCK_SIZE * 2)); rol(RndA, CRYPTO_AES_BLOCK_SIZE); PrintAndLogEx(INFO, "Expected_RndA : %s", sprint_hex(RndA, CRYPTO_AES_BLOCK_SIZE)); -PrintAndLogEx(INFO, "Generated_RndA : %s", sprint_hex(encRndA, CRYPTO_AES_BLOCK_SIZE)); - for (uint32_t x = 0; x < CRYPTO_AES_BLOCK_SIZE; x++) { - if (RndA[x] != encRndA[x]) { - if (g_debugMode > 1) { - PrintAndLogEx(DEBUG, "Expected_RndA : %s", sprint_hex(RndA, CRYPTO_AES_BLOCK_SIZE)); - PrintAndLogEx(DEBUG, "Generated_RndA : %s", sprint_hex(encRndA, CRYPTO_AES_BLOCK_SIZE)); - } - return 11; +PrintAndLogEx(INFO, "Generated_RndA : %s", sprint_hex(&data[4], CRYPTO_AES_BLOCK_SIZE)); + + if (memcmp(RndA, &data[4], CRYPTO_AES_BLOCK_SIZE) != 0) { + if (g_debugMode > 1) { + PrintAndLogEx(DEBUG, "Expected_RndA : %s", sprint_hex(RndA, CRYPTO_AES_BLOCK_SIZE)); + PrintAndLogEx(DEBUG, "Generated_RndA : %s", sprint_hex(&data[4], CRYPTO_AES_BLOCK_SIZE)); } + return 11; } + + memcpy(dctx->TI, data, 4); + memset(dctx->IV, 0, DESFIRE_MAX_KEY_SIZE); + dctx->secureChannel = secureChannel; +PrintAndLogEx(INFO, "done"); return PM3_SUCCESS; } From cddf89ca4cdee9e1004eac8c7549a7942f9f1886 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 30 Jul 2021 00:35:14 +0300 Subject: [PATCH 3/9] verbosity --- client/src/mifare/desfirecore.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 9476825b7..7b6750cc0 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -266,6 +266,12 @@ void DesfirePrintContext(DesfireContext *ctx) { PrintAndLogEx(INFO, " IV [%zu]: %s", desfire_get_key_block_length(ctx->keyType), sprint_hex(ctx->IV, desfire_get_key_block_length(ctx->keyType))); + if (ctx->secureChannel == DACEV2) { + PrintAndLogEx(INFO, " TI: %s cnTX: 0x%08x cnRx: 0x%08x", + sprint_hex(ctx->TI, 4), + ctx->cntrTx, + ctx->cntrRx); + } } } @@ -1128,10 +1134,6 @@ PrintAndLogEx(INFO, "EncBoth: %s", sprint_hex(both, CRYPTO_AES_BLOCK_SIZE * 2)); // Part 4 memcpy(encRndA, recv_data, CRYPTO_AES_BLOCK_SIZE); - - //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, CRYPTO_AES_BLOCK_SIZE)); PrintAndLogEx(INFO, "IV : %s", sprint_hex(IV, CRYPTO_AES_BLOCK_SIZE)); @@ -1155,7 +1157,15 @@ PrintAndLogEx(INFO, "Generated_RndA : %s", sprint_hex(&data[4], CRYPTO_AES_BLOCK } return 11; } + + if (verbose) { + PrintAndLogEx(INFO, " TI: %s", sprint_hex(data, 4)); + PrintAndLogEx(INFO, "pic: %s", sprint_hex(&data[20], 6)); + PrintAndLogEx(INFO, "pcd: %s", sprint_hex(&data[26], 6)); + } + dctx->cntrRx = 0; + dctx->cntrTx = 0; memcpy(dctx->TI, data, 4); memset(dctx->IV, 0, DESFIRE_MAX_KEY_SIZE); dctx->secureChannel = secureChannel; From a66dbf90fe7850308047954c82a45b12df5692fc Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 30 Jul 2021 13:14:54 +0300 Subject: [PATCH 4/9] ev2 session keys generation --- client/src/mifare/desfirecrypto.c | 31 ++++++++++++++++++++ client/src/mifare/desfirecrypto.h | 2 ++ client/src/mifare/desfiretest.c | 48 ++++++++++++++++++++++++------- 3 files changed, 71 insertions(+), 10 deletions(-) diff --git a/client/src/mifare/desfirecrypto.c b/client/src/mifare/desfirecrypto.c index 391da348a..cf26fe22d 100644 --- a/client/src/mifare/desfirecrypto.c +++ b/client/src/mifare/desfirecrypto.c @@ -386,6 +386,37 @@ uint8_t DesfireCommModeToFileCommMode(DesfireCommunicationMode comm_mode) { return fmode; } +// https://www.nxp.com/docs/en/application-note/AN12343.pdf +// page 35 +void DesfireGenSessionKeyEV2(uint8_t *key, uint8_t *rndA, uint8_t *rndB, bool enckey, uint8_t *sessionkey) { + uint8_t data[64] = {0}; + memset(sessionkey, 0, CRYPTO_AES_BLOCK_SIZE); + + if (enckey) { + data[0] = 0xa5; + data[1] = 0x5a; + } else { + data[0] = 0x5a; + data[1] = 0xa5; + } + data[3] = 0x01; + data[5] = 0x80; + + // data+6 - start of rnd part + memcpy(data + 6, rndA, 8); + bin_xor(data + 8, rndB, 6); // xor rndb 6b + memcpy(data + 14, rndB + 6, 10); + memcpy(data + 24, rndA + 8, 8); + + uint8_t cmac[CRYPTO_AES_BLOCK_SIZE] = {0}; + DesfireContext ctx = {0}; + ctx.keyType = T_AES; + memcpy(ctx.key, key, 16); // aes-128 + DesfireCryptoCMAC(&ctx, data, 32, cmac); + + memcpy(sessionkey, cmac, CRYPTO_AES_BLOCK_SIZE); +} + 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 b992a7f83..b8ba977fd 100644 --- a/client/src/mifare/desfirecrypto.h +++ b/client/src/mifare/desfirecrypto.h @@ -109,6 +109,8 @@ uint8_t DesfireDESKeyGetVersion(uint8_t *key); DesfireCommunicationMode DesfireFileCommModeToCommMode(uint8_t file_comm_mode); uint8_t DesfireCommModeToFileCommMode(DesfireCommunicationMode comm_mode); +void DesfireGenSessionKeyEV2(uint8_t *key, uint8_t *rndA, uint8_t *rndB, bool enckey, uint8_t *sessionkey); + 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/desfiretest.c b/client/src/mifare/desfiretest.c index b89963352..480f44462 100644 --- a/client/src/mifare/desfiretest.c +++ b/client/src/mifare/desfiretest.c @@ -44,9 +44,9 @@ static bool TestCRC16(void) { res = res && (len == 0); if (res) - PrintAndLogEx(INFO, "crc16............ " _GREEN_("passed")); + PrintAndLogEx(INFO, "crc16............. " _GREEN_("passed")); else - PrintAndLogEx(ERR, "crc16............ " _RED_("fail")); + PrintAndLogEx(ERR, "crc16............. " _RED_("fail")); return res; } @@ -71,9 +71,9 @@ static bool TestCRC32(void) { res = res && (len == 0); if (res) - PrintAndLogEx(INFO, "crc32............ " _GREEN_("passed")); + PrintAndLogEx(INFO, "crc32............. " _GREEN_("passed")); else - PrintAndLogEx(ERR, "crc32............ " _RED_("fail")); + PrintAndLogEx(ERR, "crc32............. " _RED_("fail")); return res; } @@ -115,9 +115,9 @@ static bool TestCMAC3TDEA(void) { res = res && (memcmp(cmac, cmac4, sizeof(cmac1)) == 0); if (res) - PrintAndLogEx(INFO, "CMAC 3TDEA....... " _GREEN_("passed")); + PrintAndLogEx(INFO, "CMAC 3TDEA........ " _GREEN_("passed")); else - PrintAndLogEx(ERR, "CMAC 3TDEA....... " _RED_("fail")); + PrintAndLogEx(ERR, "CMAC 3TDEA........ " _RED_("fail")); return res; } @@ -159,9 +159,9 @@ static bool TestCMAC2TDEA(void) { res = res && (memcmp(cmac, cmac4, sizeof(cmac1)) == 0); if (res) - PrintAndLogEx(INFO, "CMAC 2TDEA....... " _GREEN_("passed")); + PrintAndLogEx(INFO, "CMAC 2TDEA........ " _GREEN_("passed")); else - PrintAndLogEx(ERR, "CMAC 2TDEA....... " _RED_("fail")); + PrintAndLogEx(ERR, "CMAC 2TDEA........ " _RED_("fail")); return res; } @@ -199,9 +199,36 @@ static bool TestCMACDES(void) { res = res && (memcmp(cmac, cmac4, sizeof(cmac1)) == 0); if (res) - PrintAndLogEx(INFO, "CMAC DES......... " _GREEN_("passed")); + PrintAndLogEx(INFO, "CMAC DES.......... " _GREEN_("passed")); else - PrintAndLogEx(ERR, "CMAC DES......... " _RED_("fail")); + PrintAndLogEx(ERR, "CMAC DES.......... " _RED_("fail")); + + return res; +} + +// https://www.nxp.com/docs/en/application-note/AN12343.pdf +// page 33-34 +static bool TestEV2SessionKeys(void) { + bool res = true; + + uint8_t key[16] = {0}; + uint8_t rnda[] = {0xB0, 0x4D, 0x07, 0x87, 0xC9, 0x3E, 0xE0, 0xCC, 0x8C, 0xAC, 0xC8, 0xE8, 0x6F, 0x16, 0xC6, 0xFE}; + uint8_t rndb[] = {0xFA, 0x65, 0x9A, 0xD0, 0xDC, 0xA7, 0x38, 0xDD, 0x65, 0xDC, 0x7D, 0xC3, 0x86, 0x12, 0xAD, 0x81}; + uint8_t sessionkeyauth[] = {0x63, 0xDC, 0x07, 0x28, 0x62, 0x89, 0xA7, 0xA6, 0xC0, 0x33, 0x4C, 0xA3, 0x1C, 0x31, 0x4A, 0x04}; + uint8_t sessionkeymac[] = {0x77, 0x4F, 0x26, 0x74, 0x3E, 0xCE, 0x6A, 0xF5, 0x03, 0x3B, 0x6A, 0xE8, 0x52, 0x29, 0x46, 0xF6}; + + uint8_t sessionkey[16] = {0}; + DesfireGenSessionKeyEV2(key, rnda, rndb, true, sessionkey); + res = res && (memcmp(sessionkey, sessionkeyauth, sizeof(sessionkeyauth)) == 0); + + memset(sessionkey, 0, sizeof(sessionkey)); + DesfireGenSessionKeyEV2(key, rnda, rndb, false, sessionkey); + res = res && (memcmp(sessionkey, sessionkeymac, sizeof(sessionkeymac)) == 0); + + if (res) + PrintAndLogEx(INFO, "EV2 session keys.. " _GREEN_("passed")); + else + PrintAndLogEx(ERR, "EV2 session keys.. " _RED_("fail")); return res; } @@ -216,6 +243,7 @@ bool DesfireTest(bool verbose) { res = res && TestCMAC3TDEA(); res = res && TestCMAC2TDEA(); res = res && TestCMACDES(); + res = res && TestEV2SessionKeys(); PrintAndLogEx(INFO, "---------------------------"); if (res) From 48be261c1ba2fe1fe64693b0ded23c7cd9f4922b Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 30 Jul 2021 13:32:39 +0300 Subject: [PATCH 5/9] add more verbosity to auth command --- client/src/cmdhfmfdes.c | 42 +--------------------- client/src/mifare/desfirecore.c | 62 +++++++++++++++++++++++++++------ client/src/mifare/desfirecore.h | 1 + 3 files changed, 54 insertions(+), 51 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index c90a13525..f8d00fd7e 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -916,46 +916,6 @@ static int handler_desfire_auth(mfdes_authinput_t *payload, mfdes_auth_res_t *rp return PM3_SUCCESS; } -/*static void AuthToError(int error) { - switch (error) { - case 1: - PrintAndLogEx(SUCCESS, "Sending auth command failed"); - break; - case 2: - PrintAndLogEx(ERR, "Authentication failed. No data received"); - break; - case 3: - PrintAndLogEx(ERR, "Authentication failed. Invalid key number."); - break; - case 4: - PrintAndLogEx(ERR, "Authentication failed. Length of answer doesn't match algo length"); - break; - case 5: - PrintAndLogEx(ERR, "mbedtls_aes_setkey_dec failed"); - break; - case 6: - PrintAndLogEx(ERR, "mbedtls_aes_setkey_enc failed"); - break; - case 7: - PrintAndLogEx(SUCCESS, "Sending auth command failed"); - break; - case 8: - PrintAndLogEx(ERR, "Authentication failed. Card timeout."); - break; - case 9: - PrintAndLogEx(ERR, "Authentication failed."); - break; - case 10: - PrintAndLogEx(ERR, "mbedtls_aes_setkey_dec failed"); - break; - case 11: - PrintAndLogEx(ERR, "Authentication failed. Cannot verify Session Key."); - break; - default: - break; - } -}*/ - // -- test if card supports 0x0A static int test_desfire_authenticate(void) { uint8_t data[] = {0x00}; @@ -3260,7 +3220,7 @@ static int CmdHF14ADesAuth(const char *Cmd) { res = DesfireSelectAndAuthenticateEx(&dctx, securechann, appid, false, verbose); if (res != PM3_SUCCESS) { DropField(); - PrintAndLogEx(FAILED, "Select or authentication 0x%06x " _RED_("failed") " ", appid); + PrintAndLogEx(FAILED, "Select or authentication 0x%06x " _RED_("failed") ". Result [%d] %s", appid, res, DesfireAuthErrorToStr(res)); return res; } diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 7b6750cc0..8e4c59878 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -231,6 +231,42 @@ const char *DesfireGetErrorString(int res, uint16_t *sw) { return ""; } +const char *DesfireAuthErrorToStr(int error) { + switch (error) { + case 1: + return "Sending auth command failed"; + case 2: + return "Authentication failed. No data received"; + case 3: + return "Authentication failed. Invalid key number."; + case 4: + return "Authentication failed. Length of answer doesn't match algo length"; + case 5: + return "mbedtls_aes_setkey_dec failed"; + case 6: + return "mbedtls_aes_setkey_enc failed"; + case 7: + return "Sending auth command failed"; + case 8: + return "Authentication failed. Card timeout."; + case 9: + return "Authentication failed."; + case 10: + return "mbedtls_aes_setkey_dec failed"; + case 11: + return "Authentication failed. Cannot verify Session Key."; + case 100: + return "Can't find auth method for provided channel parameters."; + case 200: + return "Can't select application."; + case 201: + return "Authentication retured no error but channel not authenticated."; + default: + break; + } + return ""; +} + uint32_t DesfireAIDByteToUint(uint8_t *data) { return data[0] + (data[1] << 8) + (data[2] << 16); } @@ -724,7 +760,7 @@ int DesfireSelectAndAuthenticateEx(DesfireContext *dctx, DesfireSecureChannel se int res = DesfireSelectAIDHex(dctx, aid, false, 0); if (res != PM3_SUCCESS) { PrintAndLogEx(ERR, "Desfire select " _RED_("error") "."); - return PM3_ESOFT; + return 200; } if (verbose) PrintAndLogEx(INFO, "App %06x " _GREEN_("selected"), aid); @@ -732,15 +768,15 @@ int DesfireSelectAndAuthenticateEx(DesfireContext *dctx, DesfireSecureChannel se if (!noauth) { res = DesfireAuthenticate(dctx, secureChannel, verbose); if (res != PM3_SUCCESS) { - PrintAndLogEx(ERR, "Desfire authenticate " _RED_("error") ". Result: %d", res); - return PM3_ESOFT; + PrintAndLogEx(ERR, "Desfire authenticate " _RED_("error") ". Result: [%d] %s", res, DesfireAuthErrorToStr(res)); + return res; } if (DesfireIsAuthenticated(dctx)) { if (verbose) PrintAndLogEx(INFO, "Desfire " _GREEN_("authenticated")); } else { - return PM3_ESOFT; + return 201; } } @@ -1152,25 +1188,31 @@ PrintAndLogEx(INFO, "Generated_RndA : %s", sprint_hex(&data[4], CRYPTO_AES_BLOCK if (memcmp(RndA, &data[4], CRYPTO_AES_BLOCK_SIZE) != 0) { if (g_debugMode > 1) { - PrintAndLogEx(DEBUG, "Expected_RndA : %s", sprint_hex(RndA, CRYPTO_AES_BLOCK_SIZE)); + PrintAndLogEx(DEBUG, "Expected_RndA : %s", sprint_hex(RndA, CRYPTO_AES_BLOCK_SIZE)); PrintAndLogEx(DEBUG, "Generated_RndA : %s", sprint_hex(&data[4], CRYPTO_AES_BLOCK_SIZE)); } return 11; } if (verbose) { - PrintAndLogEx(INFO, " TI: %s", sprint_hex(data, 4)); - PrintAndLogEx(INFO, "pic: %s", sprint_hex(&data[20], 6)); - PrintAndLogEx(INFO, "pcd: %s", sprint_hex(&data[26], 6)); + PrintAndLogEx(INFO, "TI : %s", sprint_hex(data, 4)); + PrintAndLogEx(INFO, "pic : %s", sprint_hex(&data[20], 6)); + PrintAndLogEx(INFO, "pcd : %s", sprint_hex(&data[26], 6)); } dctx->cntrRx = 0; dctx->cntrTx = 0; memcpy(dctx->TI, data, 4); memset(dctx->IV, 0, DESFIRE_MAX_KEY_SIZE); + DesfireGenSessionKeyEV2(dctx->key, RndA, RndB, true, dctx->sessionKeyEnc); + DesfireGenSessionKeyEV2(dctx->key, RndA, RndB, false, dctx->sessionKeyMAC); dctx->secureChannel = secureChannel; + + if (verbose) { + PrintAndLogEx(INFO, "session key ENC: %s", sprint_hex(dctx->sessionKeyEnc, 16)); + PrintAndLogEx(INFO, "session key MAC: %s", sprint_hex(dctx->sessionKeyMAC, 16)); + } -PrintAndLogEx(INFO, "done"); return PM3_SUCCESS; } @@ -1181,7 +1223,7 @@ int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel if (secureChannel == DACEV2) return DesfireAuthenticateEV2(dctx, secureChannel, true, verbose); // TODO make 2nd auth if there is working secure channel - return PM3_SUCCESS; + return 100; } static int DesfireCommandEx(DesfireContext *dctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *resp, size_t *resplen, int checklength, size_t splitbysize) { diff --git a/client/src/mifare/desfirecore.h b/client/src/mifare/desfirecore.h index 456798504..f845bf334 100644 --- a/client/src/mifare/desfirecore.h +++ b/client/src/mifare/desfirecore.h @@ -106,6 +106,7 @@ int DesfireSelectAID(DesfireContext *ctx, uint8_t *aid1, uint8_t *aid2); int DesfireSelectAIDHex(DesfireContext *ctx, uint32_t aid1, bool select_two, uint32_t aid2); int DesfireSelectAIDHexNoFieldOn(DesfireContext *ctx, uint32_t aid); +const char *DesfireAuthErrorToStr(int error); int DesfireSelectAndAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel, uint32_t aid, bool verbose); int DesfireSelectAndAuthenticateEx(DesfireContext *dctx, DesfireSecureChannel secureChannel, uint32_t aid, bool noauth, bool verbose); int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel, bool verbose); From a5ba41f5cfa4eb975b4762e043ec85dff2d00eaf Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 30 Jul 2021 14:08:06 +0300 Subject: [PATCH 6/9] code for non-first auth --- client/src/mifare/desfirecore.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 8e4c59878..1f540a7ac 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -1085,15 +1085,14 @@ static int DesfireAuthenticateEV2(DesfireContext *dctx, DesfireSecureChannel sec uint8_t both[CRYPTO_AES_BLOCK_SIZE * 2 + 1] = {0}; // ek/dk_keyNo(RndA+RndB') uint8_t subcommand = firstauth ? MFDES_AUTHENTICATE_EV2F : MFDES_AUTHENTICATE_EV2NF; + uint8_t *key = firstauth ? dctx->key : dctx->sessionKeyEnc; size_t recv_len = 0; uint8_t respcode = 0; uint8_t recv_data[256] = {0}; - //mbedtls_aes_context ctx; - if (verbose) - PrintAndLogEx(INFO, _CYAN_("Auth:") " cmd: 0x%02x keynum: 0x%02x", subcommand, dctx->keyNum); + PrintAndLogEx(INFO, _CYAN_("Auth %s:") " cmd: 0x%02x keynum: 0x%02x key: %s", (firstauth) ? "first" : "non-first", subcommand, dctx->keyNum, sprint_hex(key, 16)); // Let's send our auth command uint8_t cdata[2] = {dctx->keyNum, 0x00}; @@ -1118,7 +1117,7 @@ static int DesfireAuthenticateEV2(DesfireContext *dctx, DesfireSecureChannel sec memcpy(encRndB, recv_data, 16); // Part 3 - if (aes_decode(IV, dctx->key, encRndB, RndB, CRYPTO_AES_BLOCK_SIZE)) + if (aes_decode(IV, key, encRndB, RndB, CRYPTO_AES_BLOCK_SIZE)) return 5; if (g_debugMode > 1) { @@ -1147,7 +1146,7 @@ PrintAndLogEx(INFO, "rotRndB: %s", sprint_hex(rotRndB, CRYPTO_AES_BLOCK_SIZE)); PrintAndLogEx(INFO, "Both: %s", sprint_hex(tmp, CRYPTO_AES_BLOCK_SIZE * 2)); - if (aes_encode(IV, dctx->key, tmp, both, CRYPTO_AES_BLOCK_SIZE * 2)) + if (aes_encode(IV, key, tmp, both, CRYPTO_AES_BLOCK_SIZE * 2)) return 6; if (g_debugMode > 1) { PrintAndLogEx(DEBUG, "EncBoth: %s", sprint_hex(both, CRYPTO_AES_BLOCK_SIZE * 2)); @@ -1176,7 +1175,7 @@ PrintAndLogEx(INFO, "IV : %s", sprint_hex(IV, CRYPTO_AES_BLOCK_SIZE)); uint8_t data[32] = {0}; - if (aes_decode(IV, dctx->key, recv_data, data, CRYPTO_AES_BLOCK_SIZE * 2)) + if (aes_decode(IV, key, recv_data, data, CRYPTO_AES_BLOCK_SIZE * 2)) return 10; PrintAndLogEx(INFO, "data : %s", sprint_hex(data, CRYPTO_AES_BLOCK_SIZE * 2)); @@ -1200,9 +1199,11 @@ PrintAndLogEx(INFO, "Generated_RndA : %s", sprint_hex(&data[4], CRYPTO_AES_BLOCK PrintAndLogEx(INFO, "pcd : %s", sprint_hex(&data[26], 6)); } - dctx->cntrRx = 0; - dctx->cntrTx = 0; - memcpy(dctx->TI, data, 4); + if (firstauth) { + dctx->cntrRx = 0; + dctx->cntrTx = 0; + memcpy(dctx->TI, data, 4); + } memset(dctx->IV, 0, DESFIRE_MAX_KEY_SIZE); DesfireGenSessionKeyEV2(dctx->key, RndA, RndB, true, dctx->sessionKeyEnc); DesfireGenSessionKeyEV2(dctx->key, RndA, RndB, false, dctx->sessionKeyMAC); @@ -1221,7 +1222,7 @@ int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel return DesfireAuthenticateEV1(dctx, secureChannel, verbose); if (secureChannel == DACEV2) - return DesfireAuthenticateEV2(dctx, secureChannel, true, verbose); // TODO make 2nd auth if there is working secure channel + return DesfireAuthenticateEV2(dctx, secureChannel, (DesfireIsAuthenticated(dctx) == false), verbose); // non first auth if there is a working secure channel return 100; } From f074386413006c6402b218e0fee3be9065725b9f Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 30 Jul 2021 14:45:26 +0300 Subject: [PATCH 7/9] ev2 iv calc --- client/src/mifare/desfirecore.c | 12 +++++------- client/src/mifare/desfirecrypto.c | 28 +++++++++++++++++++++++++-- client/src/mifare/desfirecrypto.h | 5 ++--- client/src/mifare/desfiresecurechan.c | 18 +++++++++++++++++ 4 files changed, 51 insertions(+), 12 deletions(-) diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 1f540a7ac..2598634dc 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -303,10 +303,9 @@ void DesfirePrintContext(DesfireContext *ctx) { desfire_get_key_block_length(ctx->keyType), sprint_hex(ctx->IV, desfire_get_key_block_length(ctx->keyType))); if (ctx->secureChannel == DACEV2) { - PrintAndLogEx(INFO, " TI: %s cnTX: 0x%08x cnRx: 0x%08x", + PrintAndLogEx(INFO, " TI: %s cmdCntr: 0x%08x", sprint_hex(ctx->TI, 4), - ctx->cntrTx, - ctx->cntrRx); + ctx->cmdCntr); } } @@ -1096,7 +1095,7 @@ static int DesfireAuthenticateEV2(DesfireContext *dctx, DesfireSecureChannel sec // Let's send our auth command uint8_t cdata[2] = {dctx->keyNum, 0x00}; - int res = DesfireExchangeEx(false, dctx, subcommand, cdata, sizeof(cdata), &respcode, recv_data, &recv_len, false, 0); + int res = DesfireExchangeEx(false, dctx, subcommand, cdata, (firstauth) ? sizeof(cdata) : 1, &respcode, recv_data, &recv_len, false, 0); if (res != PM3_SUCCESS) { return 1; } @@ -1175,7 +1174,7 @@ PrintAndLogEx(INFO, "IV : %s", sprint_hex(IV, CRYPTO_AES_BLOCK_SIZE)); uint8_t data[32] = {0}; - if (aes_decode(IV, key, recv_data, data, CRYPTO_AES_BLOCK_SIZE * 2)) + if (aes_decode(IV, key, recv_data, data, recv_len)) return 10; PrintAndLogEx(INFO, "data : %s", sprint_hex(data, CRYPTO_AES_BLOCK_SIZE * 2)); @@ -1200,8 +1199,7 @@ PrintAndLogEx(INFO, "Generated_RndA : %s", sprint_hex(&data[4], CRYPTO_AES_BLOCK } if (firstauth) { - dctx->cntrRx = 0; - dctx->cntrTx = 0; + dctx->cmdCntr = 0; memcpy(dctx->TI, data, 4); } memset(dctx->IV, 0, DESFIRE_MAX_KEY_SIZE); diff --git a/client/src/mifare/desfirecrypto.c b/client/src/mifare/desfirecrypto.c index cf26fe22d..0e65f5787 100644 --- a/client/src/mifare/desfirecrypto.c +++ b/client/src/mifare/desfirecrypto.c @@ -58,8 +58,7 @@ void DesfireClearSession(DesfireContext *ctx) { memset(ctx->lastIV, 0, sizeof(ctx->lastIV)); ctx->lastCommand = 0; ctx->lastRequestZeroLen = false; - ctx->cntrTx = 0; - ctx->cntrRx = 0; + ctx->cmdCntr = 0; memset(ctx->TI, 0, sizeof(ctx->TI)); } @@ -219,6 +218,10 @@ void DesfireCryptoEncDecEx(DesfireContext *ctx, bool use_session_key, uint8_t *s if (ctx->secureChannel == DACd40) { memset(ctx->IV, 0, DESFIRE_MAX_CRYPTO_BLOCK_SIZE); } + + if (ctx->secureChannel == DACEV2) { + DesfireEV2FillIV(ctx, dir_to_send, NULL); + } size_t block_size = desfire_get_key_block_length(ctx->keyType); @@ -417,6 +420,27 @@ void DesfireGenSessionKeyEV2(uint8_t *key, uint8_t *rndA, uint8_t *rndB, bool en memcpy(sessionkey, cmac, CRYPTO_AES_BLOCK_SIZE); } +void DesfireEV2FillIV(DesfireContext *ctx, bool send, uint8_t *iv) { + uint8_t xiv[CRYPTO_AES_BLOCK_SIZE] = {0}; + + if (send) { + xiv[0] = 0xa5; + xiv[1] = 0x5a; + } else { + xiv[0] = 0x5a; + xiv[1] = 0xa5; + } + + memcpy(xiv + 2, ctx->TI, 4); + Uint2byteToMemLe(xiv + 2 + 4, ctx->cmdCntr); + + if (iv == NULL) + memcpy(ctx->IV, xiv, CRYPTO_AES_BLOCK_SIZE); + else + memcpy(iv, xiv, CRYPTO_AES_BLOCK_SIZE); +} + + 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 b8ba977fd..4caff1fb9 100644 --- a/client/src/mifare/desfirecrypto.h +++ b/client/src/mifare/desfirecrypto.h @@ -82,9 +82,7 @@ typedef struct DesfireContextS { 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 + uint16_t cmdCntr; // for AES uint8_t TI[4]; // for AES } DesfireContext; @@ -110,6 +108,7 @@ DesfireCommunicationMode DesfireFileCommModeToCommMode(uint8_t file_comm_mode); uint8_t DesfireCommModeToFileCommMode(DesfireCommunicationMode comm_mode); void DesfireGenSessionKeyEV2(uint8_t *key, uint8_t *rndA, uint8_t *rndB, bool enckey, uint8_t *sessionkey); +void DesfireEV2FillIV(DesfireContext *ctx, bool send, uint8_t *iv); 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); diff --git a/client/src/mifare/desfiresecurechan.c b/client/src/mifare/desfiresecurechan.c index 7e20b9f1a..81efe69ac 100644 --- a/client/src/mifare/desfiresecurechan.c +++ b/client/src/mifare/desfiresecurechan.c @@ -24,6 +24,7 @@ #include "mifare/desfire_crypto.h" static const uint8_t CommandsCanUseAnyChannel[] = { + MFDES_S_ADDITIONAL_FRAME, MFDES_READ_DATA, MFDES_WRITE_DATA, MFDES_GET_VALUE, @@ -116,6 +117,9 @@ static const AllowedChannelModesS AllowedChannelModes[] = { {MFDES_CHANGE_KEY, DACEV1, DCCNative, DCMEncryptedPlain}, {MFDES_CHANGE_KEY_EV2, DACEV1, DCCNative, DCMEncryptedPlain}, + + {MFDES_AUTHENTICATE_EV2F, DACEV2, DCCNative, DCMPlain}, + {MFDES_AUTHENTICATE_EV2NF, DACEV2, DCCNative, DCMPlain}, }; #define CMD_HEADER_LEN_ALL 0xffff @@ -239,6 +243,13 @@ static void DesfireSecureChannelEncodeEV1(DesfireContext *ctx, uint8_t cmd, uint } } +static void DesfireSecureChannelEncodeEV2(DesfireContext *ctx, uint8_t cmd, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen) { + memcpy(dstdata, srcdata, srcdatalen); + *dstdatalen = srcdatalen; + + ctx->cmdCntr++; +} + 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 <= DesfireGetCmdHeaderLen(cmd)); @@ -251,6 +262,7 @@ void DesfireSecureChannelEncode(DesfireContext *ctx, uint8_t cmd, uint8_t *srcda DesfireSecureChannelEncodeEV1(ctx, cmd, srcdata, srcdatalen, dstdata, dstdatalen); break; case DACEV2: + DesfireSecureChannelEncodeEV2(ctx, cmd, srcdata, srcdatalen, dstdata, dstdatalen); break; case DACNone: memcpy(dstdata, srcdata, srcdatalen); @@ -361,6 +373,11 @@ static void DesfireSecureChannelDecodeEV1(DesfireContext *ctx, uint8_t *srcdata, } } +static void DesfireSecureChannelDecodeEV2(DesfireContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t respcode, uint8_t *dstdata, size_t *dstdatalen) { + memcpy(dstdata, srcdata, srcdatalen); + *dstdatalen = srcdatalen; +} + void DesfireSecureChannelDecode(DesfireContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t respcode, uint8_t *dstdata, size_t *dstdatalen) { switch (ctx->secureChannel) { case DACd40: @@ -370,6 +387,7 @@ void DesfireSecureChannelDecode(DesfireContext *ctx, uint8_t *srcdata, size_t sr DesfireSecureChannelDecodeEV1(ctx, srcdata, srcdatalen, respcode, dstdata, dstdatalen); break; case DACEV2: + DesfireSecureChannelDecodeEV2(ctx, srcdata, srcdatalen, respcode, dstdata, dstdatalen); break; case DACNone: memcpy(dstdata, srcdata, srcdatalen); From 4cc9de1183cb2230863af7f608c5a782d62510a0 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 30 Jul 2021 15:26:32 +0300 Subject: [PATCH 8/9] tests for ev2 compute iv --- client/src/mifare/desfirecrypto.c | 11 ++++---- client/src/mifare/desfirecrypto.h | 2 +- client/src/mifare/desfiresecurechan.c | 3 ++- client/src/mifare/desfiretest.c | 37 +++++++++++++++++++++++++++ 4 files changed, 45 insertions(+), 8 deletions(-) diff --git a/client/src/mifare/desfirecrypto.c b/client/src/mifare/desfirecrypto.c index 0e65f5787..5bacaaf0d 100644 --- a/client/src/mifare/desfirecrypto.c +++ b/client/src/mifare/desfirecrypto.c @@ -219,10 +219,6 @@ void DesfireCryptoEncDecEx(DesfireContext *ctx, bool use_session_key, uint8_t *s memset(ctx->IV, 0, DESFIRE_MAX_CRYPTO_BLOCK_SIZE); } - if (ctx->secureChannel == DACEV2) { - DesfireEV2FillIV(ctx, dir_to_send, NULL); - } - size_t block_size = desfire_get_key_block_length(ctx->keyType); if (iv == NULL) @@ -420,10 +416,10 @@ void DesfireGenSessionKeyEV2(uint8_t *key, uint8_t *rndA, uint8_t *rndB, bool en memcpy(sessionkey, cmac, CRYPTO_AES_BLOCK_SIZE); } -void DesfireEV2FillIV(DesfireContext *ctx, bool send, uint8_t *iv) { +void DesfireEV2FillIV(DesfireContext *ctx, bool ivforcommand, uint8_t *iv) { uint8_t xiv[CRYPTO_AES_BLOCK_SIZE] = {0}; - if (send) { + if (ivforcommand) { xiv[0] = 0xa5; xiv[1] = 0x5a; } else { @@ -434,6 +430,9 @@ void DesfireEV2FillIV(DesfireContext *ctx, bool send, uint8_t *iv) { memcpy(xiv + 2, ctx->TI, 4); Uint2byteToMemLe(xiv + 2 + 4, ctx->cmdCntr); + if (aes_encode(NULL, ctx->sessionKeyEnc, xiv, xiv, CRYPTO_AES_BLOCK_SIZE)) + return; + if (iv == NULL) memcpy(ctx->IV, xiv, CRYPTO_AES_BLOCK_SIZE); else diff --git a/client/src/mifare/desfirecrypto.h b/client/src/mifare/desfirecrypto.h index 4caff1fb9..950c5a83f 100644 --- a/client/src/mifare/desfirecrypto.h +++ b/client/src/mifare/desfirecrypto.h @@ -108,7 +108,7 @@ DesfireCommunicationMode DesfireFileCommModeToCommMode(uint8_t file_comm_mode); uint8_t DesfireCommModeToFileCommMode(DesfireCommunicationMode comm_mode); void DesfireGenSessionKeyEV2(uint8_t *key, uint8_t *rndA, uint8_t *rndB, bool enckey, uint8_t *sessionkey); -void DesfireEV2FillIV(DesfireContext *ctx, bool send, uint8_t *iv); +void DesfireEV2FillIV(DesfireContext *ctx, bool ivforcommand, uint8_t *iv); 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); diff --git a/client/src/mifare/desfiresecurechan.c b/client/src/mifare/desfiresecurechan.c index 81efe69ac..586c95285 100644 --- a/client/src/mifare/desfiresecurechan.c +++ b/client/src/mifare/desfiresecurechan.c @@ -247,7 +247,6 @@ static void DesfireSecureChannelEncodeEV2(DesfireContext *ctx, uint8_t cmd, uint memcpy(dstdata, srcdata, srcdatalen); *dstdatalen = srcdatalen; - ctx->cmdCntr++; } void DesfireSecureChannelEncode(DesfireContext *ctx, uint8_t cmd, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen) { @@ -374,6 +373,8 @@ static void DesfireSecureChannelDecodeEV1(DesfireContext *ctx, uint8_t *srcdata, } static void DesfireSecureChannelDecodeEV2(DesfireContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t respcode, uint8_t *dstdata, size_t *dstdatalen) { + ctx->cmdCntr++; + memcpy(dstdata, srcdata, srcdatalen); *dstdatalen = srcdatalen; } diff --git a/client/src/mifare/desfiretest.c b/client/src/mifare/desfiretest.c index 480f44462..5de1b312d 100644 --- a/client/src/mifare/desfiretest.c +++ b/client/src/mifare/desfiretest.c @@ -233,6 +233,42 @@ static bool TestEV2SessionKeys(void) { return res; } +static bool TestEV2IVEncode(void) { + bool res = true; + + uint8_t key[] = {0x66, 0xA8, 0xCB, 0x93, 0x26, 0x9D, 0xC9, 0xBC, 0x28, 0x85, 0xB7, 0xA9, 0x1B, 0x9C, 0x69, 0x7B}; + uint8_t ti[] = {0xED, 0x56, 0xF6, 0xE6}; + uint8_t ivres[] = {0xDA, 0x0F, 0x64, 0x4A, 0x49, 0x86, 0x27, 0x59, 0x57, 0xCF, 0x1E, 0xC3, 0xAF, 0x4C, 0xCE, 0x53}; + + DesfireContext ctx = {0}; + ctx.keyType = T_AES; + memcpy(ctx.sessionKeyEnc, key, 16); + memcpy(ctx.TI, ti, 4); + ctx.cmdCntr = 0; + + uint8_t iv[16] = {0}; + DesfireEV2FillIV(&ctx, true, iv); + res = res && (memcmp(iv, ivres, sizeof(ivres)) == 0); + + uint8_t key2[] = {0x44, 0x5A, 0x86, 0x26, 0xB3, 0x33, 0x84, 0x59, 0x32, 0x12, 0x32, 0xfA, 0xDf, 0x6a, 0xDe, 0x2B}; + uint8_t ti2[] = {0x11, 0x22, 0x33, 0x44}; + uint8_t ivres2[] = {0x17, 0x74, 0x94, 0xFC, 0xC4, 0xF1, 0xDA, 0xB2, 0xAF, 0xBE, 0x8F, 0xAE, 0x20, 0x57, 0xA9, 0xD2}; + memcpy(ctx.sessionKeyEnc, key2, 16); + memcpy(ctx.TI, ti2, 4); + ctx.cmdCntr = 5; + + memset(iv, 0, 16); + DesfireEV2FillIV(&ctx, true, iv); + res = res && (memcmp(iv, ivres2, sizeof(ivres2)) == 0); + + if (res) + PrintAndLogEx(INFO, "EV2 IV calc....... " _GREEN_("passed")); + else + PrintAndLogEx(ERR, "EV2 IV calc....... " _RED_("fail")); + + return res; +} + bool DesfireTest(bool verbose) { bool res = true; @@ -244,6 +280,7 @@ bool DesfireTest(bool verbose) { res = res && TestCMAC2TDEA(); res = res && TestCMACDES(); res = res && TestEV2SessionKeys(); + res = res && TestEV2IVEncode(); PrintAndLogEx(INFO, "---------------------------"); if (res) From e2f0d624587e3c6bc0c63555537f3af47cf0f2fb Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 30 Jul 2021 16:38:00 +0300 Subject: [PATCH 9/9] ev2 auth 1st and 2nd works --- client/src/mifare/desfirecore.c | 38 ++++++++++--------------------- client/src/mifare/desfirecrypto.c | 4 ++++ client/src/mifare/desfirecrypto.h | 1 + 3 files changed, 17 insertions(+), 26 deletions(-) diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 2598634dc..147850852 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -1084,7 +1084,7 @@ static int DesfireAuthenticateEV2(DesfireContext *dctx, DesfireSecureChannel sec uint8_t both[CRYPTO_AES_BLOCK_SIZE * 2 + 1] = {0}; // ek/dk_keyNo(RndA+RndB') uint8_t subcommand = firstauth ? MFDES_AUTHENTICATE_EV2F : MFDES_AUTHENTICATE_EV2NF; - uint8_t *key = firstauth ? dctx->key : dctx->sessionKeyEnc; + uint8_t *key = dctx->key; size_t recv_len = 0; uint8_t respcode = 0; @@ -1123,8 +1123,6 @@ static int DesfireAuthenticateEV2(DesfireContext *dctx, DesfireSecureChannel sec PrintAndLogEx(DEBUG, "encRndB: %s", sprint_hex(encRndB, CRYPTO_AES_BLOCK_SIZE)); PrintAndLogEx(DEBUG, "RndB: %s", sprint_hex(RndB, CRYPTO_AES_BLOCK_SIZE)); } -PrintAndLogEx(INFO, "encRndB: %s", sprint_hex(encRndB, 16)); -PrintAndLogEx(INFO, "RndB: %s", sprint_hex(RndB, 16)); // - Rotate RndB by 8 bits memcpy(rotRndB, RndB, CRYPTO_AES_BLOCK_SIZE); @@ -1141,18 +1139,12 @@ PrintAndLogEx(INFO, "RndB: %s", sprint_hex(RndB, 16)); PrintAndLogEx(DEBUG, "Both: %s", sprint_hex(tmp, CRYPTO_AES_BLOCK_SIZE * 2)); } -PrintAndLogEx(INFO, "rotRndB: %s", sprint_hex(rotRndB, CRYPTO_AES_BLOCK_SIZE)); -PrintAndLogEx(INFO, "Both: %s", sprint_hex(tmp, CRYPTO_AES_BLOCK_SIZE * 2)); - - if (aes_encode(IV, key, tmp, both, CRYPTO_AES_BLOCK_SIZE * 2)) return 6; if (g_debugMode > 1) { PrintAndLogEx(DEBUG, "EncBoth: %s", sprint_hex(both, CRYPTO_AES_BLOCK_SIZE * 2)); } -PrintAndLogEx(INFO, "EncBoth: %s", sprint_hex(both, CRYPTO_AES_BLOCK_SIZE * 2)); - res = DesfireExchangeEx(false, dctx, MFDES_ADDITIONAL_FRAME, both, CRYPTO_AES_BLOCK_SIZE * 2, &respcode, recv_data, &recv_len, false, 0); if (res != PM3_SUCCESS) { return 7; @@ -1169,45 +1161,39 @@ PrintAndLogEx(INFO, "EncBoth: %s", sprint_hex(both, CRYPTO_AES_BLOCK_SIZE * 2)); // Part 4 memcpy(encRndA, recv_data, CRYPTO_AES_BLOCK_SIZE); -PrintAndLogEx(INFO, "encRndA : %s", sprint_hex(encRndA, CRYPTO_AES_BLOCK_SIZE)); -PrintAndLogEx(INFO, "IV : %s", sprint_hex(IV, CRYPTO_AES_BLOCK_SIZE)); - uint8_t data[32] = {0}; if (aes_decode(IV, key, recv_data, data, recv_len)) return 10; -PrintAndLogEx(INFO, "data : %s", sprint_hex(data, CRYPTO_AES_BLOCK_SIZE * 2)); - - rol(RndA, CRYPTO_AES_BLOCK_SIZE); -PrintAndLogEx(INFO, "Expected_RndA : %s", sprint_hex(RndA, CRYPTO_AES_BLOCK_SIZE)); -PrintAndLogEx(INFO, "Generated_RndA : %s", sprint_hex(&data[4], CRYPTO_AES_BLOCK_SIZE)); + uint8_t *recRndA = (firstauth) ? &data[4] : data; - if (memcmp(RndA, &data[4], CRYPTO_AES_BLOCK_SIZE) != 0) { + if (memcmp(RndA, recRndA, CRYPTO_AES_BLOCK_SIZE) != 0) { if (g_debugMode > 1) { PrintAndLogEx(DEBUG, "Expected_RndA : %s", sprint_hex(RndA, CRYPTO_AES_BLOCK_SIZE)); - PrintAndLogEx(DEBUG, "Generated_RndA : %s", sprint_hex(&data[4], CRYPTO_AES_BLOCK_SIZE)); + PrintAndLogEx(DEBUG, "Generated_RndA : %s", sprint_hex(recRndA, CRYPTO_AES_BLOCK_SIZE)); } return 11; } - if (verbose) { - PrintAndLogEx(INFO, "TI : %s", sprint_hex(data, 4)); - PrintAndLogEx(INFO, "pic : %s", sprint_hex(&data[20], 6)); - PrintAndLogEx(INFO, "pcd : %s", sprint_hex(&data[26], 6)); - } - if (firstauth) { dctx->cmdCntr = 0; memcpy(dctx->TI, data, 4); } - memset(dctx->IV, 0, DESFIRE_MAX_KEY_SIZE); + DesfireClearIV(dctx); DesfireGenSessionKeyEV2(dctx->key, RndA, RndB, true, dctx->sessionKeyEnc); DesfireGenSessionKeyEV2(dctx->key, RndA, RndB, false, dctx->sessionKeyMAC); dctx->secureChannel = secureChannel; if (verbose) { + if (firstauth) { + PrintAndLogEx(INFO, "TI : %s", sprint_hex(data, 4)); + PrintAndLogEx(INFO, "pic : %s", sprint_hex(&data[20], 6)); + PrintAndLogEx(INFO, "pcd : %s", sprint_hex(&data[26], 6)); + } else { + PrintAndLogEx(INFO, "TI : %s", sprint_hex(dctx->TI, 4)); + } PrintAndLogEx(INFO, "session key ENC: %s", sprint_hex(dctx->sessionKeyEnc, 16)); PrintAndLogEx(INFO, "session key MAC: %s", sprint_hex(dctx->sessionKeyMAC, 16)); } diff --git a/client/src/mifare/desfirecrypto.c b/client/src/mifare/desfirecrypto.c index 5bacaaf0d..73913c449 100644 --- a/client/src/mifare/desfirecrypto.c +++ b/client/src/mifare/desfirecrypto.c @@ -62,6 +62,10 @@ void DesfireClearSession(DesfireContext *ctx) { memset(ctx->TI, 0, sizeof(ctx->TI)); } +void DesfireClearIV(DesfireContext *ctx) { + memset(ctx->IV, 0, sizeof(ctx->IV)); +} + void DesfireSetKey(DesfireContext *ctx, uint8_t keyNum, enum DESFIRE_CRYPTOALGO keyType, uint8_t *key) { DesfireClearContext(ctx); diff --git a/client/src/mifare/desfirecrypto.h b/client/src/mifare/desfirecrypto.h index 950c5a83f..2ba28bc46 100644 --- a/client/src/mifare/desfirecrypto.h +++ b/client/src/mifare/desfirecrypto.h @@ -88,6 +88,7 @@ typedef struct DesfireContextS { void DesfireClearContext(DesfireContext *ctx); void DesfireClearSession(DesfireContext *ctx); +void DesfireClearIV(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);