Merge pull request #1364 from merlokk/desfire5

Desfire GetKeySettings and ChangeKeySettings
This commit is contained in:
Oleg Moiseenko 2021-07-11 19:45:00 +03:00 committed by GitHub
commit 1d883db517
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 473 additions and 59 deletions

View file

@ -31,6 +31,7 @@
#include "mifare/desfire_crypto.h"
#include "mifare/desfirecore.h"
#include "mifare/desfiretest.h"
#include "mifare/desfiresecurechan.h"
#include "mifare/mifaredefault.h" // default keys
#include "crapto1/crapto1.h"
#include "fileutils.h"
@ -5013,7 +5014,10 @@ static int CmdDesGetSessionParameters(CLIParserContext *ctx, DesfireContext *dct
uint8_t keynoid, uint8_t algoid, uint8_t keyid,
uint8_t kdfid, uint8_t kdfiid,
uint8_t cmodeid, uint8_t ccsetid, uint8_t schannid,
int *securechannel) {
uint8_t appid,
int *securechannel,
DesfireCommunicationMode defcommmode,
uint32_t *aid) {
uint8_t keynum = defaultKeyNum;
int algores = defaultAlgoId;
@ -5024,6 +5028,8 @@ static int CmdDesGetSessionParameters(CLIParserContext *ctx, DesfireContext *dct
uint8_t kdfInput[50] = {0};
memcpy(kdfInput, defaultKdfInput, defaultKdfInputLen);
int commmode = defaultCommMode;
if (defcommmode != DCMNone)
commmode = defcommmode;
int commset = defaultCommSet;
int secchann = defaultSecureChannel;
@ -5076,10 +5082,22 @@ static int CmdDesGetSessionParameters(CLIParserContext *ctx, DesfireContext *dct
}
if (schannid) {
if (CLIGetOptionList(arg_get_str(ctx, schannid), DesfireSecureChannelOpts, &secchann))
return PM3_ESOFT;
}
if (appid && aid) {
*aid = 0x000000;
int res = arg_get_u32_hexstr_def_nlen(ctx, appid, 0x000000, aid, 3, true);
if (res == 0)
return PM3_ESOFT;
if (res == 2) {
PrintAndLogEx(ERR, "AID length must have 3 bytes length");
return PM3_EINVARG;
}
}
DesfireSetKey(dctx, keynum, algores, key);
DesfireSetKdf(dctx, kdfAlgo, kdfInput, kdfInputLen);
DesfireSetCommandSet(dctx, commset);
@ -5112,7 +5130,7 @@ static int CmdHF14ADesDefault(const char *Cmd) {
DesfireContext dctx;
int securechann = defaultSecureChannel;
int res = CmdDesGetSessionParameters(ctx, &dctx, 1, 2, 3, 4, 5, 6, 7, 8, &securechann);
int res = CmdDesGetSessionParameters(ctx, &dctx, 1, 2, 3, 4, 5, 6, 7, 8, 0, &securechann, DCMNone, NULL);
if (res) {
CLIParserFree(ctx);
return res;
@ -5144,6 +5162,192 @@ static int CmdHF14ADesDefault(const char *Cmd) {
return PM3_SUCCESS;
}
static int CmdHF14ADesChKeySettings(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfdes chkeysetings",
"Change key settings for card level or application level. WARNING: card level changes may block card!",
"hf mfdes chkeysetings -d 0e -> set picc key settings with default key/channel setup\n"\
"hf mfdes chkeysetings --aid 123456 -d 0e -> set app 123456 key settings with default key/channel setup");
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("d", "data", "<key settings HEX>", "Key settings (HEX 1 byte)"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
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, DCMEncrypted, &appid);
if (res) {
CLIParserFree(ctx);
return res;
}
uint32_t ksett32 = 0;
res = arg_get_u32_hexstr_def_nlen(ctx, 12, 0x000000, &ksett32, 1, false);
if (res == 0)
return PM3_ESOFT;
if (res == 2) {
PrintAndLogEx(ERR, "Key settings must have 1 byte length");
return PM3_EINVARG;
}
SetAPDULogging(APDULogging);
CLIParserFree(ctx);
if (verbose) {
DesfirePrintContext(&dctx);
PrintAndLogEx(SUCCESS, "\nNew key settings:");
PrintKeySettings(ksett32, 0, (appid != 0x000000), false);
}
res = DesfireSelectAIDHex(&dctx, appid, false, 0);
if (res != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Desfire select " _RED_("error") ".");
DropField();
return PM3_ESOFT;
}
res = DesfireAuthenticate(&dctx, securechann);
if (res != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Desfire authenticate " _RED_("error") ". Result: %d", res);
DropField();
return PM3_ESOFT;
}
if (DesfireIsAuthenticated(&dctx)) {
if (verbose)
PrintAndLogEx(INFO, "Desfire " _GREEN_("authenticated"));
} else {
return PM3_ESOFT;
}
uint8_t keysett = ksett32 & 0x0f;
res = DesfireChangeKeySettings(&dctx, &keysett, 1);
if (res != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Desfire DesfireChangeKeySettings command " _RED_("error") ". Result: %d", res);
DropField();
return PM3_ESOFT;
}
PrintAndLogEx(INFO, "Key settings " _GREEN_("changed"));
return PM3_SUCCESS;
}
static int CmdHF14ADesGetKeySettings(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfdes getkeysetings",
"Get key settings for card level or application level.",
"hf mfdes getkeysetings -> get picc key settings with default key/channel setup\n"\
"hf mfdes getkeysetings --aid 123456 -> get app 123456 key settings with default key/channel setup");
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_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
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;
}
SetAPDULogging(APDULogging);
CLIParserFree(ctx);
if (verbose)
DesfirePrintContext(&dctx);
res = DesfireSelectAIDHex(&dctx, appid, false, 0);
if (res != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Desfire select " _RED_("error") ".");
DropField();
return PM3_ESOFT;
}
res = DesfireAuthenticate(&dctx, securechann);
if (res != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Desfire authenticate " _RED_("error") ". Result: %d", res);
DropField();
return PM3_ESOFT;
}
if (DesfireIsAuthenticated(&dctx)) {
if (verbose)
PrintAndLogEx(INFO, "Desfire " _GREEN_("authenticated"));
} else {
return PM3_ESOFT;
}
uint8_t buf[APDU_RES_LEN] = {0};
size_t buflen = 0;
res = DesfireGetKeySettings(&dctx, buf, &buflen);
if (res != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Desfire DesfireGetKeySettings command " _RED_("error") ". Result: %d", res);
DropField();
return PM3_ESOFT;
}
if (verbose)
PrintAndLogEx(INFO, "DesfireGetKeySettings[%d]: %s", buflen, sprint_hex(buf, buflen));
if (buflen < 2) {
PrintAndLogEx(ERR, "Command DesfireGetKeySettings returned wrong length: %d", buflen);
DropField();
return PM3_ESOFT;
}
PrintAndLogEx(INFO, "----------------------- " _CYAN_("Key settings") " -----------------------");
PrintKeySettings(buf[0], buf[1], (appid != 0x000000), true);
if (buflen > 2)
PrintAndLogEx(INFO, "ak ver: %d", buf[2]);
if (buflen > 3)
PrintAndLogEx(INFO, "num keysets: %d", buf[3]);
if (buflen > 4)
PrintAndLogEx(INFO, "max keysize: %d", buf[4]);
if (buflen > 5)
PrintAndLogEx(INFO, "app key settings: 0x%02x", buf[5]);
DropField();
return PM3_SUCCESS;
}
static int CmdHF14ADesGetAIDs(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfdes getaids",
@ -5164,14 +5368,14 @@ static int CmdHF14ADesGetAIDs(const char *Cmd) {
arg_str0("s", "schann", "<d40/ev1/ev2>", "Secure channel: d40/ev1/ev2"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
CLIExecWithReturn(ctx, Cmd, argtable, true);
bool APDULogging = arg_get_lit(ctx, 1);
bool verbose = arg_get_lit(ctx, 2);
DesfireContext dctx;
int securechann = defaultSecureChannel;
int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, &securechann);
int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 0, &securechann, DCMMACed, NULL);
if (res) {
CLIParserFree(ctx);
return res;
@ -5190,7 +5394,7 @@ static int CmdHF14ADesGetAIDs(const char *Cmd) {
return PM3_ESOFT;
}
res = DesfireAuthenticate(&dctx, securechann); //DACd40 DACEV1
res = DesfireAuthenticate(&dctx, securechann);
if (res != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Desfire authenticate " _RED_("error") ". Result: %d", res);
DropField();
@ -5199,7 +5403,7 @@ static int CmdHF14ADesGetAIDs(const char *Cmd) {
if (DesfireIsAuthenticated(&dctx)) {
if (verbose)
PrintAndLogEx(ERR, "Desfire " _GREEN_("authenticated"));
PrintAndLogEx(INFO, "Desfire " _GREEN_("authenticated"));
} else {
return PM3_ESOFT;
}
@ -5246,14 +5450,14 @@ static int CmdHF14ADesGetAppNames(const char *Cmd) {
arg_str0("s", "schann", "<d40/ev1/ev2>", "Secure channel: d40/ev1/ev2"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
CLIExecWithReturn(ctx, Cmd, argtable, true);
bool APDULogging = arg_get_lit(ctx, 1);
bool verbose = arg_get_lit(ctx, 2);
DesfireContext dctx;
int securechann = defaultSecureChannel;
int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, &securechann);
int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 0, &securechann, DCMMACed, NULL);
if (res) {
CLIParserFree(ctx);
return res;
@ -5281,7 +5485,7 @@ static int CmdHF14ADesGetAppNames(const char *Cmd) {
if (DesfireIsAuthenticated(&dctx)) {
if (verbose)
PrintAndLogEx(ERR, "Desfire " _GREEN_("authenticated"));
PrintAndLogEx(INFO, "Desfire " _GREEN_("authenticated"));
} else {
return PM3_ESOFT;
}
@ -5323,7 +5527,6 @@ static command_t CommandTable[] = {
{"-----------", CmdHelp, IfPm3Iso14443a, "---------------------- " _CYAN_("general") " ----------------------"},
{"default", CmdHF14ADesDefault, IfPm3Iso14443a, "[new]Set defaults for all the commands"},
{"auth", CmdHF14ADesAuth, IfPm3Iso14443a, "Tries a MIFARE DesFire Authentication"},
{"changekey", CmdHF14ADesChangeKey, IfPm3Iso14443a, "Change Key"},
{"chk", CmdHF14aDesChk, IfPm3Iso14443a, "Check keys"},
{"enum", CmdHF14ADesEnumApplications, IfPm3Iso14443a, "Tries enumerate all applications"},
{"formatpicc", CmdHF14ADesFormatPICC, IfPm3Iso14443a, "Format PICC"},
@ -5332,6 +5535,10 @@ static command_t CommandTable[] = {
{"list", CmdHF14ADesList, AlwaysAvailable, "List DESFire (ISO 14443A) history"},
// {"ndefread", CmdHF14aDesNDEFRead, IfPm3Iso14443a, "Prints NDEF records from card"},
// {"mad", CmdHF14aDesMAD, IfPm3Iso14443a, "Prints MAD records from card"},
{"-----------", CmdHelp, IfPm3Iso14443a, "------------------------ " _CYAN_("Keys") " -----------------------"},
{"changekey", CmdHF14ADesChangeKey, IfPm3Iso14443a, "Change Key"},
{"chkeysetings", CmdHF14ADesChKeySettings, IfPm3Iso14443a, "[new]Change Key Settings"},
{"getkeysetings", CmdHF14ADesGetKeySettings, IfPm3Iso14443a, "[new]Get Key Settings"},
{"-----------", CmdHelp, IfPm3Iso14443a, "-------------------- " _CYAN_("Applications") " -------------------"},
{"bruteaid", CmdHF14ADesBruteApps, IfPm3Iso14443a, "Recover AIDs by bruteforce"},
{"createaid", CmdHF14ADesCreateApp, IfPm3Iso14443a, "Create Application ID"},

View file

@ -967,31 +967,3 @@ void mifare_cypher_blocks_chained(desfiretag_t tag, desfirekey_t key, uint8_t *i
offset += block_size;
}
}
void desfire_crc32(const uint8_t *data, const size_t len, uint8_t *crc) {
crc32_ex(data, len, crc);
}
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);
}
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);
}

View file

@ -147,10 +147,4 @@ void cmac(const desfirekey_t key, uint8_t *ivect, const uint8_t *data, size_t l
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

View file

@ -524,6 +524,9 @@ static void DesfireSplitBytesToBlock(uint8_t *blockdata, size_t *blockdatacount,
int DesfireExchangeEx(bool activate_field, DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen, bool enable_chaining, size_t splitbysize) {
int res = PM3_SUCCESS;
if (!PrintChannelModeWarning(cmd, ctx->secureChannel, ctx->cmdSet, ctx->commMode))
DesfirePrintContext(ctx);
uint8_t databuf[250 * 5] = {0};
size_t databuflen = 0;
@ -820,8 +823,8 @@ int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel
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, rndlen));
PrintAndLogEx(INFO, "IV : %s", sprint_hex(IV, rndlen));
//PrintAndLogEx(INFO, "encRndA : %s", sprint_hex(encRndA, rndlen));
//PrintAndLogEx(INFO, "IV : %s", sprint_hex(IV, rndlen));
if (dctx->keyType == T_DES) {
if (secureChannel == DACd40)
des_decrypt(encRndA, encRndA, key->data);
@ -839,8 +842,8 @@ int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel
}
rol(RndA, rndlen);
PrintAndLogEx(INFO, "Expected_RndA : %s", sprint_hex(RndA, rndlen));
PrintAndLogEx(INFO, "Generated_RndA : %s", sprint_hex(encRndA, rndlen));
//PrintAndLogEx(INFO, "Expected_RndA : %s", sprint_hex(RndA, rndlen));
//PrintAndLogEx(INFO, "Generated_RndA : %s", sprint_hex(encRndA, rndlen));
for (uint32_t x = 0; x < rndlen; x++) {
if (RndA[x] != encRndA[x]) {
if (g_debugMode > 1) {
@ -867,7 +870,7 @@ int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel
memset(dctx->IV, 0, DESFIRE_MAX_KEY_SIZE);
dctx->secureChannel = secureChannel;
memcpy(dctx->sessionKeyMAC, dctx->sessionKeyEnc, desfire_get_key_length(dctx->keyType));
PrintAndLogEx(INFO, "sessionKeyEnc : %s", sprint_hex(dctx->sessionKeyEnc, desfire_get_key_length(dctx->keyType)));
PrintAndLogEx(INFO, "Session key : %s", sprint_hex(dctx->sessionKeyEnc, desfire_get_key_length(dctx->keyType)));
return PM3_SUCCESS;
}
@ -906,7 +909,7 @@ int DesfireCreateApplication(DesfireContext *dctx, uint8_t *appdata, size_t appd
uint8_t respcode = 0xff;
uint8_t resp[257] = {0};
size_t resplen = 0;
int res = DesfireExchangeEx(false, dctx, MFDES_CREATE_APPLICATION, appdata, appdatalen, &respcode, resp, &resplen, true, 24);
int res = DesfireExchangeEx(false, dctx, MFDES_CREATE_APPLICATION, appdata, appdatalen, &respcode, resp, &resplen, true, 0);
if (res != PM3_SUCCESS)
return res;
if (respcode != MFDES_S_OPERATION_OK || resplen != 0)
@ -920,7 +923,7 @@ int DesfireDeleteApplication(DesfireContext *dctx, uint32_t aid) {
DesfireAIDUintToByte(aid, data);
uint8_t resp[257] = {0};
size_t resplen = 0;
int res = DesfireExchangeEx(false, dctx, MFDES_DELETE_APPLICATION, data, sizeof(data), &respcode, resp, &resplen, true, 24);
int res = DesfireExchangeEx(false, dctx, MFDES_DELETE_APPLICATION, data, sizeof(data), &respcode, resp, &resplen, true, 0);
if (res != PM3_SUCCESS)
return res;
if (respcode != MFDES_S_OPERATION_OK || resplen != 0)
@ -928,3 +931,105 @@ int DesfireDeleteApplication(DesfireContext *dctx, uint32_t aid) {
return PM3_SUCCESS;
}
int DesfireGetKeySettings(DesfireContext *dctx, uint8_t *resp, size_t *resplen) {
uint8_t respcode = 0xff;
int res = DesfireExchange(dctx, MFDES_GET_KEY_SETTINGS, 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 DesfireGetKeyVersion(DesfireContext *dctx, uint8_t *resp, size_t *resplen) {
uint8_t respcode = 0xff;
int res = DesfireExchange(dctx, MFDES_GET_KEY_VERSION, 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 DesfireChangeKeySettings(DesfireContext *dctx, uint8_t *data, size_t len) {
uint8_t respcode = 0xff;
uint8_t resp[257] = {0};
size_t resplen = 0;
int res = DesfireExchange(dctx, MFDES_CHANGE_KEY_SETTINGS, data, len, &respcode, resp, &resplen);
if (res != PM3_SUCCESS)
return res;
if (respcode != MFDES_S_OPERATION_OK || resplen != 0)
return PM3_EAPDU_FAIL;
return PM3_SUCCESS;
}
static void PrintKeyType(uint8_t keytype) {
switch (keytype) {
case 00:
PrintAndLogEx(SUCCESS, "Key: 2TDEA");
break;
case 01:
PrintAndLogEx(SUCCESS, "Key: 3TDEA");
break;
case 02:
PrintAndLogEx(SUCCESS, "Key: AES");
break;
default:
PrintAndLogEx(SUCCESS, "Key: unknown: 0x%02x", keytype);
break;
}
}
static void PrintKeySettingsPICC(uint8_t keysettings, uint8_t numkeys, bool print2ndbyte) {
PrintAndLogEx(SUCCESS, "PICC level rights:");
PrintAndLogEx(SUCCESS, "[%c...] CMK Configuration changeable : %s", (keysettings & (1 << 3)) ? '1' : '0', (keysettings & (1 << 3)) ? _GREEN_("YES") : "NO (frozen)");
PrintAndLogEx(SUCCESS, "[.%c..] CMK required for create/delete : %s", (keysettings & (1 << 2)) ? '1' : '0', (keysettings & (1 << 2)) ? _GREEN_("NO") : "YES");
PrintAndLogEx(SUCCESS, "[..%c.] Directory list access with CMK : %s", (keysettings & (1 << 1)) ? '1' : '0', (keysettings & (1 << 1)) ? _GREEN_("NO") : "YES");
PrintAndLogEx(SUCCESS, "[...%c] CMK is changeable : %s", (keysettings & (1 << 0)) ? '1' : '0', (keysettings & (1 << 0)) ? _GREEN_("YES") : "NO (frozen)");
PrintAndLogEx(SUCCESS, "");
if (print2ndbyte)
PrintAndLogEx(SUCCESS, "key count: %d", numkeys & 0x0f);
}
static void PrintKeySettingsApp(uint8_t keysettings, uint8_t numkeys, bool print2ndbyte) {
// Access rights.
PrintAndLogEx(SUCCESS, "Application level rights:");
uint8_t rights = ((keysettings >> 4) & 0x0F);
switch (rights) {
case 0x0:
PrintAndLogEx(SUCCESS, "-- AMK authentication is necessary to change any key (default)");
break;
case 0xE:
PrintAndLogEx(SUCCESS, "-- Authentication with the key to be changed (same KeyNo) is necessary to change a key");
break;
case 0xF:
PrintAndLogEx(SUCCESS, "-- All keys (except AMK,see Bit0) within this application are frozen");
break;
default:
PrintAndLogEx(SUCCESS,
"-- Authentication with the specified key is necessary to change any key.\n"
"A change key and a PICC master key (CMK) can only be changed after authentication with the master key.\n"
"For keys other then the master or change key, an authentication with the same key is needed."
);
break;
}
PrintAndLogEx(SUCCESS, "[%c...] AMK Configuration changeable : %s", (keysettings & (1 << 3)) ? '1' : '0', (keysettings & (1 << 3)) ? _GREEN_("YES") : "NO (frozen)");
PrintAndLogEx(SUCCESS, "[.%c..] AMK required for create/delete : %s", (keysettings & (1 << 2)) ? '1' : '0', (keysettings & (1 << 2)) ? "NO" : "YES");
PrintAndLogEx(SUCCESS, "[..%c.] Directory list access with AMK : %s", (keysettings & (1 << 1)) ? '1' : '0', (keysettings & (1 << 1)) ? "NO" : "YES");
PrintAndLogEx(SUCCESS, "[...%c] AMK is changeable : %s", (keysettings & (1 << 0)) ? '1' : '0', (keysettings & (1 << 0)) ? _GREEN_("YES") : "NO (frozen)");
PrintAndLogEx(SUCCESS, "");
if (print2ndbyte) {
PrintKeyType(numkeys >> 6);
PrintAndLogEx(SUCCESS, "key count: %d", numkeys & 0x0f);
}
}
void PrintKeySettings(uint8_t keysettings, uint8_t numkeys, bool applevel, bool print2ndbyte) {
if (applevel)
PrintKeySettingsApp(keysettings, numkeys, print2ndbyte);
else
PrintKeySettingsPICC(keysettings, numkeys, print2ndbyte);
}

View file

@ -46,4 +46,9 @@ int DesfireGetDFList(DesfireContext *dctx, uint8_t *resp, size_t *resplen);
int DesfireCreateApplication(DesfireContext *dctx, uint8_t *appdata, size_t appdatalen);
int DesfireDeleteApplication(DesfireContext *dctx, uint32_t aid);
int DesfireGetKeyVersion(DesfireContext *dctx, uint8_t *resp, size_t *resplen);
int DesfireGetKeySettings(DesfireContext *dctx, uint8_t *resp, size_t *resplen);
int DesfireChangeKeySettings(DesfireContext *dctx, uint8_t *data, size_t len);
void PrintKeySettings(uint8_t keysettings, uint8_t numkeys, bool applevel, bool print2ndbyte);
#endif // __DESFIRECORE_H

View file

@ -215,8 +215,11 @@ void DesfireCryptoEncDecEx(DesfireContext *ctx, bool use_session_key, uint8_t *s
uint8_t data[1024] = {0};
uint8_t xiv[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0};
if (ctx->secureChannel == DACd40)
bool xencode = encode;
if (ctx->secureChannel == DACd40) {
memset(ctx->IV, 0, DESFIRE_MAX_CRYPTO_BLOCK_SIZE);
xencode = false;
}
size_t block_size = desfire_get_key_block_length(ctx->keyType);
@ -228,9 +231,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 + offset, xiv, encode, encode);
DesfireCryptoEncDecSingleBlock(ctx->sessionKeyMAC, ctx->keyType, srcdata + offset, data + offset, xiv, encode, xencode);
else
DesfireCryptoEncDecSingleBlock(ctx->key, ctx->keyType, srcdata + offset, data + offset, xiv, encode, encode);
DesfireCryptoEncDecSingleBlock(ctx->key, ctx->keyType, srcdata + offset, data + offset, xiv, encode, xencode);
offset += block_size;
}
@ -308,3 +311,31 @@ void DesfireCryptoCMAC(DesfireContext *ctx, uint8_t *data, size_t len, uint8_t *
memcpy(cmac, ctx->IV, kbs);
}
void desfire_crc32(const uint8_t *data, const size_t len, uint8_t *crc) {
crc32_ex(data, len, crc);
}
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);
}
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);
}

View file

@ -101,5 +101,11 @@ void DesfireCryptoEncDec(DesfireContext *ctx, bool use_session_key, uint8_t *src
void DesfireCryptoEncDecEx(DesfireContext *ctx, bool use_session_key, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool encode, uint8_t *iv);
void DesfireCryptoCMAC(DesfireContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t *cmac);
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 // __DESFIRECRYPTO_H

View file

@ -20,8 +20,46 @@
#include "crc16.h" // crc16 ccitt
#include "crc32.h"
#include "commonutil.h"
#include "protocols.h"
#include "mifare/desfire_crypto.h"
AllowedChannelModesS AllowedChannelModes[] = {
{MFDES_CREATE_APPLICATION, DACd40, DCCNative, DCMPlain},
{MFDES_DELETE_APPLICATION, DACd40, DCCNative, DCMPlain},
{MFDES_GET_APPLICATION_IDS, DACd40, DCCNative, DCMPlain},
{MFDES_GET_DF_NAMES, DACd40, DCCNative, DCMPlain},
{MFDES_GET_KEY_SETTINGS, DACd40, DCCNative, DCMPlain},
{MFDES_READ_DATA, DACd40, DCCNative, DCMMACed},
{MFDES_WRITE_DATA, DACd40, DCCNative, DCMMACed},
{MFDES_GET_VALUE, DACd40, DCCNative, DCMMACed},
{MFDES_CREDIT, DACd40, DCCNative, DCMMACed},
{MFDES_DEBIT, DACd40, DCCNative, DCMMACed},
{MFDES_LIMITED_CREDIT, DACd40, DCCNative, DCMMACed},
{MFDES_READ_RECORDS, DACd40, DCCNative, DCMMACed},
{MFDES_WRITE_RECORD, DACd40, DCCNative, DCMMACed},
{MFDES_UPDATE_RECORD1, DACd40, DCCNative, DCMMACed},
{MFDES_UPDATE_RECORD2, DACd40, DCCNativeISO, DCMMACed},
{MFDES_INIT_KEY_SETTINGS, DACd40, DCCNative, DCMMACed},
{MFDES_FINALIZE_KEY_SETTINGS, DACd40, DCCNative, DCMMACed},
{MFDES_ROLL_KEY_SETTINGS, DACd40, DCCNative, DCMMACed},
{MFDES_COMMIT_READER_ID, DACd40, DCCNative, DCMMACed},
{MFDES_GET_UID, DACd40, DCCNative, DCMEncrypted},
{MFDES_CHANGE_KEY_SETTINGS, DACd40, DCCNative, DCMEncrypted},
{MFDES_READ_DATA, DACd40, DCCNative, DCMEncrypted},
{MFDES_WRITE_DATA, DACd40, DCCNative, DCMEncrypted},
{MFDES_CREATE_APPLICATION, DACEV1, DCCNative, DCMMACed},
{MFDES_DELETE_APPLICATION, DACEV1, DCCNative, DCMMACed},
{MFDES_GET_APPLICATION_IDS, DACEV1, DCCNative, DCMMACed},
{MFDES_GET_DF_NAMES, DACEV1, DCCNative, DCMMACed},
{MFDES_GET_KEY_SETTINGS, DACEV1, DCCNative, DCMMACed},
{MFDES_GET_UID, DACEV1, DCCNative, DCMEncrypted},
{MFDES_CHANGE_KEY_SETTINGS, DACEV1, DCCNative, DCMEncrypted},
};
static void DesfireSecureChannelEncodeD40(DesfireContext *ctx, uint8_t cmd, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen) {
memcpy(dstdata, srcdata, srcdatalen);
*dstdatalen = srcdatalen;
@ -38,10 +76,9 @@ static void DesfireSecureChannelEncodeD40(DesfireContext *ctx, uint8_t cmd, uint
if (srcdatalen == 0)
break;
rlen = padded_data_length(srcdatalen, desfire_get_key_block_length(ctx->keyType));
rlen = srcdatalen + DesfireGetMACLength(ctx);
memcpy(data, srcdata, srcdatalen);
memset(ctx->IV, 0, sizeof(ctx->IV));
DesfireCryptoEncDec(ctx, true, data, rlen, NULL, true);
DesfireCryptoEncDec(ctx, true, data, srcdatalen, NULL, true);
memcpy(dstdata, srcdata, srcdatalen);
memcpy(&dstdata[srcdatalen], ctx->IV, 4);
*dstdatalen = rlen;
@ -53,7 +90,6 @@ static void DesfireSecureChannelEncodeD40(DesfireContext *ctx, uint8_t cmd, uint
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;
@ -64,6 +100,7 @@ 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};
size_t rlen = 0;
// we calc MAC anyway
// if encypted channel and no data - we only calc MAC
@ -74,14 +111,20 @@ static void DesfireSecureChannelEncodeEV1(DesfireContext *ctx, uint8_t cmd, uint
DesfireCryptoCMAC(ctx, data, srcdatalen + 1, cmac);
memcpy(dstdata, srcdata, srcdatalen);
*dstdatalen = srcdatalen;
if (srcdatalen != 0 && ctx->commMode == DCMMACed) {
memcpy(&dstdata[srcdatalen], cmac, DesfireGetMACLength(ctx));
*dstdatalen = srcdatalen + DesfireGetMACLength(ctx);
}
} else if (ctx->commMode == DCMEncrypted) {
rlen = padded_data_length(srcdatalen + 4, desfire_get_key_block_length(ctx->keyType));
data[0] = cmd;
memcpy(&data[1], srcdata, srcdatalen);
desfire_crc32_append(data, srcdatalen + 1);
DesfireCryptoEncDec(ctx, true, &data[1], rlen, dstdata, true);
*dstdatalen = rlen;
} else {
memcpy(dstdata, srcdata, srcdatalen);
*dstdatalen = srcdatalen;
@ -207,3 +250,44 @@ void DesfireSecureChannelDecode(DesfireContext *ctx, uint8_t *srcdata, size_t sr
break;
}
}
bool PrintChannelModeWarning(uint8_t cmd, DesfireSecureChannel secureChannel, DesfireCommandSet cmdSet, DesfireCommunicationMode commMode) {
if (commMode == DCMNone) {
PrintAndLogEx(WARNING, "Communication mode can't be NONE. command: %02x", cmd);
return false;
}
// no security set
if (secureChannel == DACNone)
return true;
bool found = false;
for (int i = 0; i < ARRAY_LENGTH(AllowedChannelModes); i++)
if (AllowedChannelModes[i].cmd == cmd) {
// full compare
if (AllowedChannelModes[i].secureChannel == secureChannel &&
(AllowedChannelModes[i].cmdSet == cmdSet || (AllowedChannelModes[i].cmdSet == DCCNative && cmdSet == DCCNativeISO)) &&
AllowedChannelModes[i].commMode == commMode) {
found = true;
break;
}
// ev1 plain and mac are the same
if (AllowedChannelModes[i].secureChannel == secureChannel &&
AllowedChannelModes[i].secureChannel == DACEV1 &&
(AllowedChannelModes[i].cmdSet == cmdSet || (AllowedChannelModes[i].cmdSet == DCCNative && cmdSet == DCCNativeISO)) &&
(commMode == DCMPlain || commMode == DCMMACed)) {
found = true;
break;
}
}
if (!found)
PrintAndLogEx(WARNING, "Wrong communication mode. Check settings. command: %02x", cmd);
return found;
}

View file

@ -19,8 +19,16 @@
#include "mifare/desfire_crypto.h"
#include "mifare/mifare4.h"
typedef struct {
uint8_t cmd;
DesfireSecureChannel secureChannel;
DesfireCommandSet cmdSet;
DesfireCommunicationMode commMode;
} AllowedChannelModesS;
void DesfireSecureChannelEncode(DesfireContext *ctx, uint8_t cmd, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen);
void DesfireSecureChannelDecode(DesfireContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t respcode, uint8_t *dstdata, size_t *dstdatalen);
bool PrintChannelModeWarning(uint8_t cmd, DesfireSecureChannel secureChannel, DesfireCommandSet cmdSet, DesfireCommunicationMode commMode);
#endif // __DESFIRESECURECHAN_H

View file

@ -436,6 +436,7 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
#define MFDES_GET_FILE_IDS 0x6F
#define MFDES_ABORT_TRANSACTION 0xA7
#define MFDES_ADDITIONAL_FRAME 0xAF
#define MFDES_UPDATE_RECORD1 0xBA
#define MFDES_READ_RECORDS 0xBB
#define MFDES_READ_DATA 0xBD
#define MFDES_CREATE_CYCLIC_RECORD_FILE 0xC0
@ -451,6 +452,7 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
#define MFDES_CREATE_STD_DATA_FILE 0xCD
#define MFDES_CREATE_TRANS_MAC_FILE 0xCE
#define MFDES_DELETE_APPLICATION 0xDA
#define MFDES_UPDATE_RECORD2 0xDB
#define MFDES_DEBIT 0xDC
#define MFDES_DELETE_FILE 0xDF
#define MFDES_CLEAR_RECORD_FILE 0xEB