Merge pull request #1415 from merlokk/ev2mac

Ev2 mac calc and channel sketch
This commit is contained in:
Oleg Moiseenko 2021-08-04 15:30:18 +03:00 committed by GitHub
commit 45073eb969
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 203 additions and 28 deletions

View file

@ -349,7 +349,7 @@ void DesfirePrintContext(DesfireContext *ctx) {
desfire_get_key_block_length(ctx->keyType), desfire_get_key_block_length(ctx->keyType),
sprint_hex(ctx->IV, desfire_get_key_block_length(ctx->keyType))); sprint_hex(ctx->IV, desfire_get_key_block_length(ctx->keyType)));
if (ctx->secureChannel == DACEV2) { if (ctx->secureChannel == DACEV2) {
PrintAndLogEx(INFO, " TI: %s cmdCntr: 0x%08x", PrintAndLogEx(INFO, " TI: %s cmdCntr: 0x%04x",
sprint_hex(ctx->TI, 4), sprint_hex(ctx->TI, 4),
ctx->cmdCntr); ctx->cmdCntr);
} }
@ -1180,6 +1180,7 @@ static int DesfireAuthenticateEV2(DesfireContext *dctx, DesfireSecureChannel sec
uint8_t RndA[CRYPTO_AES_BLOCK_SIZE] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16}; uint8_t RndA[CRYPTO_AES_BLOCK_SIZE] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16};
uint8_t RndB[CRYPTO_AES_BLOCK_SIZE] = {0}; uint8_t RndB[CRYPTO_AES_BLOCK_SIZE] = {0};
uint8_t encRndB[CRYPTO_AES_BLOCK_SIZE] = {0}; uint8_t encRndB[CRYPTO_AES_BLOCK_SIZE] = {0};
uint8_t rotRndA[CRYPTO_AES_BLOCK_SIZE] = {0}; //RndA'
uint8_t rotRndB[CRYPTO_AES_BLOCK_SIZE] = {0}; //RndB' uint8_t rotRndB[CRYPTO_AES_BLOCK_SIZE] = {0}; //RndB'
uint8_t both[CRYPTO_AES_BLOCK_SIZE * 2 + 1] = {0}; // ek/dk_keyNo(RndA+RndB') uint8_t both[CRYPTO_AES_BLOCK_SIZE * 2 + 1] = {0}; // ek/dk_keyNo(RndA+RndB')
@ -1228,8 +1229,6 @@ static int DesfireAuthenticateEV2(DesfireContext *dctx, DesfireSecureChannel sec
memcpy(rotRndB, RndB, CRYPTO_AES_BLOCK_SIZE); memcpy(rotRndB, RndB, CRYPTO_AES_BLOCK_SIZE);
rol(rotRndB, CRYPTO_AES_BLOCK_SIZE); rol(rotRndB, CRYPTO_AES_BLOCK_SIZE);
uint8_t encRndA[16] = {0x00};
// - Encrypt our response // - Encrypt our response
uint8_t tmp[32] = {0x00}; uint8_t tmp[32] = {0x00};
memcpy(tmp, RndA, CRYPTO_AES_BLOCK_SIZE); memcpy(tmp, RndA, CRYPTO_AES_BLOCK_SIZE);
@ -1259,20 +1258,21 @@ static int DesfireAuthenticateEV2(DesfireContext *dctx, DesfireSecureChannel sec
} }
// Part 4 // Part 4
memcpy(encRndA, recv_data, CRYPTO_AES_BLOCK_SIZE);
uint8_t data[32] = {0}; uint8_t data[32] = {0};
if (aes_decode(IV, key, recv_data, data, recv_len)) if (aes_decode(IV, key, recv_data, data, recv_len))
return 10; return 10;
rol(RndA, CRYPTO_AES_BLOCK_SIZE); // rotate rndA to check
memcpy(rotRndA, RndA, CRYPTO_AES_BLOCK_SIZE);
rol(rotRndA, CRYPTO_AES_BLOCK_SIZE);
uint8_t *recRndA = (firstauth) ? &data[4] : data; uint8_t *recRndA = (firstauth) ? &data[4] : data;
if (memcmp(RndA, recRndA, CRYPTO_AES_BLOCK_SIZE) != 0) { if (memcmp(rotRndA, recRndA, CRYPTO_AES_BLOCK_SIZE) != 0) {
if (g_debugMode > 1) { if (g_debugMode > 1) {
PrintAndLogEx(DEBUG, "Expected_RndA : %s", sprint_hex(RndA, CRYPTO_AES_BLOCK_SIZE)); PrintAndLogEx(DEBUG, "Expected_RndA' : %s", sprint_hex(rotRndA, CRYPTO_AES_BLOCK_SIZE));
PrintAndLogEx(DEBUG, "Generated_RndA : %s", sprint_hex(recRndA, CRYPTO_AES_BLOCK_SIZE)); PrintAndLogEx(DEBUG, "Generated_RndA' : %s", sprint_hex(recRndA, CRYPTO_AES_BLOCK_SIZE));
} }
return 11; return 11;
} }
@ -1322,7 +1322,7 @@ static int DesfireAuthenticateISO(DesfireContext *dctx, DesfireSecureChannel sec
// encode // encode
DesfireClearIV(dctx); DesfireClearIV(dctx);
DesfireCryptoEncDec(dctx, false, both, rndlen * 2, both, true); // error 303 DesfireCryptoEncDec(dctx, DCOMainKey, both, rndlen * 2, both, true); // error 303
// external authenticate // external authenticate
res = DesfireISOExternalAuth(dctx, dctx->appSelected, dctx->keyNum, dctx->keyType, both); res = DesfireISOExternalAuth(dctx, dctx->appSelected, dctx->keyNum, dctx->keyType, both);
@ -1341,7 +1341,7 @@ static int DesfireAuthenticateISO(DesfireContext *dctx, DesfireSecureChannel sec
// decode rnddata // decode rnddata
uint8_t piccrnd2[64] = {0}; uint8_t piccrnd2[64] = {0};
DesfireCryptoEncDec(dctx, false, rnddata, rndlen * 2, piccrnd2, false); // error 307 DesfireCryptoEncDec(dctx, DCOMainKey, rnddata, rndlen * 2, piccrnd2, false); // error 307
// check // check
if (memcmp(hostrnd2, &piccrnd2[rndlen], rndlen) != 0) if (memcmp(hostrnd2, &piccrnd2[rndlen], rndlen) != 0)

View file

@ -217,7 +217,7 @@ static void DesfireCryptoEncDecSingleBlock(uint8_t *key, DesfireCryptoAlgorythm
memcpy(dstdata, edata, block_size); memcpy(dstdata, edata, block_size);
} }
void DesfireCryptoEncDecEx(DesfireContext *ctx, bool use_session_key, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool dir_to_send, bool encode, uint8_t *iv) { 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) {
uint8_t data[1024] = {0}; uint8_t data[1024] = {0};
uint8_t xiv[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0}; uint8_t xiv[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0};
@ -234,10 +234,13 @@ void DesfireCryptoEncDecEx(DesfireContext *ctx, bool use_session_key, uint8_t *s
size_t offset = 0; size_t offset = 0;
while (offset < srcdatalen) { while (offset < srcdatalen) {
if (use_session_key) if (key_type == DCOSessionKeyMac) {
DesfireCryptoEncDecSingleBlock(ctx->sessionKeyMAC, ctx->keyType, srcdata + offset, data + offset, xiv, dir_to_send, encode); DesfireCryptoEncDecSingleBlock(ctx->sessionKeyMAC, ctx->keyType, srcdata + offset, data + offset, xiv, dir_to_send, encode);
else } 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(ctx->key, ctx->keyType, srcdata + offset, data + offset, xiv, dir_to_send, encode);
}
offset += block_size; offset += block_size;
} }
@ -250,13 +253,13 @@ void DesfireCryptoEncDecEx(DesfireContext *ctx, bool use_session_key, uint8_t *s
memcpy(dstdata, data, srcdatalen); memcpy(dstdata, data, srcdatalen);
} }
void DesfireCryptoEncDec(DesfireContext *ctx, bool use_session_key, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool encode) { void DesfireCryptoEncDec(DesfireContext *ctx, DesfireCryptoOpKeyType key_type, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool encode) {
bool dir_to_send = encode; bool dir_to_send = encode;
bool xencode = encode; bool xencode = encode;
if (ctx->secureChannel == DACd40) if (ctx->secureChannel == DACd40)
xencode = false; xencode = false;
DesfireCryptoEncDecEx(ctx, use_session_key, srcdata, srcdatalen, dstdata, dir_to_send, xencode, NULL); DesfireCryptoEncDecEx(ctx, key_type, srcdata, srcdatalen, dstdata, dir_to_send, xencode, NULL);
} }
static void DesfireCMACGenerateSubkeys(DesfireContext *ctx, uint8_t *sk1, uint8_t *sk2) { static void DesfireCMACGenerateSubkeys(DesfireContext *ctx, uint8_t *sk1, uint8_t *sk2) {
@ -269,7 +272,7 @@ static void DesfireCMACGenerateSubkeys(DesfireContext *ctx, uint8_t *sk1, uint8_
uint8_t ivect[kbs]; uint8_t ivect[kbs];
memset(ivect, 0, kbs); memset(ivect, 0, kbs);
DesfireCryptoEncDecEx(ctx, true, l, kbs, l, true, true, ivect); DesfireCryptoEncDecEx(ctx, DCOSessionKeyMac, l, kbs, l, true, true, ivect);
bool txor = false; bool txor = false;
@ -314,7 +317,7 @@ void DesfireCryptoCMAC(DesfireContext *ctx, uint8_t *data, size_t len, uint8_t *
bin_xor(buffer + len - kbs, sk1, kbs); bin_xor(buffer + len - kbs, sk1, kbs);
} }
DesfireCryptoEncDec(ctx, true, buffer, len, NULL, true); DesfireCryptoEncDec(ctx, DCOSessionKeyMac, buffer, len, NULL, true);
if (cmac != NULL) if (cmac != NULL)
memcpy(cmac, ctx->IV, kbs); memcpy(cmac, ctx->IV, kbs);
@ -518,6 +521,19 @@ void DesfireEV2FillIV(DesfireContext *ctx, bool ivforcommand, uint8_t *iv) {
memcpy(iv, xiv, CRYPTO_AES_BLOCK_SIZE); memcpy(iv, xiv, CRYPTO_AES_BLOCK_SIZE);
} }
int DesfireEV2CalcCMAC(DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *mac) {
uint8_t mdata[1050] = {0};
size_t mdatalen = 0;
mdata[0] = cmd;
Uint2byteToMemLe(&mdata[1], ctx->cmdCntr);
memcpy(&mdata[3], ctx->TI, 4);
if (data != NULL && datalen > 0)
memcpy(&mdata[7], data, datalen);
mdatalen = 1 + 2 + 4 + datalen;
return aes_cmac8(NULL, ctx->sessionKeyMAC, mdata, mac, mdatalen);
}
void desfire_crc32(const uint8_t *data, const size_t len, uint8_t *crc) { void desfire_crc32(const uint8_t *data, const size_t len, uint8_t *crc) {
crc32_ex(data, len, crc); crc32_ex(data, len, crc);

View file

@ -61,6 +61,11 @@ typedef enum {
DCMEncryptedPlain DCMEncryptedPlain
} DesfireCommunicationMode; } DesfireCommunicationMode;
typedef enum {
DCOMainKey,
DCOSessionKeyMac,
DCOSessionKeyEnc
} DesfireCryptoOpKeyType;
typedef struct DesfireContextS { typedef struct DesfireContextS {
uint8_t keyNum; uint8_t keyNum;
@ -100,8 +105,8 @@ size_t DesfireGetMACLength(DesfireContext *ctx);
size_t DesfireSearchCRCPos(uint8_t *data, size_t datalen, uint8_t respcode, uint8_t crclen); size_t DesfireSearchCRCPos(uint8_t *data, size_t datalen, uint8_t respcode, uint8_t crclen);
void DesfireCryptoEncDec(DesfireContext *ctx, bool use_session_key, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool encode); void DesfireCryptoEncDec(DesfireContext *ctx, DesfireCryptoOpKeyType key_type, 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 dir_to_send, bool encode, uint8_t *iv); 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 DesfireCryptoCMAC(DesfireContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t *cmac); void DesfireCryptoCMAC(DesfireContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t *cmac);
void DesfireDESKeySetVersion(uint8_t *key, DesfireCryptoAlgorythm keytype, uint8_t version); void DesfireDESKeySetVersion(uint8_t *key, DesfireCryptoAlgorythm keytype, uint8_t version);
@ -117,6 +122,7 @@ uint8_t DesfireCommModeToFileCommMode(DesfireCommunicationMode comm_mode);
void DesfireGenSessionKeyEV1(const uint8_t rnda[], const uint8_t rndb[], DesfireCryptoAlgorythm keytype, uint8_t *key); 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 DesfireGenSessionKeyEV2(uint8_t *key, uint8_t *rndA, uint8_t *rndB, bool enckey, uint8_t *sessionkey);
void DesfireEV2FillIV(DesfireContext *ctx, bool ivforcommand, uint8_t *iv); 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);
void desfire_crc32(const uint8_t *data, const size_t len, uint8_t *crc); 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); void desfire_crc32_append(uint8_t *data, const size_t len);

View file

@ -166,7 +166,7 @@ static void DesfireSecureChannelEncodeD40(DesfireContext *ctx, uint8_t cmd, uint
size_t srcmaclen = padded_data_length(srcdatalen - hdrlen, desfire_get_key_block_length(ctx->keyType)); size_t srcmaclen = padded_data_length(srcdatalen - hdrlen, desfire_get_key_block_length(ctx->keyType));
uint8_t mac[32] = {0}; uint8_t mac[32] = {0};
DesfireCryptoEncDecEx(ctx, true, data, srcmaclen, NULL, true, true, mac); DesfireCryptoEncDecEx(ctx, DCOSessionKeyMac, data, srcmaclen, NULL, true, true, mac);
memcpy(dstdata, srcdata, srcdatalen); memcpy(dstdata, srcdata, srcdatalen);
memcpy(&dstdata[srcdatalen], mac, DesfireGetMACLength(ctx)); memcpy(&dstdata[srcdatalen], mac, DesfireGetMACLength(ctx));
@ -181,7 +181,7 @@ static void DesfireSecureChannelEncodeD40(DesfireContext *ctx, uint8_t cmd, uint
memcpy(dstdata, srcdata, hdrlen); memcpy(dstdata, srcdata, hdrlen);
//PrintAndLogEx(INFO, "src[%d]: %s", srcdatalen - hdrlen + 2, sprint_hex(data, srcdatalen - hdrlen + 2)); //PrintAndLogEx(INFO, "src[%d]: %s", srcdatalen - hdrlen + 2, sprint_hex(data, srcdatalen - hdrlen + 2));
DesfireCryptoEncDec(ctx, true, data, rlen - hdrlen, &dstdata[hdrlen], true); DesfireCryptoEncDec(ctx, DCOSessionKeyEnc, data, rlen - hdrlen, &dstdata[hdrlen], true);
*dstdatalen = rlen; *dstdatalen = rlen;
} else if (ctx->commMode == DCMEncryptedPlain) { } else if (ctx->commMode == DCMEncryptedPlain) {
@ -191,7 +191,7 @@ static void DesfireSecureChannelEncodeD40(DesfireContext *ctx, uint8_t cmd, uint
rlen = padded_data_length(srcdatalen - hdrlen, desfire_get_key_block_length(ctx->keyType)) + hdrlen; rlen = padded_data_length(srcdatalen - hdrlen, desfire_get_key_block_length(ctx->keyType)) + hdrlen;
memcpy(data, srcdata, srcdatalen); memcpy(data, srcdata, srcdatalen);
memcpy(dstdata, srcdata, hdrlen); memcpy(dstdata, srcdata, hdrlen);
DesfireCryptoEncDec(ctx, true, &data[hdrlen], rlen - hdrlen, &dstdata[hdrlen], true); DesfireCryptoEncDec(ctx, DCOSessionKeyEnc, &data[hdrlen], rlen - hdrlen, &dstdata[hdrlen], true);
*dstdatalen = rlen; *dstdatalen = rlen;
ctx->commMode = DCMEncrypted; ctx->commMode = DCMEncrypted;
} }
@ -227,7 +227,7 @@ static void DesfireSecureChannelEncodeEV1(DesfireContext *ctx, uint8_t cmd, uint
desfire_crc32_append(data, srcdatalen + 1); desfire_crc32_append(data, srcdatalen + 1);
memcpy(dstdata, srcdata, hdrlen); memcpy(dstdata, srcdata, hdrlen);
DesfireCryptoEncDec(ctx, true, &data[1 + hdrlen], rlen, &dstdata[hdrlen], true); DesfireCryptoEncDec(ctx, DCOSessionKeyEnc, &data[1 + hdrlen], rlen, &dstdata[hdrlen], true);
*dstdatalen = hdrlen + rlen; *dstdatalen = hdrlen + rlen;
} else if (ctx->commMode == DCMEncryptedPlain) { } else if (ctx->commMode == DCMEncryptedPlain) {
@ -237,16 +237,53 @@ static void DesfireSecureChannelEncodeEV1(DesfireContext *ctx, uint8_t cmd, uint
memcpy(dstdata, srcdata, hdrlen); memcpy(dstdata, srcdata, hdrlen);
memcpy(data, &srcdata[hdrlen], srcdatalen); memcpy(data, &srcdata[hdrlen], srcdatalen);
rlen = padded_data_length(srcdatalen - hdrlen, desfire_get_key_block_length(ctx->keyType)); rlen = padded_data_length(srcdatalen - hdrlen, desfire_get_key_block_length(ctx->keyType));
DesfireCryptoEncDec(ctx, true, data, rlen, &dstdata[hdrlen], true); DesfireCryptoEncDec(ctx, DCOSessionKeyEnc, data, rlen, &dstdata[hdrlen], true);
*dstdatalen = hdrlen + rlen; *dstdatalen = hdrlen + rlen;
ctx->commMode = DCMEncrypted; ctx->commMode = DCMEncrypted;
} }
} }
static void DesfireSecureChannelEncodeEV2(DesfireContext *ctx, uint8_t cmd, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen) { static void DesfireSecureChannelEncodeEV2(DesfireContext *ctx, uint8_t cmd, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen) {
uint8_t data[1050] = {0};
size_t rlen = 0;
memcpy(dstdata, srcdata, srcdatalen); memcpy(dstdata, srcdata, srcdatalen);
*dstdatalen = srcdatalen; *dstdatalen = srcdatalen;
uint8_t hdrlen = DesfireGetCmdHeaderLen(cmd);
if (ctx->commMode == DCMPlain || ctx->commMode == DCMMACed || (ctx->commMode == DCMEncrypted && srcdatalen <= hdrlen)) {
if (ctx->commMode == DCMMACed || ctx->commMode == DCMEncrypted) {
uint8_t cmac[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0};
DesfireEV2CalcCMAC(ctx, cmd, srcdata, srcdatalen, cmac);
memcpy(&dstdata[srcdatalen], cmac, DesfireGetMACLength(ctx));
*dstdatalen = srcdatalen + DesfireGetMACLength(ctx);
}
} else if (ctx->commMode == DCMEncrypted) {
DesfireEV2FillIV(ctx, true, NULL); // fill IV to ctx
rlen = padded_data_length(srcdatalen + 1 - hdrlen, desfire_get_key_block_length(ctx->keyType));
memcpy(data, &srcdata[hdrlen], srcdatalen - hdrlen);
data[hdrlen] = 0x80; // padding
dstdata[0] = cmd;
memcpy(&dstdata[1], srcdata, hdrlen);
DesfireCryptoEncDec(ctx, DCOSessionKeyEnc, data, rlen, &dstdata[1 + hdrlen], true);
uint8_t cmac[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0};
DesfireEV2CalcCMAC(ctx, cmd, &dstdata[1], hdrlen + rlen, cmac);
memcpy(&dstdata[ + hdrlen + rlen], cmac, DesfireGetMACLength(ctx));
*dstdatalen = hdrlen + rlen + DesfireGetMACLength(ctx);
} else if (ctx->commMode == DCMEncryptedPlain) {
if (srcdatalen <= hdrlen)
return;
// TODO !!!
}
} }
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) {
@ -284,7 +321,7 @@ static void DesfireSecureChannelDecodeD40(DesfireContext *ctx, uint8_t *srcdata,
uint8_t mac[16] = {0}; uint8_t mac[16] = {0};
rlen = padded_data_length(srcdatalen - maclen, desfire_get_key_block_length(ctx->keyType)); rlen = padded_data_length(srcdatalen - maclen, desfire_get_key_block_length(ctx->keyType));
memcpy(data, srcdata, srcdatalen - maclen); memcpy(data, srcdata, srcdatalen - maclen);
DesfireCryptoEncDecEx(ctx, true, data, rlen, NULL, true, true, mac); DesfireCryptoEncDecEx(ctx, DCOSessionKeyMac, data, rlen, NULL, true, true, mac);
if (memcmp(mac, &srcdata[srcdatalen - maclen], maclen) == 0) { if (memcmp(mac, &srcdata[srcdatalen - maclen], maclen) == 0) {
*dstdatalen = srcdatalen - maclen; *dstdatalen = srcdatalen - maclen;
@ -303,7 +340,7 @@ static void DesfireSecureChannelDecodeD40(DesfireContext *ctx, uint8_t *srcdata,
return; return;
} }
DesfireCryptoEncDec(ctx, true, srcdata, srcdatalen, dstdata, false); DesfireCryptoEncDec(ctx, DCOSessionKeyEnc, srcdata, srcdatalen, dstdata, false);
//PrintAndLogEx(INFO, "decoded[%d]: %s", srcdatalen, sprint_hex(dstdata, srcdatalen)); //PrintAndLogEx(INFO, "decoded[%d]: %s", srcdatalen, sprint_hex(dstdata, srcdatalen));
size_t puredatalen = DesfireSearchCRCPos(dstdata, srcdatalen, respcode, 2); size_t puredatalen = DesfireSearchCRCPos(dstdata, srcdatalen, respcode, 2);
@ -355,7 +392,7 @@ static void DesfireSecureChannelDecodeEV1(DesfireContext *ctx, uint8_t *srcdata,
return; return;
} }
DesfireCryptoEncDec(ctx, true, srcdata, srcdatalen, dstdata, false); DesfireCryptoEncDec(ctx, DCOSessionKeyEnc, srcdata, srcdatalen, dstdata, false);
//PrintAndLogEx(INFO, "decoded[%d]: %s", srcdatalen, sprint_hex(dstdata, srcdatalen)); //PrintAndLogEx(INFO, "decoded[%d]: %s", srcdatalen, sprint_hex(dstdata, srcdatalen));
size_t puredatalen = DesfireSearchCRCPos(dstdata, srcdatalen, respcode, 4); size_t puredatalen = DesfireSearchCRCPos(dstdata, srcdatalen, respcode, 4);
@ -377,6 +414,54 @@ static void DesfireSecureChannelDecodeEV2(DesfireContext *ctx, uint8_t *srcdata,
memcpy(dstdata, srcdata, srcdatalen); memcpy(dstdata, srcdata, srcdatalen);
*dstdatalen = srcdatalen; *dstdatalen = srcdatalen;
uint8_t cmac[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0};
// if comm mode = plain --> response with MAC
// if request is not zero length --> response MAC
if (ctx->commMode == DCMPlain || ctx->commMode == DCMMACed || (ctx->commMode == DCMEncrypted && !ctx->lastRequestZeroLen)) {
if (srcdatalen < DesfireGetMACLength(ctx)) {
memcpy(dstdata, srcdata, srcdatalen);
*dstdatalen = srcdatalen;
return;
}
memcpy(dstdata, srcdata, srcdatalen - DesfireGetMACLength(ctx));
*dstdatalen = srcdatalen - DesfireGetMACLength(ctx);
DesfireEV2CalcCMAC(ctx, 0x00, srcdata, *dstdatalen, 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)));
}
} else if (ctx->commMode == DCMEncrypted) {
if (srcdatalen < desfire_get_key_block_length(ctx->keyType) + DesfireGetMACLength(ctx)) {
memcpy(dstdata, srcdata, srcdatalen);
*dstdatalen = srcdatalen;
return;
}
*dstdatalen = srcdatalen - DesfireGetMACLength(ctx);
DesfireEV2CalcCMAC(ctx, 0x00, srcdata, *dstdatalen, 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)));
} else {
//PrintAndLogEx(INFO, "Received MAC OK");
}
DesfireEV2FillIV(ctx, false, NULL); // fill response IV to ctx
DesfireCryptoEncDec(ctx, DCOSessionKeyEnc, srcdata, *dstdatalen, dstdata, false);
size_t puredatalen = FindISO9797M2PaddingDataLen(dstdata, *dstdatalen);
if (puredatalen != 0) {
*dstdatalen = puredatalen;
} else {
PrintAndLogEx(WARNING, "Padding search error.");
}
}
} }
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) {
@ -431,6 +516,15 @@ bool PrintChannelModeWarning(uint8_t cmd, DesfireSecureChannel secureChannel, De
break; break;
} }
// ev2 like ev1
if (secureChannel == DACEV2 &&
AllowedChannelModes[i].secureChannel == DACEV1 &&
(AllowedChannelModes[i].cmdSet == cmdSet || (AllowedChannelModes[i].cmdSet == DCCNative && cmdSet == DCCNativeISO)) &&
AllowedChannelModes[i].commMode == commMode) {
found = true;
break;
}
} }
if (!found) if (!found)

