set config works auth lrp checks

This commit is contained in:
merlokk 2021-08-17 23:31:42 +03:00
commit e28b6cfe83
2 changed files with 149 additions and 15 deletions

View file

@ -1960,8 +1960,8 @@ static int CmdHF14ADesAuth(const char *Cmd) {
arg_str0("c", "ccset", "<native/niso/iso>", "Communicaton command set: native/niso/iso"), arg_str0("c", "ccset", "<native/niso/iso>", "Communicaton command set: native/niso/iso"),
arg_str0("s", "schann", "<d40/ev1/ev2/lrp>", "Secure channel: d40/ev1/ev2/lrp"), arg_str0("s", "schann", "<d40/ev1/ev2/lrp>", "Secure channel: d40/ev1/ev2/lrp"),
arg_str0(NULL, "aid", "<app id hex>", "Application ID of application for some parameters (3 hex bytes, big endian)"), arg_str0(NULL, "aid", "<app id hex>", "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", "<isoid hex>", "Application ISO ID (ISO DF ID) (2 hex bytes, big endian). Works only for ISO read commands."), arg_str0(NULL, "appisoid", "<isoid hex>", "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 arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, false); CLIExecWithReturn(ctx, Cmd, argtable, false);
@ -1973,13 +1973,13 @@ static int CmdHF14ADesAuth(const char *Cmd) {
int securechann = defaultSecureChannel; int securechann = defaultSecureChannel;
uint32_t id = 0x000000; uint32_t id = 0x000000;
DesfireISOSelectWay selectway = ISW6bAID; 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) { if (res) {
CLIParserFree(ctx); CLIParserFree(ctx);
return res; return res;
} }
bool save = arg_get_lit(ctx, 12); bool save = arg_get_lit(ctx, 13);
SetAPDULogging(APDULogging); SetAPDULogging(APDULogging);
CLIParserFree(ctx); CLIParserFree(ctx);
@ -2026,15 +2026,16 @@ static int CmdHF14ADesSetConfiguration(const char *Cmd) {
"02h ATS update.\n" "02h ATS update.\n"
"03h SAK update\n" "03h SAK update\n"
"04h Secure Messaging Configuration.\n" "04h Secure Messaging Configuration.\n"
"05h Capability data. (here change for LRP in the Desfire Light)\n" "05h Capability data. (here change for LRP in the Desfire Light [00000000010000000000])\n"
"06h DF Name renaming\n" "06h DF Name renaming (one-time)\n"
"08h File renaming\n" "08h File renaming (one-time)\n"
"09h Value file configuration\n" "09h Value file configuration (one-time)\n"
"0Ah Failed authentication counter setting\n" "0Ah Failed authentication counter setting\n"
"0Bh HW configuration\n" "0Bh HW configuration\n"
"\n" "\n"
"hf mfdes setconfig --param 03 --data 0428 -> set SAK\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[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
@ -2049,6 +2050,7 @@ static int CmdHF14ADesSetConfiguration(const char *Cmd) {
arg_str0("c", "ccset", "<native/niso/iso>", "Communicaton command set: native/niso/iso"), arg_str0("c", "ccset", "<native/niso/iso>", "Communicaton command set: native/niso/iso"),
arg_str0("s", "schann", "<d40/ev1/ev2/lrp>", "Secure channel: d40/ev1/ev2/lrp"), arg_str0("s", "schann", "<d40/ev1/ev2/lrp>", "Secure channel: d40/ev1/ev2/lrp"),
arg_str0(NULL, "aid", "<app id hex>", "Application ID of application for some parameters (3 hex bytes, big endian)"), arg_str0(NULL, "aid", "<app id hex>", "Application ID of application for some parameters (3 hex bytes, big endian)"),
arg_str0(NULL, "appisoid", "<isoid hex>", "Application ISO ID (ISO DF ID) (2 hex bytes, big endian). Works only for ISO read commands."),
arg_str0("p", "param", "<HEX 1 byte>", "Parameter id (HEX 1 byte)"), arg_str0("p", "param", "<HEX 1 byte>", "Parameter id (HEX 1 byte)"),
arg_str0("d", "data", "<data HEX>", "Data for parameter (HEX 1..30 bytes)"), arg_str0("d", "data", "<data HEX>", "Data for parameter (HEX 1..30 bytes)"),
arg_param_end arg_param_end
@ -2060,22 +2062,23 @@ static int CmdHF14ADesSetConfiguration(const char *Cmd) {
DesfireContext dctx; DesfireContext dctx;
int securechann = defaultSecureChannel; int securechann = defaultSecureChannel;
uint32_t appid = 0x000000; uint32_t id = 0x000000;
int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, &securechann, DCMEncrypted, &appid, NULL); DesfireISOSelectWay selectway = ISW6bAID;
int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, &securechann, DCMEncrypted, &id, &selectway);
if (res) { if (res) {
CLIParserFree(ctx); CLIParserFree(ctx);
return res; return res;
} }
uint32_t paramid = 0; uint32_t paramid = 0;
if (CLIGetUint32Hex(ctx, 12, 0, &paramid, NULL, 1, "Parameter ID must have 1 bytes length")) { if (CLIGetUint32Hex(ctx, 13, 0, &paramid, NULL, 1, "Parameter ID must have 1 bytes length")) {
CLIParserFree(ctx); CLIParserFree(ctx);
return PM3_EINVARG; return PM3_EINVARG;
} }
uint8_t param[250] = {0}; uint8_t param[250] = {0};
int paramlen = sizeof(param); int paramlen = sizeof(param);
CLIGetHexWithReturn(ctx, 13, param, &paramlen); CLIGetHexWithReturn(ctx, 14, param, &paramlen);
if (paramlen == 0) { if (paramlen == 0) {
PrintAndLogEx(ERR, "Parameter must have a data."); PrintAndLogEx(ERR, "Parameter must have a data.");
CLIParserFree(ctx); CLIParserFree(ctx);
@ -2091,13 +2094,13 @@ static int CmdHF14ADesSetConfiguration(const char *Cmd) {
CLIParserFree(ctx); CLIParserFree(ctx);
if (verbose) { 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)); PrintAndLogEx(INFO, _CYAN_("PICC") " param ID: 0x%02x param[%d]: %s", paramid, paramlen, sprint_hex(param, paramlen));
else 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) { if (res != PM3_SUCCESS) {
DropField(); DropField();
return res; return res;

View file

@ -1373,6 +1373,134 @@ static int DesfireAuthenticateISO(DesfireContext *dctx, DesfireSecureChannel sec
return PM3_SUCCESS; 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) { int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel, bool verbose) {
if (dctx->kdfAlgo == MFDES_KDF_ALGO_AN10922) { if (dctx->kdfAlgo == MFDES_KDF_ALGO_AN10922) {
MifareKdfAn10922(dctx, DCOMasterKey, dctx->kdfInput, dctx->kdfInputLen); MifareKdfAn10922(dctx, DCOMasterKey, dctx->kdfInput, dctx->kdfInputLen);
@ -1399,6 +1527,9 @@ int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel
if (secureChannel == DACEV2) if (secureChannel == DACEV2)
return DesfireAuthenticateEV2(dctx, secureChannel, (DesfireIsAuthenticated(dctx) == false), verbose); // non first auth if there is a working secure channel 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; return 100;
} }