mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2024-09-21 15:56:21 +08:00
Merge pull request #1359 from merlokk/desfire4
Desfire encoded channel for d40/ev1
This commit is contained in:
commit
60d132fcc0
|
@ -976,6 +976,12 @@ void desfire_crc32_append(uint8_t *data, const size_t len) {
|
|||
crc32_ex(data, len, data + len);
|
||||
}
|
||||
|
||||
bool desfire_crc32_check(uint8_t *data, const size_t len, uint8_t *crc) {
|
||||
uint8_t ccrc[4] = {0};
|
||||
desfire_crc32(data, len, ccrc);
|
||||
return (memcmp(ccrc, crc, 4) == 0);
|
||||
}
|
||||
|
||||
void iso14443a_crc_append(uint8_t *data, size_t len) {
|
||||
return compute_crc(CRC_14443_A, data, len, data + len, data + len + 1);
|
||||
}
|
||||
|
@ -983,3 +989,9 @@ void iso14443a_crc_append(uint8_t *data, size_t len) {
|
|||
void iso14443a_crc(uint8_t *data, size_t len, uint8_t *pbtCrc) {
|
||||
return compute_crc(CRC_14443_A, data, len, pbtCrc, pbtCrc + 1);
|
||||
}
|
||||
|
||||
bool iso14443a_crc_check(uint8_t *data, const size_t len, uint8_t *crc) {
|
||||
uint8_t ccrc[2] = {0};
|
||||
iso14443a_crc(data, len, ccrc);
|
||||
return (memcmp(ccrc, crc, 2) == 0);
|
||||
}
|
||||
|
|
|
@ -149,6 +149,8 @@ void mifare_kdf_an10922(const desfirekey_t key, const uint8_t *data, size_t len)
|
|||
|
||||
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);
|
||||
void iso14443a_crc_append(uint8_t *data, size_t len);
|
||||
void iso14443a_crc(uint8_t *data, size_t len, uint8_t *pbtCrc);
|
||||
bool iso14443a_crc_check(uint8_t *data, const size_t len, uint8_t *crc);
|
||||
#endif
|
||||
|
|
|
@ -872,6 +872,16 @@ int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int DesfireGetUID(DesfireContext *dctx, uint8_t *resp, size_t *resplen) {
|
||||
uint8_t respcode = 0xff;
|
||||
int res = DesfireExchange(dctx, MFDES_GET_UID, NULL, 0, &respcode, resp, resplen);
|
||||
if (res != PM3_SUCCESS)
|
||||
return res;
|
||||
if (respcode != MFDES_S_OPERATION_OK)
|
||||
return PM3_EAPDU_FAIL;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int DesfireGetAIDList(DesfireContext *dctx, uint8_t *resp, size_t *resplen) {
|
||||
uint8_t respcode = 0xff;
|
||||
int res = DesfireExchange(dctx, MFDES_GET_APPLICATION_IDS, NULL, 0, &respcode, resp, resplen);
|
||||
|
|
|
@ -39,6 +39,7 @@ int DesfireSelectAIDHex(DesfireContext *ctx, uint32_t aid1, bool select_two, uin
|
|||
|
||||
int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel);
|
||||
|
||||
int DesfireGetUID(DesfireContext *dctx, uint8_t *resp, size_t *resplen);
|
||||
int DesfireGetAIDList(DesfireContext *dctx, uint8_t *resp, size_t *resplen);
|
||||
int DesfireGetDFList(DesfireContext *dctx, uint8_t *resp, size_t *resplen);
|
||||
|
||||
|
|
|
@ -56,6 +56,8 @@ void DesfireClearSession(DesfireContext *ctx) {
|
|||
memset(ctx->sessionKeyMAC, 0, sizeof(ctx->sessionKeyMAC));
|
||||
memset(ctx->sessionKeyEnc, 0, sizeof(ctx->sessionKeyEnc));
|
||||
memset(ctx->lastIV, 0, sizeof(ctx->lastIV));
|
||||
ctx->lastCommand = 0;
|
||||
ctx->lastRequestZeroLen = false;
|
||||
ctx->cntrTx = 0;
|
||||
ctx->cntrRx = 0;
|
||||
memset(ctx->TI, 0, sizeof(ctx->TI));
|
||||
|
@ -107,6 +109,42 @@ size_t DesfireGetMACLength(DesfireContext *ctx) {
|
|||
return mac_length;
|
||||
}
|
||||
|
||||
size_t DesfireSearchCRCPos(uint8_t *data, size_t datalen, uint8_t respcode, uint8_t crclen) {
|
||||
size_t crcpos = datalen - 1;
|
||||
while (crcpos > 0)
|
||||
if (data[crcpos] == 0)
|
||||
crcpos--;
|
||||
else
|
||||
break;
|
||||
crcpos++; // crc may be 0x00000000 or 0x0000
|
||||
if (crcpos < crclen) {
|
||||
PrintAndLogEx(WARNING, "No space for crc. pos: %d", crcpos);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t crcdata[1024] = {0};
|
||||
size_t crcposfound = 0;
|
||||
for (int i = 0; i < crclen + 1; i++) {
|
||||
if (crcpos - i == 0)
|
||||
break;
|
||||
if (crcpos - i + crclen > datalen)
|
||||
continue;
|
||||
|
||||
memcpy(crcdata, data, crcpos - i);
|
||||
crcdata[crcpos - i] = respcode;
|
||||
bool res;
|
||||
if (crclen == 4)
|
||||
res = desfire_crc32_check(crcdata, crcpos - i + 1, &data[crcpos - i]);
|
||||
else
|
||||
res = iso14443a_crc_check(data, crcpos - i, &data[crcpos - i]);
|
||||
if (res) {
|
||||
crcposfound = crcpos - i;
|
||||
}
|
||||
}
|
||||
|
||||
return crcposfound;
|
||||
}
|
||||
|
||||
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};
|
||||
|
@ -163,13 +201,14 @@ static void DesfireCryptoEncDecSingleBlock(uint8_t *key, DesfireCryptoAlgorythm
|
|||
break;
|
||||
}
|
||||
|
||||
memcpy(dstdata, edata, block_size);
|
||||
|
||||
if (dir_to_send) {
|
||||
memcpy(ivect, edata, block_size);
|
||||
} else {
|
||||
bin_xor(edata, ivect, block_size);
|
||||
memcpy(ivect, data, 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 encode, uint8_t *iv) {
|
||||
|
@ -189,9 +228,9 @@ void DesfireCryptoEncDecEx(DesfireContext *ctx, bool use_session_key, uint8_t *s
|
|||
size_t offset = 0;
|
||||
while (offset < srcdatalen) {
|
||||
if (use_session_key)
|
||||
DesfireCryptoEncDecSingleBlock(ctx->sessionKeyMAC, ctx->keyType, srcdata + offset, data, xiv, encode, encode);
|
||||
DesfireCryptoEncDecSingleBlock(ctx->sessionKeyMAC, ctx->keyType, srcdata + offset, data + offset, xiv, encode, encode);
|
||||
else
|
||||
DesfireCryptoEncDecSingleBlock(ctx->key, ctx->keyType, srcdata + offset, data, xiv, encode, encode);
|
||||
DesfireCryptoEncDecSingleBlock(ctx->key, ctx->keyType, srcdata + offset, data + offset, xiv, encode, encode);
|
||||
offset += block_size;
|
||||
}
|
||||
|
||||
|
@ -265,6 +304,7 @@ void DesfireCryptoCMAC(DesfireContext *ctx, uint8_t *data, size_t len, uint8_t *
|
|||
|
||||
DesfireCryptoEncDec(ctx, true, buffer, len, NULL, true);
|
||||
|
||||
memcpy(cmac, ctx->IV, kbs);
|
||||
if (cmac != NULL)
|
||||
memcpy(cmac, ctx->IV, kbs);
|
||||
}
|
||||
|
||||
|
|
|
@ -78,6 +78,8 @@ typedef struct DesfireContextS {
|
|||
uint8_t sessionKeyMAC[DESFIRE_MAX_KEY_SIZE];
|
||||
uint8_t sessionKeyEnc[DESFIRE_MAX_KEY_SIZE]; // look at mifare4.h - mf4Session_t
|
||||
uint8_t lastIV[DESFIRE_MAX_KEY_SIZE];
|
||||
uint8_t lastCommand;
|
||||
bool lastRequestZeroLen;
|
||||
//mf4Session_t AESSession;
|
||||
uint16_t cntrTx; // for AES
|
||||
uint16_t cntrRx; // for AES
|
||||
|
@ -93,6 +95,7 @@ void DesfireSetKdf(DesfireContext *ctx, uint8_t kdfAlgo, uint8_t *kdfInput, uint
|
|||
bool DesfireIsAuthenticated(DesfireContext *dctx);
|
||||
size_t DesfireGetMACLength(DesfireContext *ctx);
|
||||
|
||||
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 DesfireCryptoEncDecEx(DesfireContext *ctx, bool use_session_key, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool encode, uint8_t *iv);
|
||||
|
|
|
@ -40,15 +40,20 @@ static void DesfireSecureChannelEncodeD40(DesfireContext *ctx, uint8_t cmd, uint
|
|||
|
||||
rlen = padded_data_length(srcdatalen, desfire_get_key_block_length(ctx->keyType));
|
||||
memcpy(data, srcdata, srcdatalen);
|
||||
memset(ctx->IV, 0, sizeof(ctx->IV));
|
||||
DesfireCryptoEncDec(ctx, true, data, rlen, NULL, true);
|
||||
memcpy(dstdata, srcdata, srcdatalen);
|
||||
memcpy(&dstdata[srcdatalen], ctx->IV, 4);
|
||||
*dstdatalen = rlen;
|
||||
break;
|
||||
case DCMEncrypted:
|
||||
if (srcdatalen == 0)
|
||||
break;
|
||||
|
||||
rlen = padded_data_length(srcdatalen + 2, desfire_get_key_block_length(ctx->keyType)); // 2 - crc16
|
||||
memcpy(data, srcdata, srcdatalen);
|
||||
compute_crc(CRC_14443_A, data, srcdatalen, &data[srcdatalen], &data[srcdatalen + 1]);
|
||||
memset(ctx->IV, 0, sizeof(ctx->IV));
|
||||
DesfireCryptoEncDec(ctx, true, data, rlen, dstdata, true);
|
||||
*dstdatalen = rlen;
|
||||
break;
|
||||
|
@ -60,31 +65,33 @@ static void DesfireSecureChannelEncodeD40(DesfireContext *ctx, uint8_t cmd, uint
|
|||
static void DesfireSecureChannelEncodeEV1(DesfireContext *ctx, uint8_t cmd, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen) {
|
||||
uint8_t data[1024] = {0};
|
||||
|
||||
memcpy(dstdata, srcdata, srcdatalen);
|
||||
*dstdatalen = srcdatalen;
|
||||
// we calc MAC anyway
|
||||
// if encypted channel and no data - we only calc MAC
|
||||
if (ctx->commMode == DCMPlain || ctx->commMode == DCMMACed || (ctx->commMode == DCMEncrypted && srcdatalen == 0)) {
|
||||
data[0] = cmd;
|
||||
memcpy(&data[1], srcdata, srcdatalen);
|
||||
uint8_t cmac[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0};
|
||||
DesfireCryptoCMAC(ctx, data, srcdatalen + 1, cmac);
|
||||
|
||||
switch (ctx->commMode) {
|
||||
case DCMPlain:
|
||||
case DCMMACed:
|
||||
data[0] = cmd;
|
||||
memcpy(&data[1], srcdata, srcdatalen);
|
||||
uint8_t cmac[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0};
|
||||
DesfireCryptoCMAC(ctx, data, srcdatalen + 1, cmac);
|
||||
|
||||
memcpy(dstdata, srcdata, srcdatalen);
|
||||
if (srcdatalen != 0 && ctx->commMode == DCMMACed) {
|
||||
memcpy(&dstdata[srcdatalen], cmac, DesfireGetMACLength(ctx));
|
||||
*dstdatalen = srcdatalen + DesfireGetMACLength(ctx);
|
||||
}
|
||||
break;
|
||||
case DCMEncrypted:
|
||||
break;
|
||||
case DCMNone:
|
||||
;
|
||||
memcpy(dstdata, srcdata, srcdatalen);
|
||||
if (srcdatalen != 0 && ctx->commMode == DCMMACed) {
|
||||
memcpy(&dstdata[srcdatalen], cmac, DesfireGetMACLength(ctx));
|
||||
*dstdatalen = srcdatalen + DesfireGetMACLength(ctx);
|
||||
}
|
||||
} else if (ctx->commMode == DCMEncrypted) {
|
||||
|
||||
|
||||
|
||||
} else {
|
||||
memcpy(dstdata, srcdata, srcdatalen);
|
||||
*dstdatalen = srcdatalen;
|
||||
}
|
||||
}
|
||||
|
||||
void DesfireSecureChannelEncode(DesfireContext *ctx, uint8_t cmd, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen) {
|
||||
ctx->lastCommand = cmd;
|
||||
ctx->lastRequestZeroLen = (srcdatalen == 0);
|
||||
|
||||
switch (ctx->secureChannel) {
|
||||
case DACd40:
|
||||
DesfireSecureChannelEncodeD40(ctx, cmd, srcdata, srcdatalen, dstdata, dstdatalen);
|
||||
|
@ -110,6 +117,22 @@ static void DesfireSecureChannelDecodeD40(DesfireContext *ctx, uint8_t *srcdata,
|
|||
|
||||
break;
|
||||
case DCMEncrypted:
|
||||
if (srcdatalen < desfire_get_key_block_length(ctx->keyType)) {
|
||||
memcpy(dstdata, srcdata, srcdatalen);
|
||||
*dstdatalen = srcdatalen;
|
||||
return;
|
||||
}
|
||||
|
||||
DesfireCryptoEncDec(ctx, true, srcdata, srcdatalen, dstdata, false);
|
||||
//PrintAndLogEx(INFO, "decoded[%d]: %s", srcdatalen, sprint_hex(dstdata, srcdatalen));
|
||||
|
||||
size_t puredatalen = DesfireSearchCRCPos(dstdata, srcdatalen, respcode, 2);
|
||||
if (puredatalen != 0) {
|
||||
*dstdatalen = puredatalen;
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "CRC16 error.");
|
||||
*dstdatalen = srcdatalen;
|
||||
}
|
||||
break;
|
||||
case DCMPlain:
|
||||
case DACNone:
|
||||
|
@ -122,36 +145,49 @@ static void DesfireSecureChannelDecodeD40(DesfireContext *ctx, uint8_t *srcdata,
|
|||
static void DesfireSecureChannelDecodeEV1(DesfireContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t respcode, uint8_t *dstdata, size_t *dstdatalen) {
|
||||
uint8_t data[1024] = {0};
|
||||
|
||||
memcpy(dstdata, srcdata, srcdatalen);
|
||||
*dstdatalen = srcdatalen;
|
||||
|
||||
switch (ctx->commMode) {
|
||||
case DCMPlain:
|
||||
case DCMMACed:
|
||||
if (srcdatalen < DesfireGetMACLength(ctx))
|
||||
break;
|
||||
|
||||
memcpy(dstdata, srcdata, srcdatalen - DesfireGetMACLength(ctx));
|
||||
*dstdatalen = srcdatalen - DesfireGetMACLength(ctx);
|
||||
|
||||
memcpy(data, srcdata, *dstdatalen);
|
||||
data[*dstdatalen] = respcode;
|
||||
|
||||
uint8_t cmac[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0};
|
||||
DesfireCryptoCMAC(ctx, data, *dstdatalen + 1, cmac);
|
||||
if (memcmp(&srcdata[*dstdatalen], cmac, DesfireGetMACLength(ctx)) != 0) {
|
||||
PrintAndLogEx(WARNING, "Received MAC is not match with calculated");
|
||||
PrintAndLogEx(INFO, " received MAC: %s", sprint_hex(&srcdata[*dstdatalen], desfire_get_key_block_length(ctx->keyType)));
|
||||
PrintAndLogEx(INFO, " calculated MAC: %s", sprint_hex(cmac, desfire_get_key_block_length(ctx->keyType)));
|
||||
}
|
||||
|
||||
break;
|
||||
case DCMEncrypted:
|
||||
break;
|
||||
case DACNone:
|
||||
// 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;
|
||||
break;
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(dstdata, srcdata, srcdatalen - DesfireGetMACLength(ctx));
|
||||
*dstdatalen = srcdatalen - DesfireGetMACLength(ctx);
|
||||
|
||||
memcpy(data, srcdata, *dstdatalen);
|
||||
data[*dstdatalen] = respcode;
|
||||
|
||||
uint8_t cmac[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0};
|
||||
DesfireCryptoCMAC(ctx, data, *dstdatalen + 1, cmac);
|
||||
if (memcmp(&srcdata[*dstdatalen], cmac, DesfireGetMACLength(ctx)) != 0) {
|
||||
PrintAndLogEx(WARNING, "Received MAC is not match with calculated");
|
||||
PrintAndLogEx(INFO, " received MAC: %s", sprint_hex(&srcdata[*dstdatalen], desfire_get_key_block_length(ctx->keyType)));
|
||||
PrintAndLogEx(INFO, " calculated MAC: %s", sprint_hex(cmac, desfire_get_key_block_length(ctx->keyType)));
|
||||
}
|
||||
} else if (ctx->commMode == DCMEncrypted) {
|
||||
if (srcdatalen < desfire_get_key_block_length(ctx->keyType)) {
|
||||
memcpy(dstdata, srcdata, srcdatalen);
|
||||
*dstdatalen = srcdatalen;
|
||||
return;
|
||||
}
|
||||
|
||||
DesfireCryptoEncDec(ctx, true, srcdata, srcdatalen, dstdata, false);
|
||||
//PrintAndLogEx(INFO, "decoded[%d]: %s", srcdatalen, sprint_hex(dstdata, srcdatalen));
|
||||
|
||||
size_t puredatalen = DesfireSearchCRCPos(dstdata, srcdatalen, respcode, 4);
|
||||
if (puredatalen != 0) {
|
||||
*dstdatalen = puredatalen;
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "CRC32 error.");
|
||||
*dstdatalen = srcdatalen;
|
||||
}
|
||||
|
||||
} else {
|
||||
memcpy(dstdata, srcdata, srcdatalen);
|
||||
*dstdatalen = srcdatalen;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue