authentication works

This commit is contained in:
merlokk
2021-07-02 17:37:15 +03:00
parent b5ee999c73
commit e5d24ff81f
3 changed files with 319 additions and 13 deletions
+14 -2
View File
@@ -5106,8 +5106,8 @@ static int CmdHF14ADesGetAIDs(const char *Cmd) {
uint8_t key[24] = {0};
DesfireContext dctx;
DesfireSetKey(&dctx, 1, T_DES, key);
dctx.cmdChannel = DCCNativeISO;
DesfireSetKey(&dctx, 0, T_DES, key); // T_DES T_3DES T_3K3DES T_AES
DesfireSetCommandChannel(&dctx, DCCNativeISO);
//size_t len = 0;
@@ -5120,6 +5120,18 @@ static int CmdHF14ADesGetAIDs(const char *Cmd) {
DropField();
return PM3_ESOFT;
}
res = DesfireAuthenticate(&dctx, DACd40); //DACd40 DACEV1
if (res != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Desfire authenticate " _RED_("error") ". Result: %d", res);
DropField();
return PM3_ESOFT;
}
if (DesfireIsAuthenticated(&dctx))
PrintAndLogEx(ERR, "Desfire " _GREEN_("authenticated") , res);
else
return PM3_ESOFT;
+294 -7
View File
@@ -19,13 +19,15 @@
#include <stdlib.h>
#include <string.h>
#include <util.h>
#include "aes.h"
#include "ui.h"
#include "protocols.h"
#include "commonutil.h"
#include "cmdhf14a.h"
#include "iso7816/apduinfo.h" // APDU manipulation / errorcodes
#include "iso7816/iso7816core.h" // APDU logging
#include "util_posix.h" // msleep
#include "mifare/desfire_crypto.h"\
#include "iso7816/apduinfo.h" // APDU manipulation / errorcodes
#include "iso7816/iso7816core.h" // APDU logging
#include "util_posix.h" // msleep
#include "mifare/desfire_crypto.h"
static const char *getstatus(uint16_t *sw) {
if (sw == NULL) return "--> sw argument error. This should never happen !";
@@ -155,6 +157,16 @@ void DesfireClearContext(DesfireContext *ctx) {
ctx->cmdChannel = DCCNative;
ctx->commMode = DCMNone;
ctx->kdfAlgo = 0;
ctx->kdfInputLen = 0;
memset(ctx->kdfInput, 0, sizeof(ctx->kdfInput));
DesfireClearSession(ctx);
}
void DesfireClearSession(DesfireContext *ctx) {
ctx->authChannel = DACNone; // here none - not authenticared
memset(ctx->sessionKeyMAC, 0, sizeof(ctx->sessionKeyMAC));
memset(ctx->sessionKeyEnc, 0, sizeof(ctx->sessionKeyEnc));
memset(ctx->lastIV, 0, sizeof(ctx->lastIV));
@@ -171,6 +183,10 @@ void DesfireSetKey(DesfireContext *ctx, uint8_t keyNum, enum DESFIRE_CRYPTOALGO
memcpy(ctx->key, key, desfire_get_key_length(keyType));
}
void DesfireSetCommandChannel(DesfireContext *ctx, DesfireCommandChannel cmdChannel) {
ctx->cmdChannel = cmdChannel;
}
static int DESFIRESendApdu(bool activate_field, sAPDU apdu, uint8_t *result, uint32_t max_result_len, uint32_t *result_len, uint16_t *sw) {
if (result_len) *result_len = 0;
if (sw) *sw = 0;
@@ -272,12 +288,12 @@ static int DesfireExchangeISO(bool activate_field, DesfireContext *ctx, uint8_t
pos += buflen;
if (!enable_chaining) {
if (sw == DESFIRE_GET_ISO_STATUS(MFDES_ADDITIONAL_FRAME)) {
if (sw == DESFIRE_GET_ISO_STATUS(MFDES_S_OPERATION_OK) ||
sw == DESFIRE_GET_ISO_STATUS(MFDES_ADDITIONAL_FRAME)) {
if (resplen)
*resplen = pos;
return PM3_SUCCESS;
}
return res;
return PM3_SUCCESS;
}
while (sw == DESFIRE_GET_ISO_STATUS(MFDES_ADDITIONAL_FRAME)) {
@@ -312,6 +328,7 @@ static int DesfireExchangeISO(bool activate_field, DesfireContext *ctx, uint8_t
if (resplen)
*resplen = (splitbysize) ? i : pos;
return PM3_SUCCESS;
}
@@ -377,3 +394,273 @@ int DesfireSelectAIDHex(DesfireContext *ctx, uint32_t aid1, bool select_two, uin
return DesfireSelectAID(ctx, data, (select_two) ? &data[3] : NULL);
}
bool DesfireIsAuthenticated(DesfireContext *dctx) {
return dctx->authChannel != DACNone;
}
int DesfireAuthenticate(DesfireContext *dctx, DesfireAuthChannel authChannel) {
// 3 different way to authenticate AUTH (CRC16) , AUTH_ISO (CRC32) , AUTH_AES (CRC32)
// 4 different crypto arg1 DES, 3DES, 3K3DES, AES
// 3 different communication modes, PLAIN,MAC,CRYPTO
DesfireClearSession(dctx);
if (authChannel == DACNone)
return PM3_SUCCESS;
mbedtls_aes_context ctx;
uint8_t keybytes[24] = {0};
// Crypt constants
uint8_t IV[16] = {0};
uint8_t RndA[16] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16};
uint8_t RndB[16] = {0};
uint8_t encRndB[16] = {0};
uint8_t rotRndB[16] = {0}; //RndB'
uint8_t both[32 + 1] = {0}; // ek/dk_keyNo(RndA+RndB')
// 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;
dctx->authChannel = authChannel;
if (dctx->authChannel == DACEV1) {
if (dctx->keyType == T_AES)
subcommand = MFDES_AUTHENTICATE_AES;
else
subcommand = MFDES_AUTHENTICATE_ISO;
}
uint32_t recv_len = 0;
uint8_t respcode = 0;
uint8_t recv_data[256] = {0};
// Let's send our auth command
int res = DesfireExchangeEx(false, dctx, subcommand, &dctx->keyNum, 1, &respcode, recv_data, &recv_len, false);
if (res != PM3_SUCCESS) {
return 1;
}
if (!recv_len) {
return 2;
}
if (respcode != MFDES_ADDITIONAL_FRAME) {
return 3;
}
uint32_t expectedlen = 8;
if (dctx->keyType == T_AES || dctx->keyType == T_3K3DES) {
expectedlen = 16;
}
if (recv_len != expectedlen) {
return 4;
}
// Part 2
uint32_t rndlen = recv_len;
memcpy(encRndB, recv_data, rndlen);
// 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)
des_decrypt(RndB, encRndB, key->data);
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);
}
if (g_debugMode > 1) {
PrintAndLogEx(DEBUG, "encRndB: %s", sprint_hex(encRndB, 8));
PrintAndLogEx(DEBUG, "RndB: %s", sprint_hex(RndB, 8));
}
// - Rotate RndB by 8 bits
memcpy(rotRndB, RndB, rndlen);
rol(rotRndB, rndlen);
uint8_t encRndA[16] = {0x00};
// - Encrypt our response
if (dctx->authChannel == DACd40) {
des_decrypt(encRndA, RndA, key->data);
memcpy(both, encRndA, rndlen);
for (uint32_t x = 0; x < rndlen; x++) {
rotRndB[x] = rotRndB[x] ^ encRndA[x];
}
des_decrypt(encRndB, rotRndB, key->data);
memcpy(both + rndlen, encRndB, rndlen);
} else if (dctx->authChannel == DACEV1 && dctx->keyType != T_AES) {
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) {
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 (dctx->authChannel == 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));
}
}
}
uint32_t bothlen = 16;
if (dctx->keyType == T_AES || dctx->keyType == T_3K3DES) {
bothlen = 32;
}
res = DesfireExchangeEx(false, dctx, MFDES_ADDITIONAL_FRAME, both, bothlen, &respcode, recv_data, &recv_len, false);
if (res != PM3_SUCCESS) {
return 7;
}
if (!recv_len) {
return 8;
}
if (respcode != MFDES_S_OPERATION_OK) {
return 9;
}
// Part 4
memcpy(encRndA, recv_data, rndlen);
// tag->session_key = &default_key;
/*struct desfire_key *p = realloc(tag->session_key, sizeof(struct desfire_key));
if (!p) {
PrintAndLogEx(FAILED, "Cannot allocate memory for session keys");
free(tag->session_key);
return PM3_EMALLOC;
}
tag->session_key = p;
memset(tag->session_key, 0x00, sizeof(struct desfire_key));
*/
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));
if (dctx->keyType == T_DES)
des_decrypt(encRndA, encRndA, key->data);
else if (dctx->keyType == T_3DES)
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);
}
rol(RndA, rndlen);
PrintAndLogEx(INFO, "Expected_RndA : %s", sprint_hex(RndA, rndlen));
PrintAndLogEx(INFO, "Generated_RndA : %s", sprint_hex(encRndA, rndlen));
for (uint32_t x = 0; x < rndlen; x++) {
if (RndA[x] != encRndA[x]) {
if (g_debugMode > 1) {
PrintAndLogEx(DEBUG, "Expected_RndA : %s", sprint_hex(RndA, rndlen));
PrintAndLogEx(DEBUG, "Generated_RndA : %s", sprint_hex(encRndA, rndlen));
}
return 11;
}
}
// 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)
memcpy(&dctx->sessionKeyEnc[8], dctx->sessionKeyEnc, 8);
}
// rpayload->sessionkeylen = payload->keylen;
// memcpy(rpayload->sessionkey, tag->session_key->data, rpayload->sessionkeylen);
// memset(tag->ivect, 0, MAX_CRYPTO_BLOCK_SIZE);
// tag->authenticated_key_no = payload->keyno;
if (dctx->authChannel == 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));
}
memcpy(dctx->sessionKeyMAC, dctx->sessionKeyEnc, desfire_get_key_length(dctx->keyType));
PrintAndLogEx(INFO, "sessionKeyEnc : %s", sprint_hex(dctx->sessionKeyEnc, desfire_get_key_length(dctx->keyType)));
return PM3_SUCCESS;
}
+11 -4
View File
@@ -44,11 +44,13 @@ typedef enum {
typedef struct DesfireContextS {
uint8_t keyNum;
enum DESFIRE_CRYPTOALGO keyType; // des,2tdea,3tdea,aes
enum DESFIRE_CRYPTOALGO keyType; // des/2tdea/3tdea/aes
uint8_t key[DESF_MAX_KEY_LEN];
// KDF finction
// KDF input
uint8_t kdfAlgo;
uint8_t kdfInputLen;
uint8_t kdfInput[31];
DesfireAuthChannel authChannel; // none/d40/ev1/ev2
DesfireCommandChannel cmdChannel; // native/nativeiso/iso
@@ -64,14 +66,19 @@ typedef struct DesfireContextS {
} DesfireContext;
void DesfireClearContext(DesfireContext *ctx);
void DesfireClearSession(DesfireContext *ctx);
void DesfireSetKey(DesfireContext *ctx, uint8_t keyNum, enum DESFIRE_CRYPTOALGO keyType, uint8_t *key);
void DesfireSetCommandChannel(DesfireContext *ctx, DesfireCommandChannel cmdChannel);
const char *DesfireGetErrorString(int res, uint16_t *sw);
int DesfireSelectAID(DesfireContext *ctx, uint8_t *aid1, uint8_t *aid2);
int DesfireSelectAIDHex(DesfireContext *ctx, uint32_t aid1, bool select_two, uint32_t aid2);
int DesfireExchange(DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen);
int DesfireExchangeEx(bool activate_field, DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *respcode, uint8_t *resp, size_t *resplen, bool enable_chaining);
int DesfireSelectAID(DesfireContext *ctx, uint8_t *aid1, uint8_t *aid2);
int DesfireSelectAIDHex(DesfireContext *ctx, uint32_t aid1, bool select_two, uint32_t aid2);
int DesfireAuthenticate(DesfireContext *dctx, DesfireAuthChannel authChannel);
bool DesfireIsAuthenticated(DesfireContext *dctx);
#endif // __DESFIRECORE_H