View file

@ -269,6 +269,64 @@ static bool TestEV2IVEncode(void) {
return res; return res;
} }
// https://www.nxp.com/docs/en/application-note/AN12343.pdf
// page 54
static bool TestEV2MAC(void) {
bool res = true;
uint8_t key[] = {0x93, 0x66, 0xFA, 0x19, 0x5E, 0xB5, 0x66, 0xF5, 0xBD, 0x2B, 0xAD, 0x40, 0x20, 0xB8, 0x30, 0x02};
uint8_t ti[] = {0xE2, 0xD3, 0xAF, 0x69};
uint8_t cmd = 0x8D;
uint8_t cmddata[] = {0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22};
uint8_t macres[] = {0x68, 0xF2, 0xC2, 0x8C, 0x57, 0x5A, 0x16, 0x28};
// init
DesfireContext ctx = {0};
ctx.keyType = T_AES;
memcpy(ctx.sessionKeyMAC, key, 16);
memcpy(ctx.TI, ti, 4);
ctx.cmdCntr = 0;
// tx 1
uint8_t mac[16] = {0};
DesfireEV2CalcCMAC(&ctx, cmd, cmddata, sizeof(cmddata), mac);
res = res && (memcmp(mac, macres, sizeof(macres)) == 0);
// rx 1
memset(mac, 0, sizeof(mac));
uint8_t macres2[] = {0x08, 0x20, 0xF6, 0x88, 0x98, 0xC2, 0xA7, 0xF1};
uint8_t rc = 0;
ctx.cmdCntr++;
DesfireEV2CalcCMAC(&ctx, rc, NULL, 0, mac);
res = res && (memcmp(mac, macres2, sizeof(macres2)) == 0);
// tx 2
memset(mac, 0, sizeof(mac));
cmd = 0xAD;
uint8_t cmddata3[] = {0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00};
uint8_t macres3[] = {0x0D, 0x9B, 0xE1, 0x91, 0xD5, 0x96, 0x08, 0x34};
DesfireEV2CalcCMAC(&ctx, cmd, cmddata3, sizeof(cmddata3), mac);
res = res && (memcmp(mac, macres3, sizeof(macres3)) == 0);
// rx 2
rc = 0;
ctx.cmdCntr++;
uint8_t cmddata4[] = {0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t macres4[] = {0xA4, 0x9A, 0x44, 0x22, 0x2D, 0x92, 0x66, 0x66};
DesfireEV2CalcCMAC(&ctx, rc, cmddata4, sizeof(cmddata4), mac);
res = res && (memcmp(mac, macres4, sizeof(macres4)) == 0);
if (res)
PrintAndLogEx(INFO, "EV2 MAC calc...... " _GREEN_("passed"));
else
PrintAndLogEx(ERR, "EV2 MAC calc...... " _RED_("fail"));
return res;
}
bool DesfireTest(bool verbose) { bool DesfireTest(bool verbose) {
bool res = true; bool res = true;
@ -281,6 +339,7 @@ bool DesfireTest(bool verbose) {
res = res && TestCMACDES(); res = res && TestCMACDES();
res = res && TestEV2SessionKeys(); res = res && TestEV2SessionKeys();
res = res && TestEV2IVEncode(); res = res && TestEV2IVEncode();
res = res && TestEV2MAC();
PrintAndLogEx(INFO, "---------------------------"); PrintAndLogEx(INFO, "---------------------------");
if (res) if (res)