From e28b6cfe83cf684ee0671c0a5f631edad5141d4b Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Tue, 17 Aug 2021 23:31:42 +0300 Subject: [PATCH] set config works auth lrp checks --- client/src/cmdhfmfdes.c | 33 ++++---- client/src/mifare/desfirecore.c | 131 ++++++++++++++++++++++++++++++++ 2 files changed, 149 insertions(+), 15 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index f257e9354..929ccb800 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -1960,8 +1960,8 @@ static int CmdHF14ADesAuth(const char *Cmd) { arg_str0("c", "ccset", "", "Communicaton command set: native/niso/iso"), arg_str0("s", "schann", "", "Secure channel: d40/ev1/ev2/lrp"), arg_str0(NULL, "aid", "", "Application ID of application for some parameters (3 hex bytes, big endian)"), - arg_lit0(NULL, "save", "saves channels parameters to defaults if authentication succeeds"), arg_str0(NULL, "appisoid", "", "Application ISO ID (ISO DF ID) (2 hex bytes, big endian). Works only for ISO read commands."), + arg_lit0(NULL, "save", "saves channels parameters to defaults if authentication succeeds"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -1973,13 +1973,13 @@ static int CmdHF14ADesAuth(const char *Cmd) { int securechann = defaultSecureChannel; uint32_t id = 0x000000; DesfireISOSelectWay selectway = ISW6bAID; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, &securechann, DCMPlain, &id, &selectway); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, &securechann, DCMPlain, &id, &selectway); if (res) { CLIParserFree(ctx); return res; } - bool save = arg_get_lit(ctx, 12); + bool save = arg_get_lit(ctx, 13); SetAPDULogging(APDULogging); CLIParserFree(ctx); @@ -2026,15 +2026,16 @@ static int CmdHF14ADesSetConfiguration(const char *Cmd) { "02h ATS update.\n" "03h SAK update\n" "04h Secure Messaging Configuration.\n" - "05h Capability data. (here change for LRP in the Desfire Light)\n" - "06h DF Name renaming\n" - "08h File renaming\n" - "09h Value file configuration\n" + "05h Capability data. (here change for LRP in the Desfire Light [00000000010000000000])\n" + "06h DF Name renaming (one-time)\n" + "08h File renaming (one-time)\n" + "09h Value file configuration (one-time)\n" "0Ah Failed authentication counter setting\n" "0Bh HW configuration\n" "\n" "hf mfdes setconfig --param 03 --data 0428 -> set SAK\n" - "hf mfdes setconfig --param 02 --data 0875778102637264 -> set ATS (first byte - length)"); + "hf mfdes setconfig --param 02 --data 0875778102637264 -> set ATS (first byte - length)\n" + "hf mfdes setconfig --appisoid 01df -t aes -s ev2 --param 05 --data 00000000020000000000 -> set LRP mode enable for Desfire Light"); void *argtable[] = { arg_param_begin, @@ -2049,6 +2050,7 @@ static int CmdHF14ADesSetConfiguration(const char *Cmd) { arg_str0("c", "ccset", "", "Communicaton command set: native/niso/iso"), arg_str0("s", "schann", "", "Secure channel: d40/ev1/ev2/lrp"), arg_str0(NULL, "aid", "", "Application ID of application for some parameters (3 hex bytes, big endian)"), + arg_str0(NULL, "appisoid", "", "Application ISO ID (ISO DF ID) (2 hex bytes, big endian). Works only for ISO read commands."), arg_str0("p", "param", "", "Parameter id (HEX 1 byte)"), arg_str0("d", "data", "", "Data for parameter (HEX 1..30 bytes)"), arg_param_end @@ -2060,22 +2062,23 @@ static int CmdHF14ADesSetConfiguration(const char *Cmd) { DesfireContext dctx; int securechann = defaultSecureChannel; - uint32_t appid = 0x000000; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, &securechann, DCMEncrypted, &appid, NULL); + uint32_t id = 0x000000; + DesfireISOSelectWay selectway = ISW6bAID; + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, &securechann, DCMEncrypted, &id, &selectway); if (res) { CLIParserFree(ctx); return res; } uint32_t paramid = 0; - if (CLIGetUint32Hex(ctx, 12, 0, ¶mid, NULL, 1, "Parameter ID must have 1 bytes length")) { + if (CLIGetUint32Hex(ctx, 13, 0, ¶mid, NULL, 1, "Parameter ID must have 1 bytes length")) { CLIParserFree(ctx); return PM3_EINVARG; } uint8_t param[250] = {0}; int paramlen = sizeof(param); - CLIGetHexWithReturn(ctx, 13, param, ¶mlen); + CLIGetHexWithReturn(ctx, 14, param, ¶mlen); if (paramlen == 0) { PrintAndLogEx(ERR, "Parameter must have a data."); CLIParserFree(ctx); @@ -2091,13 +2094,13 @@ static int CmdHF14ADesSetConfiguration(const char *Cmd) { CLIParserFree(ctx); if (verbose) { - if (appid == 0x000000) + if (DesfireMFSelected(selectway, id)) PrintAndLogEx(INFO, _CYAN_("PICC") " param ID: 0x%02x param[%d]: %s", paramid, paramlen, sprint_hex(param, paramlen)); else - PrintAndLogEx(INFO, _CYAN_("Application %06x") " param ID: 0x%02x param[%d]: %s", appid, paramid, paramlen, sprint_hex(param, paramlen)); + PrintAndLogEx(INFO, _CYAN_("%s %06x") " param ID: 0x%02x param[%d]: %s", DesfireSelectWayToStr(selectway), id, paramid, paramlen, sprint_hex(param, paramlen)); } - res = DesfireSelectAndAuthenticate(&dctx, securechann, appid, verbose); + res = DesfireSelectAndAuthenticateW(&dctx, securechann, selectway, id, false, 0, false, verbose); if (res != PM3_SUCCESS) { DropField(); return res; diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index fbdde02e5..721900072 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -1373,6 +1373,134 @@ static int DesfireAuthenticateISO(DesfireContext *dctx, DesfireSecureChannel sec return PM3_SUCCESS; } +static int DesfireAuthenticateLRP(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 rotRndA[CRYPTO_AES_BLOCK_SIZE] = {0}; //RndA' + 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; + uint8_t *key = dctx->key; + + size_t recv_len = 0; + uint8_t respcode = 0; + uint8_t recv_data[256] = {0}; + + if (verbose) + 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[] = {dctx->keyNum, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02}; + int res = DesfireExchangeEx(false, dctx, subcommand, cdata, (firstauth) ? sizeof(cdata) : 1, &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 (aes_decode(IV, 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)); + } + + // - Rotate RndB by 8 bits + memcpy(rotRndB, RndB, CRYPTO_AES_BLOCK_SIZE); + rol(rotRndB, CRYPTO_AES_BLOCK_SIZE); + + // - 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)); + } + + 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)); + } + + 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 + uint8_t data[32] = {0}; + + if (aes_decode(IV, key, recv_data, data, recv_len)) + return 10; + + // rotate rndA to check + memcpy(rotRndA, RndA, CRYPTO_AES_BLOCK_SIZE); + rol(rotRndA, CRYPTO_AES_BLOCK_SIZE); + + uint8_t *recRndA = (firstauth) ? &data[4] : data; + + if (memcmp(rotRndA, recRndA, CRYPTO_AES_BLOCK_SIZE) != 0) { + if (g_debugMode > 1) { + PrintAndLogEx(DEBUG, "Expected_RndA' : %s", sprint_hex(rotRndA, CRYPTO_AES_BLOCK_SIZE)); + PrintAndLogEx(DEBUG, "Generated_RndA' : %s", sprint_hex(recRndA, CRYPTO_AES_BLOCK_SIZE)); + } + return 11; + } + + if (firstauth) { + dctx->cmdCntr = 0; + memcpy(dctx->TI, data, 4); + } + 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)); + } + + return PM3_SUCCESS; +} + + int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel, bool verbose) { if (dctx->kdfAlgo == MFDES_KDF_ALGO_AN10922) { MifareKdfAn10922(dctx, DCOMasterKey, dctx->kdfInput, dctx->kdfInputLen); @@ -1399,6 +1527,9 @@ int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel if (secureChannel == DACEV2) return DesfireAuthenticateEV2(dctx, secureChannel, (DesfireIsAuthenticated(dctx) == false), verbose); // non first auth if there is a working secure channel + if (secureChannel == DACLRP) + return DesfireAuthenticateLRP(dctx, secureChannel, (DesfireIsAuthenticated(dctx) == false), verbose); + return 100; }