desfire channel sketch

This commit is contained in:
merlokk 2021-07-01 19:53:57 +03:00
commit 2fa6c4643e
8 changed files with 444 additions and 0 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

@ -572,6 +572,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

@ -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[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"},
{"-----------", CmdHelp, IfPm3Iso14443a, "---------------------- " _CYAN_("general") " ----------------------"},
@ -5134,6 +5249,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, "Get Application IDs list"},
{"getappnames", CmdHF14ADesGetAppNames, IfPm3Iso14443a, "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

@ -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) {

View file

@ -60,6 +60,8 @@ enum DESFIRE_CRYPTOALGO {
T_AES = 0x03
};
int desfire_get_key_length(enum DESFIRE_CRYPTOALGO key_type);
enum DESFIRE_AUTH_SCHEME {
AS_LEGACY,
AS_NEW

View 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);
}

View 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

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