mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-19 21:03:48 -07:00
Merge pull request #1357 from merlokk/desfire3
Desfire ev1/plain and ev1/mac
This commit is contained in:
commit
e2303a8bdc
10 changed files with 446 additions and 175 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/desfirecrypto.c
|
||||||
${PM3_ROOT}/client/src/mifare/desfiresecurechan.c
|
${PM3_ROOT}/client/src/mifare/desfiresecurechan.c
|
||||||
${PM3_ROOT}/client/src/mifare/desfirecore.c
|
${PM3_ROOT}/client/src/mifare/desfirecore.c
|
||||||
${PM3_ROOT}/client/src/uart/uart_posix.c
|
${PM3_ROOT}/client/src/uart/uart_posix.c
|
||||||
|
|
|
@ -589,6 +589,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/desfirecrypto.c \
|
||||||
mifare/desfirecore.c \
|
mifare/desfirecore.c \
|
||||||
mifare/desfiresecurechan.c \
|
mifare/desfiresecurechan.c \
|
||||||
mifare/mad.c \
|
mifare/mad.c \
|
||||||
|
|
|
@ -5217,6 +5217,8 @@ static int CmdHF14ADesGetAIDs(const char *Cmd) {
|
||||||
PrintAndLogEx(INFO, "---- " _CYAN_("AID list") " ----");
|
PrintAndLogEx(INFO, "---- " _CYAN_("AID list") " ----");
|
||||||
for (int i = 0; i < buflen; i += 3)
|
for (int i = 0; i < buflen; i += 3)
|
||||||
PrintAndLogEx(INFO, "AID: %06x", DesfireAIDByteToUint(&buf[i]));
|
PrintAndLogEx(INFO, "AID: %06x", DesfireAIDByteToUint(&buf[i]));
|
||||||
|
} else {
|
||||||
|
PrintAndLogEx(INFO, "There is no applications on the card");
|
||||||
}
|
}
|
||||||
|
|
||||||
DropField();
|
DropField();
|
||||||
|
@ -5302,12 +5304,15 @@ static int CmdHF14ADesGetAppNames(const char *Cmd) {
|
||||||
buf[i * 24 + 1 + 3], buf[i * 24 + 1 + 4],
|
buf[i * 24 + 1 + 3], buf[i * 24 + 1 + 4],
|
||||||
strlen((char *)&buf[i * 24 + 1 + 5]),
|
strlen((char *)&buf[i * 24 + 1 + 5]),
|
||||||
&buf[i * 24 + 1 + 5]);
|
&buf[i * 24 + 1 + 5]);
|
||||||
|
} else {
|
||||||
|
PrintAndLogEx(INFO, "There is no applications on the card");
|
||||||
}
|
}
|
||||||
|
|
||||||
DropField();
|
DropField();
|
||||||
return PM3_SUCCESS;
|
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") " ----------------------"},
|
||||||
|
@ -5340,6 +5345,8 @@ static command_t CommandTable[] = {
|
||||||
{"getvalue", CmdHF14ADesGetValueData, IfPm3Iso14443a, "Get value of file"},
|
{"getvalue", CmdHF14ADesGetValueData, IfPm3Iso14443a, "Get value of file"},
|
||||||
{"read", CmdHF14ADesReadData, IfPm3Iso14443a, "Read data from standard/backup/record file"},
|
{"read", CmdHF14ADesReadData, IfPm3Iso14443a, "Read data from standard/backup/record file"},
|
||||||
{"write", CmdHF14ADesWriteData, IfPm3Iso14443a, "Write data to standard/backup/record file"},
|
{"write", CmdHF14ADesWriteData, IfPm3Iso14443a, "Write data to standard/backup/record file"},
|
||||||
|
{"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("System") " -----------------------"},
|
||||||
|
// {"test", CmdHF14ADesTest, IfPm3Iso14443a, "Test crypto"},
|
||||||
{NULL, NULL, NULL, NULL}
|
{NULL, NULL, NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -25,10 +25,9 @@
|
||||||
#include "mifare.h" // structs
|
#include "mifare.h" // structs
|
||||||
#include "crc32.h"
|
#include "crc32.h"
|
||||||
#include "crypto/libpcrypto.h"
|
#include "crypto/libpcrypto.h"
|
||||||
|
#include "mifare/desfirecrypto.h"
|
||||||
|
|
||||||
|
|
||||||
#define MAX_CRYPTO_BLOCK_SIZE 16
|
|
||||||
#define DESFIRE_MAX_KEY_SIZE 24
|
|
||||||
/* Mifare DESFire EV1 Application crypto operations */
|
/* Mifare DESFire EV1 Application crypto operations */
|
||||||
#define APPLICATION_CRYPTO_DES 0x00
|
#define APPLICATION_CRYPTO_DES 0x00
|
||||||
#define APPLICATION_CRYPTO_3K3DES 0x40
|
#define APPLICATION_CRYPTO_3K3DES 0x40
|
||||||
|
@ -75,13 +74,6 @@ typedef enum {
|
||||||
/* Error code managed by the library */
|
/* Error code managed by the library */
|
||||||
#define CRYPTO_ERROR 0x01
|
#define CRYPTO_ERROR 0x01
|
||||||
|
|
||||||
enum DESFIRE_CRYPTOALGO {
|
|
||||||
T_DES = 0x00,
|
|
||||||
T_3DES = 0x01, //aka 2K3DES
|
|
||||||
T_3K3DES = 0x02,
|
|
||||||
T_AES = 0x03
|
|
||||||
};
|
|
||||||
|
|
||||||
int desfire_get_key_length(enum DESFIRE_CRYPTOALGO key_type);
|
int desfire_get_key_length(enum DESFIRE_CRYPTOALGO key_type);
|
||||||
size_t desfire_get_key_block_length(enum DESFIRE_CRYPTOALGO key_type);
|
size_t desfire_get_key_block_length(enum DESFIRE_CRYPTOALGO key_type);
|
||||||
|
|
||||||
|
|
|
@ -203,34 +203,6 @@ void DesfireAIDUintToByte(uint32_t aid, uint8_t *data) {
|
||||||
data[2] = (aid >> 16) & 0xff;
|
data[2] = (aid >> 16) & 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DesfireClearContext(DesfireContext *ctx) {
|
|
||||||
ctx->keyNum = 0;
|
|
||||||
ctx->keyType = T_DES;
|
|
||||||
memset(ctx->key, 0, sizeof(ctx->key));
|
|
||||||
|
|
||||||
ctx->secureChannel = DACNone;
|
|
||||||
ctx->cmdSet = DCCNative;
|
|
||||||
ctx->commMode = DCMNone;
|
|
||||||
|
|
||||||
ctx->kdfAlgo = 0;
|
|
||||||
ctx->kdfInputLen = 0;
|
|
||||||
memset(ctx->kdfInput, 0, sizeof(ctx->kdfInput));
|
|
||||||
|
|
||||||
DesfireClearSession(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DesfireClearSession(DesfireContext *ctx) {
|
|
||||||
ctx->secureChannel = DACNone; // here none - not authenticared
|
|
||||||
|
|
||||||
memset(ctx->IV, 0, sizeof(ctx->IV));
|
|
||||||
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 DesfirePrintContext(DesfireContext *ctx) {
|
void DesfirePrintContext(DesfireContext *ctx) {
|
||||||
PrintAndLogEx(INFO, "Key num: %d Key algo: %s Key[%d]: %s",
|
PrintAndLogEx(INFO, "Key num: %d Key algo: %s Key[%d]: %s",
|
||||||
ctx->keyNum,
|
ctx->keyNum,
|
||||||
|
@ -248,39 +220,18 @@ void DesfirePrintContext(DesfireContext *ctx) {
|
||||||
CLIGetOptionListStr(DesfireCommunicationModeOpts, ctx->commMode));
|
CLIGetOptionListStr(DesfireCommunicationModeOpts, ctx->commMode));
|
||||||
|
|
||||||
if (DesfireIsAuthenticated(ctx)) {
|
if (DesfireIsAuthenticated(ctx)) {
|
||||||
PrintAndLogEx(INFO, "Session key MAC [%d]: %s ENC: %s IV [%d]: %s",
|
PrintAndLogEx(INFO, "Session key MAC [%d]: %s ",
|
||||||
desfire_get_key_length(ctx->keyType),
|
desfire_get_key_length(ctx->keyType),
|
||||||
sprint_hex(ctx->sessionKeyMAC, desfire_get_key_length(ctx->keyType)),
|
sprint_hex(ctx->sessionKeyMAC, desfire_get_key_length(ctx->keyType)));
|
||||||
sprint_hex(ctx->sessionKeyEnc, desfire_get_key_length(ctx->keyType)),
|
PrintAndLogEx(INFO, " ENC: %s",
|
||||||
|
sprint_hex(ctx->sessionKeyEnc, desfire_get_key_length(ctx->keyType)));
|
||||||
|
PrintAndLogEx(INFO, " IV [%d]: %s",
|
||||||
desfire_get_key_block_length(ctx->keyType),
|
desfire_get_key_block_length(ctx->keyType),
|
||||||
sprint_hex(ctx->sessionKeyEnc, desfire_get_key_block_length(ctx->keyType)));
|
sprint_hex(ctx->IV, desfire_get_key_block_length(ctx->keyType)));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
|
|
||||||
void DesfireSetCommandSet(DesfireContext *ctx, DesfireCommandSet cmdSet) {
|
|
||||||
ctx->cmdSet = cmdSet;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DesfireSetCommMode(DesfireContext *ctx, DesfireCommunicationMode commMode) {
|
|
||||||
ctx->commMode = commMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DesfireSetKdf(DesfireContext *ctx, uint8_t kdfAlgo, uint8_t *kdfInput, uint8_t kdfInputLen) {
|
|
||||||
ctx->kdfAlgo = kdfAlgo;
|
|
||||||
ctx->kdfInputLen = kdfInputLen;
|
|
||||||
if (kdfInputLen)
|
|
||||||
memcpy(ctx->kdfInput, kdfInput, kdfInputLen);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int DESFIRESendApdu(bool activate_field, sAPDU apdu, uint8_t *result, uint32_t max_result_len, uint32_t *result_len, uint16_t *sw) {
|
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 (result_len) *result_len = 0;
|
||||||
if (sw) *sw = 0;
|
if (sw) *sw = 0;
|
||||||
|
@ -648,10 +599,6 @@ int DesfireSelectAIDHex(DesfireContext *ctx, uint32_t aid1, bool select_two, uin
|
||||||
return DesfireSelectAID(ctx, data, (select_two) ? &data[3] : NULL);
|
return DesfireSelectAID(ctx, data, (select_two) ? &data[3] : NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DesfireIsAuthenticated(DesfireContext *dctx) {
|
|
||||||
return dctx->secureChannel != DACNone;
|
|
||||||
}
|
|
||||||
|
|
||||||
int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel) {
|
int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel) {
|
||||||
// 3 different way to authenticate AUTH (CRC16) , AUTH_ISO (CRC32) , AUTH_AES (CRC32)
|
// 3 different way to authenticate AUTH (CRC16) , AUTH_ISO (CRC32) , AUTH_AES (CRC32)
|
||||||
// 4 different crypto arg1 DES, 3DES, 3K3DES, AES
|
// 4 different crypto arg1 DES, 3DES, 3K3DES, AES
|
||||||
|
@ -917,6 +864,7 @@ int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel
|
||||||
//memcpy(dctx->sessionKeyEnc, sesskey.data, desfire_get_key_length(dctx->keyType));
|
//memcpy(dctx->sessionKeyEnc, sesskey.data, desfire_get_key_length(dctx->keyType));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memset(dctx->IV, 0, DESFIRE_MAX_KEY_SIZE);
|
||||||
dctx->secureChannel = secureChannel;
|
dctx->secureChannel = secureChannel;
|
||||||
memcpy(dctx->sessionKeyMAC, dctx->sessionKeyEnc, desfire_get_key_length(dctx->keyType));
|
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, "sessionKeyEnc : %s", sprint_hex(dctx->sessionKeyEnc, desfire_get_key_length(dctx->keyType)));
|
||||||
|
@ -943,3 +891,30 @@ int DesfireGetDFList(DesfireContext *dctx, uint8_t *resp, size_t *resplen) {
|
||||||
return PM3_EAPDU_FAIL;
|
return PM3_EAPDU_FAIL;
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int DesfireCreateApplication(DesfireContext *dctx, uint8_t *appdata, size_t appdatalen) {
|
||||||
|
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);
|
||||||
|
if (res != PM3_SUCCESS)
|
||||||
|
return res;
|
||||||
|
if (respcode != MFDES_S_OPERATION_OK || resplen != 0)
|
||||||
|
return PM3_EAPDU_FAIL;
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DesfireDeleteApplication(DesfireContext *dctx, uint32_t aid) {
|
||||||
|
uint8_t respcode = 0xff;
|
||||||
|
uint8_t data[3] = {0};
|
||||||
|
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);
|
||||||
|
if (res != PM3_SUCCESS)
|
||||||
|
return res;
|
||||||
|
if (respcode != MFDES_S_OPERATION_OK || resplen != 0)
|
||||||
|
return PM3_EAPDU_FAIL;
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,78 +15,22 @@
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "cliparser.h"
|
#include "cliparser.h"
|
||||||
|
#include "mifare/desfirecrypto.h"
|
||||||
#include "mifare/desfire_crypto.h"
|
#include "mifare/desfire_crypto.h"
|
||||||
#include "mifare/mifare4.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 DesfireAlgoOpts[];
|
||||||
extern const CLIParserOption DesfireKDFAlgoOpts[];
|
extern const CLIParserOption DesfireKDFAlgoOpts[];
|
||||||
extern const CLIParserOption DesfireCommunicationModeOpts[];
|
extern const CLIParserOption DesfireCommunicationModeOpts[];
|
||||||
extern const CLIParserOption DesfireCommandSetOpts[];
|
extern const CLIParserOption DesfireCommandSetOpts[];
|
||||||
extern const CLIParserOption DesfireSecureChannelOpts[];
|
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);
|
const char *DesfireGetErrorString(int res, uint16_t *sw);
|
||||||
uint32_t DesfireAIDByteToUint(uint8_t *data);
|
uint32_t DesfireAIDByteToUint(uint8_t *data);
|
||||||
void DesfireAIDUintToByte(uint32_t aid, uint8_t *data);
|
void DesfireAIDUintToByte(uint32_t aid, uint8_t *data);
|
||||||
|
|
||||||
|
void DesfirePrintContext(DesfireContext *ctx);
|
||||||
|
|
||||||
int DesfireExchange(DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen);
|
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 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);
|
||||||
|
|
||||||
|
@ -94,10 +38,11 @@ int DesfireSelectAID(DesfireContext *ctx, uint8_t *aid1, uint8_t *aid2);
|
||||||
int DesfireSelectAIDHex(DesfireContext *ctx, uint32_t aid1, bool select_two, uint32_t aid2);
|
int DesfireSelectAIDHex(DesfireContext *ctx, uint32_t aid1, bool select_two, uint32_t aid2);
|
||||||
|
|
||||||
int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel);
|
int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel);
|
||||||
bool DesfireIsAuthenticated(DesfireContext *dctx);
|
|
||||||
|
|
||||||
int DesfireGetAIDList(DesfireContext *dctx, uint8_t *resp, size_t *resplen);
|
int DesfireGetAIDList(DesfireContext *dctx, uint8_t *resp, size_t *resplen);
|
||||||
int DesfireGetDFList(DesfireContext *dctx, uint8_t *resp, size_t *resplen);
|
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);
|
||||||
|
|
||||||
#endif // __DESFIRECORE_H
|
#endif // __DESFIRECORE_H
|
||||||
|
|
270
client/src/mifare/desfirecrypto.c
Normal file
270
client/src/mifare/desfirecrypto.c
Normal file
|
@ -0,0 +1,270 @@
|
||||||
|
/*-
|
||||||
|
* 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$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "desfirecrypto.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <util.h>
|
||||||
|
#include "ui.h"
|
||||||
|
#include "aes.h"
|
||||||
|
#include "des.h"
|
||||||
|
#include <mbedtls/cmac.h>
|
||||||
|
#include "crc.h"
|
||||||
|
#include "crc16.h" // crc16 ccitt
|
||||||
|
#include "crc32.h"
|
||||||
|
#include "commonutil.h"
|
||||||
|
#include "mifare/desfire_crypto.h"
|
||||||
|
|
||||||
|
void DesfireClearContext(DesfireContext *ctx) {
|
||||||
|
ctx->keyNum = 0;
|
||||||
|
ctx->keyType = T_DES;
|
||||||
|
memset(ctx->key, 0, sizeof(ctx->key));
|
||||||
|
|
||||||
|
ctx->secureChannel = DACNone;
|
||||||
|
ctx->cmdSet = DCCNative;
|
||||||
|
ctx->commMode = DCMNone;
|
||||||
|
|
||||||
|
ctx->kdfAlgo = 0;
|
||||||
|
ctx->kdfInputLen = 0;
|
||||||
|
memset(ctx->kdfInput, 0, sizeof(ctx->kdfInput));
|
||||||
|
|
||||||
|
DesfireClearSession(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DesfireClearSession(DesfireContext *ctx) {
|
||||||
|
ctx->secureChannel = DACNone; // here none - not authenticared
|
||||||
|
|
||||||
|
memset(ctx->IV, 0, sizeof(ctx->IV));
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DesfireSetCommandSet(DesfireContext *ctx, DesfireCommandSet cmdSet) {
|
||||||
|
ctx->cmdSet = cmdSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DesfireSetCommMode(DesfireContext *ctx, DesfireCommunicationMode commMode) {
|
||||||
|
ctx->commMode = commMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DesfireSetKdf(DesfireContext *ctx, uint8_t kdfAlgo, uint8_t *kdfInput, uint8_t kdfInputLen) {
|
||||||
|
ctx->kdfAlgo = kdfAlgo;
|
||||||
|
ctx->kdfInputLen = kdfInputLen;
|
||||||
|
if (kdfInputLen)
|
||||||
|
memcpy(ctx->kdfInput, kdfInput, kdfInputLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DesfireIsAuthenticated(DesfireContext *dctx) {
|
||||||
|
return dctx->secureChannel != DACNone;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t DesfireGetMACLength(DesfireContext *ctx) {
|
||||||
|
size_t mac_length = MAC_LENGTH;
|
||||||
|
switch (ctx->secureChannel) {
|
||||||
|
case DACNone:
|
||||||
|
mac_length = 0;
|
||||||
|
break;
|
||||||
|
case DACd40:
|
||||||
|
mac_length = 4;
|
||||||
|
break;
|
||||||
|
case DACEV1:
|
||||||
|
mac_length = 8;
|
||||||
|
break;
|
||||||
|
case DACEV2:
|
||||||
|
mac_length = 8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return mac_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DesfireCryptoEncDecSingleBlock(uint8_t *key, DesfireCryptoAlgorythm keyType, uint8_t *data, uint8_t *dstdata, uint8_t *ivect, bool dir_to_send, bool encode) {
|
||||||
|
size_t block_size = desfire_get_key_block_length(keyType);
|
||||||
|
uint8_t sdata[MAX_CRYPTO_BLOCK_SIZE] = {0};
|
||||||
|
memcpy(sdata, data, block_size);
|
||||||
|
if (dir_to_send) {
|
||||||
|
bin_xor(sdata, ivect, block_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t edata[MAX_CRYPTO_BLOCK_SIZE] = {0};
|
||||||
|
|
||||||
|
switch (keyType) {
|
||||||
|
case T_DES:
|
||||||
|
if (encode)
|
||||||
|
des_encrypt(edata, sdata, key);
|
||||||
|
else
|
||||||
|
des_decrypt(edata, sdata, key);
|
||||||
|
break;
|
||||||
|
case T_3DES:
|
||||||
|
if (encode) {
|
||||||
|
mbedtls_des3_context ctx3;
|
||||||
|
mbedtls_des3_set2key_enc(&ctx3, key);
|
||||||
|
mbedtls_des3_crypt_ecb(&ctx3, sdata, edata);
|
||||||
|
} else {
|
||||||
|
mbedtls_des3_context ctx3;
|
||||||
|
mbedtls_des3_set2key_dec(&ctx3, key);
|
||||||
|
mbedtls_des3_crypt_ecb(&ctx3, sdata, edata);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case T_3K3DES:
|
||||||
|
if (encode) {
|
||||||
|
mbedtls_des3_context ctx3;
|
||||||
|
mbedtls_des3_set3key_enc(&ctx3, key);
|
||||||
|
mbedtls_des3_crypt_ecb(&ctx3, sdata, edata);
|
||||||
|
} else {
|
||||||
|
mbedtls_des3_context ctx3;
|
||||||
|
mbedtls_des3_set3key_dec(&ctx3, key);
|
||||||
|
mbedtls_des3_crypt_ecb(&ctx3, sdata, edata);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case T_AES:
|
||||||
|
if (encode) {
|
||||||
|
mbedtls_aes_context actx;
|
||||||
|
mbedtls_aes_init(&actx);
|
||||||
|
mbedtls_aes_setkey_enc(&actx, key, 128);
|
||||||
|
mbedtls_aes_crypt_ecb(&actx, MBEDTLS_AES_ENCRYPT, sdata, edata);
|
||||||
|
mbedtls_aes_free(&actx);
|
||||||
|
} else {
|
||||||
|
mbedtls_aes_context actx;
|
||||||
|
mbedtls_aes_init(&actx);
|
||||||
|
mbedtls_aes_setkey_dec(&actx, key, 128);
|
||||||
|
mbedtls_aes_crypt_ecb(&actx, MBEDTLS_AES_DECRYPT, sdata, edata);
|
||||||
|
mbedtls_aes_free(&actx);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(dstdata, edata, block_size);
|
||||||
|
|
||||||
|
if (dir_to_send) {
|
||||||
|
memcpy(ivect, edata, block_size);
|
||||||
|
} else {
|
||||||
|
memcpy(ivect, data, block_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DesfireCryptoEncDecEx(DesfireContext *ctx, bool use_session_key, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool encode, uint8_t *iv) {
|
||||||
|
uint8_t data[1024] = {0};
|
||||||
|
uint8_t xiv[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0};
|
||||||
|
|
||||||
|
if (ctx->secureChannel == DACd40)
|
||||||
|
memset(ctx->IV, 0, DESFIRE_MAX_CRYPTO_BLOCK_SIZE);
|
||||||
|
|
||||||
|
size_t block_size = desfire_get_key_block_length(ctx->keyType);
|
||||||
|
|
||||||
|
if (iv == NULL)
|
||||||
|
memcpy(xiv, ctx->IV, block_size);
|
||||||
|
else
|
||||||
|
memcpy(xiv, iv, block_size);
|
||||||
|
|
||||||
|
size_t offset = 0;
|
||||||
|
while (offset < srcdatalen) {
|
||||||
|
if (use_session_key)
|
||||||
|
DesfireCryptoEncDecSingleBlock(ctx->sessionKeyMAC, ctx->keyType, srcdata + offset, data, xiv, encode, encode);
|
||||||
|
else
|
||||||
|
DesfireCryptoEncDecSingleBlock(ctx->key, ctx->keyType, srcdata + offset, data, xiv, encode, encode);
|
||||||
|
offset += block_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iv == NULL)
|
||||||
|
memcpy(ctx->IV, xiv, block_size);
|
||||||
|
else
|
||||||
|
memcpy(iv, xiv, block_size);
|
||||||
|
|
||||||
|
if (dstdata)
|
||||||
|
memcpy(dstdata, data, srcdatalen);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DesfireCryptoEncDec(DesfireContext *ctx, bool use_session_key, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool encode) {
|
||||||
|
DesfireCryptoEncDecEx(ctx, use_session_key, srcdata, srcdatalen, dstdata, encode, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DesfireCMACGenerateSubkeys(DesfireContext *ctx, uint8_t *sk1, uint8_t *sk2) {
|
||||||
|
int kbs = desfire_get_key_block_length(ctx->keyType);
|
||||||
|
const uint8_t R = (kbs == 8) ? 0x1B : 0x87;
|
||||||
|
|
||||||
|
uint8_t l[kbs];
|
||||||
|
memset(l, 0, kbs);
|
||||||
|
|
||||||
|
uint8_t ivect[kbs];
|
||||||
|
memset(ivect, 0, kbs);
|
||||||
|
|
||||||
|
DesfireCryptoEncDecEx(ctx, true, l, kbs, l, true, ivect);
|
||||||
|
|
||||||
|
bool txor = false;
|
||||||
|
|
||||||
|
// Used to compute CMAC on complete blocks
|
||||||
|
memcpy(sk1, l, kbs);
|
||||||
|
txor = l[0] & 0x80;
|
||||||
|
lsl(sk1, kbs);
|
||||||
|
if (txor) {
|
||||||
|
sk1[kbs - 1] ^= R;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used to compute CMAC on the last block if non-complete
|
||||||
|
memcpy(sk2, sk1, kbs);
|
||||||
|
txor = sk1[0] & 0x80;
|
||||||
|
lsl(sk2, kbs);
|
||||||
|
if (txor) {
|
||||||
|
sk2[kbs - 1] ^= R;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DesfireCryptoCMAC(DesfireContext *ctx, uint8_t *data, size_t len, uint8_t *cmac) {
|
||||||
|
int kbs = desfire_get_key_block_length(ctx->keyType);
|
||||||
|
if (kbs == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint8_t buffer[padded_data_length(len, kbs)];
|
||||||
|
memset(buffer, 0, sizeof(buffer));
|
||||||
|
|
||||||
|
uint8_t sk1[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0};
|
||||||
|
uint8_t sk2[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0};
|
||||||
|
DesfireCMACGenerateSubkeys(ctx, sk1, sk2);
|
||||||
|
|
||||||
|
memcpy(buffer, data, len);
|
||||||
|
|
||||||
|
if ((!len) || (len % kbs)) {
|
||||||
|
buffer[len++] = 0x80;
|
||||||
|
while (len % kbs) {
|
||||||
|
buffer[len++] = 0x00;
|
||||||
|
}
|
||||||
|
bin_xor(buffer + len - kbs, sk2, kbs);
|
||||||
|
} else {
|
||||||
|
bin_xor(buffer + len - kbs, sk1, kbs);
|
||||||
|
}
|
||||||
|
|
||||||
|
DesfireCryptoEncDec(ctx, true, buffer, len, NULL, true);
|
||||||
|
|
||||||
|
memcpy(cmac, ctx->IV, kbs);
|
||||||
|
}
|
||||||
|
|
102
client/src/mifare/desfirecrypto.h
Normal file
102
client/src/mifare/desfirecrypto.h
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
/*-
|
||||||
|
* 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 __DESFIRECRYPTO_H
|
||||||
|
#define __DESFIRECRYPTO_H
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "mifare/mifare4.h"
|
||||||
|
|
||||||
|
#define MAX_CRYPTO_BLOCK_SIZE 16
|
||||||
|
#define DESFIRE_MAX_CRYPTO_BLOCK_SIZE 16
|
||||||
|
#define DESFIRE_MAX_KEY_SIZE 24
|
||||||
|
|
||||||
|
#define DESFIRE_GET_ISO_STATUS(x) ( ((uint16_t)(0x91<<8)) + (uint16_t)x )
|
||||||
|
|
||||||
|
enum DESFIRE_CRYPTOALGO {
|
||||||
|
T_DES = 0x00,
|
||||||
|
T_3DES = 0x01, //aka 2K3DES
|
||||||
|
T_3K3DES = 0x02,
|
||||||
|
T_AES = 0x03
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
DesfireCryptoAlgorythm keyType; // des/2tdea/3tdea/aes
|
||||||
|
uint8_t key[DESFIRE_MAX_KEY_SIZE];
|
||||||
|
|
||||||
|
// 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[DESFIRE_MAX_KEY_SIZE];
|
||||||
|
uint8_t sessionKeyMAC[DESFIRE_MAX_KEY_SIZE];
|
||||||
|
uint8_t sessionKeyEnc[DESFIRE_MAX_KEY_SIZE]; // look at mifare4.h - mf4Session_t
|
||||||
|
uint8_t lastIV[DESFIRE_MAX_KEY_SIZE];
|
||||||
|
//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 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);
|
||||||
|
bool DesfireIsAuthenticated(DesfireContext *dctx);
|
||||||
|
size_t DesfireGetMACLength(DesfireContext *ctx);
|
||||||
|
|
||||||
|
|
||||||
|
void DesfireCryptoEncDec(DesfireContext *ctx, bool use_session_key, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool encode);
|
||||||
|
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);
|
||||||
|
|
||||||
|
|
||||||
|
#endif // __DESFIRECRYPTO_H
|
|
@ -22,42 +22,6 @@
|
||||||
#include "commonutil.h"
|
#include "commonutil.h"
|
||||||
#include "mifare/desfire_crypto.h"
|
#include "mifare/desfire_crypto.h"
|
||||||
|
|
||||||
void DesfireCryptoEncDec(DesfireContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool encode) {
|
|
||||||
uint8_t data[1024] = {0};
|
|
||||||
|
|
||||||
switch (ctx->keyType) {
|
|
||||||
case T_DES:
|
|
||||||
if (ctx->secureChannel == DACd40) {
|
|
||||||
if (encode)
|
|
||||||
des_encrypt_ecb(data, srcdata, srcdatalen, ctx->key);
|
|
||||||
else
|
|
||||||
des_decrypt_ecb(data, srcdata, srcdatalen, ctx->key);
|
|
||||||
}
|
|
||||||
if (ctx->secureChannel == DACEV1) {
|
|
||||||
if (encode)
|
|
||||||
des_encrypt_cbc(data, srcdata, srcdatalen, ctx->key, ctx->IV);
|
|
||||||
else
|
|
||||||
des_decrypt_cbc(data, srcdata, srcdatalen, ctx->key, ctx->IV);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dstdata)
|
|
||||||
memcpy(dstdata, data, srcdatalen);
|
|
||||||
break;
|
|
||||||
case T_3DES:
|
|
||||||
break;
|
|
||||||
case T_3K3DES:
|
|
||||||
break;
|
|
||||||
case T_AES:
|
|
||||||
if (encode)
|
|
||||||
aes_encode(ctx->IV, ctx->key, srcdata, data, srcdatalen);
|
|
||||||
else
|
|
||||||
aes_decode(ctx->IV, ctx->key, srcdata, data, srcdatalen);
|
|
||||||
if (dstdata)
|
|
||||||
memcpy(dstdata, data, srcdatalen);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void DesfireSecureChannelEncodeD40(DesfireContext *ctx, uint8_t cmd, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen) {
|
static void DesfireSecureChannelEncodeD40(DesfireContext *ctx, uint8_t cmd, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen) {
|
||||||
memcpy(dstdata, srcdata, srcdatalen);
|
memcpy(dstdata, srcdata, srcdatalen);
|
||||||
*dstdatalen = srcdatalen;
|
*dstdatalen = srcdatalen;
|
||||||
|
@ -76,7 +40,7 @@ static void DesfireSecureChannelEncodeD40(DesfireContext *ctx, uint8_t cmd, uint
|
||||||
|
|
||||||
rlen = padded_data_length(srcdatalen, desfire_get_key_block_length(ctx->keyType));
|
rlen = padded_data_length(srcdatalen, desfire_get_key_block_length(ctx->keyType));
|
||||||
memcpy(data, srcdata, srcdatalen);
|
memcpy(data, srcdata, srcdatalen);
|
||||||
DesfireCryptoEncDec(ctx, data, rlen, NULL, true);
|
DesfireCryptoEncDec(ctx, true, data, rlen, NULL, true);
|
||||||
memcpy(dstdata, srcdata, srcdatalen);
|
memcpy(dstdata, srcdata, srcdatalen);
|
||||||
memcpy(&dstdata[srcdatalen], ctx->IV, 4);
|
memcpy(&dstdata[srcdatalen], ctx->IV, 4);
|
||||||
*dstdatalen = rlen;
|
*dstdatalen = rlen;
|
||||||
|
@ -85,7 +49,7 @@ static void DesfireSecureChannelEncodeD40(DesfireContext *ctx, uint8_t cmd, uint
|
||||||
rlen = padded_data_length(srcdatalen + 2, desfire_get_key_block_length(ctx->keyType)); // 2 - crc16
|
rlen = padded_data_length(srcdatalen + 2, desfire_get_key_block_length(ctx->keyType)); // 2 - crc16
|
||||||
memcpy(data, srcdata, srcdatalen);
|
memcpy(data, srcdata, srcdatalen);
|
||||||
compute_crc(CRC_14443_A, data, srcdatalen, &data[srcdatalen], &data[srcdatalen + 1]);
|
compute_crc(CRC_14443_A, data, srcdatalen, &data[srcdatalen], &data[srcdatalen + 1]);
|
||||||
DesfireCryptoEncDec(ctx, data, rlen, dstdata, true);
|
DesfireCryptoEncDec(ctx, true, data, rlen, dstdata, true);
|
||||||
*dstdatalen = rlen;
|
*dstdatalen = rlen;
|
||||||
break;
|
break;
|
||||||
case DCMNone:
|
case DCMNone:
|
||||||
|
@ -95,7 +59,6 @@ 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) {
|
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};
|
uint8_t data[1024] = {0};
|
||||||
size_t rlen = 0;
|
|
||||||
|
|
||||||
memcpy(dstdata, srcdata, srcdatalen);
|
memcpy(dstdata, srcdata, srcdatalen);
|
||||||
*dstdatalen = srcdatalen;
|
*dstdatalen = srcdatalen;
|
||||||
|
@ -104,14 +67,14 @@ static void DesfireSecureChannelEncodeEV1(DesfireContext *ctx, uint8_t cmd, uint
|
||||||
case DCMPlain:
|
case DCMPlain:
|
||||||
case DCMMACed:
|
case DCMMACed:
|
||||||
data[0] = cmd;
|
data[0] = cmd;
|
||||||
rlen = padded_data_length(srcdatalen + 1, desfire_get_key_block_length(ctx->keyType));
|
|
||||||
memcpy(&data[1], srcdata, srcdatalen);
|
memcpy(&data[1], srcdata, srcdatalen);
|
||||||
DesfireCryptoEncDec(ctx, data, rlen, NULL, true);
|
uint8_t cmac[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0};
|
||||||
|
DesfireCryptoCMAC(ctx, data, srcdatalen + 1, cmac);
|
||||||
|
|
||||||
memcpy(dstdata, srcdata, srcdatalen);
|
memcpy(dstdata, srcdata, srcdatalen);
|
||||||
if (srcdatalen != 0 && ctx->commMode == DCMMACed) {
|
if (srcdatalen != 0 && ctx->commMode == DCMMACed) {
|
||||||
memcpy(&dstdata[srcdatalen], ctx->IV, 4);
|
memcpy(&dstdata[srcdatalen], cmac, DesfireGetMACLength(ctx));
|
||||||
*dstdatalen = rlen;
|
*dstdatalen = srcdatalen + DesfireGetMACLength(ctx);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DCMEncrypted:
|
case DCMEncrypted:
|
||||||
|
@ -157,14 +120,30 @@ static void DesfireSecureChannelDecodeD40(DesfireContext *ctx, uint8_t *srcdata,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DesfireSecureChannelDecodeEV1(DesfireContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t respcode, uint8_t *dstdata, size_t *dstdatalen) {
|
static void DesfireSecureChannelDecodeEV1(DesfireContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t respcode, uint8_t *dstdata, size_t *dstdatalen) {
|
||||||
|
uint8_t data[1024] = {0};
|
||||||
|
|
||||||
memcpy(dstdata, srcdata, srcdatalen);
|
memcpy(dstdata, srcdata, srcdatalen);
|
||||||
*dstdatalen = srcdatalen;
|
*dstdatalen = srcdatalen;
|
||||||
|
|
||||||
switch (ctx->commMode) {
|
switch (ctx->commMode) {
|
||||||
case DCMPlain:
|
case DCMPlain:
|
||||||
case DCMMACed:
|
case DCMMACed:
|
||||||
memcpy(dstdata, srcdata, srcdatalen - 8);
|
if (srcdatalen < DesfireGetMACLength(ctx))
|
||||||
*dstdatalen = srcdatalen - 8;
|
break;
|
||||||
|
|
||||||
|
memcpy(dstdata, srcdata, srcdatalen - DesfireGetMACLength(ctx));
|
||||||
|
*dstdatalen = srcdatalen - DesfireGetMACLength(ctx);
|
||||||
|
|
||||||
|
memcpy(data, srcdata, *dstdatalen);
|
||||||
|
data[*dstdatalen] = respcode;
|
||||||
|
|
||||||
|
uint8_t cmac[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0};
|
||||||
|
DesfireCryptoCMAC(ctx, data, *dstdatalen + 1, cmac);
|
||||||
|
if (memcmp(&srcdata[*dstdatalen], cmac, DesfireGetMACLength(ctx)) != 0) {
|
||||||
|
PrintAndLogEx(WARNING, "Received MAC is not match with calculated");
|
||||||
|
PrintAndLogEx(INFO, " received MAC: %s", sprint_hex(&srcdata[*dstdatalen], desfire_get_key_block_length(ctx->keyType)));
|
||||||
|
PrintAndLogEx(INFO, " calculated MAC: %s", sprint_hex(cmac, desfire_get_key_block_length(ctx->keyType)));
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case DCMEncrypted:
|
case DCMEncrypted:
|
||||||
|
|
|
@ -15,11 +15,10 @@
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "mifare/desfirecore.h"
|
#include "mifare/desfirecore.h"
|
||||||
|
#include "mifare/desfirecrypto.h"
|
||||||
#include "mifare/desfire_crypto.h"
|
#include "mifare/desfire_crypto.h"
|
||||||
#include "mifare/mifare4.h"
|
#include "mifare/mifare4.h"
|
||||||
|
|
||||||
void DesfireCryptoEncDec(DesfireContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool encode);
|
|
||||||
|
|
||||||
void DesfireSecureChannelEncode(DesfireContext *ctx, uint8_t cmd, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen);
|
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);
|
void DesfireSecureChannelDecode(DesfireContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t respcode, uint8_t *dstdata, size_t *dstdatalen);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue