detect command and detect type of the key

This commit is contained in:
merlokk 2021-08-11 15:48:46 +03:00
parent c590befca9
commit b5f323672f

View file

@ -367,6 +367,164 @@ static void swap24(uint8_t *data) {
data[2] = tmp;
};
// default parameters
static uint8_t defaultKeyNum = 0;
static enum DESFIRE_CRYPTOALGO defaultAlgoId = T_DES;
static uint8_t defaultKey[DESFIRE_MAX_KEY_SIZE] = {0};
static int defaultKdfAlgo = MFDES_KDF_ALGO_NONE;
static int defaultKdfInputLen = 0;
static uint8_t defaultKdfInput[50] = {0};
static DesfireSecureChannel defaultSecureChannel = DACEV1;
static DesfireCommandSet defaultCommSet = DCCNativeISO;
static DesfireCommunicationMode defaultCommMode = DCMPlain;
static int CmdDesGetSessionParameters(CLIParserContext *ctx, DesfireContext *dctx,
uint8_t keynoid, uint8_t algoid, uint8_t keyid,
uint8_t kdfid, uint8_t kdfiid,
uint8_t cmodeid, uint8_t ccsetid, uint8_t schannid,
uint8_t appid,
int *securechannel,
DesfireCommunicationMode defcommmode,
uint32_t *aid) {
uint8_t keynum = defaultKeyNum;
int algores = defaultAlgoId;
uint8_t key[DESFIRE_MAX_KEY_SIZE] = {0};
memcpy(key, defaultKey, DESFIRE_MAX_KEY_SIZE);
int kdfAlgo = defaultKdfAlgo;
int kdfInputLen = defaultKdfInputLen;
uint8_t kdfInput[50] = {0};
memcpy(kdfInput, defaultKdfInput, defaultKdfInputLen);
int commmode = defaultCommMode;
if (defcommmode != DCMNone)
commmode = defcommmode;
int commset = defaultCommSet;
int secchann = defaultSecureChannel;
if (keynoid) {
keynum = arg_get_int_def(ctx, keynoid, keynum);
}
if (algoid) {
if (CLIGetOptionList(arg_get_str(ctx, algoid), DesfireAlgoOpts, &algores))
return PM3_ESOFT;
}
if (keyid) {
int keylen = 0;
uint8_t keydata[200] = {0};
if (CLIParamHexToBuf(arg_get_str(ctx, keyid), keydata, sizeof(keydata), &keylen))
return PM3_ESOFT;
if (keylen && keylen != desfire_get_key_length(algores)) {
PrintAndLogEx(ERR, "%s key must have %d bytes length instead of %d.", CLIGetOptionListStr(DesfireAlgoOpts, algores), desfire_get_key_length(algores), keylen);
return PM3_EINVARG;
}
if (keylen)
memcpy(key, keydata, keylen);
}
if (kdfid) {
if (CLIGetOptionList(arg_get_str(ctx, kdfid), DesfireKDFAlgoOpts, &kdfAlgo))
return PM3_ESOFT;
}
if (kdfiid) {
int datalen = kdfInputLen;
uint8_t data[200] = {0};
if (CLIParamHexToBuf(arg_get_str(ctx, kdfiid), data, sizeof(data), &datalen))
return PM3_ESOFT;
if (datalen) {
kdfInputLen = datalen;
memcpy(kdfInput, data, datalen);
}
}
if (cmodeid) {
if (CLIGetOptionList(arg_get_str(ctx, cmodeid), DesfireCommunicationModeOpts, &commmode))
return PM3_ESOFT;
}
if (ccsetid) {
if (CLIGetOptionList(arg_get_str(ctx, ccsetid), DesfireCommandSetOpts, &commset))
return PM3_ESOFT;
}
if (schannid) {
if (CLIGetOptionList(arg_get_str(ctx, schannid), DesfireSecureChannelOpts, &secchann))
return PM3_ESOFT;
}
if (appid && aid) {
*aid = 0x000000;
if (CLIGetUint32Hex(ctx, appid, 0x000000, aid, NULL, 3, "AID must have 3 bytes length"))
return PM3_EINVARG;
}
DesfireSetKey(dctx, keynum, algores, key);
DesfireSetKdf(dctx, kdfAlgo, kdfInput, kdfInputLen);
DesfireSetCommandSet(dctx, commset);
DesfireSetCommMode(dctx, commmode);
if (securechannel)
*securechannel = secchann;
return PM3_SUCCESS;
}
static int CmdHF14ADesDefault(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfdes default",
"Set default parameters for access to desfire card.",
"hf mfdes default -n 0 -t des -k 0000000000000000 -f none -> save to the default parameters");
void *argtable[] = {
arg_param_begin,
arg_int0("n", "keyno", "<keyno>", "Key number"),
arg_str0("t", "algo", "<DES/2TDEA/3TDEA/AES>", "Crypt algo: DES, 2TDEA, 3TDEA, AES"),
arg_str0("k", "key", "<Key>", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"),
arg_str0("f", "kdf", "<none/AN10922/gallagher>", "Key Derivation Function (KDF): None, AN10922, Gallagher"),
arg_str0("i", "kdfi", "<kdfi>", "KDF input (HEX 1-31 bytes)"),
arg_str0("m", "cmode", "<plain/mac/encrypt>", "Communicaton mode: plain/mac/encrypt"),
arg_str0("c", "ccset", "<native/niso/iso>", "Communicaton command set: native/niso/iso"),
arg_str0("s", "schann", "<d40/ev1/ev2>", "Secure channel: d40/ev1/ev2"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
DesfireContext dctx;
int securechann = defaultSecureChannel;
int res = CmdDesGetSessionParameters(ctx, &dctx, 1, 2, 3, 4, 5, 6, 7, 8, 0, &securechann, DCMNone, NULL);
if (res) {
CLIParserFree(ctx);
return res;
}
CLIParserFree(ctx);
defaultKeyNum = dctx.keyNum;
defaultAlgoId = dctx.keyType;
memcpy(defaultKey, dctx.key, DESFIRE_MAX_KEY_SIZE);
defaultKdfAlgo = dctx.kdfAlgo;
defaultKdfInputLen = dctx.kdfInputLen;
memcpy(defaultKdfInput, dctx.kdfInput, sizeof(dctx.kdfInput));
defaultSecureChannel = securechann;
defaultCommSet = dctx.cmdSet;
defaultCommMode = dctx.commMode;
PrintAndLogEx(INFO, "-----------" _CYAN_("Default parameters") "---------------------------------");
PrintAndLogEx(INFO, "Key Num : %d", defaultKeyNum);
PrintAndLogEx(INFO, "Algo : %s", CLIGetOptionListStr(DesfireAlgoOpts, defaultAlgoId));
PrintAndLogEx(INFO, "Key : %s", sprint_hex(defaultKey, desfire_get_key_length(defaultAlgoId)));
PrintAndLogEx(INFO, "KDF algo : %s", CLIGetOptionListStr(DesfireKDFAlgoOpts, defaultKdfAlgo));
PrintAndLogEx(INFO, "KDF input : [%d] %s", defaultKdfInputLen, sprint_hex(defaultKdfInput, defaultKdfInputLen));
PrintAndLogEx(INFO, "Secure chan : %s", CLIGetOptionListStr(DesfireSecureChannelOpts, defaultSecureChannel));
PrintAndLogEx(INFO, "Command set : %s", CLIGetOptionListStr(DesfireCommandSetOpts, defaultCommSet));
PrintAndLogEx(INFO, "Comm mode : %s", CLIGetOptionListStr(DesfireCommunicationModeOpts, defaultCommMode));
return PM3_SUCCESS;
}
static int CmdHF14ADesInfo(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfdes info",
@ -1112,6 +1270,184 @@ static int CmdHF14ADesList(const char *Cmd) {
return CmdTraceListAlias(Cmd, "hf mfdes", "des");
}
static int CmdHF14aDesDetect(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfdes detect",
"Detect key type and tries to find one from the list.",
"hf mfdes detect -> detect key 0 from PICC level\n"
"hf mfdes detect -s d40 -> detect key 0 from PICC level via secure channel D40\n"
"hf mfdes detect --dict mfdes_default_keys -> detect key 0 from PICC level with help of the standard dictionary\n"
"hf mfdes detect --aid 123456 -n 2 --save -> detect key 2 from app 123456 and if succeed - save params to defaults (`default` command)");
void *argtable[] = {
arg_param_begin,
arg_lit0("a", "apdu", "show APDU requests and responses"),
arg_lit0("v", "verbose", "show technical data"),
arg_int0("n", "keyno", "<keyno>", "Key number"),
arg_str0("t", "algo", "<DES/2TDEA/3TDEA/AES>", "Crypt algo: DES, 2TDEA, 3TDEA, AES"),
arg_str0("k", "key", "<Key>", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"),
arg_str0("f", "kdf", "<none/AN10922/gallagher>", "Key Derivation Function (KDF): None, AN10922, Gallagher"),
arg_str0("i", "kdfi", "<kdfi>", "KDF input (HEX 1-31 bytes)"),
arg_str0("m", "cmode", "<plain/mac/encrypt>", "Communicaton mode: plain/mac/encrypt"),
arg_str0("c", "ccset", "<native/niso/iso>", "Communicaton command set: native/niso/iso"),
arg_str0("s", "schann", "<d40/ev1/ev2>", "Secure channel: d40/ev1/ev2"),
arg_str0(NULL, "aid", "<app id hex>", "Application ID (3 hex bytes, big endian)"),
arg_str0(NULL, "dict", "<file>", "File with keys dictionary"),
arg_lit0(NULL, "save", "save found key and parameters to defaults"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
bool APDULogging = arg_get_lit(ctx, 1);
bool verbose = arg_get_lit(ctx, 2);
DesfireContext dctx;
int securechann = defaultSecureChannel;
uint32_t appid = 0x000000;
int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, &securechann, DCMMACed, &appid);
if (res) {
CLIParserFree(ctx);
return res;
}
uint32_t fnum = 1;
if (CLIGetUint32Hex(ctx, 12, 1, &fnum, NULL, 1, "File ID must have 1 byte length")) {
CLIParserFree(ctx);
return PM3_EINVARG;
}
bool save = arg_get_lit(ctx, 13);
SetAPDULogging(APDULogging);
CLIParserFree(ctx);
// no auth and fill KDF if needs
res = DesfireSelectAndAuthenticateEx(&dctx, securechann, appid, true, verbose);
if (res != PM3_SUCCESS) {
DropField();
PrintAndLogEx(FAILED, "Select AID 0x%06x " _RED_("failed") ". Result: %d", appid, res);
return res;
}
bool keytypes[4] = {0};
/*T_DES = 0x00,
T_3DES = 0x01, //aka 2K3DES
T_3K3DES = 0x02,
T_AES = 0x03 */
uint8_t data[250] = {0};
size_t datalen = 0;
res = DesfireGetKeySettings(&dctx, data, &datalen);
if (res == PM3_SUCCESS && datalen >= 2) {
uint8_t num_keys = data[1];
switch (num_keys >> 6) {
case 0:
keytypes[T_DES] = true;
keytypes[T_3DES] = true;
break;
case 1:
keytypes[T_3K3DES] = true;
break;
case 2:
keytypes[T_AES] = true;
break;
default:
break;
}
} else {
// if fail - check auth commands
AuthCommandsChk authCmdCheck = {0};
DesfireCheckAuthCommands(appid, NULL, 0, &authCmdCheck);
if (authCmdCheck.checked) {
if (authCmdCheck.auth) {
keytypes[T_DES] = true;
keytypes[T_3DES] = true;
if (authCmdCheck.authISO) {
keytypes[T_3K3DES] = true;
}
}
if (authCmdCheck.authAES || authCmdCheck.authEV2) {
keytypes[T_AES] = true;
}
} else {
// if nothing helps - we check DES only
keytypes[T_DES] = true;
}
res = DesfireSelectAIDHex(&dctx, appid, false, 0);
if (res != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Desfire select " _RED_("error") ".");
return res;
}
}
if (verbose) {
PrintAndLogEx(INFO, "Check keys: DES: %s 2TDEA: %s 3TDEA: %s AES: %s",
keytypes[T_DES] ? _GREEN_("YES") : _RED_("NO"),
keytypes[T_3DES] ? _GREEN_("YES") : _RED_("NO"),
keytypes[T_3K3DES] ? _GREEN_("YES") : _RED_("NO"),
keytypes[T_AES] ? _GREEN_("YES") : _RED_("NO")
);
}
// for key types
for (uint8_t ktype = T_DES; ktype <= T_AES; ktype++) {
}
/*
// load keys from file
size_t endFilePosition = 0;
if (dict_filenamelen) {
res = loadFileDICTIONARYEx((char *)dict_filename, deskeyList, sizeof(deskeyList), NULL, 8, &deskeyListLen, 0, &endFilePosition, true);
if (res == PM3_SUCCESS && endFilePosition)
PrintAndLogEx(SUCCESS, "First part of des dictionary successfully loaded.");
// checks
if (usedkeys[keyno] == 1 && foundKeys[0][keyno][0] == 0) {
for (uint32_t curkey = 0; curkey < deskeyListLen; curkey++) {
DesfireSetKeyNoClear(dctx, keyno, T_DES, deskeyList[curkey]);
res = DesfireAuthenticate(dctx, secureChannel, false);
if (res == PM3_SUCCESS) {
PrintAndLogEx(SUCCESS, "AID 0x%06X, Found DES Key %02u : " _GREEN_("%s"), curaid, keyno, sprint_hex(deskeyList[curkey], 8));
foundKeys[0][keyno][0] = 0x01;
*result = true;
memcpy(&foundKeys[0][keyno][1], deskeyList[curkey], 8);
break;
} else if (res < 7) {
badlen = true;
DropField();
res = DesfireSelectAIDHex(dctx, curaid, false, 0);
if (res != PM3_SUCCESS) {
return res;
}
break;
}
}
if (badlen == true) {
badlen = false;
break;
}
}
}
// load keys from file
uint32_t keycnt = 0;
res = loadFileDICTIONARYEx((char *)dict_filename, deskeyList, sizeof(deskeyList), NULL, 16, &keycnt, endFilePosition, &endFilePosition, false);
if (res == PM3_SUCCESS && endFilePosition)
deskeyListLen = keycnt;
*/
DropField();
if (save) {
}
return PM3_SUCCESS;
}
/*
static int CmdHF14aDesNDEFRead(const char *Cmd) {
DropFieldDesfire();
@ -1241,163 +1577,6 @@ static int CmdHF14aDesMAD(const char *Cmd) {
}
*/
static uint8_t defaultKeyNum = 0;
static enum DESFIRE_CRYPTOALGO defaultAlgoId = T_DES;
static uint8_t defaultKey[DESFIRE_MAX_KEY_SIZE] = {0};
static int defaultKdfAlgo = MFDES_KDF_ALGO_NONE;
static int defaultKdfInputLen = 0;
static uint8_t defaultKdfInput[50] = {0};
static DesfireSecureChannel defaultSecureChannel = DACEV1;
static DesfireCommandSet defaultCommSet = DCCNativeISO;
static DesfireCommunicationMode defaultCommMode = DCMPlain;
static int CmdDesGetSessionParameters(CLIParserContext *ctx, DesfireContext *dctx,
uint8_t keynoid, uint8_t algoid, uint8_t keyid,
uint8_t kdfid, uint8_t kdfiid,
uint8_t cmodeid, uint8_t ccsetid, uint8_t schannid,
uint8_t appid,
int *securechannel,
DesfireCommunicationMode defcommmode,
uint32_t *aid) {
uint8_t keynum = defaultKeyNum;
int algores = defaultAlgoId;
uint8_t key[DESFIRE_MAX_KEY_SIZE] = {0};
memcpy(key, defaultKey, DESFIRE_MAX_KEY_SIZE);
int kdfAlgo = defaultKdfAlgo;
int kdfInputLen = defaultKdfInputLen;
uint8_t kdfInput[50] = {0};
memcpy(kdfInput, defaultKdfInput, defaultKdfInputLen);
int commmode = defaultCommMode;
if (defcommmode != DCMNone)
commmode = defcommmode;
int commset = defaultCommSet;
int secchann = defaultSecureChannel;
if (keynoid) {
keynum = arg_get_int_def(ctx, keynoid, keynum);
}
if (algoid) {
if (CLIGetOptionList(arg_get_str(ctx, algoid), DesfireAlgoOpts, &algores))
return PM3_ESOFT;
}
if (keyid) {
int keylen = 0;
uint8_t keydata[200] = {0};
if (CLIParamHexToBuf(arg_get_str(ctx, keyid), keydata, sizeof(keydata), &keylen))
return PM3_ESOFT;
if (keylen && keylen != desfire_get_key_length(algores)) {
PrintAndLogEx(ERR, "%s key must have %d bytes length instead of %d.", CLIGetOptionListStr(DesfireAlgoOpts, algores), desfire_get_key_length(algores), keylen);
return PM3_EINVARG;
}
if (keylen)
memcpy(key, keydata, keylen);
}
if (kdfid) {
if (CLIGetOptionList(arg_get_str(ctx, kdfid), DesfireKDFAlgoOpts, &kdfAlgo))
return PM3_ESOFT;
}
if (kdfiid) {
int datalen = kdfInputLen;
uint8_t data[200] = {0};
if (CLIParamHexToBuf(arg_get_str(ctx, kdfiid), data, sizeof(data), &datalen))
return PM3_ESOFT;
if (datalen) {
kdfInputLen = datalen;
memcpy(kdfInput, data, datalen);
}
}
if (cmodeid) {
if (CLIGetOptionList(arg_get_str(ctx, cmodeid), DesfireCommunicationModeOpts, &commmode))
return PM3_ESOFT;
}
if (ccsetid) {
if (CLIGetOptionList(arg_get_str(ctx, ccsetid), DesfireCommandSetOpts, &commset))
return PM3_ESOFT;
}
if (schannid) {
if (CLIGetOptionList(arg_get_str(ctx, schannid), DesfireSecureChannelOpts, &secchann))
return PM3_ESOFT;
}
if (appid && aid) {
*aid = 0x000000;
if (CLIGetUint32Hex(ctx, appid, 0x000000, aid, NULL, 3, "AID must have 3 bytes length"))
return PM3_EINVARG;
}
DesfireSetKey(dctx, keynum, algores, key);
DesfireSetKdf(dctx, kdfAlgo, kdfInput, kdfInputLen);
DesfireSetCommandSet(dctx, commset);
DesfireSetCommMode(dctx, commmode);
if (securechannel)
*securechannel = secchann;
return PM3_SUCCESS;
}
static int CmdHF14ADesDefault(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfdes default",
"Set default parameters for access to desfire card.",
"hf mfdes default -n 0 -t des -k 0000000000000000 -f none -> save to the default parameters");
void *argtable[] = {
arg_param_begin,
arg_int0("n", "keyno", "<keyno>", "Key number"),
arg_str0("t", "algo", "<DES/2TDEA/3TDEA/AES>", "Crypt algo: DES, 2TDEA, 3TDEA, AES"),
arg_str0("k", "key", "<Key>", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"),
arg_str0("f", "kdf", "<none/AN10922/gallagher>", "Key Derivation Function (KDF): None, AN10922, Gallagher"),
arg_str0("i", "kdfi", "<kdfi>", "KDF input (HEX 1-31 bytes)"),
arg_str0("m", "cmode", "<plain/mac/encrypt>", "Communicaton mode: plain/mac/encrypt"),
arg_str0("c", "ccset", "<native/niso/iso>", "Communicaton command set: native/niso/iso"),
arg_str0("s", "schann", "<d40/ev1/ev2>", "Secure channel: d40/ev1/ev2"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
DesfireContext dctx;
int securechann = defaultSecureChannel;
int res = CmdDesGetSessionParameters(ctx, &dctx, 1, 2, 3, 4, 5, 6, 7, 8, 0, &securechann, DCMNone, NULL);
if (res) {
CLIParserFree(ctx);
return res;
}
CLIParserFree(ctx);
defaultKeyNum = dctx.keyNum;
defaultAlgoId = dctx.keyType;
memcpy(defaultKey, dctx.key, DESFIRE_MAX_KEY_SIZE);
defaultKdfAlgo = dctx.kdfAlgo;
defaultKdfInputLen = dctx.kdfInputLen;
memcpy(defaultKdfInput, dctx.kdfInput, sizeof(dctx.kdfInput));
defaultSecureChannel = securechann;
defaultCommSet = dctx.cmdSet;
defaultCommMode = dctx.commMode;
PrintAndLogEx(INFO, "-----------" _CYAN_("Default parameters") "---------------------------------");
PrintAndLogEx(INFO, "Key Num : %d", defaultKeyNum);
PrintAndLogEx(INFO, "Algo : %s", CLIGetOptionListStr(DesfireAlgoOpts, defaultAlgoId));
PrintAndLogEx(INFO, "Key : %s", sprint_hex(defaultKey, desfire_get_key_length(defaultAlgoId)));
PrintAndLogEx(INFO, "KDF algo : %s", CLIGetOptionListStr(DesfireKDFAlgoOpts, defaultKdfAlgo));
PrintAndLogEx(INFO, "KDF input : [%d] %s", defaultKdfInputLen, sprint_hex(defaultKdfInput, defaultKdfInputLen));
PrintAndLogEx(INFO, "Secure chan : %s", CLIGetOptionListStr(DesfireSecureChannelOpts, defaultSecureChannel));
PrintAndLogEx(INFO, "Command set : %s", CLIGetOptionListStr(DesfireCommandSetOpts, defaultCommSet));
PrintAndLogEx(INFO, "Comm mode : %s", CLIGetOptionListStr(DesfireCommunicationModeOpts, defaultCommMode));
return PM3_SUCCESS;
}
static int CmdHF14ADesSelectApp(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfdes selectapp",
@ -4951,6 +5130,7 @@ static command_t CommandTable[] = {
{"default", CmdHF14ADesDefault, IfPm3Iso14443a, "Set defaults for all the commands"},
{"auth", CmdHF14ADesAuth, IfPm3Iso14443a, "MIFARE DesFire Authentication"},
{"chk", CmdHF14aDesChk, IfPm3Iso14443a, "Check keys"},
{"detect", CmdHF14aDesDetect, IfPm3Iso14443a, "Detect key type and tries to find one from the list"},
{"freemem", CmdHF14ADesGetFreeMem, IfPm3Iso14443a, "Get free memory size"},
{"setconfig", CmdHF14ADesSetConfiguration, IfPm3Iso14443a, "Set card configuration"},
{"formatpicc", CmdHF14ADesFormatPICC, IfPm3Iso14443a, "Format PICC"},