diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index f2b75f31d..b1ac5ce8a 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -4931,6 +4931,15 @@ static int CmdHF14ADesChangeKey(const char *Cmd) { return PM3_ESOFT; uint8_t oldkey[DESFIRE_MAX_KEY_SIZE] = {0}; + uint8_t keydata[200] = {0}; + int keylen = sizeof(keydata); + CLIGetHexWithReturn(ctx, 13, keydata, &keylen); + if (keylen && keylen != desfire_get_key_length(oldkeytype)) { + PrintAndLogEx(ERR, "%s old key must have %d bytes length instead of %d.", CLIGetOptionListStr(DesfireAlgoOpts, oldkeytype), desfire_get_key_length(oldkeytype), keylen); + return PM3_EINVARG; + } + if (keylen) + memcpy(oldkey, keydata, keylen); uint8_t newkeynum = arg_get_int_def(ctx, 14, 0); @@ -4939,8 +4948,22 @@ static int CmdHF14ADesChangeKey(const char *Cmd) { return PM3_ESOFT; uint8_t newkey[DESFIRE_MAX_KEY_SIZE] = {0}; + memset(keydata, 0x00, sizeof(keydata)); + CLIGetHexWithReturn(ctx, 16, keydata, &keylen); + if (keylen && keylen != desfire_get_key_length(newkeytype)) { + PrintAndLogEx(ERR, "%s new key must have %d bytes length instead of %d.", CLIGetOptionListStr(DesfireAlgoOpts, newkeytype), desfire_get_key_length(newkeytype), keylen); + return PM3_EINVARG; + } + if (keylen) + memcpy(newkey, keydata, keylen); - uint8_t newkeyver = arg_get_int_def(ctx, 17, 0x100); + uint32_t newkeyver = 0x100; + res = arg_get_u32_hexstr_def_nlen(ctx, 17, 0x100, &newkeyver, 1, true); + if (res == 2) { + PrintAndLogEx(ERR, "Key version must have 1 bytes length"); + CLIParserFree(ctx); + return PM3_EINVARG; + } SetAPDULogging(APDULogging); CLIParserFree(ctx); @@ -4956,6 +4979,7 @@ static int CmdHF14ADesChangeKey(const char *Cmd) { return res; } + DesfireSetCommMode(&dctx, DCMEncryptedPlain); res = DesfireChangeKey(&dctx, newkeynum, newkeytype, newkeyver, newkey, oldkeytype, oldkey); if (res == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "Change key " _GREEN_("ok") " "); diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 27401944f..42d52e4c7 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -989,7 +989,7 @@ int DesfireChangeKeySettings(DesfireContext *dctx, uint8_t *data, size_t len) { } int DesfireChangeKeyCmd(DesfireContext *dctx, uint8_t *data, size_t len, uint8_t *resp, size_t *resplen) { - return DesfireCommand(dctx, MFDES_GET_KEY_VERSION, data, len, resp, resplen, -1); + return DesfireCommand(dctx, MFDES_CHANGE_KEY, data, len, resp, resplen, -1); } uint8_t DesfireKeyAlgoToType(DesfireCryptoAlgorythm keyType) { @@ -1083,26 +1083,35 @@ int DesfireChangeKey(DesfireContext *dctx, uint8_t newkeynum, DesfireCryptoAlgor uint8_t okeybuf[DESFIRE_MAX_KEY_SIZE] = {0}; uint8_t nkeybuf[DESFIRE_MAX_KEY_SIZE] = {0}; - uint8_t cdata[DESFIRE_MAX_KEY_SIZE + 10] = {0}; + uint8_t pckcdata[DESFIRE_MAX_KEY_SIZE + 10] = {0}; + uint8_t *cdata = &pckcdata[2]; + uint8_t keynodata = newkeynum & 0x3f; + keynodata |= (DesfireKeyAlgoToType(newkeytype) & 0x03) << 6; + pckcdata[0] = MFDES_CHANGE_KEY; // TODO + pckcdata[1] = keynodata; // DES -> 2TDEA memcpy(okeybuf, oldkey, desfire_get_key_length(oldkeytype)); if (oldkeytype == T_DES) { memcpy(&okeybuf[8], oldkey, 8); - oldkeytype = T_3DES; } memcpy(nkeybuf, newkey, desfire_get_key_length(newkeytype)); + size_t nkeylen = desfire_get_key_length(newkeytype); if (newkeytype == T_DES) { memcpy(&nkeybuf[8], newkey, 8); - newkeytype = T_3DES; + nkeylen = desfire_get_key_length(T_3DES); } - size_t nkeylen = desfire_get_key_length(newkeytype); + +PrintAndLogEx(SUCCESS, "--oldk [%d]: %s", desfire_get_key_length(oldkeytype), sprint_hex(okeybuf, desfire_get_key_length(oldkeytype))); +PrintAndLogEx(SUCCESS, "--newk [%d]: %s", nkeylen, sprint_hex(nkeybuf, nkeylen)); // set key version for DES. if newkeyver > 0xff - setting key version is disabled if (newkeytype != T_AES && newkeyver < 0x100) DesfireDESKeySetVersion(nkeybuf, newkeytype, newkeyver); +PrintAndLogEx(SUCCESS, "--newk [%d]: %s", nkeylen, sprint_hex(nkeybuf, nkeylen)); + // xor if we change current auth key if (newkeynum == dctx->keyNum) { memcpy(cdata, nkeybuf, nkeylen); @@ -1113,10 +1122,12 @@ int DesfireChangeKey(DesfireContext *dctx, uint8_t newkeynum, DesfireCryptoAlgor // add key version for AES size_t cdatalen = nkeylen; +PrintAndLogEx(SUCCESS, "--cdata [%d]: %s kv = 0x%02x", cdatalen, sprint_hex(cdata, cdatalen), newkeyver); if (newkeytype == T_AES) { cdata[cdatalen] = newkeyver; cdatalen++; } +PrintAndLogEx(SUCCESS, "--cdata [%d]: %s", cdatalen, sprint_hex(cdata, cdatalen)); // add crc||crc_new_key if (dctx->secureChannel == DACd40) { @@ -1127,13 +1138,15 @@ int DesfireChangeKey(DesfireContext *dctx, uint8_t newkeynum, DesfireCryptoAlgor cdatalen += 2; } } else { - desfire_crc32_append(cdata, cdatalen); + // EV1 Checksum must cover : [] + desfire_crc32_append(pckcdata, cdatalen + 2); cdatalen += 4; if (newkeynum != dctx->keyNum) { desfire_crc32(nkeybuf, nkeylen, &cdata[cdatalen]); cdatalen += 4; } } +PrintAndLogEx(SUCCESS, "--cdata [%d]: %s", cdatalen, sprint_hex(cdata, cdatalen)); // get padded data length size_t rlen = padded_data_length(cdatalen, desfire_get_key_block_length(newkeytype)); @@ -1141,7 +1154,8 @@ int DesfireChangeKey(DesfireContext *dctx, uint8_t newkeynum, DesfireCryptoAlgor // send command uint8_t resp[257] = {0}; size_t resplen = 0; - int res = DesfireChangeKeyCmd(dctx, cdata, rlen, resp, &resplen); +PrintAndLogEx(SUCCESS, "--pckdata [%d]: %s", rlen + 1, sprint_hex(&pckcdata[1], rlen + 1)); + int res = DesfireChangeKeyCmd(dctx, &pckcdata[1], rlen + 1, resp, &resplen); // check response diff --git a/client/src/mifare/desfirecrypto.c b/client/src/mifare/desfirecrypto.c index 51bfc6eb4..79604f5eb 100644 --- a/client/src/mifare/desfirecrypto.c +++ b/client/src/mifare/desfirecrypto.c @@ -331,7 +331,7 @@ void DesfireDESKeySetVersion(uint8_t *key, DesfireCryptoAlgorythm keytype, uint8 } else { // Write ~version to avoid turning a 3DES key into a DES key key[n + 8] &= 0xFE; - key[n + 8] |= ~version_bit; + key[n + 8] |= (~version_bit) & 0x01; } } } diff --git a/client/src/mifare/desfirecrypto.h b/client/src/mifare/desfirecrypto.h index c83720d80..0ec729a04 100644 --- a/client/src/mifare/desfirecrypto.h +++ b/client/src/mifare/desfirecrypto.h @@ -56,7 +56,8 @@ typedef enum { DCMNone, DCMPlain, DCMMACed, - DCMEncrypted + DCMEncrypted, + DCMEncryptedPlain } DesfireCommunicationMode; diff --git a/client/src/mifare/desfiresecurechan.c b/client/src/mifare/desfiresecurechan.c index 2e49ce5ac..c5b90c29d 100644 --- a/client/src/mifare/desfiresecurechan.c +++ b/client/src/mifare/desfiresecurechan.c @@ -52,6 +52,9 @@ AllowedChannelModesS AllowedChannelModes[] = { {MFDES_READ_DATA, DACd40, DCCNative, DCMEncrypted}, {MFDES_WRITE_DATA, DACd40, DCCNative, DCMEncrypted}, + {MFDES_CHANGE_KEY, DACd40, DCCNative, DCMEncryptedPlain}, + {MFDES_CHANGE_KEY_EV2, DACd40, DCCNative, DCMEncryptedPlain}, + {MFDES_GET_KEY_VERSION, DACEV1, DCCNative, DCMPlain}, {MFDES_GET_FREE_MEMORY, DACEV1, DCCNative, DCMPlain}, @@ -63,14 +66,28 @@ AllowedChannelModesS AllowedChannelModes[] = { {MFDES_GET_UID, DACEV1, DCCNative, DCMEncrypted}, {MFDES_CHANGE_KEY_SETTINGS, DACEV1, DCCNative, DCMEncrypted}, + + {MFDES_CHANGE_KEY, DACEV1, DCCNative, DCMEncryptedPlain}, + {MFDES_CHANGE_KEY_EV2, DACEV1, DCCNative, DCMEncryptedPlain}, }; +static uint8_t DesfireGetCmdHeaderLen(uint8_t cmd) { + if (cmd == MFDES_CHANGE_KEY || cmd == MFDES_CHANGE_CONFIGURATION) + return 1; + + if (cmd == MFDES_CHANGE_KEY_EV2) + return 2; + + return 0; +} + static void DesfireSecureChannelEncodeD40(DesfireContext *ctx, uint8_t cmd, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen) { memcpy(dstdata, srcdata, srcdatalen); *dstdatalen = srcdatalen; uint8_t data[1024] = {0}; size_t rlen = 0; + uint8_t hdrlen = DesfireGetCmdHeaderLen(cmd); switch (ctx->commMode) { case DCMPlain: @@ -89,7 +106,7 @@ static void DesfireSecureChannelEncodeD40(DesfireContext *ctx, uint8_t cmd, uint *dstdatalen = rlen; break; case DCMEncrypted: - if (srcdatalen == 0) + if (srcdatalen == 0 || srcdatalen <= hdrlen) break; rlen = padded_data_length(srcdatalen + 2, desfire_get_key_block_length(ctx->keyType)); // 2 - crc16 @@ -98,6 +115,16 @@ static void DesfireSecureChannelEncodeD40(DesfireContext *ctx, uint8_t cmd, uint DesfireCryptoEncDec(ctx, true, data, rlen, dstdata, true); *dstdatalen = rlen; break; + case DCMEncryptedPlain: + if (srcdatalen == 0 || srcdatalen <= hdrlen) + break; + + rlen = padded_data_length(srcdatalen - hdrlen, desfire_get_key_block_length(ctx->keyType)) + hdrlen; + memcpy(data, srcdata, srcdatalen); + memcpy(dstdata, srcdata, hdrlen); + DesfireCryptoEncDec(ctx, true, &data[hdrlen], rlen - hdrlen, &dstdata[hdrlen], true); + *dstdatalen = rlen; + break; case DCMNone: ; } @@ -107,6 +134,10 @@ static void DesfireSecureChannelEncodeEV1(DesfireContext *ctx, uint8_t cmd, uint uint8_t data[1024] = {0}; size_t rlen = 0; + memcpy(dstdata, srcdata, srcdatalen); + *dstdatalen = srcdatalen; + uint8_t hdrlen = DesfireGetCmdHeaderLen(cmd); + // 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)) { @@ -130,9 +161,19 @@ static void DesfireSecureChannelEncodeEV1(DesfireContext *ctx, uint8_t cmd, uint DesfireCryptoEncDec(ctx, true, &data[1], rlen, dstdata, true); *dstdatalen = rlen; - } else { - memcpy(dstdata, srcdata, srcdatalen); - *dstdatalen = srcdatalen; + } else if (ctx->commMode == DCMEncryptedPlain) { + if (srcdatalen == 0 || srcdatalen <= hdrlen) + return; + +PrintAndLogEx(SUCCESS, "--ch hdrlen: %d, cmd: %02x", hdrlen, cmd); + //dstdata[0] = cmd; + memcpy(&dstdata[0], srcdata, hdrlen); + memcpy(data, &srcdata[hdrlen], srcdatalen); + rlen = padded_data_length(srcdatalen - hdrlen, desfire_get_key_block_length(ctx->keyType)); +PrintAndLogEx(SUCCESS, "--ch src rlen: %d data: %s", rlen, sprint_hex(data, rlen)); + DesfireCryptoEncDec(ctx, true, data, rlen, &dstdata[hdrlen], true); + *dstdatalen = hdrlen + rlen; +PrintAndLogEx(SUCCESS, "--ch dst len: %d data: %s", *dstdatalen, sprint_hex(dstdata, *dstdatalen)); } } @@ -184,6 +225,7 @@ static void DesfireSecureChannelDecodeD40(DesfireContext *ctx, uint8_t *srcdata, break; case DCMPlain: case DACNone: + case DCMEncryptedPlain: memcpy(dstdata, srcdata, srcdatalen); *dstdatalen = srcdatalen; break; diff --git a/include/protocols.h b/include/protocols.h index 58bd7e90f..efa3e0a78 100644 --- a/include/protocols.h +++ b/include/protocols.h @@ -424,6 +424,7 @@ ISO 7816-4 Basic interindustry commands. For command APDU's. #define MFDES_INIT_KEY_SETTINGS 0x56 #define MFDES_FINALIZE_KEY_SETTINGS 0x57 #define MFDES_SELECT_APPLICATION 0x5A +#define MFDES_CHANGE_CONFIGURATION 0x5C #define MFDES_CHANGE_FILE_SETTINGS 0x5F #define MFDES_GET_VERSION 0x60 #define MFDES_GET_ISOFILE_IDS 0x61