mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-20 13:23:51 -07:00
desfire channel sketch
This commit is contained in:
parent
bf1212f63e
commit
2fa6c4643e
8 changed files with 444 additions and 0 deletions
|
@ -226,6 +226,7 @@ set (TARGET_SOURCES
|
||||||
${PM3_ROOT}/client/src/mifare/mifarehost.c
|
${PM3_ROOT}/client/src/mifare/mifarehost.c
|
||||||
${PM3_ROOT}/client/src/nfc/ndef.c
|
${PM3_ROOT}/client/src/nfc/ndef.c
|
||||||
${PM3_ROOT}/client/src/mifare/desfire_crypto.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_posix.c
|
||||||
${PM3_ROOT}/client/src/uart/uart_win32.c
|
${PM3_ROOT}/client/src/uart/uart_win32.c
|
||||||
${PM3_ROOT}/client/src/ui/overlays.ui
|
${PM3_ROOT}/client/src/ui/overlays.ui
|
||||||
|
|
|
@ -572,6 +572,7 @@ SRCS = aiddesfire.c \
|
||||||
loclass/elite_crack.c \
|
loclass/elite_crack.c \
|
||||||
loclass/ikeys.c \
|
loclass/ikeys.c \
|
||||||
mifare/desfire_crypto.c \
|
mifare/desfire_crypto.c \
|
||||||
|
mifare/desfirecore.c \
|
||||||
mifare/mad.c \
|
mifare/mad.c \
|
||||||
mifare/mfkey.c \
|
mifare/mfkey.c \
|
||||||
mifare/mifare4.c \
|
mifare/mifare4.c \
|
||||||
|
|
|
@ -5116,6 +5116,121 @@ static int CmdHF14aDesMAD(const char *Cmd) {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
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_int0("t", "algo", "<algo>", "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_int0("f", "kdf", "<kdf>", "Key Derivation Function (KDF): None(default), AN10922, Gallagher"),
|
||||||
|
arg_str0("i", "kdfi", "<kdfi>", "KDF input (HEX 1-31 bytes)"),
|
||||||
|
arg_param_end
|
||||||
|
};
|
||||||
|
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
int aidlength = 0;
|
||||||
|
uint8_t aid[3] = {0};
|
||||||
|
CLIGetHexWithReturn(ctx, 1, aid, &aidlength);
|
||||||
|
swap24(aid);
|
||||||
|
uint8_t vkey[16] = {0};
|
||||||
|
int vkeylen = 0;
|
||||||
|
CLIGetHexWithReturn(ctx, 2, vkey, &vkeylen);
|
||||||
|
|
||||||
|
if (vkeylen > 0) {
|
||||||
|
if (vkeylen == 8) {
|
||||||
|
memcpy(&deskeyList[deskeyListLen], vkey, 8);
|
||||||
|
deskeyListLen++;
|
||||||
|
} else if (vkeylen == 16) {
|
||||||
|
memcpy(&aeskeyList[aeskeyListLen], vkey, 16);
|
||||||
|
aeskeyListLen++;
|
||||||
|
} else if (vkeylen == 24) {
|
||||||
|
memcpy(&k3kkeyList[k3kkeyListLen], vkey, 16);
|
||||||
|
k3kkeyListLen++;
|
||||||
|
} else {
|
||||||
|
PrintAndLogEx(ERR, "Specified key must have 8, 16 or 24 bytes length.");
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t dict_filename[FILE_PATH_SIZE + 2] = {0};
|
||||||
|
int dict_filenamelen = 0;
|
||||||
|
if (CLIParamStrToBuf(arg_get_str(ctx, 3), dict_filename, FILE_PATH_SIZE, &dict_filenamelen)) {
|
||||||
|
PrintAndLogEx(FAILED, "File name too long or invalid.");
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pattern1b = arg_get_lit(ctx, 4);
|
||||||
|
bool pattern2b = arg_get_lit(ctx, 5);
|
||||||
|
|
||||||
|
if (pattern1b && pattern2b) {
|
||||||
|
PrintAndLogEx(ERR, "Pattern search mode must be 2-byte or 1-byte only.");
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dict_filenamelen && (pattern1b || pattern2b)) {
|
||||||
|
PrintAndLogEx(ERR, "Pattern search mode and dictionary mode can't be used in one command.");
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t startPattern = 0x0000;
|
||||||
|
uint8_t vpattern[2];
|
||||||
|
int vpatternlen = 0;
|
||||||
|
CLIGetHexWithReturn(ctx, 6, vpattern, &vpatternlen);
|
||||||
|
if (vpatternlen > 0) {
|
||||||
|
if (vpatternlen <= 2) {
|
||||||
|
startPattern = (vpattern[0] << 8) + vpattern[1];
|
||||||
|
} else {
|
||||||
|
PrintAndLogEx(ERR, "Pattern must be 2-byte length.");
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
if (!pattern2b)
|
||||||
|
PrintAndLogEx(WARNING, "Pattern entered, but search mode not is 2-byte search.");
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t jsonname[250] = {0};
|
||||||
|
int jsonnamelen = 0;
|
||||||
|
if (CLIParamStrToBuf(arg_get_str(ctx, 7), jsonname, sizeof(jsonname), &jsonnamelen)) {
|
||||||
|
PrintAndLogEx(ERR, "Invalid json name.");
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
jsonname[jsonnamelen] = 0;
|
||||||
|
|
||||||
|
bool verbose = arg_get_lit(ctx, 8);
|
||||||
|
|
||||||
|
// Get KDF input
|
||||||
|
uint8_t kdfInput[31] = {0};
|
||||||
|
int kdfInputLen = 0;
|
||||||
|
uint8_t cmdKDFAlgo = arg_get_int_def(ctx, 9, 0);
|
||||||
|
CLIGetHexWithReturn(ctx, 10, kdfInput, &kdfInputLen);
|
||||||
|
*/
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// {"getappnames", CmdHF14ADesGetAppNames, IfPm3Iso14443a, "Get Applications list"},
|
||||||
|
static int CmdHF14ADesGetAppNames(const char *Cmd) {
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static command_t CommandTable[] = {
|
static command_t CommandTable[] = {
|
||||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||||
{"-----------", CmdHelp, IfPm3Iso14443a, "---------------------- " _CYAN_("general") " ----------------------"},
|
{"-----------", CmdHelp, IfPm3Iso14443a, "---------------------- " _CYAN_("general") " ----------------------"},
|
||||||
|
@ -5134,6 +5249,8 @@ static command_t CommandTable[] = {
|
||||||
{"createaid", CmdHF14ADesCreateApp, IfPm3Iso14443a, "Create Application ID"},
|
{"createaid", CmdHF14ADesCreateApp, IfPm3Iso14443a, "Create Application ID"},
|
||||||
{"deleteaid", CmdHF14ADesDeleteApp, IfPm3Iso14443a, "Delete Application ID"},
|
{"deleteaid", CmdHF14ADesDeleteApp, IfPm3Iso14443a, "Delete Application ID"},
|
||||||
{"selectaid", CmdHF14ADesSelectApp, IfPm3Iso14443a, "Select Application ID"},
|
{"selectaid", CmdHF14ADesSelectApp, IfPm3Iso14443a, "Select Application ID"},
|
||||||
|
{"getaids", CmdHF14ADesGetAIDs, IfPm3Iso14443a, "Get Application IDs list"},
|
||||||
|
{"getappnames", CmdHF14ADesGetAppNames, IfPm3Iso14443a, "Get Applications list"},
|
||||||
{"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("Files") " -----------------------"},
|
{"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("Files") " -----------------------"},
|
||||||
{"changevalue", CmdHF14ADesChangeValue, IfPm3Iso14443a, "Write value of a value file (credit/debit/clear)"},
|
{"changevalue", CmdHF14ADesChangeValue, IfPm3Iso14443a, "Write value of a value file (credit/debit/clear)"},
|
||||||
{"clearfile", CmdHF14ADesClearRecordFile, IfPm3Iso14443a, "Clear record File"},
|
{"clearfile", CmdHF14ADesClearRecordFile, IfPm3Iso14443a, "Clear record File"},
|
||||||
|
|
|
@ -51,6 +51,17 @@ 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 des_encrypt(void *out, const void *in, const void *key) {
|
void des_encrypt(void *out, const void *in, const void *key) {
|
||||||
|
|
|
@ -60,6 +60,8 @@ enum DESFIRE_CRYPTOALGO {
|
||||||
T_AES = 0x03
|
T_AES = 0x03
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int desfire_get_key_length(enum DESFIRE_CRYPTOALGO key_type);
|
||||||
|
|
||||||
enum DESFIRE_AUTH_SCHEME {
|
enum DESFIRE_AUTH_SCHEME {
|
||||||
AS_LEGACY,
|
AS_LEGACY,
|
||||||
AS_NEW
|
AS_NEW
|
||||||
|
|
236
client/src/mifare/desfirecore.c
Normal file
236
client/src/mifare/desfirecore.c
Normal file
|
@ -0,0 +1,236 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// 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
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Info from here and many other soursec from the internet
|
||||||
|
// https://github.com/revk/DESFireAES
|
||||||
|
// https://github.com/step21/desfire_rfid
|
||||||
|
// https://github.com/patsys/desfire-python/blob/master/Desfire/DESFire.py
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "desfirecore.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <util.h>
|
||||||
|
#include "ui.h"
|
||||||
|
#include "protocols.h"
|
||||||
|
#include "cmdhf14a.h"
|
||||||
|
#include "iso7816/apduinfo.h" // APDU manipulation / errorcodes
|
||||||
|
#include "iso7816/iso7816core.h" // APDU logging
|
||||||
|
#include "util_posix.h" // msleep
|
||||||
|
#include "mifare/desfire_crypto.h"
|
||||||
|
|
||||||
|
void DesfireClearContext(DesfireContext *ctx) {
|
||||||
|
ctx->keyNum = 0;
|
||||||
|
ctx->keyType = T_DES;
|
||||||
|
memset(ctx->key, 0, sizeof(ctx->key));
|
||||||
|
|
||||||
|
ctx->authChannel = DACNone;
|
||||||
|
ctx->cmdChannel = DCCNative;
|
||||||
|
ctx->commMode = DCMNone;
|
||||||
|
|
||||||
|
memset(ctx->sessionKeyMAC, 0, sizeof(ctx->sessionKeyMAC));
|
||||||
|
memset(ctx->sessionKeyEnc, 0, sizeof(ctx->sessionKeyEnc));
|
||||||
|
memset(ctx->lastIV, 0, sizeof(ctx->lastIV));
|
||||||
|
ctx->cntrTx = 0;
|
||||||
|
ctx->cntrRx = 0;
|
||||||
|
memset(ctx->TI, 0, sizeof(ctx->TI));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DesfireSetKey(DesfireContext *ctx, uint8_t keyNum, enum DESFIRE_CRYPTOALGO keyType, uint8_t *key) {
|
||||||
|
DesfireClearContext(ctx);
|
||||||
|
|
||||||
|
ctx->keyNum = keyNum;
|
||||||
|
ctx->keyType = keyType;
|
||||||
|
memcpy(ctx->key, key, desfire_get_key_length(keyType));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int DESFIRESendApdu(bool activate_field, sAPDU apdu, uint8_t *result, uint32_t max_result_len, uint32_t *result_len, uint16_t *sw) {
|
||||||
|
if (result_len) *result_len = 0;
|
||||||
|
if (sw) *sw = 0;
|
||||||
|
|
||||||
|
uint16_t isw = 0;
|
||||||
|
int res = 0;
|
||||||
|
|
||||||
|
if (activate_field) {
|
||||||
|
DropField();
|
||||||
|
msleep(50);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t data[APDU_RES_LEN] = {0};
|
||||||
|
|
||||||
|
// COMPUTE APDU
|
||||||
|
int datalen = 0;
|
||||||
|
if (APDUEncodeS(&apdu, false, 0x100, data, &datalen)) { // 100 == with Le
|
||||||
|
PrintAndLogEx(ERR, "APDU encoding error.");
|
||||||
|
return PM3_EAPDU_ENCODEFAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAPDULogging())
|
||||||
|
PrintAndLogEx(SUCCESS, ">>>> %s", sprint_hex(data, datalen));
|
||||||
|
|
||||||
|
res = ExchangeAPDU14a(data, datalen, activate_field, true, result, max_result_len, (int *)result_len);
|
||||||
|
if (res != PM3_SUCCESS) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAPDULogging())
|
||||||
|
PrintAndLogEx(SUCCESS, "<<<< %s", sprint_hex(result, *result_len));
|
||||||
|
|
||||||
|
if (*result_len < 2) {
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
*result_len -= 2;
|
||||||
|
isw = (result[*result_len] << 8) + result[*result_len + 1];
|
||||||
|
if (sw)
|
||||||
|
*sw = isw;
|
||||||
|
|
||||||
|
if (isw != 0x9000 &&
|
||||||
|
isw != DESFIRE_GET_ISO_STATUS(MFDES_S_OPERATION_OK) &&
|
||||||
|
isw != DESFIRE_GET_ISO_STATUS(MFDES_S_SIGNATURE) &&
|
||||||
|
isw != DESFIRE_GET_ISO_STATUS(MFDES_S_ADDITIONAL_FRAME) &&
|
||||||
|
isw != DESFIRE_GET_ISO_STATUS(MFDES_S_NO_CHANGES)) {
|
||||||
|
if (GetAPDULogging()) {
|
||||||
|
if (isw >> 8 == 0x61) {
|
||||||
|
PrintAndLogEx(ERR, "APDU chaining len: 0x%02x -->", isw & 0xff);
|
||||||
|
} else {
|
||||||
|
PrintAndLogEx(ERR, "APDU(%02x%02x) ERROR: [0x%4X] %s", apdu.CLA, apdu.INS, isw, GetAPDUCodeDescription(isw >> 8, isw & 0xff));
|
||||||
|
return PM3_EAPDU_FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return PM3_EAPDU_FAIL;
|
||||||
|
}
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int DesfireExchangeNative(bool activate_field, DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *resp, size_t *resplen, bool enable_chaining) {
|
||||||
|
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int DesfireExchangeISO(bool activate_field, DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *resp, size_t *resplen, bool enable_chaining) {
|
||||||
|
if (resplen)
|
||||||
|
*resplen = 0;
|
||||||
|
|
||||||
|
// TODO !!!
|
||||||
|
size_t splitbysize = 0;
|
||||||
|
|
||||||
|
uint16_t sw = 0;
|
||||||
|
uint8_t buf[255 * 5] = {0x00};
|
||||||
|
uint32_t buflen = 0;
|
||||||
|
uint32_t pos = 0;
|
||||||
|
uint32_t i = 1;
|
||||||
|
|
||||||
|
sAPDU apdu = {0};
|
||||||
|
apdu.CLA = MFDES_NATIVE_ISO7816_WRAP_CLA; //0x90
|
||||||
|
apdu.INS = cmd;
|
||||||
|
apdu.Lc = datalen;
|
||||||
|
apdu.P1 = 0;
|
||||||
|
apdu.P2 = 0;
|
||||||
|
apdu.data = data;
|
||||||
|
|
||||||
|
int res = DESFIRESendApdu(activate_field, apdu, buf, sizeof(buf), &buflen, &sw);
|
||||||
|
if (res != PM3_SUCCESS) {
|
||||||
|
//PrintAndLogEx(DEBUG, "error DESFIRESendApdu %s", GetErrorString(res, &sw));
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
if (resp)
|
||||||
|
memcpy(resp, buf, buflen);
|
||||||
|
|
||||||
|
pos += buflen;
|
||||||
|
if (!enable_chaining) {
|
||||||
|
if (sw == DESFIRE_GET_ISO_STATUS(MFDES_ADDITIONAL_FRAME)) {
|
||||||
|
if (resplen)
|
||||||
|
*resplen = pos;
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (sw == DESFIRE_GET_ISO_STATUS(MFDES_ADDITIONAL_FRAME)) {
|
||||||
|
apdu.CLA = MFDES_NATIVE_ISO7816_WRAP_CLA; //0x90
|
||||||
|
apdu.INS = MFDES_ADDITIONAL_FRAME; //0xAF
|
||||||
|
apdu.Lc = 0;
|
||||||
|
apdu.P1 = 0;
|
||||||
|
apdu.P2 = 0;
|
||||||
|
apdu.data = NULL;
|
||||||
|
|
||||||
|
res = DESFIRESendApdu(false, apdu, buf, sizeof(buf), &buflen, &sw);
|
||||||
|
if (res != PM3_SUCCESS) {
|
||||||
|
//PrintAndLogEx(DEBUG, "error DESFIRESendApdu %s", GetErrorString(res, &sw));
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resp != NULL) {
|
||||||
|
if (splitbysize) {
|
||||||
|
memcpy(&resp[i * splitbysize], buf, buflen);
|
||||||
|
i += 1;
|
||||||
|
} else {
|
||||||
|
memcpy(&resp[pos], buf, buflen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pos += buflen;
|
||||||
|
|
||||||
|
if (sw != DESFIRE_GET_ISO_STATUS(MFDES_ADDITIONAL_FRAME)) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resplen)
|
||||||
|
*resplen = (splitbysize) ? i : pos;
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DesfireExchangeEx(bool activate_field, DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *resp, size_t *resplen, bool enable_chaining) {
|
||||||
|
int res = PM3_SUCCESS;
|
||||||
|
|
||||||
|
switch(ctx->cmdChannel) {
|
||||||
|
case DCCNative:
|
||||||
|
res = DesfireExchangeNative(activate_field, ctx, cmd, data, datalen, resp, resplen, enable_chaining);
|
||||||
|
break;
|
||||||
|
case DCCNativeISO:
|
||||||
|
res = DesfireExchangeISO(activate_field, ctx, cmd, data, datalen, resp, resplen, enable_chaining);
|
||||||
|
break;
|
||||||
|
case DCCISO:
|
||||||
|
return PM3_EAPDU_FAIL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DesfireExchange(DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *resp, size_t *resplen) {
|
||||||
|
return DesfireExchangeEx(false, ctx, cmd, data, datalen, resp, resplen, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
int DesfireSelectAID(DesfireContext *ctx, uint8_t *aid1, uint8_t *aid2) {
|
||||||
|
if (aid1 == NULL)
|
||||||
|
return PM3_EINVARG;
|
||||||
|
|
||||||
|
uint8_t data[6] = {0};
|
||||||
|
memcpy(data, aid1, 3);
|
||||||
|
if (aid2 != NULL)
|
||||||
|
memcpy(&data[3], aid2, 3);
|
||||||
|
uint8_t resp[257] = {0};
|
||||||
|
size_t resplen = 0;
|
||||||
|
int res = DesfireExchangeEx(true, ctx, MFDES_SELECT_APPLICATION, data, (aid2 == NULL) ? 3 : 6, resp, &resplen, true);
|
||||||
|
if (res == PM3_SUCCESS && resplen != 0)
|
||||||
|
return PM3_ECARDEXCHANGE;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DesfireSelectAIDHex(DesfireContext *ctx, uint32_t aid1, bool select_two, uint32_t aid2) {
|
||||||
|
uint8_t data[6] = {0};
|
||||||
|
// TODO !!!!
|
||||||
|
data[0] = aid1 & 0xff;
|
||||||
|
data[1] = (aid1 >> 8) & 0xff;
|
||||||
|
data[2] = (aid1 >> 16) & 0xff;
|
||||||
|
return DesfireSelectAID(ctx, data, (select_two) ? &data[3] : NULL);
|
||||||
|
}
|
||||||
|
|
75
client/src/mifare/desfirecore.h
Normal file
75
client/src/mifare/desfirecore.h
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// 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 "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 {
|
||||||
|
DACNone,
|
||||||
|
DACd40,
|
||||||
|
DACEV1,
|
||||||
|
DACEV2
|
||||||
|
} DesfireAuthChannel;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
DCCNative,
|
||||||
|
DCCNativeISO,
|
||||||
|
DCCISO
|
||||||
|
} DesfireCommandChannel;
|
||||||
|
|
||||||
|
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
|
||||||
|
// KDF input
|
||||||
|
|
||||||
|
DesfireAuthChannel authChannel; // none/d40/ev1/ev2
|
||||||
|
DesfireCommandChannel cmdChannel; // native/nativeiso/iso
|
||||||
|
DesfireCommunicationMode commMode; // plain/mac/enc
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
void DesfireClearContext(DesfireContext *ctx);
|
||||||
|
void DesfireSetKey(DesfireContext *ctx, uint8_t keyNum, enum DESFIRE_CRYPTOALGO keyType, uint8_t *key);
|
||||||
|
|
||||||
|
int DesfireSelectAID(DesfireContext *ctx, uint8_t *aid1, uint8_t *aid2);
|
||||||
|
int DesfireSelectAIDHex(DesfireContext *ctx, uint32_t aid1, bool select_two, uint32_t aid2);
|
||||||
|
int DesfireExchange(DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *resp, size_t *resplen);
|
||||||
|
int DesfireExchangeEx(bool activate_field, DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *resp, size_t *resplen, bool enable_chaining);
|
||||||
|
|
||||||
|
|
||||||
|
#endif // __DESFIRECORE_H
|
|
@ -459,6 +459,7 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
|
||||||
#define MFDES_GET_FILE_SETTINGS 0xF5
|
#define MFDES_GET_FILE_SETTINGS 0xF5
|
||||||
#define MFDES_FORMAT_PICC 0xFC
|
#define MFDES_FORMAT_PICC 0xFC
|
||||||
#define MFDES_VERIFY_PC 0xFD
|
#define MFDES_VERIFY_PC 0xFD
|
||||||
|
#define MFDES_NATIVE_ISO7816_WRAP_CLA 0x90
|
||||||
|
|
||||||
// MIFARE DESFire status & error codes:
|
// MIFARE DESFire status & error codes:
|
||||||
#define MFDES_S_OPERATION_OK 0x00
|
#define MFDES_S_OPERATION_OK 0x00
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue