mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 22:03:42 -07:00
Merge pull request #1415 from merlokk/ev2mac
Ev2 mac calc and channel sketch
This commit is contained in:
commit
45073eb969
5 changed files with 203 additions and 28 deletions
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue