Merge pull request #1346 from merlokk/desf_update

Desfire functionality update
This commit is contained in:
Oleg Moiseenko 2021-07-05 14:50:19 +03:00 committed by GitHub
commit 8a598ce33c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 1594 additions and 150 deletions

View file

@ -226,6 +226,7 @@ set (TARGET_SOURCES
${PM3_ROOT}/client/src/mifare/mifarehost.c
${PM3_ROOT}/client/src/nfc/ndef.c
${PM3_ROOT}/client/src/mifare/desfire_crypto.c
${PM3_ROOT}/client/src/mifare/desfirecore.c
${PM3_ROOT}/client/src/uart/uart_posix.c
${PM3_ROOT}/client/src/uart/uart_win32.c
${PM3_ROOT}/client/src/ui/overlays.ui

View file

@ -589,6 +589,7 @@ SRCS = aiddesfire.c \
loclass/elite_crack.c \
loclass/ikeys.c \
mifare/desfire_crypto.c \
mifare/desfirecore.c \
mifare/mad.c \
mifare/mfkey.c \
mifare/mifare4.c \

View file

@ -1,5 +1,6 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2014 Iceman
// Copyright (C) 2021 Merlok
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
@ -28,6 +29,7 @@
#include "iso7816/iso7816core.h" // APDU logging
#include "util_posix.h" // msleep
#include "mifare/desfire_crypto.h"
#include "mifare/desfirecore.h"
#include "crapto1/crapto1.h"
#include "fileutils.h"
#include "mifare/mifaredefault.h" // default keys
@ -508,125 +510,6 @@ static int DESFIRESendApdu(bool activate_field, bool leavefield_on, sAPDU apdu,
return PM3_SUCCESS;
}
static const char *getstatus(uint16_t *sw) {
if (sw == NULL) return "--> sw argument error. This should never happen !";
if (((*sw >> 8) & 0xFF) == 0x91) {
switch (*sw & 0xFF) {
case MFDES_E_OUT_OF_EEPROM:
return "Out of Eeprom, insufficient NV-Memory to complete command";
case MFDES_E_ILLEGAL_COMMAND_CODE:
return "Command code not supported";
case MFDES_E_INTEGRITY_ERROR:
return "CRC or MAC does not match data / Padding bytes invalid";
case MFDES_E_NO_SUCH_KEY:
return "Invalid key number specified";
case MFDES_E_LENGTH:
return "Length of command string invalid";
case MFDES_E_PERMISSION_DENIED:
return "Current configuration/status does not allow the requested command";
case MFDES_E_PARAMETER_ERROR:
return "Value of the parameter(s) invalid";
case MFDES_E_APPLICATION_NOT_FOUND:
return "Requested AID not present on PICC";
case MFDES_E_APPL_INTEGRITY:
return "Application integrity error, application will be disabled";
case MFDES_E_AUTHENTIFICATION_ERROR:
return "Current authentication status does not allow the requested command";
case MFDES_E_BOUNDARY:
return "Attempted to read/write data from/to beyond the file's/record's limit";
case MFDES_E_PICC_INTEGRITY:
return "PICC integrity error, PICC will be disabled";
case MFDES_E_COMMAND_ABORTED:
return "Previous command was not fully completed / Not all Frames were requested or provided by the PCD";
case MFDES_E_PICC_DISABLED:
return "PICC was disabled by an unrecoverable error";
case MFDES_E_COUNT:
return "Application count is limited to 28, not addition CreateApplication possible";
case MFDES_E_DUPLICATE:
return "Duplicate entry: File/Application/ISO Text does already exist";
case MFDES_E_EEPROM:
return "Eeprom error due to loss of power, internal backup/rollback mechanism activated";
case MFDES_E_FILE_NOT_FOUND:
return "Specified file number does not exist";
case MFDES_E_FILE_INTEGRITY:
return "File integrity error, file will be disabled";
default:
return "Unknown error";
}
}
return "Unknown error";
}
static const char *GetErrorString(int res, uint16_t *sw) {
switch (res) {
case PM3_EAPDU_FAIL:
return getstatus(sw);
case PM3_EUNDEF:
return "Undefined error";
case PM3_EINVARG:
return "Invalid argument(s)";
case PM3_EDEVNOTSUPP:
return "Operation not supported by device";
case PM3_ETIMEOUT:
return "Operation timed out";
case PM3_EOPABORTED:
return "Operation aborted (by user)";
case PM3_ENOTIMPL:
return "Not (yet) implemented";
case PM3_ERFTRANS:
return "Error while RF transmission";
case PM3_EIO:
return "Input / output error";
case PM3_EOVFLOW:
return "Buffer overflow";
case PM3_ESOFT:
return "Software error";
case PM3_EFLASH:
return "Flash error";
case PM3_EMALLOC:
return "Memory allocation error";
case PM3_EFILE:
return "File error";
case PM3_ENOTTY:
return "Generic TTY error";
case PM3_EINIT:
return "Initialization error";
case PM3_EWRONGANSWER:
return "Expected a different answer error";
case PM3_EOUTOFBOUND:
return "Memory out-of-bounds error";
case PM3_ECARDEXCHANGE:
return "Exchange with card error";
case PM3_EAPDU_ENCODEFAIL:
return "Failed to create APDU";
case PM3_ENODATA:
return "No data";
case PM3_EFATAL:
return "Fatal error";
default:
break;
}
return "";
}
static int send_desfire_cmd(sAPDU *apdu, bool select, uint8_t *dest, uint32_t *recv_len, uint16_t *sw, uint32_t splitbysize, bool readalldata) {
if (apdu == NULL) {
PrintAndLogEx(DEBUG, "APDU=NULL");
@ -648,7 +531,7 @@ static int send_desfire_cmd(sAPDU *apdu, bool select, uint8_t *dest, uint32_t *r
uint32_t i = 1;
int res = DESFIRESendApdu(select, true, *apdu, data, sizeof(data), &resplen, sw);
if (res != PM3_SUCCESS) {
PrintAndLogEx(DEBUG, "%s", GetErrorString(res, sw));
PrintAndLogEx(DEBUG, "%s", DesfireGetErrorString(res, sw));
DropFieldDesfire();
return res;
}
@ -673,7 +556,7 @@ static int send_desfire_cmd(sAPDU *apdu, bool select, uint8_t *dest, uint32_t *r
res = DESFIRESendApdu(false, true, *apdu, data, sizeof(data), &resplen, sw);
if (res != PM3_SUCCESS) {
PrintAndLogEx(DEBUG, "%s", GetErrorString(res, sw));
PrintAndLogEx(DEBUG, "%s", DesfireGetErrorString(res, sw));
DropFieldDesfire();
return res;
}
@ -1340,7 +1223,7 @@ static int mifare_desfire_change_key(uint8_t key_no, uint8_t *new_key, uint8_t n
int res = send_desfire_cmd(&apdu, false, NULL, &recv_len, &sw, 0, true);
if (res != PM3_SUCCESS) {
PrintAndLogEx(WARNING, _RED_("can't change key -> %s"), GetErrorString(res, &sw));
PrintAndLogEx(WARNING, _RED_("can't change key -> %s"), DesfireGetErrorString(res, &sw));
DropFieldDesfire();
return res;
}
@ -1770,7 +1653,7 @@ static int handler_desfire_select_application(uint8_t *aid) {
PrintAndLogEx(WARNING,
_RED_(" Can't select AID 0x%X -> %s"),
(aid[2] << 16) + (aid[1] << 8) + aid[0],
GetErrorString(res, &sw)
DesfireGetErrorString(res, &sw)
);
DropFieldDesfire();
return res;
@ -1813,7 +1696,7 @@ static int handler_desfire_fileids(uint8_t *dest, uint32_t *file_ids_len) {
*file_ids_len = 0;
int res = send_desfire_cmd(&apdu, false, dest, &recv_len, &sw, 0, true);
if (res != PM3_SUCCESS) {
PrintAndLogEx(WARNING, _RED_(" Can't get file ids -> %s"), GetErrorString(res, &sw));
PrintAndLogEx(WARNING, _RED_(" Can't get file ids -> %s"), DesfireGetErrorString(res, &sw));
DropFieldDesfire();
return res;
}
@ -1832,7 +1715,7 @@ static int handler_desfire_filesettings(uint8_t file_id, uint8_t *dest, uint32_t
uint16_t sw = 0;
int res = send_desfire_cmd(&apdu, false, dest, destlen, &sw, 0, true);
if (res != PM3_SUCCESS) {
PrintAndLogEx(WARNING, _RED_(" Can't get file settings -> %s"), GetErrorString(res, &sw));
PrintAndLogEx(WARNING, _RED_(" Can't get file settings -> %s"), DesfireGetErrorString(res, &sw));
DropFieldDesfire();
return res;
}
@ -1872,7 +1755,7 @@ static int handler_desfire_createapp(aidhdr_t *aidhdr, bool usename, bool usefid
free(data);
}
if (res != PM3_SUCCESS) {
PrintAndLogEx(WARNING, _RED_(" Can't create aid -> %s"), GetErrorString(res, &sw));
PrintAndLogEx(WARNING, _RED_(" Can't create aid -> %s"), DesfireGetErrorString(res, &sw));
DropFieldDesfire();
}
return res;
@ -1887,7 +1770,7 @@ static int handler_desfire_deleteapp(const uint8_t *aid) {
uint32_t recvlen = 0;
int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true);
if (res != PM3_SUCCESS) {
PrintAndLogEx(WARNING, _RED_(" Can't delete aid -> %s"), GetErrorString(res, &sw));
PrintAndLogEx(WARNING, _RED_(" Can't delete aid -> %s"), DesfireGetErrorString(res, &sw));
DropFieldDesfire();
}
return res;
@ -1905,7 +1788,7 @@ static int handler_desfire_credit(mfdes_value_t *value, uint8_t cs) {
int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true);
if (res != PM3_SUCCESS) {
PrintAndLogEx(WARNING, _RED_(" Can't credit value -> %s"), GetErrorString(res, &sw));
PrintAndLogEx(WARNING, _RED_(" Can't credit value -> %s"), DesfireGetErrorString(res, &sw));
DropFieldDesfire();
return res;
}
@ -1924,7 +1807,7 @@ static int handler_desfire_limitedcredit(mfdes_value_t *value, uint8_t cs) {
int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true);
if (res != PM3_SUCCESS) {
PrintAndLogEx(WARNING, _RED_(" Can't credit limited value -> %s"), GetErrorString(res, &sw));
PrintAndLogEx(WARNING, _RED_(" Can't credit limited value -> %s"), DesfireGetErrorString(res, &sw));
DropFieldDesfire();
return res;
}
@ -1943,7 +1826,7 @@ static int handler_desfire_debit(mfdes_value_t *value, uint8_t cs) {
int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true);
if (res != PM3_SUCCESS) {
PrintAndLogEx(WARNING, _RED_(" Can't debit value -> %s"), GetErrorString(res, &sw));
PrintAndLogEx(WARNING, _RED_(" Can't debit value -> %s"), DesfireGetErrorString(res, &sw));
DropFieldDesfire();
return res;
}
@ -1981,7 +1864,7 @@ static int handler_desfire_readdata(mfdes_data_t *data, MFDES_FILE_TYPE_T type,
uint32_t resplen = 0;
int res = send_desfire_cmd(&apdu, false, data->data, &resplen, &sw, 0, true);
if (res != PM3_SUCCESS) {
PrintAndLogEx(WARNING, _RED_(" Can't read data -> %s"), GetErrorString(res, &sw));
PrintAndLogEx(WARNING, _RED_(" Can't read data -> %s"), DesfireGetErrorString(res, &sw));
DropFieldDesfire();
return res;
}
@ -2013,7 +1896,7 @@ static int handler_desfire_getvalue(mfdes_value_t *value, uint32_t *resplen, uin
int res = send_desfire_cmd(&apdu, false, value->value, resplen, &sw, 0, true);
if (res != PM3_SUCCESS) {
PrintAndLogEx(WARNING, _RED_(" Can't read data -> %s"), GetErrorString(res, &sw));
PrintAndLogEx(WARNING, _RED_(" Can't read data -> %s"), DesfireGetErrorString(res, &sw));
DropFieldDesfire();
return res;
}
@ -2089,7 +1972,7 @@ static int handler_desfire_writedata(mfdes_data_t *data, MFDES_FILE_TYPE_T type,
res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true);
if (res != PM3_SUCCESS) {
PrintAndLogEx(WARNING, _RED_(" Can't write data -> %s"), GetErrorString(res, &sw));
PrintAndLogEx(WARNING, _RED_(" Can't write data -> %s"), DesfireGetErrorString(res, &sw));
DropFieldDesfire();
return res;
}
@ -2098,7 +1981,7 @@ static int handler_desfire_writedata(mfdes_data_t *data, MFDES_FILE_TYPE_T type,
}
if (type == MFDES_RECORD_FILE) {
if (handler_desfire_commit_transaction() != PM3_SUCCESS) {
PrintAndLogEx(WARNING, _RED_(" Can't commit transaction -> %s"), GetErrorString(res, &sw));
PrintAndLogEx(WARNING, _RED_(" Can't commit transaction -> %s"), DesfireGetErrorString(res, &sw));
DropFieldDesfire();
return res;
}
@ -2115,7 +1998,7 @@ static int handler_desfire_deletefile(uint8_t file_no) {
uint32_t recvlen = 0;
int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true);
if (res != PM3_SUCCESS) {
PrintAndLogEx(WARNING, _RED_(" Can't delete file -> %s"), GetErrorString(res, &sw));
PrintAndLogEx(WARNING, _RED_(" Can't delete file -> %s"), DesfireGetErrorString(res, &sw));
DropFieldDesfire();
return res;
}
@ -2131,13 +2014,13 @@ static int handler_desfire_clear_record_file(uint8_t file_no) {
uint32_t recvlen = 0;
int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true);
if (res != PM3_SUCCESS) {
PrintAndLogEx(WARNING, _RED_(" Can't clear record file -> %s"), GetErrorString(res, &sw));
PrintAndLogEx(WARNING, _RED_(" Can't clear record file -> %s"), DesfireGetErrorString(res, &sw));
DropFieldDesfire();
return res;
} else {
res = handler_desfire_commit_transaction();
if (res != PM3_SUCCESS) {
PrintAndLogEx(WARNING, _RED_(" Can't commit transaction -> %s"), GetErrorString(res, &sw));
PrintAndLogEx(WARNING, _RED_(" Can't commit transaction -> %s"), DesfireGetErrorString(res, &sw));
DropFieldDesfire();
return res;
}
@ -2154,7 +2037,7 @@ static int handler_desfire_create_value_file(mfdes_value_file_t *value) {
uint32_t recvlen = 0;
int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true);
if (res != PM3_SUCCESS) {
PrintAndLogEx(WARNING, _RED_(" Can't create value -> %s"), GetErrorString(res, &sw));
PrintAndLogEx(WARNING, _RED_(" Can't create value -> %s"), DesfireGetErrorString(res, &sw));
DropFieldDesfire();
return res;
}
@ -2171,7 +2054,7 @@ static int handler_desfire_create_std_file(mfdes_file_t *file) {
uint32_t recvlen = 0;
int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true);
if (res != PM3_SUCCESS) {
PrintAndLogEx(WARNING, _RED_(" Can't create file -> %s"), GetErrorString(res, &sw));
PrintAndLogEx(WARNING, _RED_(" Can't create file -> %s"), DesfireGetErrorString(res, &sw));
DropFieldDesfire();
return res;
}
@ -2189,7 +2072,7 @@ static int handler_desfire_create_linearrecordfile(mfdes_linear_t *file) {
uint32_t recvlen = 0;
int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true);
if (res != PM3_SUCCESS) {
PrintAndLogEx(WARNING, _RED_(" Can't create linear record file -> %s"), GetErrorString(res, &sw));
PrintAndLogEx(WARNING, _RED_(" Can't create linear record file -> %s"), DesfireGetErrorString(res, &sw));
DropFieldDesfire();
return res;
}
@ -2209,7 +2092,7 @@ static int handler_desfire_create_cyclicrecordfile(mfdes_linear_t *file) {
uint32_t recvlen = 0;
int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true);
if (res != PM3_SUCCESS) {
PrintAndLogEx(WARNING, _RED_(" Can't create cyclic record file -> %s"), GetErrorString(res, &sw));
PrintAndLogEx(WARNING, _RED_(" Can't create cyclic record file -> %s"), DesfireGetErrorString(res, &sw));
DropFieldDesfire();
return res;
}
@ -2225,7 +2108,7 @@ static int handler_desfire_create_backup_file(mfdes_file_t *file) {
uint32_t recvlen = 0;
int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true);
if (res != PM3_SUCCESS) {
PrintAndLogEx(WARNING, _RED_(" Can't create backup file -> %s"), GetErrorString(res, &sw));
PrintAndLogEx(WARNING, _RED_(" Can't create backup file -> %s"), DesfireGetErrorString(res, &sw));
DropFieldDesfire();
return res;
}
@ -3572,7 +3455,7 @@ static int CmdHF14ADesFormatPICC(const char *Cmd) {
uint32_t recvlen = 0;
int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true);
if (res != PM3_SUCCESS) {
PrintAndLogEx(WARNING, _RED_(" Can't format picc -> %s"), GetErrorString(res, &sw));
PrintAndLogEx(WARNING, _RED_(" Can't format picc -> %s"), DesfireGetErrorString(res, &sw));
} else {
PrintAndLogEx(INFO, "Card successfully reset");
}
@ -5115,10 +4998,320 @@ static int CmdHF14aDesMAD(const char *Cmd) {
return PM3_SUCCESS;
}
*/
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,
int *securechannel) {
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;
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;
}
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",
"Get Application IDs, ISO IDs and DF names from card. Master key needs to be provided.",
"hf mfdes getappnames -n 0 -t des -k 0000000000000000 -f none -> execute with default factory setup");
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, &securechann);
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 CmdHF14ADesGetAIDs(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfdes getaids",
"Get Application IDs list from card. Master key needs to be provided.",
"hf mfdes getaids -n 0 -t des -k 0000000000000000 -f none -> execute with default factory 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_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;
int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, &securechann);
if (res) {
CLIParserFree(ctx);
return res;
}
SetAPDULogging(APDULogging);
CLIParserFree(ctx);
if (verbose)
DesfirePrintContext(&dctx);
res = DesfireSelectAIDHex(&dctx, 0x000000, false, 0);
if (res != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Desfire select " _RED_("error") ".");
DropField();
return PM3_ESOFT;
}
res = DesfireAuthenticate(&dctx, securechann); //DACd40 DACEV1
if (res != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Desfire authenticate " _RED_("error") ". Result: %d", res);
DropField();
return PM3_ESOFT;
}
if (DesfireIsAuthenticated(&dctx)) {
if (verbose)
PrintAndLogEx(ERR, "Desfire " _GREEN_("authenticated") , res);
} else {
return PM3_ESOFT;
}
uint8_t buf[APDU_RES_LEN] = {0};
size_t buflen = 0;
res = DesfireGetAIDList(&dctx, buf, &buflen);
if (res != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Desfire GetAIDList command " _RED_("error") ". Result: %d", res);
DropField();
return PM3_ESOFT;
}
if (buflen >= 3) {
PrintAndLogEx(INFO, "---- " _CYAN_("AID list") " ----");
for (int i = 0; i < buflen; i += 3)
PrintAndLogEx(INFO, "AID: %06x", DesfireAIDByteToUint(&buf[i]));
}
DropField();
return PM3_SUCCESS;
}
static int CmdHF14ADesGetAppNames(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfdes getappnames",
"Get Application IDs, ISO IDs and DF names from card. Master key needs to be provided.",
"hf mfdes getappnames -n 0 -t des -k 0000000000000000 -f none -> execute with default factory 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_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;
int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, &securechann);
if (res) {
CLIParserFree(ctx);
return res;
}
SetAPDULogging(APDULogging);
CLIParserFree(ctx);
if (verbose)
DesfirePrintContext(&dctx);
res = DesfireSelectAIDHex(&dctx, 0x000000, 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(ERR, "Desfire " _GREEN_("authenticated") , res);
} else {
return PM3_ESOFT;
}
uint8_t buf[APDU_RES_LEN] = {0};
size_t buflen = 0;
// result bytes: 3, 2, 1-16. total record size = 24
res = DesfireGetDFList(&dctx, buf, &buflen);
if (res != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Desfire DesfireGetDFList command " _RED_("error") ". Result: %d", res);
DropField();
return PM3_ESOFT;
}
if (buflen > 0) {
PrintAndLogEx(INFO, "----------------------- " _CYAN_("File list") " -----------------------");
for (int i = 0; i < buflen; i++)
PrintAndLogEx(INFO, "AID: %06x ISO file id: %02x%02x ISO DF name[%d]: %s",
DesfireAIDByteToUint(&buf[i * 24 + 1]),
buf[i * 24 + 1 + 3], buf[i * 24 + 1 + 4],
strlen((char *)&buf[i * 24 + 1 + 5]),
&buf[i * 24 + 1 + 5]);
}
DropField();
return PM3_SUCCESS;
}
static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"},
{"-----------", 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"},
@ -5134,6 +5327,8 @@ static command_t CommandTable[] = {
{"createaid", CmdHF14ADesCreateApp, IfPm3Iso14443a, "Create Application ID"},
{"deleteaid", CmdHF14ADesDeleteApp, IfPm3Iso14443a, "Delete Application ID"},
{"selectaid", CmdHF14ADesSelectApp, IfPm3Iso14443a, "Select Application ID"},
{"getaids", CmdHF14ADesGetAIDs, IfPm3Iso14443a, "[new]Get Application IDs list"},
{"getappnames", CmdHF14ADesGetAppNames, IfPm3Iso14443a, "[new]Get Applications list"},
{"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("Files") " -----------------------"},
{"changevalue", CmdHF14ADesChangeValue, IfPm3Iso14443a, "Write value of a value file (credit/debit/clear)"},
{"clearfile", CmdHF14ADesClearRecordFile, IfPm3Iso14443a, "Clear record File"},

View file

@ -1,5 +1,6 @@
//-----------------------------------------------------------------------------
// Iceman, 2014
// Copyright (C) Iceman, 2014
// Copyright (C) 2021 Merlok
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of

View file

@ -1,5 +1,6 @@
/*-
* Copyright (C) 2010, Romain Tartiere.
* Copyright (C) 2021 Merlok
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
@ -52,6 +53,16 @@ static inline void update_key_schedules(desfirekey_t key) {
// }
}
int desfire_get_key_length(enum DESFIRE_CRYPTOALGO key_type) {
switch (key_type) {
case T_DES: return 8;
case T_3DES: return 16;
case T_3K3DES: return 24;
case T_AES: return 16;
}
return 0;
}
/******************************************************************************/
void tdes_nxp_receive(const void *in, void *out, size_t length, const void *key, unsigned char iv[8], int keymode) {
@ -367,12 +378,9 @@ void mifare_kdf_an10922(const desfirekey_t key, const uint8_t *data, size_t len)
free(buffer);
}
size_t key_block_size(const desfirekey_t key) {
if (key == NULL) {
return 0;
}
size_t desfire_get_key_block_length(enum DESFIRE_CRYPTOALGO key_type) {
size_t block_size = 8;
switch (key->type) {
switch (key_type) {
case T_DES:
case T_3DES:
case T_3K3DES:
@ -385,6 +393,13 @@ size_t key_block_size(const desfirekey_t key) {
return block_size;
}
size_t key_block_size(const desfirekey_t key) {
if (key == NULL) {
return 0;
}
return desfire_get_key_block_length(key->type);
}
/*
* Size of MACing produced with the key.
*/

View file

@ -1,12 +1,34 @@
#ifndef __DESFIRE_CRYPTO_H
/*-
* Copyright (C) 2010, Romain Tartiere.
* Copyright (C) 2021 Merlok
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
* $Id$
*/
#ifndef __DESFIRE_CRYPTO_H
#define __DESFIRE_CRYPTO_H
#include "common.h"
#include "mifare.h" // structs
#include "crc32.h"
#include "crypto/libpcrypto.h"
#define MAX_CRYPTO_BLOCK_SIZE 16
#define DESFIRE_MAX_KEY_SIZE 24
/* Mifare DESFire EV1 Application crypto operations */
#define APPLICATION_CRYPTO_DES 0x00
#define APPLICATION_CRYPTO_3K3DES 0x40
@ -60,6 +82,9 @@ enum DESFIRE_CRYPTOALGO {
T_AES = 0x03
};
int desfire_get_key_length(enum DESFIRE_CRYPTOALGO key_type);
size_t desfire_get_key_block_length(enum DESFIRE_CRYPTOALGO key_type);
enum DESFIRE_AUTH_SCHEME {
AS_LEGACY,
AS_NEW

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,103 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2010 Romain Tartiere.
// Copyright (C) 2014 Iceman
// Copyright (C) 2021 Merlok
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// High frequency Desfire core functions
//-----------------------------------------------------------------------------
#ifndef __DESFIRECORE_H
#define __DESFIRECORE_H
#include "common.h"
#include "cliparser.h"
#include "mifare/desfire_crypto.h"
#include "mifare/mifare4.h"
#define DESF_MAX_KEY_LEN 24
#define DESFIRE_GET_ISO_STATUS(x) ( ((uint16_t)(0x91<<8)) + (uint16_t)x )
typedef enum DESFIRE_CRYPTOALGO DesfireCryptoAlgorythm;
typedef enum {
DACNone,
DACd40,
DACEV1,
DACEV2
} DesfireSecureChannel;
typedef enum {
DCCNative,
DCCNativeISO,
DCCISO
} DesfireCommandSet;
typedef enum {
DCMNone,
DCMPlain,
DCMMACed,
DCMEncrypted
} DesfireCommunicationMode;
typedef struct DesfireContextS {
uint8_t keyNum;
enum DESFIRE_CRYPTOALGO keyType; // des/2tdea/3tdea/aes
uint8_t key[DESF_MAX_KEY_LEN];
// KDF finction
uint8_t kdfAlgo;
uint8_t kdfInputLen;
uint8_t kdfInput[31];
DesfireSecureChannel secureChannel; // none/d40/ev1/ev2
DesfireCommandSet cmdSet; // native/nativeiso/iso
DesfireCommunicationMode commMode; // plain/mac/enc
uint8_t IV[DESF_MAX_KEY_LEN];
uint8_t sessionKeyMAC[DESF_MAX_KEY_LEN];
uint8_t sessionKeyEnc[DESF_MAX_KEY_LEN]; // look at mifare4.h - mf4Session_t
uint8_t lastIV[DESF_MAX_KEY_LEN];
//mf4Session_t AESSession;
uint16_t cntrTx; // for AES
uint16_t cntrRx; // for AES
uint8_t TI[4]; // for AES
} DesfireContext;
extern const CLIParserOption DesfireAlgoOpts[];
extern const CLIParserOption DesfireKDFAlgoOpts[];
extern const CLIParserOption DesfireCommunicationModeOpts[];
extern const CLIParserOption DesfireCommandSetOpts[];
extern const CLIParserOption DesfireSecureChannelOpts[];
void DesfireClearContext(DesfireContext *ctx);
void DesfirePrintContext(DesfireContext *ctx);
void DesfireClearSession(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);
void DesfireSetKdf(DesfireContext *ctx, uint8_t kdfAlgo,uint8_t *kdfInput, uint8_t kdfInputLen);
const char *DesfireGetErrorString(int res, uint16_t *sw);
uint32_t DesfireAIDByteToUint(uint8_t *data);
void DesfireAIDUintToByte(uint32_t aid, uint8_t *data);
int DesfireExchange(DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen);
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 DesfireSelectAID(DesfireContext *ctx, uint8_t *aid1, uint8_t *aid2);
int DesfireSelectAIDHex(DesfireContext *ctx, uint32_t aid1, bool select_two, uint32_t aid2);
int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel);
bool DesfireIsAuthenticated(DesfireContext *dctx);
int DesfireGetAIDList(DesfireContext *dctx, uint8_t *resp, size_t *resplen);
int DesfireGetDFList(DesfireContext *dctx, uint8_t *resp, size_t *resplen);
#endif // __DESFIRECORE_H

View file

@ -16,6 +16,8 @@
#include <endian.h>
#endif
#define ARRAY_LENGTH( array ) ( sizeof( array ) / sizeof( *( array ) ) )
// used for save/load files
#ifndef FILE_PATH_SIZE
# define FILE_PATH_SIZE 1000

View file

@ -459,6 +459,7 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
#define MFDES_GET_FILE_SETTINGS 0xF5
#define MFDES_FORMAT_PICC 0xFC
#define MFDES_VERIFY_PC 0xFD
#define MFDES_NATIVE_ISO7816_WRAP_CLA 0x90
// MIFARE DESFire status & error codes:
#define MFDES_S_OPERATION_OK 0x00