mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 05:43:48 -07:00
Merge pull request #1407 from merlokk/esf_isoauth
Desfire iso authentication
This commit is contained in:
commit
d490485920
6 changed files with 284 additions and 16 deletions
|
@ -3053,6 +3053,7 @@ static int CmdHF14ADesSelectApp(const char *Cmd) {
|
|||
arg_str0("c", "ccset", "<native/niso/iso>", "Communicaton command set: native/niso/iso"),
|
||||
arg_str0("s", "schann", "<d40/ev1/ev2>", "Secure channel: d40/ev1/ev2"),
|
||||
arg_str0(NULL, "aid", "<app id hex>", "Application ID of application for some parameters (3 hex bytes, big endian)"),
|
||||
arg_str0(NULL, "dfname", "<df name str>", "Application DF Name (string, max 16 chars). Selects application via ISO SELECT command"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
@ -3068,19 +3069,45 @@ static int CmdHF14ADesSelectApp(const char *Cmd) {
|
|||
CLIParserFree(ctx);
|
||||
return res;
|
||||
}
|
||||
|
||||
uint8_t dfname[32] = {0};
|
||||
int dfnamelen = 16;
|
||||
CLIGetStrWithReturn(ctx, 12, dfname, &dfnamelen);
|
||||
|
||||
SetAPDULogging(APDULogging);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
res = DesfireSelectAndAuthenticateEx(&dctx, securechann, appid, true, verbose);
|
||||
if (res != PM3_SUCCESS) {
|
||||
DropField();
|
||||
PrintAndLogEx(FAILED, "Select application 0x%06x " _RED_("failed") " ", appid);
|
||||
return res;
|
||||
if (dctx.cmdSet == DCCISO || dfnamelen > 0) {
|
||||
uint8_t resp[250] = {0};
|
||||
size_t resplen = 0;
|
||||
if (dfnamelen > 0)
|
||||
res = DesfireISOSelectDF(&dctx, (char *)dfname, resp, &resplen);
|
||||
else
|
||||
res = DesfireISOSelect(&dctx, ISSMFDFEF, NULL, 0, resp, &resplen);
|
||||
if (res != PM3_SUCCESS) {
|
||||
DropField();
|
||||
PrintAndLogEx(FAILED, "ISO Select application `%s` " _RED_("failed"), (char *)dfname);
|
||||
return res;
|
||||
}
|
||||
|
||||
if (resplen > 0)
|
||||
PrintAndLogEx(FAILED, "Application " _CYAN_("FCI template") " [%zu]%s", resplen, sprint_hex(resp, resplen));
|
||||
|
||||
if (dfnamelen > 0)
|
||||
PrintAndLogEx(SUCCESS, "Application `%s` selected " _GREEN_("succesfully"), (char *)dfname);
|
||||
else
|
||||
PrintAndLogEx(SUCCESS, "PICC MF selected " _GREEN_("succesfully"));
|
||||
} else {
|
||||
res = DesfireSelectAndAuthenticateEx(&dctx, securechann, appid, true, verbose);
|
||||
if (res != PM3_SUCCESS) {
|
||||
DropField();
|
||||
PrintAndLogEx(FAILED, "Select application 0x%06x " _RED_("failed") " ", appid);
|
||||
return res;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Application 0x%06x selected " _GREEN_("succesfully") " ", appid);
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Application 0x%06x selected " _GREEN_("succesfully") " ", appid);
|
||||
|
||||
DropField();
|
||||
return res;
|
||||
}
|
||||
|
@ -6327,12 +6354,9 @@ int CmdHFMFDes(const char *Cmd) {
|
|||
|
||||
ISO/IEC 7816 Cmds
|
||||
-----------------
|
||||
'A4' Select
|
||||
'B0' Read Binary
|
||||
'D6' Update Binary
|
||||
'B2' Read Records
|
||||
'E2' Append Records
|
||||
'84' Get Challenge
|
||||
'88' Internal Authenticate
|
||||
'82' External Authenticate
|
||||
|
||||
*/
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
#define APDUCODE_TYPE_ERROR 3
|
||||
#define APDUCODE_TYPE_SECURITY 4
|
||||
|
||||
#define APDU_INCLUDE_LE_00 0x100
|
||||
|
||||
typedef struct {
|
||||
const char *ID;
|
||||
const uint8_t Type;
|
||||
|
|
|
@ -261,6 +261,22 @@ const char *DesfireAuthErrorToStr(int error) {
|
|||
return "Can't select application.";
|
||||
case 201:
|
||||
return "Authentication retured no error but channel not authenticated.";
|
||||
case 301:
|
||||
return "ISO Get challenge error.";
|
||||
case 302:
|
||||
return "ISO Get challenge returned wrong length.";
|
||||
case 303:
|
||||
return "Crypto encode piccrnd1 error.";
|
||||
case 304:
|
||||
return "External authenticate error.";
|
||||
case 305:
|
||||
return "Internal authenticate error.";
|
||||
case 306:
|
||||
return "Internal authenticate returned wrong length.";
|
||||
case 307:
|
||||
return "Crypto decode piccrnd2 error.";
|
||||
case 308:
|
||||
return "Random numbers dont match. Authentication failed.";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -277,6 +293,34 @@ void DesfireAIDUintToByte(uint32_t aid, uint8_t *data) {
|
|||
data[2] = (aid >> 16) & 0xff;
|
||||
}
|
||||
|
||||
static uint8_t DesfireKeyToISOKey(DesfireCryptoAlgorythm keytype) {
|
||||
switch (keytype) {
|
||||
case T_DES:
|
||||
return 0x02;
|
||||
case T_3DES:
|
||||
return 0x02;
|
||||
case T_3K3DES:
|
||||
return 0x04;
|
||||
case T_AES:
|
||||
return 0x09;
|
||||
}
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
static uint8_t DesfireGetRndLenForKey(DesfireCryptoAlgorythm keytype) {
|
||||
switch (keytype) {
|
||||
case T_DES:
|
||||
return 0x08;
|
||||
case T_3DES:
|
||||
return 0x08;
|
||||
case T_3K3DES:
|
||||
return 0x10;
|
||||
case T_AES:
|
||||
return 0x10;
|
||||
}
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
void DesfirePrintContext(DesfireContext *ctx) {
|
||||
PrintAndLogEx(INFO, "Key num: %d Key algo: %s Key[%d]: %s",
|
||||
ctx->keyNum,
|
||||
|
@ -311,7 +355,7 @@ void DesfirePrintContext(DesfireContext *ctx) {
|
|||
}
|
||||
}
|
||||
|
||||
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 DESFIRESendApduEx(bool activate_field, sAPDU apdu, uint16_t le, 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;
|
||||
|
||||
|
@ -327,7 +371,7 @@ static int DESFIRESendApdu(bool activate_field, sAPDU apdu, uint8_t *result, uin
|
|||
|
||||
// COMPUTE APDU
|
||||
int datalen = 0;
|
||||
if (APDUEncodeS(&apdu, false, 0x100, data, &datalen)) { // 100 == with Le
|
||||
if (APDUEncodeS(&apdu, false, le, data, &datalen)) { // 100 == with Le
|
||||
PrintAndLogEx(ERR, "APDU encoding error.");
|
||||
return PM3_EAPDU_ENCODEFAIL;
|
||||
}
|
||||
|
@ -370,6 +414,10 @@ static int DESFIRESendApdu(bool activate_field, sAPDU apdu, uint8_t *result, uin
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int DESFIRESendApdu(bool activate_field, sAPDU apdu, uint8_t *result, uint32_t max_result_len, uint32_t *result_len, uint16_t *sw) {
|
||||
return DESFIRESendApduEx(activate_field, apdu, APDU_INCLUDE_LE_00, result, max_result_len, result_len, sw);
|
||||
}
|
||||
|
||||
static int DESFIRESendRaw(bool activate_field, uint8_t *data, size_t datalen, uint8_t *result, uint32_t max_result_len, uint32_t *result_len, uint8_t *respcode) {
|
||||
*result_len = 0;
|
||||
if (respcode) *respcode = 0xff;
|
||||
|
@ -516,7 +564,7 @@ static int DesfireExchangeNative(bool activate_field, DesfireContext *ctx, uint8
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int DesfireExchangeISO(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) {
|
||||
static int DesfireExchangeISONative(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) {
|
||||
if (resplen)
|
||||
*resplen = 0;
|
||||
if (respcode)
|
||||
|
@ -622,6 +670,16 @@ static int DesfireExchangeISO(bool activate_field, DesfireContext *ctx, uint8_t
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int DesfireExchangeISO(bool activate_field, DesfireContext *ctx, sAPDU apdu, uint16_t le, uint8_t *resp, size_t *resplen, uint16_t *sw) {
|
||||
uint32_t rlen = 0;
|
||||
int res = DESFIRESendApduEx(activate_field, apdu, le, resp, 255, &rlen, sw);
|
||||
|
||||
if (res == PM3_SUCCESS)
|
||||
*resplen = rlen;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// move data from blockdata [format: <length, data><length, data>...] to single data block
|
||||
static void DesfireJoinBlockToBytes(uint8_t *blockdata, size_t blockdatacount, size_t blockdatasize, uint8_t *dstdata, size_t *dstdatalen) {
|
||||
*dstdatalen = 0;
|
||||
|
@ -665,7 +723,7 @@ int DesfireExchangeEx(bool activate_field, DesfireContext *ctx, uint8_t cmd, uin
|
|||
if (ctx->cmdSet == DCCNative)
|
||||
res = DesfireExchangeNative(activate_field, ctx, cmd, databuf, databuflen, respcode, databuf, &databuflen, enable_chaining, splitbysize);
|
||||
else
|
||||
res = DesfireExchangeISO(activate_field, ctx, cmd, databuf, databuflen, respcode, databuf, &databuflen, enable_chaining, splitbysize);
|
||||
res = DesfireExchangeISONative(activate_field, ctx, cmd, databuf, databuflen, respcode, databuf, &databuflen, enable_chaining, splitbysize);
|
||||
|
||||
if (splitbysize) {
|
||||
uint8_t sdata[250 * 5] = {0};
|
||||
|
@ -715,8 +773,12 @@ int DesfireSelectAID(DesfireContext *ctx, uint8_t *aid1, uint8_t *aid2) {
|
|||
if (respcode != MFDES_S_OPERATION_OK)
|
||||
return PM3_EAPDU_FAIL;
|
||||
|
||||
DesfireClearSession(ctx);
|
||||
ctx->appSelected = (aid1[0] != 0x00 || aid1[1] != 0x00 || aid1[2] != 0x00);
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -755,6 +817,14 @@ int DesfireSelectAIDHexNoFieldOn(DesfireContext *ctx, uint32_t aid) {
|
|||
int DesfireSelectAndAuthenticateEx(DesfireContext *dctx, DesfireSecureChannel secureChannel, uint32_t aid, bool noauth, bool verbose) {
|
||||
if (verbose)
|
||||
DesfirePrintContext(dctx);
|
||||
|
||||
bool isosw = false;
|
||||
if (dctx->cmdSet == DCCISO) {
|
||||
dctx->cmdSet = DCCNativeISO;
|
||||
isosw = true;
|
||||
if (verbose)
|
||||
PrintAndLogEx(INFO, "Switch to " _CYAN_("native") " for select");
|
||||
}
|
||||
|
||||
int res = DesfireSelectAIDHex(dctx, aid, false, 0);
|
||||
if (res != PM3_SUCCESS) {
|
||||
|
@ -763,6 +833,9 @@ int DesfireSelectAndAuthenticateEx(DesfireContext *dctx, DesfireSecureChannel se
|
|||
}
|
||||
if (verbose)
|
||||
PrintAndLogEx(INFO, "App %06x " _GREEN_("selected"), aid);
|
||||
|
||||
if (isosw)
|
||||
dctx->cmdSet = DCCISO;
|
||||
|
||||
if (!noauth) {
|
||||
res = DesfireAuthenticate(dctx, secureChannel, verbose);
|
||||
|
@ -1201,7 +1274,67 @@ static int DesfireAuthenticateEV2(DesfireContext *dctx, DesfireSecureChannel sec
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int DesfireAuthenticateISO(DesfireContext *dctx, DesfireSecureChannel secureChannel, bool verbose) {
|
||||
uint8_t rndlen = DesfireGetRndLenForKey(dctx->keyType);
|
||||
|
||||
uint8_t hostrnd[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16};
|
||||
uint8_t hostrnd2[] = {0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01};
|
||||
|
||||
uint8_t piccrnd[64];
|
||||
size_t xlen = 0;
|
||||
int res = DesfireISOGetChallenge(dctx, dctx->keyType, piccrnd, &xlen);
|
||||
if (res != PM3_SUCCESS)
|
||||
return 301;
|
||||
|
||||
if (xlen != rndlen)
|
||||
return 302;
|
||||
|
||||
uint8_t both[32] = {0};
|
||||
memcpy(both, hostrnd, rndlen);
|
||||
memcpy(&both[rndlen], piccrnd, rndlen);
|
||||
|
||||
// encode
|
||||
DesfireClearIV(dctx);
|
||||
DesfireCryptoEncDec(dctx, false, both, rndlen * 2, both, true); // error 303
|
||||
|
||||
// external authenticate
|
||||
res = DesfireISOExternalAuth(dctx, dctx->appSelected, dctx->keyNum, dctx->keyType, both);
|
||||
if (res != PM3_SUCCESS)
|
||||
return 304;
|
||||
|
||||
// internal authenticate
|
||||
uint8_t rnddata[64] = {0};
|
||||
xlen = 0;
|
||||
res = DesfireISOInternalAuth(dctx, dctx->appSelected, dctx->keyNum, dctx->keyType, hostrnd2, rnddata, &xlen);
|
||||
if (res != PM3_SUCCESS)
|
||||
return 305;
|
||||
|
||||
if (xlen != rndlen * 2)
|
||||
return 306;
|
||||
|
||||
// decode rnddata
|
||||
uint8_t piccrnd2[64] = {0};
|
||||
DesfireCryptoEncDec(dctx, false, rnddata, rndlen * 2, piccrnd2, false); // error 307
|
||||
|
||||
// check
|
||||
if (memcmp(hostrnd2, &piccrnd2[rndlen], rndlen) != 0)
|
||||
return 308;
|
||||
|
||||
DesfireGenSessionKeyEV1(hostrnd, piccrnd2, dctx->keyType, dctx->sessionKeyEnc);
|
||||
DesfireClearIV(dctx);
|
||||
memcpy(dctx->sessionKeyMAC, dctx->sessionKeyEnc, desfire_get_key_length(dctx->keyType));
|
||||
dctx->secureChannel = secureChannel;
|
||||
|
||||
if (verbose)
|
||||
PrintAndLogEx(INFO, "session key: %s", sprint_hex(dctx->sessionKeyEnc, desfire_get_key_length(dctx->keyType)));
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel, bool verbose) {
|
||||
if (dctx->cmdSet == DCCISO && secureChannel != DACEV2)
|
||||
return DesfireAuthenticateISO(dctx, secureChannel, verbose);
|
||||
|
||||
if (secureChannel == DACd40 || secureChannel == DACEV1)
|
||||
return DesfireAuthenticateEV1(dctx, secureChannel, verbose);
|
||||
|
||||
|
@ -1382,7 +1515,6 @@ int DesfireFillFileList(DesfireContext *dctx, FileListS FileList, size_t *filesc
|
|||
return res;
|
||||
}
|
||||
|
||||
|
||||
int DesfireCreateFile(DesfireContext *dctx, uint8_t ftype, uint8_t *fdata, size_t fdatalen, bool checklen) {
|
||||
const DesfireCreateFileCommandsS *rcmd = GetDesfireFileCmdRec(ftype);
|
||||
if (rcmd == NULL)
|
||||
|
@ -2087,3 +2219,64 @@ int DesfireSetConfiguration(DesfireContext *dctx, uint8_t paramid, uint8_t *para
|
|||
|
||||
return res;
|
||||
}
|
||||
|
||||
int DesfireISOSelect(DesfireContext *dctx, DesfireISOSelectControl cntr, uint8_t *data, uint8_t datalen, uint8_t *resp, size_t *resplen) {
|
||||
uint8_t xresp[250] = {0};
|
||||
size_t xresplen = 0;
|
||||
uint16_t sw = 0;
|
||||
int res = DesfireExchangeISO(true, dctx, (sAPDU) {0x00, ISO7816_SELECT_FILE, cntr, ((resp == NULL) ? 0x0C : 0x00), datalen, data}, APDU_INCLUDE_LE_00, xresp, &xresplen, &sw);
|
||||
if (res == PM3_SUCCESS && sw != 0x9000)
|
||||
return PM3_ESOFT;
|
||||
|
||||
if (resp != NULL && resplen != NULL) {
|
||||
*resplen = xresplen;
|
||||
memcpy(resp, xresp, xresplen);
|
||||
}
|
||||
|
||||
DesfireClearSession(dctx);
|
||||
dctx->appSelected = !( (cntr == ISSMFDFEF && datalen == 0) || (cntr == ISSEFByFileID && datalen == 2 && data[0] == 0 && data[1] == 0) );
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int DesfireISOSelectDF(DesfireContext *dctx, char *dfname, uint8_t *resp, size_t *resplen) {
|
||||
return DesfireISOSelect(dctx, ISSDFName, (uint8_t *)dfname, strnlen(dfname, 16), resp, resplen);
|
||||
}
|
||||
|
||||
int DesfireISOGetChallenge(DesfireContext *dctx, DesfireCryptoAlgorythm keytype, uint8_t *resp, size_t *resplen) {
|
||||
uint16_t sw = 0;
|
||||
int res = DesfireExchangeISO(false, dctx, (sAPDU) {0x00, ISO7816_GET_CHALLENGE, 0x00, 0x00, 0x00, NULL}, DesfireGetRndLenForKey(keytype), resp, resplen, &sw);
|
||||
if (res == PM3_SUCCESS && sw != 0x9000)
|
||||
return PM3_ESOFT;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int DesfireISOExternalAuth(DesfireContext *dctx, bool app_level, uint8_t keynum, DesfireCryptoAlgorythm keytype, uint8_t *data) {
|
||||
uint8_t p1 = DesfireKeyToISOKey(keytype);
|
||||
uint8_t p2 = ((app_level) ? 0x80 : 0x00) | keynum;
|
||||
|
||||
uint8_t resp[250] = {0};
|
||||
size_t resplen = 0;
|
||||
|
||||
uint16_t sw = 0;
|
||||
int res = DesfireExchangeISO(false, dctx, (sAPDU) {0x00, ISO7816_EXTERNAL_AUTHENTICATION, p1, p2, DesfireGetRndLenForKey(keytype) * 2, data}, 0, resp, &resplen, &sw);
|
||||
if (res == PM3_SUCCESS && sw != 0x9000)
|
||||
return PM3_ESOFT;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int DesfireISOInternalAuth(DesfireContext *dctx, bool app_level, uint8_t keynum, DesfireCryptoAlgorythm keytype, uint8_t *data, uint8_t *resp, size_t *resplen) {
|
||||
uint8_t keylen = DesfireGetRndLenForKey(keytype);
|
||||
uint8_t p1 = DesfireKeyToISOKey(keytype);
|
||||
uint8_t p2 = ((app_level) ? 0x80 : 0x00) | keynum;
|
||||
|
||||
uint16_t sw = 0;
|
||||
int res = DesfireExchangeISO(false, dctx, (sAPDU) {0x00, ISO7816_INTERNAL_AUTHENTICATION, p1, p2, keylen, data}, keylen * 2, resp, resplen, &sw);
|
||||
if (res == PM3_SUCCESS && sw != 0x9000)
|
||||
return PM3_ESOFT;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,15 @@
|
|||
|
||||
#define DESFIRE_TX_FRAME_MAX_LEN 54
|
||||
|
||||
enum DesfireISOSelectControlEnum {
|
||||
ISSMFDFEF = 0x00,
|
||||
ISSChildDF = 0x01,
|
||||
ISSEFByFileID = 0x02,
|
||||
ISSParentDF = 0x03,
|
||||
ISSDFName = 0x04
|
||||
};
|
||||
typedef enum DesfireISOSelectControlEnum DesfireISOSelectControl;
|
||||
|
||||
typedef struct {
|
||||
const uint8_t id;
|
||||
const char *text;
|
||||
|
@ -167,4 +176,10 @@ int DesfireReadRecords(DesfireContext *dctx, uint8_t fnum, uint32_t recnum, uint
|
|||
int DesfireWriteRecord(DesfireContext *dctx, uint8_t fnum, uint32_t offset, uint32_t len, uint8_t *data);
|
||||
int DesfireUpdateRecord(DesfireContext *dctx, uint8_t fnum, uint32_t recnum, uint32_t offset, uint32_t len, uint8_t *data);
|
||||
|
||||
int DesfireISOSelectDF(DesfireContext *dctx, char *dfname, uint8_t *resp, size_t *resplen);
|
||||
int DesfireISOSelect(DesfireContext *dctx, DesfireISOSelectControl cntr, uint8_t *data, uint8_t datalen, uint8_t *resp, size_t *resplen);
|
||||
int DesfireISOGetChallenge(DesfireContext *dctx, DesfireCryptoAlgorythm keytype, uint8_t *resp, size_t *resplen);
|
||||
int DesfireISOExternalAuth(DesfireContext *dctx, bool app_level, uint8_t keynum, DesfireCryptoAlgorythm keytype, uint8_t *data);
|
||||
int DesfireISOInternalAuth(DesfireContext *dctx, bool app_level, uint8_t keynum, DesfireCryptoAlgorythm keytype, uint8_t *data, uint8_t *resp, size_t *resplen);
|
||||
|
||||
#endif // __DESFIRECORE_H
|
||||
|
|
|
@ -41,6 +41,8 @@ void DesfireClearContext(DesfireContext *ctx) {
|
|||
ctx->secureChannel = DACNone;
|
||||
ctx->cmdSet = DCCNative;
|
||||
ctx->commMode = DCMNone;
|
||||
|
||||
ctx->appSelected = false;
|
||||
|
||||
ctx->kdfAlgo = 0;
|
||||
ctx->kdfInputLen = 0;
|
||||
|
@ -389,6 +391,35 @@ uint8_t DesfireCommModeToFileCommMode(DesfireCommunicationMode comm_mode) {
|
|||
return fmode;
|
||||
}
|
||||
|
||||
void DesfireGenSessionKeyEV1(const uint8_t rnda[], const uint8_t rndb[], DesfireCryptoAlgorythm keytype, uint8_t *key) {
|
||||
switch (keytype) {
|
||||
case T_DES:
|
||||
memcpy(key, rnda, 4);
|
||||
memcpy(key + 4, rndb, 4);
|
||||
break;
|
||||
case T_3DES:
|
||||
memcpy(key, rnda, 4);
|
||||
memcpy(key + 4, rndb, 4);
|
||||
memcpy(key + 8, rnda + 4, 4);
|
||||
memcpy(key + 12, rndb + 4, 4);
|
||||
break;
|
||||
case T_3K3DES:
|
||||
memcpy(key, rnda, 4);
|
||||
memcpy(key + 4, rndb, 4);
|
||||
memcpy(key + 8, rnda + 6, 4);
|
||||
memcpy(key + 12, rndb + 6, 4);
|
||||
memcpy(key + 16, rnda + 12, 4);
|
||||
memcpy(key + 20, rndb + 12, 4);
|
||||
break;
|
||||
case T_AES:
|
||||
memcpy(key, rnda, 4);
|
||||
memcpy(key + 4, rndb, 4);
|
||||
memcpy(key + 8, rnda + 12, 4);
|
||||
memcpy(key + 12, rndb + 12, 4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// https://www.nxp.com/docs/en/application-note/AN12343.pdf
|
||||
// page 35
|
||||
void DesfireGenSessionKeyEV2(uint8_t *key, uint8_t *rndA, uint8_t *rndB, bool enckey, uint8_t *sessionkey) {
|
||||
|
|
|
@ -75,6 +75,8 @@ typedef struct DesfireContextS {
|
|||
DesfireSecureChannel secureChannel; // none/d40/ev1/ev2
|
||||
DesfireCommandSet cmdSet; // native/nativeiso/iso
|
||||
DesfireCommunicationMode commMode; // plain/mac/enc
|
||||
|
||||
bool appSelected; // for iso auth
|
||||
|
||||
uint8_t IV[DESFIRE_MAX_KEY_SIZE];
|
||||
uint8_t sessionKeyMAC[DESFIRE_MAX_KEY_SIZE];
|
||||
|
@ -108,6 +110,7 @@ uint8_t DesfireDESKeyGetVersion(uint8_t *key);
|
|||
DesfireCommunicationMode DesfireFileCommModeToCommMode(uint8_t file_comm_mode);
|
||||
uint8_t DesfireCommModeToFileCommMode(DesfireCommunicationMode comm_mode);
|
||||
|
||||
void DesfireGenSessionKeyEV1(const uint8_t rnda[], const uint8_t rndb[], DesfireCryptoAlgorythm keytype, uint8_t *key);
|
||||
void DesfireGenSessionKeyEV2(uint8_t *key, uint8_t *rndA, uint8_t *rndB, bool enckey, uint8_t *sessionkey);
|
||||
void DesfireEV2FillIV(DesfireContext *ctx, bool ivforcommand, uint8_t *iv);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue