Merge pull request #1432 from merlokk/auth_ref

desfire authentication refactoring
This commit is contained in:
Oleg Moiseenko 2021-08-09 00:06:10 +03:00 committed by GitHub
commit 1d695ef777
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 350 additions and 221 deletions

View file

@ -53,20 +53,6 @@ static inline void update_key_schedules(desfirekey_t key) {
// }
}
int desfire_get_key_length(enum DESFIRE_CRYPTOALGO key_type) {
switch (key_type) {
case T_DES:
return 8;
case T_3DES:
return 16;
case T_3K3DES:
return 24;
case T_AES:
return 16;
}
return 0;
}
/******************************************************************************/
void tdes_nxp_receive(const void *in, void *out, size_t length, const void *key, unsigned char iv[8], int keymode) {
@ -334,7 +320,6 @@ void cmac(const desfirekey_t key, uint8_t *ivect, const uint8_t *data, size_t le
// This function is almot like cmac(...). but with some key differences.
void mifare_kdf_an10922(const desfirekey_t key, const uint8_t *data, size_t len) {
int kbs = key_block_size(key);
int kbs2 = kbs * 2;
if (key == NULL || kbs == 0 || data == NULL || len < 1 || len > 31) {
return;
}
@ -342,6 +327,7 @@ void mifare_kdf_an10922(const desfirekey_t key, const uint8_t *data, size_t len)
// AES uses 16 byte IV
if (kbs < 16)
kbs = 16;
int kbs2 = kbs * 2;
cmac_generate_subkeys(key, MCD_SEND);
@ -382,21 +368,6 @@ void mifare_kdf_an10922(const desfirekey_t key, const uint8_t *data, size_t len)
free(buffer);
}
size_t desfire_get_key_block_length(enum DESFIRE_CRYPTOALGO key_type) {
size_t block_size = 8;
switch (key_type) {
case T_DES:
case T_3DES:
case T_3K3DES:
block_size = 8;
break;
case T_AES:
block_size = 16;
break;
}
return block_size;
}
size_t key_block_size(const desfirekey_t key) {
if (key == NULL) {
return 0;
@ -422,16 +393,6 @@ static size_t key_macing_length(const desfirekey_t key) {
return mac_length;
}
/*
* Size required to store nbytes of data in a buffer of size n*block_size.
*/
size_t padded_data_length(const size_t nbytes, const size_t block_size) {
if ((!nbytes) || (nbytes % block_size))
return ((nbytes / block_size) + 1) * block_size;
else
return nbytes;
}
/*
* Buffer size required to MAC nbytes of data
*/

View file

@ -74,16 +74,11 @@ typedef enum {
/* Error code managed by the library */
#define CRYPTO_ERROR 0x01
int desfire_get_key_length(enum DESFIRE_CRYPTOALGO key_type);
size_t desfire_get_key_block_length(enum DESFIRE_CRYPTOALGO key_type);
enum DESFIRE_AUTH_SCHEME {
AS_LEGACY,
AS_NEW
};
#define DESFIRE_KEY(key) ((struct desfire_key *) key)
struct desfire_key {
enum DESFIRE_CRYPTOALGO type;
@ -139,7 +134,6 @@ void *mifare_cryto_postprocess_data(desfiretag_t tag, void *data, size_t *nbytes
void mifare_cypher_single_block(desfirekey_t key, uint8_t *data, uint8_t *ivect, MifareCryptoDirection direction, MifareCryptoOperation operation, size_t block_size);
void mifare_cypher_blocks_chained(desfiretag_t tag, desfirekey_t key, uint8_t *ivect, uint8_t *data, size_t data_size, MifareCryptoDirection direction, MifareCryptoOperation operation);
size_t key_block_size(const desfirekey_t key);
size_t padded_data_length(const size_t nbytes, const size_t block_size);
size_t maced_data_length(const desfirekey_t key, const size_t nbytes);
size_t enciphered_data_length(const desfiretag_t tag, const size_t nbytes, int communication_settings);
void cmac_generate_subkeys(desfirekey_t key, MifareCryptoDirection direction);

View file

@ -20,6 +20,7 @@
#include <string.h>
#include <util.h>
#include "commonutil.h"
#include "generator.h"
#include "aes.h"
#include "ui.h"
#include "crc.h"
@ -30,7 +31,6 @@
#include "iso7816/apduinfo.h" // APDU manipulation / errorcodes
#include "iso7816/iso7816core.h" // APDU logging
#include "util_posix.h" // msleep
#include "mifare/desfire_crypto.h"
#include "desfiresecurechan.h"
#include "mifare/mad.h"
#include "mifare/aiddesfire.h"
@ -335,14 +335,17 @@ void DesfirePrintContext(DesfireContext *ctx) {
sprint_hex(ctx->key,
desfire_get_key_length(ctx->keyType)));
if (ctx->kdfAlgo != MFDES_KDF_ALGO_NONE)
if (ctx->kdfAlgo != MFDES_KDF_ALGO_NONE) {
PrintAndLogEx(INFO, "KDF algo: %s KDF input[%d]: %s", CLIGetOptionListStr(DesfireKDFAlgoOpts, ctx->kdfAlgo), ctx->kdfInputLen, sprint_hex(ctx->kdfInput, ctx->kdfInputLen));
PrintAndLogEx(INFO, "AID: %06x UID[%d]: %s", ctx->selectedAID, ctx->uidlen, sprint_hex(ctx->uid, ctx->uidlen));
}
PrintAndLogEx(INFO, "Secure channel: %s Command set: %s Communication mode: %s",
CLIGetOptionListStr(DesfireSecureChannelOpts, ctx->secureChannel),
CLIGetOptionListStr(DesfireCommandSetOpts, ctx->cmdSet),
CLIGetOptionListStr(DesfireCommunicationModeOpts, ctx->commMode));
if (DesfireIsAuthenticated(ctx)) {
PrintAndLogEx(INFO, "Session key MAC [%d]: %s ",
desfire_get_key_length(ctx->keyType),
@ -789,6 +792,7 @@ int DesfireSelectAID(DesfireContext *ctx, uint8_t *aid1, uint8_t *aid2) {
DesfireClearSession(ctx);
ctx->appSelected = (aid1[0] != 0x00 || aid1[1] != 0x00 || aid1[2] != 0x00);
ctx->selectedAID = DesfireAIDByteToUint(aid1);
return PM3_SUCCESS;
}
@ -826,6 +830,7 @@ int DesfireSelectAIDHexNoFieldOn(DesfireContext *ctx, uint32_t aid) {
DesfireClearSession(ctx);
ctx->appSelected = (aid != 0x000000);
ctx->selectedAID = aid;
return PM3_SUCCESS;
}
@ -845,11 +850,14 @@ void DesfirePrintAIDFunctions(uint32_t appid) {
}
}
int DesfireSelectAndAuthenticateEx(DesfireContext *dctx, DesfireSecureChannel secureChannel, uint32_t aid, bool noauth, bool verbose) {
if (verbose)
DesfirePrintContext(dctx);
// needs card uid for diversification
if (dctx->kdfAlgo == MFDES_KDF_ALGO_GALLAGHER)
DesfireGetCardUID(dctx);
bool isosw = false;
if (dctx->cmdSet == DCCISO) {
dctx->cmdSet = DCCNativeISO;
@ -957,8 +965,6 @@ static int DesfireAuthenticateEV1(DesfireContext *dctx, DesfireSecureChannel sec
if (secureChannel == DACNone)
return PM3_SUCCESS;
mbedtls_aes_context ctx;
uint8_t keybytes[24] = {0};
// Crypt constants
uint8_t IV[16] = {0};
@ -971,37 +977,6 @@ static int DesfireAuthenticateEV1(DesfireContext *dctx, DesfireSecureChannel sec
// Part 1
memcpy(keybytes, dctx->key, desfire_get_key_length(dctx->keyType));
struct desfire_key dkey = {0};
desfirekey_t key = &dkey;
if (dctx->keyType == T_AES) {
mbedtls_aes_init(&ctx);
Desfire_aes_key_new(keybytes, key);
} else if (dctx->keyType == T_3DES) {
Desfire_3des_key_new_with_version(keybytes, key);
} else if (dctx->keyType == T_DES) {
Desfire_des_key_new(keybytes, key);
} else if (dctx->keyType == T_3K3DES) {
Desfire_3k3des_key_new_with_version(keybytes, key);
}
if (dctx->kdfAlgo == MFDES_KDF_ALGO_AN10922) {
mifare_kdf_an10922(key, dctx->kdfInput, dctx->kdfInputLen);
PrintAndLogEx(DEBUG, " Derrived key: " _GREEN_("%s"), sprint_hex(key->data, key_block_size(key)));
} else if (dctx->kdfAlgo == MFDES_KDF_ALGO_GALLAGHER) {
// We will overrite any provided KDF input since a gallagher specific KDF was requested.
dctx->kdfInputLen = 11;
/*if (mfdes_kdf_input_gallagher(tag->info.uid, tag->info.uidlen, dctx->keyNum, tag->selected_application, dctx->kdfInput, &dctx->kdfInputLen) != PM3_SUCCESS) {
PrintAndLogEx(FAILED, "Could not generate Gallagher KDF input");
}*/
mifare_kdf_an10922(key, dctx->kdfInput, dctx->kdfInputLen);
PrintAndLogEx(DEBUG, " KDF Input: " _YELLOW_("%s"), sprint_hex(dctx->kdfInput, dctx->kdfInputLen));
PrintAndLogEx(DEBUG, " Derrived key: " _GREEN_("%s"), sprint_hex(key->data, key_block_size(key)));
}
uint8_t subcommand = MFDES_AUTHENTICATE;
if (secureChannel == DACEV1) {
if (dctx->keyType == T_AES)
@ -1046,21 +1021,7 @@ static int DesfireAuthenticateEV1(DesfireContext *dctx, DesfireSecureChannel sec
// Part 3
if (dctx->keyType == T_AES) {
if (mbedtls_aes_setkey_dec(&ctx, key->data, 128) != 0) {
return 5;
}
mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_DECRYPT, rndlen, IV, encRndB, RndB);
} else if (dctx->keyType == T_DES) {
if (secureChannel == DACd40)
des_decrypt(RndB, encRndB, key->data);
if (secureChannel == DACEV1)
des_decrypt_cbc(RndB, encRndB, rndlen, key->data, IV);
} else if (dctx->keyType == T_3DES)
tdes_nxp_receive(encRndB, RndB, rndlen, key->data, IV, 2);
else if (dctx->keyType == T_3K3DES) {
tdes_nxp_receive(encRndB, RndB, rndlen, key->data, IV, 3);
}
DesfireCryptoEncDecEx(dctx, DCOMainKey, encRndB, rndlen, RndB, false, false, IV);
if (g_debugMode > 1) {
PrintAndLogEx(DEBUG, "encRndB: %s", sprint_hex(encRndB, 8));
@ -1075,82 +1036,25 @@ static int DesfireAuthenticateEV1(DesfireContext *dctx, DesfireSecureChannel sec
// - Encrypt our response
if (secureChannel == DACd40) {
if (dctx->keyType == T_DES) {
des_decrypt(encRndA, RndA, key->data);
memset(IV, 0, DESFIRE_MAX_CRYPTO_BLOCK_SIZE);
DesfireCryptoEncDecEx(dctx, DCOMainKey, RndA, rndlen, encRndA, true, true, IV);
memcpy(both, encRndA, rndlen);
bin_xor(rotRndB, encRndA, rndlen);
for (uint32_t x = 0; x < rndlen; x++) {
rotRndB[x] = rotRndB[x] ^ encRndA[x];
}
memset(IV, 0, DESFIRE_MAX_CRYPTO_BLOCK_SIZE);
DesfireCryptoEncDecEx(dctx, DCOMainKey, rotRndB, rndlen, encRndB, true, true, IV);
des_decrypt(encRndB, rotRndB, key->data);
memcpy(both + rndlen, encRndB, rndlen);
} else if (dctx->keyType == T_3DES) {
des3_decrypt(encRndA, RndA, key->data, 2);
memcpy(both, encRndA, rndlen);
for (uint32_t x = 0; x < rndlen; x++) {
rotRndB[x] = rotRndB[x] ^ encRndA[x];
}
des3_decrypt(encRndB, rotRndB, key->data, 2);
memcpy(both + rndlen, encRndB, rndlen);
}
} else if (secureChannel == DACEV1 && dctx->keyType != T_AES) {
if (dctx->keyType == T_DES) {
uint8_t tmp[16] = {0x00};
memcpy(tmp, RndA, rndlen);
memcpy(tmp + rndlen, rotRndB, rndlen);
if (g_debugMode > 1) {
PrintAndLogEx(DEBUG, "rotRndB: %s", sprint_hex(rotRndB, rndlen));
PrintAndLogEx(DEBUG, "Both: %s", sprint_hex(tmp, 16));
}
des_encrypt_cbc(both, tmp, 16, key->data, IV);
if (g_debugMode > 1) {
PrintAndLogEx(DEBUG, "EncBoth: %s", sprint_hex(both, 16));
}
} else if (dctx->keyType == T_3DES) {
uint8_t tmp[16] = {0x00};
memcpy(tmp, RndA, rndlen);
memcpy(tmp + rndlen, rotRndB, rndlen);
if (g_debugMode > 1) {
PrintAndLogEx(DEBUG, "rotRndB: %s", sprint_hex(rotRndB, rndlen));
PrintAndLogEx(DEBUG, "Both: %s", sprint_hex(tmp, 16));
}
tdes_nxp_send(tmp, both, 16, key->data, IV, 2);
if (g_debugMode > 1) {
PrintAndLogEx(DEBUG, "EncBoth: %s", sprint_hex(both, 16));
}
} else if (dctx->keyType == T_3K3DES) {
} else if (secureChannel == DACEV1) {
uint8_t tmp[32] = {0x00};
memcpy(tmp, RndA, rndlen);
memcpy(tmp + rndlen, rotRndB, rndlen);
if (g_debugMode > 1) {
PrintAndLogEx(DEBUG, "rotRndB: %s", sprint_hex(rotRndB, rndlen));
PrintAndLogEx(DEBUG, "Both3k3: %s", sprint_hex(tmp, 32));
}
tdes_nxp_send(tmp, both, 32, key->data, IV, 3);
if (g_debugMode > 1) {
PrintAndLogEx(DEBUG, "EncBoth: %s", sprint_hex(both, 32));
}
}
} else if (secureChannel == DACEV1 && dctx->keyType == T_AES) {
uint8_t tmp[32] = {0x00};
memcpy(tmp, RndA, rndlen);
memcpy(tmp + rndlen, rotRndB, rndlen);
if (g_debugMode > 1) {
PrintAndLogEx(DEBUG, "rotRndB: %s", sprint_hex(rotRndB, rndlen));
PrintAndLogEx(DEBUG, "Both3k3: %s", sprint_hex(tmp, 32));
}
if (dctx->keyType == T_AES) {
if (mbedtls_aes_setkey_enc(&ctx, key->data, 128) != 0) {
return 6;
}
mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_ENCRYPT, 32, IV, tmp, both);
if (g_debugMode > 1) {
PrintAndLogEx(DEBUG, "EncBoth: %s", sprint_hex(both, 32));
}
PrintAndLogEx(DEBUG, "Both : %s", sprint_hex(tmp, 32));
}
DesfireCryptoEncDecEx(dctx, DCOMainKey, tmp, rndlen * 2, both, true, true, IV);
}
uint32_t bothlen = 16;
@ -1174,31 +1078,15 @@ static int DesfireAuthenticateEV1(DesfireContext *dctx, DesfireSecureChannel sec
// Part 4
memcpy(encRndA, recv_data, rndlen);
struct desfire_key sesskey = {0};
Desfire_session_key_new(RndA, RndB, key, &sesskey);
memcpy(dctx->sessionKeyEnc, sesskey.data, desfire_get_key_length(dctx->keyType));
//PrintAndLogEx(INFO, "encRndA : %s", sprint_hex(encRndA, rndlen));
//PrintAndLogEx(INFO, "IV : %s", sprint_hex(IV, rndlen));
if (dctx->keyType == T_DES) {
if (secureChannel == DACd40)
des_decrypt(encRndA, encRndA, key->data);
if (secureChannel == DACEV1)
des_decrypt_cbc(encRndA, encRndA, rndlen, key->data, IV);
} else if (dctx->keyType == T_3DES)
if (secureChannel == DACd40)
des3_decrypt(encRndA, encRndA, key->data, 2);
else
tdes_nxp_receive(encRndA, encRndA, rndlen, key->data, IV, 2);
else if (dctx->keyType == T_3K3DES)
tdes_nxp_receive(encRndA, encRndA, rndlen, key->data, IV, 3);
else if (dctx->keyType == T_AES) {
if (mbedtls_aes_setkey_dec(&ctx, key->data, 128) != 0) {
return 10;
}
mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_DECRYPT, rndlen, IV, encRndA, encRndA);
}
memset(IV, 0, DESFIRE_MAX_CRYPTO_BLOCK_SIZE);
DesfireCryptoEncDecEx(dctx, DCOMainKey, encRndA, rndlen, encRndA, false, false, IV);
// generate session key from rnda and rndb. before rol(RndA)!
DesfireGenSessionKeyEV1(RndA, RndB, dctx->keyType, dctx->sessionKeyEnc);
rol(RndA, rndlen);
//PrintAndLogEx(INFO, "Expected_RndA : %s", sprint_hex(RndA, rndlen));
@ -1216,16 +1104,10 @@ static int DesfireAuthenticateEV1(DesfireContext *dctx, DesfireSecureChannel sec
// If the 3Des key first 8 bytes = 2nd 8 Bytes then we are really using Singe Des
// As such we need to set the session key such that the 2nd 8 bytes = 1st 8 Bytes
if (dctx->keyType == T_3DES) {
if (memcmp(key->data, &key->data[8], 8) == 0)
if (memcmp(dctx->key, &dctx->key[8], 8) == 0)
memcpy(&dctx->sessionKeyEnc[8], dctx->sessionKeyEnc, 8);
}
if (secureChannel == DACEV1) {
cmac_generate_subkeys(&sesskey, MCD_RECEIVE);
//key->cmac_sk1 and key->cmac_sk2
//memcpy(dctx->sessionKeyEnc, sesskey.data, desfire_get_key_length(dctx->keyType));
}
memset(dctx->IV, 0, DESFIRE_MAX_KEY_SIZE);
dctx->secureChannel = secureChannel;
memcpy(dctx->sessionKeyMAC, dctx->sessionKeyEnc, desfire_get_key_length(dctx->keyType));
@ -1420,6 +1302,22 @@ static int DesfireAuthenticateISO(DesfireContext *dctx, DesfireSecureChannel sec
}
int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel, bool verbose) {
if (dctx->kdfAlgo == MFDES_KDF_ALGO_AN10922) {
MifareKdfAn10922(dctx, DCOMasterKey, dctx->kdfInput, dctx->kdfInputLen);
PrintAndLogEx(DEBUG, " Derrived key: " _GREEN_("%s"), sprint_hex(dctx->key, desfire_get_key_block_length(dctx->keyType)));
} else if (dctx->kdfAlgo == MFDES_KDF_ALGO_GALLAGHER) {
// We will overrite any provided KDF input since a gallagher specific KDF was requested.
dctx->kdfInputLen = 11;
if (mfdes_kdf_input_gallagher(dctx->uid, dctx->uidlen, dctx->keyNum, dctx->selectedAID, dctx->kdfInput, &dctx->kdfInputLen) != PM3_SUCCESS) {
PrintAndLogEx(FAILED, "Could not generate Gallagher KDF input");
}
PrintAndLogEx(DEBUG, " KDF Input: " _YELLOW_("%s"), sprint_hex(dctx->kdfInput, dctx->kdfInputLen));
MifareKdfAn10922(dctx, DCOMasterKey, dctx->kdfInput, dctx->kdfInputLen);
PrintAndLogEx(DEBUG, " Derrived key: " _GREEN_("%s"), sprint_hex(dctx->key, desfire_get_key_block_length(dctx->keyType)));
}
if (dctx->cmdSet == DCCISO && secureChannel != DACEV2)
return DesfireAuthenticateISO(dctx, secureChannel, verbose);
@ -2642,6 +2540,7 @@ int DesfireISOSelectEx(DesfireContext *dctx, bool fieldon, DesfireISOSelectContr
DesfireClearSession(dctx);
dctx->appSelected = !((cntr == ISSMFDFEF && datalen == 0) || (cntr == ISSEFByFileID && datalen == 2 && data[0] == 0 && data[1] == 0));
dctx->selectedAID = 0;
return res;
}
@ -2751,6 +2650,26 @@ int DesfireISOAppendRecord(DesfireContext *dctx, uint8_t fileid, uint8_t *data,
return res;
}
int DesfireGetCardUID(DesfireContext *ctx) {
iso14a_card_select_t card = {0};
SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT, 0, 0, NULL, 0);
PacketResponseNG resp;
WaitForResponse(CMD_ACK, &resp);
memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t));
uint64_t select_status = resp.oldarg[0];
if (select_status == 0 || select_status == 2 || select_status == 3) {
return PM3_ESOFT;
}
memcpy(ctx->uid, card.uid, card.uidlen);
ctx->uidlen = card.uidlen;
return PM3_SUCCESS;
}
int DesfireSelectEx(DesfireContext *ctx, bool fieldon, DesfireISOSelectWay way, uint32_t id, char *dfname) {
uint8_t resp[250] = {0};
size_t resplen = 0;

View file

@ -16,8 +16,6 @@
#include "common.h"
#include "cliparser.h"
#include "mifare/desfirecrypto.h"
#include "mifare/desfire_crypto.h"
#include "mifare/mifare4.h"
#define DESFIRE_TX_FRAME_MAX_LEN 54
@ -168,6 +166,8 @@ int DesfireSelectAIDHex(DesfireContext *ctx, uint32_t aid1, bool select_two, uin
int DesfireSelectAIDHexNoFieldOn(DesfireContext *ctx, uint32_t aid);
void DesfirePrintAIDFunctions(uint32_t appid);
int DesfireGetCardUID(DesfireContext *ctx);
int DesfireSelectEx(DesfireContext *ctx, bool fieldon, DesfireISOSelectWay way, uint32_t id, char *dfname);
int DesfireSelect(DesfireContext *ctx, DesfireISOSelectWay way, uint32_t id, char *dfname);

View file

@ -31,7 +31,7 @@
#include "crc16.h" // crc16 ccitt
#include "crc32.h"
#include "commonutil.h"
#include "mifare/desfire_crypto.h"
#include "crypto/libpcrypto.h"
void DesfireClearContext(DesfireContext *ctx) {
ctx->keyNum = 0;
@ -43,6 +43,10 @@ void DesfireClearContext(DesfireContext *ctx) {
ctx->commMode = DCMNone;
ctx->appSelected = false;
ctx->selectedAID = 0;
memset(ctx->uid, 0, sizeof(ctx->uid));
ctx->uidlen = 0;
ctx->kdfAlgo = 0;
ctx->kdfInputLen = 0;
@ -74,6 +78,7 @@ void DesfireSetKey(DesfireContext *ctx, uint8_t keyNum, enum DESFIRE_CRYPTOALGO
ctx->keyNum = keyNum;
ctx->keyType = keyType;
memcpy(ctx->key, key, desfire_get_key_length(keyType));
memcpy(ctx->masterKey, key, desfire_get_key_length(keyType));
}
void DesfireSetCommandSet(DesfireContext *ctx, DesfireCommandSet cmdSet) {
@ -96,7 +101,7 @@ bool DesfireIsAuthenticated(DesfireContext *dctx) {
}
size_t DesfireGetMACLength(DesfireContext *ctx) {
size_t mac_length = MAC_LENGTH;
size_t mac_length = DESFIRE_MAC_LENGTH;
switch (ctx->secureChannel) {
case DACNone:
mac_length = 0;
@ -151,6 +156,19 @@ size_t DesfireSearchCRCPos(uint8_t *data, size_t datalen, uint8_t respcode, uint
return crcposfound;
}
uint8_t *DesfireGetKey(DesfireContext *ctx, DesfireCryptoOpKeyType key_type) {
if (key_type == DCOSessionKeyMac) {
return ctx->sessionKeyMAC;
} else if (key_type == DCOSessionKeyEnc) {
return ctx->sessionKeyEnc;
} else if (key_type == DCOMasterKey) {
return ctx->masterKey;
}
return ctx->key;
}
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};
@ -232,15 +250,14 @@ void DesfireCryptoEncDecEx(DesfireContext *ctx, DesfireCryptoOpKeyType key_type,
else
memcpy(xiv, iv, block_size);
uint8_t *key = DesfireGetKey(ctx, key_type);
if (key == NULL)
return;
size_t offset = 0;
while (offset < srcdatalen) {
if (key_type == DCOSessionKeyMac) {
DesfireCryptoEncDecSingleBlock(ctx->sessionKeyMAC, ctx->keyType, srcdata + offset, data + offset, xiv, dir_to_send, encode);
} else if (key_type == DCOSessionKeyEnc) {
DesfireCryptoEncDecSingleBlock(ctx->sessionKeyEnc, ctx->keyType, srcdata + offset, data + offset, xiv, dir_to_send, encode);
} else {
DesfireCryptoEncDecSingleBlock(ctx->key, ctx->keyType, srcdata + offset, data + offset, xiv, dir_to_send, encode);
}
DesfireCryptoEncDecSingleBlock(key, ctx->keyType, srcdata + offset, data + offset, xiv, dir_to_send, encode);
offset += block_size;
}
@ -262,7 +279,7 @@ void DesfireCryptoEncDec(DesfireContext *ctx, DesfireCryptoOpKeyType key_type, u
DesfireCryptoEncDecEx(ctx, key_type, srcdata, srcdatalen, dstdata, dir_to_send, xencode, NULL);
}
static void DesfireCMACGenerateSubkeys(DesfireContext *ctx, uint8_t *sk1, uint8_t *sk2) {
void DesfireCMACGenerateSubkeys(DesfireContext *ctx, DesfireCryptoOpKeyType key_type, uint8_t *sk1, uint8_t *sk2) {
int kbs = desfire_get_key_block_length(ctx->keyType);
const uint8_t R = (kbs == 8) ? 0x1B : 0x87;
@ -272,7 +289,7 @@ static void DesfireCMACGenerateSubkeys(DesfireContext *ctx, uint8_t *sk1, uint8_
uint8_t ivect[kbs];
memset(ivect, 0, kbs);
DesfireCryptoEncDecEx(ctx, DCOSessionKeyMac, l, kbs, l, true, true, ivect);
DesfireCryptoEncDecEx(ctx, key_type, l, kbs, l, true, true, ivect);
bool txor = false;
@ -293,23 +310,23 @@ static void DesfireCMACGenerateSubkeys(DesfireContext *ctx, uint8_t *sk1, uint8_
}
}
void DesfireCryptoCMAC(DesfireContext *ctx, uint8_t *data, size_t len, uint8_t *cmac) {
void DesfireCryptoCMACEx(DesfireContext *ctx, DesfireCryptoOpKeyType key_type, uint8_t *data, size_t len, size_t minlen, uint8_t *cmac) {
int kbs = desfire_get_key_block_length(ctx->keyType);
if (kbs == 0)
return;
uint8_t buffer[padded_data_length(len, kbs)];
uint8_t buffer[padded_data_length(MAX(minlen, len) + 1, 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);
DesfireCMACGenerateSubkeys(ctx, key_type, sk1, sk2);
memcpy(buffer, data, len);
if ((!len) || (len % kbs)) {
if ((!len) || (len % kbs) || (len < minlen)) {
buffer[len++] = 0x80;
while (len % kbs) {
while (len % kbs || len < minlen) {
buffer[len++] = 0x00;
}
bin_xor(buffer + len - kbs, sk2, kbs);
@ -317,12 +334,73 @@ void DesfireCryptoCMAC(DesfireContext *ctx, uint8_t *data, size_t len, uint8_t *
bin_xor(buffer + len - kbs, sk1, kbs);
}
DesfireCryptoEncDec(ctx, DCOSessionKeyMac, buffer, len, NULL, true);
DesfireCryptoEncDec(ctx, key_type, buffer, len, NULL, true);
if (cmac != NULL)
memcpy(cmac, ctx->IV, kbs);
}
void DesfireCryptoCMAC(DesfireContext *ctx, uint8_t *data, size_t len, uint8_t *cmac) {
DesfireCryptoCMACEx(ctx, DCOSessionKeyMac, data, len, 0, cmac);
}
// This function is almot like cmac(...). but with some key differences.
void MifareKdfAn10922(DesfireContext *ctx, DesfireCryptoOpKeyType key_type, const uint8_t *data, size_t len) {
int kbs = desfire_get_key_block_length(ctx->keyType); // 8 or 16
if (ctx == NULL || kbs == 0 || data == NULL || len < 1 || len > 31) {
return;
}
uint8_t cmac[DESFIRE_MAX_CRYPTO_BLOCK_SIZE * 3] = {0};
uint8_t buffer[DESFIRE_MAX_CRYPTO_BLOCK_SIZE * 3] = {0};
if (ctx->keyType == T_AES) {
// AES uses 16 byte IV
if (kbs < CRYPTO_AES_BLOCK_SIZE)
kbs = CRYPTO_AES_BLOCK_SIZE;
buffer[0] = 0x01;
memcpy(&buffer[1], data, len);
DesfireCryptoCMACEx(ctx, key_type, buffer, len + 1, kbs * 2, cmac);
memcpy(ctx->key, cmac, kbs);
} else if (ctx->keyType == T_3DES) {
buffer[0] = 0x21;
memcpy(&buffer[1], data, len);
DesfireClearIV(ctx);
DesfireCryptoCMACEx(ctx, key_type, buffer, len + 1, kbs * 2, cmac);
buffer[0] = 0x22;
memcpy(&buffer[1], data, len);
DesfireClearIV(ctx);
DesfireCryptoCMACEx(ctx, key_type, buffer, len + 1, kbs * 2, &cmac[kbs]);
memcpy(ctx->key, cmac, kbs * 2);
} else if (ctx->keyType == T_3K3DES) {
buffer[0] = 0x31;
memcpy(&buffer[1], data, len);
DesfireClearIV(ctx);
DesfireCryptoCMACEx(ctx, key_type, buffer, len + 1, kbs * 2, cmac);
buffer[0] = 0x32;
memcpy(&buffer[1], data, len);
DesfireClearIV(ctx);
DesfireCryptoCMACEx(ctx, key_type, buffer, len + 1, kbs * 2, &cmac[kbs]);
buffer[0] = 0x33;
memcpy(&buffer[1], data, len);
DesfireClearIV(ctx);
DesfireCryptoCMACEx(ctx, key_type, buffer, len + 1, kbs * 2, &cmac[kbs * 2]);
memcpy(ctx->key, cmac, kbs * 3);
}
}
void DesfireDESKeySetVersion(uint8_t *key, DesfireCryptoAlgorythm keytype, uint8_t version) {
if (keytype == T_AES)
return;
@ -536,6 +614,45 @@ int DesfireEV2CalcCMAC(DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t d
return aes_cmac8(NULL, ctx->sessionKeyMAC, mdata, mac, mdatalen);
}
int desfire_get_key_length(DesfireCryptoAlgorythm 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;
}
size_t desfire_get_key_block_length(DesfireCryptoAlgorythm key_type) {
size_t block_size = 8;
switch (key_type) {
case T_DES:
case T_3DES:
case T_3K3DES:
block_size = 8;
break;
case T_AES:
block_size = 16;
break;
}
return block_size;
}
/*
* Size required to store nbytes of data in a buffer of size n*block_size.
*/
size_t padded_data_length(const size_t nbytes, const size_t block_size) {
if ((!nbytes) || (nbytes % block_size))
return ((nbytes / block_size) + 1) * block_size;
else
return nbytes;
}
void desfire_crc32(const uint8_t *data, const size_t len, uint8_t *crc) {
crc32_ex(data, len, crc);
}

View file

@ -22,12 +22,14 @@
#define __DESFIRECRYPTO_H
#include "common.h"
#include "mifare/mifare4.h"
#include "crypto/libpcrypto.h"
#define CRYPTO_AES_BLOCK_SIZE 16
#define MAX_CRYPTO_BLOCK_SIZE 16
#define DESFIRE_MAX_CRYPTO_BLOCK_SIZE 16
#define DESFIRE_MAX_KEY_SIZE 24
#define DESFIRE_MAC_LENGTH 4
#define DESFIRE_CMAC_LENGTH 8
#define DESFIRE_GET_ISO_STATUS(x) ( ((uint16_t)(0x91<<8)) + (uint16_t)x )
@ -63,6 +65,7 @@ typedef enum {
} DesfireCommunicationMode;
typedef enum {
DCOMasterKey,
DCOMainKey,
DCOSessionKeyMac,
DCOSessionKeyEnc
@ -72,6 +75,7 @@ typedef struct DesfireContextS {
uint8_t keyNum;
DesfireCryptoAlgorythm keyType; // des/2tdea/3tdea/aes
uint8_t key[DESFIRE_MAX_KEY_SIZE];
uint8_t masterKey[DESFIRE_MAX_KEY_SIZE]; // source for kdf
// KDF finction
uint8_t kdfAlgo;
@ -83,6 +87,10 @@ typedef struct DesfireContextS {
DesfireCommunicationMode commMode; // plain/mac/enc
bool appSelected; // for iso auth
uint32_t selectedAID;
uint8_t uid[10];
uint8_t uidlen;
uint8_t IV[DESFIRE_MAX_KEY_SIZE];
uint8_t sessionKeyMAC[DESFIRE_MAX_KEY_SIZE];
@ -106,9 +114,13 @@ size_t DesfireGetMACLength(DesfireContext *ctx);
size_t DesfireSearchCRCPos(uint8_t *data, size_t datalen, uint8_t respcode, uint8_t crclen);
uint8_t *DesfireGetKey(DesfireContext *ctx, DesfireCryptoOpKeyType key_type);
void DesfireCryptoEncDec(DesfireContext *ctx, DesfireCryptoOpKeyType key_type, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool encode);
void DesfireCryptoEncDecEx(DesfireContext *ctx, DesfireCryptoOpKeyType key_type, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool dir_to_send, bool encode, uint8_t *iv);
void DesfireCMACGenerateSubkeys(DesfireContext *ctx, DesfireCryptoOpKeyType key_type, uint8_t *sk1, uint8_t *sk2);
void DesfireCryptoCMAC(DesfireContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t *cmac);
void DesfireCryptoCMACEx(DesfireContext *ctx, DesfireCryptoOpKeyType key_type, uint8_t *data, size_t len, size_t minlen, uint8_t *cmac);
void MifareKdfAn10922(DesfireContext *ctx, DesfireCryptoOpKeyType key_type, const uint8_t *data, size_t len);
void DesfireDESKeySetVersion(uint8_t *key, DesfireCryptoAlgorythm keytype, uint8_t version);
uint8_t DesfireDESKeyGetVersion(uint8_t *key);
@ -125,6 +137,10 @@ void DesfireGenSessionKeyEV2(uint8_t *key, uint8_t *rndA, uint8_t *rndB, bool en
void DesfireEV2FillIV(DesfireContext *ctx, bool ivforcommand, uint8_t *iv);
int DesfireEV2CalcCMAC(DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *mac);
int desfire_get_key_length(DesfireCryptoAlgorythm key_type);
size_t desfire_get_key_block_length(DesfireCryptoAlgorythm key_type);
size_t padded_data_length(const size_t nbytes, const size_t block_size);
void desfire_crc32(const uint8_t *data, const size_t len, uint8_t *crc);
void desfire_crc32_append(uint8_t *data, const size_t len);
bool desfire_crc32_check(uint8_t *data, const size_t len, uint8_t *crc);

View file

@ -21,7 +21,6 @@
#include "crc32.h"
#include "commonutil.h"
#include "protocols.h"
#include "mifare/desfire_crypto.h"
static const uint8_t CommandsCanUseAnyChannel[] = {
MFDES_S_ADDITIONAL_FRAME,

View file

@ -16,7 +16,6 @@
#include "common.h"
#include "mifare/desfirecore.h"
#include "mifare/desfirecrypto.h"
#include "mifare/desfire_crypto.h"
#include "mifare/mifare4.h"
typedef struct {

View file

@ -78,6 +78,126 @@ static bool TestCRC32(void) {
return res;
}
// https://www.nxp.com/docs/en/application-note/AN10922.pdf
static bool TestCMACSubkeys(void) {
bool res = true;
uint8_t key[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF};
uint8_t sk1[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0};
uint8_t sk2[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0};
DesfireContext dctx;
// AES
DesfireSetKey(&dctx, 0, T_AES, key);
DesfireCMACGenerateSubkeys(&dctx, DCOMainKey, sk1, sk2);
uint8_t sk1test[] = {0xFB, 0xC9, 0xF7, 0x5C, 0x94, 0x13, 0xC0, 0x41, 0xDF, 0xEE, 0x45, 0x2D, 0x3F, 0x07, 0x06, 0xD1};
uint8_t sk2test[] = {0xF7, 0x93, 0xEE, 0xB9, 0x28, 0x27, 0x80, 0x83, 0xBF, 0xDC, 0x8A, 0x5A, 0x7E, 0x0E, 0x0D, 0x25};
res = res && (memcmp(sk1, sk1test, sizeof(sk1test)) == 0);
res = res && (memcmp(sk2, sk2test, sizeof(sk2test)) == 0);
// 2tdea
DesfireSetKey(&dctx, 0, T_3DES, key);
DesfireCMACGenerateSubkeys(&dctx, DCOMainKey, sk1, sk2);
uint8_t sk1_2tdea[] = {0xF6, 0x12, 0xEB, 0x32, 0xE4, 0x60, 0x35, 0xF3};
uint8_t sk2_2tdea[] = {0xEC, 0x25, 0xD6, 0x65, 0xC8, 0xC0, 0x6B, 0xFD};
res = res && (memcmp(sk1, sk1_2tdea, sizeof(sk1_2tdea)) == 0);
res = res && (memcmp(sk2, sk2_2tdea, sizeof(sk2_2tdea)) == 0);
// 3tdea
uint8_t key3[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
DesfireSetKey(&dctx, 0, T_3K3DES, key3);
DesfireCMACGenerateSubkeys(&dctx, DCOMainKey, sk1, sk2);
uint8_t sk1_3tdea[] = {0xA3, 0xED, 0x58, 0xF8, 0xE6, 0x94, 0x1B, 0xCA};
uint8_t sk2_3tdea[] = {0x47, 0xDA, 0xB1, 0xF1, 0xCD, 0x28, 0x37, 0x8F};
res = res && (memcmp(sk1, sk1_3tdea, sizeof(sk1_3tdea)) == 0);
res = res && (memcmp(sk2, sk2_3tdea, sizeof(sk2_3tdea)) == 0);
if (res)
PrintAndLogEx(INFO, "CMAC subkeys...... " _GREEN_("passed"));
else
PrintAndLogEx(ERR, "CMAC subkeys...... " _RED_("fail"));
return res;
}
// https://www.nxp.com/docs/en/application-note/AN10922.pdf
// page 8
static bool TestAn10922KDFAES(void) {
bool res = true;
uint8_t key[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF};
DesfireContext dctx;
DesfireSetKey(&dctx, 0, T_AES, key);
uint8_t kdfInput[] = {0x04, 0x78, 0x2E, 0x21, 0x80, 0x1D, 0x80, 0x30, 0x42, 0xF5, 0x4E, 0x58, 0x50, 0x20, 0x41, 0x62, 0x75};
MifareKdfAn10922(&dctx, DCOMainKey, kdfInput, sizeof(kdfInput));
uint8_t dkey[] = {0xA8, 0xDD, 0x63, 0xA3, 0xB8, 0x9D, 0x54, 0xB3, 0x7C, 0xA8, 0x02, 0x47, 0x3F, 0xDA, 0x91, 0x75};
res = res && (memcmp(dctx.key, dkey, sizeof(dkey)) == 0);
if (res)
PrintAndLogEx(INFO, "An10922 AES....... " _GREEN_("passed"));
else
PrintAndLogEx(ERR, "An10922 AES....... " _RED_("fail"));
return res;
}
static bool TestAn10922KDF2TDEA(void) {
bool res = true;
uint8_t key[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF};
DesfireContext dctx;
DesfireSetKey(&dctx, 0, T_3DES, key);
uint8_t kdfInput[] = {0x04, 0x78, 0x2E, 0x21, 0x80, 0x1D, 0x80, 0x30, 0x42, 0xF5, 0x4E, 0x58, 0x50, 0x20, 0x41};
MifareKdfAn10922(&dctx, DCOMainKey, kdfInput, sizeof(kdfInput));
uint8_t dkey[] = {0x16, 0xF8, 0x59, 0x7C, 0x9E, 0x89, 0x10, 0xC8, 0x6B, 0x96, 0x48, 0xD0, 0x06, 0x10, 0x7D, 0xD7};
res = res && (memcmp(dctx.key, dkey, sizeof(dkey)) == 0);
if (res)
PrintAndLogEx(INFO, "An10922 2TDEA..... " _GREEN_("passed"));
else
PrintAndLogEx(ERR, "An10922 2TDEA..... " _RED_("fail"));
return res;
}
static bool TestAn10922KDF3TDEA(void) {
bool res = true;
uint8_t key[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
DesfireContext dctx;
DesfireSetKey(&dctx, 0, T_3K3DES, key);
uint8_t kdfInput[] = {0x04, 0x78, 0x2E, 0x21, 0x80, 0x1D, 0x80, 0x30, 0x42, 0xF5, 0x4E, 0x58, 0x50};
MifareKdfAn10922(&dctx, DCOMainKey, kdfInput, sizeof(kdfInput));
uint8_t dkey[] = {0x2F, 0x0D, 0xD0, 0x36, 0x75, 0xD3, 0xFB, 0x9A, 0x57, 0x05, 0xAB, 0x0B, 0xDA, 0x91, 0xCA, 0x0B,
0x55, 0xB8, 0xE0, 0x7F, 0xCD, 0xBF, 0x10, 0xEC};
res = res && (memcmp(dctx.key, dkey, sizeof(dkey)) == 0);
if (res)
PrintAndLogEx(INFO, "An10922 3TDEA..... " _GREEN_("passed"));
else
PrintAndLogEx(ERR, "An10922 3TDEA..... " _RED_("fail"));
return res;
}
// https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/TDES_CMAC.pdf
static bool TestCMAC3TDEA(void) {
bool res = true;
@ -336,6 +456,10 @@ bool DesfireTest(bool verbose) {
res = res && TestCRC16();
res = res && TestCRC32();
res = res && TestCMACSubkeys();
res = res && TestAn10922KDFAES();
res = res && TestAn10922KDF2TDEA();
res = res && TestAn10922KDF3TDEA();
res = res && TestCMAC3TDEA();
res = res && TestCMAC2TDEA();
res = res && TestCMACDES();