mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 05:43:48 -07:00
Merge pull request #1432 from merlokk/auth_ref
desfire authentication refactoring
This commit is contained in:
commit
1d695ef777
9 changed files with 350 additions and 221 deletions
|
@ -53,20 +53,6 @@ static inline void update_key_schedules(desfirekey_t key) {
|
|||
// }
|
||||
}
|
||||
|
||||
int desfire_get_key_length(enum DESFIRE_CRYPTOALGO key_type) {
|
||||
switch (key_type) {
|
||||
case T_DES:
|
||||
return 8;
|
||||
case T_3DES:
|
||||
return 16;
|
||||
case T_3K3DES:
|
||||
return 24;
|
||||
case T_AES:
|
||||
return 16;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void tdes_nxp_receive(const void *in, void *out, size_t length, const void *key, unsigned char iv[8], int keymode) {
|
||||
|
@ -334,7 +320,6 @@ void cmac(const desfirekey_t key, uint8_t *ivect, const uint8_t *data, size_t le
|
|||
// This function is almot like cmac(...). but with some key differences.
|
||||
void mifare_kdf_an10922(const desfirekey_t key, const uint8_t *data, size_t len) {
|
||||
int kbs = key_block_size(key);
|
||||
int kbs2 = kbs * 2;
|
||||
if (key == NULL || kbs == 0 || data == NULL || len < 1 || len > 31) {
|
||||
return;
|
||||
}
|
||||
|
@ -342,6 +327,7 @@ void mifare_kdf_an10922(const desfirekey_t key, const uint8_t *data, size_t len)
|
|||
// AES uses 16 byte IV
|
||||
if (kbs < 16)
|
||||
kbs = 16;
|
||||
int kbs2 = kbs * 2;
|
||||
|
||||
cmac_generate_subkeys(key, MCD_SEND);
|
||||
|
||||
|
@ -382,21 +368,6 @@ void mifare_kdf_an10922(const desfirekey_t key, const uint8_t *data, size_t len)
|
|||
free(buffer);
|
||||
}
|
||||
|
||||
size_t desfire_get_key_block_length(enum DESFIRE_CRYPTOALGO key_type) {
|
||||
size_t block_size = 8;
|
||||
switch (key_type) {
|
||||
case T_DES:
|
||||
case T_3DES:
|
||||
case T_3K3DES:
|
||||
block_size = 8;
|
||||
break;
|
||||
case T_AES:
|
||||
block_size = 16;
|
||||
break;
|
||||
}
|
||||
return block_size;
|
||||
}
|
||||
|
||||
size_t key_block_size(const desfirekey_t key) {
|
||||
if (key == NULL) {
|
||||
return 0;
|
||||
|
@ -422,16 +393,6 @@ static size_t key_macing_length(const desfirekey_t key) {
|
|||
return mac_length;
|
||||
}
|
||||
|
||||
/*
|
||||
* Size required to store nbytes of data in a buffer of size n*block_size.
|
||||
*/
|
||||
size_t padded_data_length(const size_t nbytes, const size_t block_size) {
|
||||
if ((!nbytes) || (nbytes % block_size))
|
||||
return ((nbytes / block_size) + 1) * block_size;
|
||||
else
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
/*
|
||||
* Buffer size required to MAC nbytes of data
|
||||
*/
|
||||
|
|
|
@ -74,16 +74,11 @@ typedef enum {
|
|||
/* Error code managed by the library */
|
||||
#define CRYPTO_ERROR 0x01
|
||||
|
||||
int desfire_get_key_length(enum DESFIRE_CRYPTOALGO key_type);
|
||||
size_t desfire_get_key_block_length(enum DESFIRE_CRYPTOALGO key_type);
|
||||
|
||||
enum DESFIRE_AUTH_SCHEME {
|
||||
AS_LEGACY,
|
||||
AS_NEW
|
||||
};
|
||||
|
||||
|
||||
|
||||
#define DESFIRE_KEY(key) ((struct desfire_key *) key)
|
||||
struct desfire_key {
|
||||
enum DESFIRE_CRYPTOALGO type;
|
||||
|
@ -139,7 +134,6 @@ void *mifare_cryto_postprocess_data(desfiretag_t tag, void *data, size_t *nbytes
|
|||
void mifare_cypher_single_block(desfirekey_t key, uint8_t *data, uint8_t *ivect, MifareCryptoDirection direction, MifareCryptoOperation operation, size_t block_size);
|
||||
void mifare_cypher_blocks_chained(desfiretag_t tag, desfirekey_t key, uint8_t *ivect, uint8_t *data, size_t data_size, MifareCryptoDirection direction, MifareCryptoOperation operation);
|
||||
size_t key_block_size(const desfirekey_t key);
|
||||
size_t padded_data_length(const size_t nbytes, const size_t block_size);
|
||||
size_t maced_data_length(const desfirekey_t key, const size_t nbytes);
|
||||
size_t enciphered_data_length(const desfiretag_t tag, const size_t nbytes, int communication_settings);
|
||||
void cmac_generate_subkeys(desfirekey_t key, MifareCryptoDirection direction);
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <string.h>
|
||||
#include <util.h>
|
||||
#include "commonutil.h"
|
||||
#include "generator.h"
|
||||
#include "aes.h"
|
||||
#include "ui.h"
|
||||
#include "crc.h"
|
||||
|
@ -30,7 +31,6 @@
|
|||
#include "iso7816/apduinfo.h" // APDU manipulation / errorcodes
|
||||
#include "iso7816/iso7816core.h" // APDU logging
|
||||
#include "util_posix.h" // msleep
|
||||
#include "mifare/desfire_crypto.h"
|
||||
#include "desfiresecurechan.h"
|
||||
#include "mifare/mad.h"
|
||||
#include "mifare/aiddesfire.h"
|
||||
|
@ -335,13 +335,16 @@ void DesfirePrintContext(DesfireContext *ctx) {
|
|||
sprint_hex(ctx->key,
|
||||
desfire_get_key_length(ctx->keyType)));
|
||||
|
||||
if (ctx->kdfAlgo != MFDES_KDF_ALGO_NONE)
|
||||
if (ctx->kdfAlgo != MFDES_KDF_ALGO_NONE) {
|
||||
PrintAndLogEx(INFO, "KDF algo: %s KDF input[%d]: %s", CLIGetOptionListStr(DesfireKDFAlgoOpts, ctx->kdfAlgo), ctx->kdfInputLen, sprint_hex(ctx->kdfInput, ctx->kdfInputLen));
|
||||
PrintAndLogEx(INFO, "AID: %06x UID[%d]: %s", ctx->selectedAID, ctx->uidlen, sprint_hex(ctx->uid, ctx->uidlen));
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Secure channel: %s Command set: %s Communication mode: %s",
|
||||
CLIGetOptionListStr(DesfireSecureChannelOpts, ctx->secureChannel),
|
||||
CLIGetOptionListStr(DesfireCommandSetOpts, ctx->cmdSet),
|
||||
CLIGetOptionListStr(DesfireCommunicationModeOpts, ctx->commMode));
|
||||
|
||||
|
||||
if (DesfireIsAuthenticated(ctx)) {
|
||||
PrintAndLogEx(INFO, "Session key MAC [%d]: %s ",
|
||||
|
@ -789,6 +792,7 @@ int DesfireSelectAID(DesfireContext *ctx, uint8_t *aid1, uint8_t *aid2) {
|
|||
|
||||
DesfireClearSession(ctx);
|
||||
ctx->appSelected = (aid1[0] != 0x00 || aid1[1] != 0x00 || aid1[2] != 0x00);
|
||||
ctx->selectedAID = DesfireAIDByteToUint(aid1);
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
@ -826,6 +830,7 @@ int DesfireSelectAIDHexNoFieldOn(DesfireContext *ctx, uint32_t aid) {
|
|||
|
||||
DesfireClearSession(ctx);
|
||||
ctx->appSelected = (aid != 0x000000);
|
||||
ctx->selectedAID = aid;
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
@ -845,10 +850,13 @@ void DesfirePrintAIDFunctions(uint32_t appid) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
int DesfireSelectAndAuthenticateEx(DesfireContext *dctx, DesfireSecureChannel secureChannel, uint32_t aid, bool noauth, bool verbose) {
|
||||
if (verbose)
|
||||
DesfirePrintContext(dctx);
|
||||
|
||||
// needs card uid for diversification
|
||||
if (dctx->kdfAlgo == MFDES_KDF_ALGO_GALLAGHER)
|
||||
DesfireGetCardUID(dctx);
|
||||
|
||||
bool isosw = false;
|
||||
if (dctx->cmdSet == DCCISO) {
|
||||
|
@ -957,8 +965,6 @@ static int DesfireAuthenticateEV1(DesfireContext *dctx, DesfireSecureChannel sec
|
|||
if (secureChannel == DACNone)
|
||||
return PM3_SUCCESS;
|
||||
|
||||
mbedtls_aes_context ctx;
|
||||
|
||||
uint8_t keybytes[24] = {0};
|
||||
// Crypt constants
|
||||
uint8_t IV[16] = {0};
|
||||
|
@ -971,37 +977,6 @@ static int DesfireAuthenticateEV1(DesfireContext *dctx, DesfireSecureChannel sec
|
|||
// 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;
|
||||
if (secureChannel == DACEV1) {
|
||||
if (dctx->keyType == T_AES)
|
||||
|
@ -1046,21 +1021,7 @@ static int DesfireAuthenticateEV1(DesfireContext *dctx, DesfireSecureChannel sec
|
|||
|
||||
|
||||
// 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) {
|
||||
if (secureChannel == DACd40)
|
||||
des_decrypt(RndB, encRndB, key->data);
|
||||
if (secureChannel == DACEV1)
|
||||
des_decrypt_cbc(RndB, encRndB, rndlen, key->data, IV);
|
||||
} 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);
|
||||
}
|
||||
DesfireCryptoEncDecEx(dctx, DCOMainKey, encRndB, rndlen, RndB, false, false, IV);
|
||||
|
||||
if (g_debugMode > 1) {
|
||||
PrintAndLogEx(DEBUG, "encRndB: %s", sprint_hex(encRndB, 8));
|
||||
|
@ -1075,82 +1036,25 @@ static int DesfireAuthenticateEV1(DesfireContext *dctx, DesfireSecureChannel sec
|
|||
|
||||
// - Encrypt our response
|
||||
if (secureChannel == DACd40) {
|
||||
if (dctx->keyType == T_DES) {
|
||||
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->keyType == T_3DES) {
|
||||
des3_decrypt(encRndA, RndA, key->data, 2);
|
||||
memcpy(both, encRndA, rndlen);
|
||||
|
||||
for (uint32_t x = 0; x < rndlen; x++) {
|
||||
rotRndB[x] = rotRndB[x] ^ encRndA[x];
|
||||
}
|
||||
|
||||
des3_decrypt(encRndB, rotRndB, key->data, 2);
|
||||
memcpy(both + rndlen, encRndB, rndlen);
|
||||
}
|
||||
} else if (secureChannel == DACEV1 && dctx->keyType != T_AES) {
|
||||
if (dctx->keyType == T_DES) {
|
||||
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));
|
||||
}
|
||||
des_encrypt_cbc(both, tmp, 16, key->data, IV);
|
||||
if (g_debugMode > 1) {
|
||||
PrintAndLogEx(DEBUG, "EncBoth: %s", sprint_hex(both, 16));
|
||||
}
|
||||
} else 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 (secureChannel == DACEV1 && dctx->keyType == T_AES) {
|
||||
memset(IV, 0, DESFIRE_MAX_CRYPTO_BLOCK_SIZE);
|
||||
DesfireCryptoEncDecEx(dctx, DCOMainKey, RndA, rndlen, encRndA, true, true, IV);
|
||||
|
||||
memcpy(both, encRndA, rndlen);
|
||||
bin_xor(rotRndB, encRndA, rndlen);
|
||||
|
||||
memset(IV, 0, DESFIRE_MAX_CRYPTO_BLOCK_SIZE);
|
||||
DesfireCryptoEncDecEx(dctx, DCOMainKey, rotRndB, rndlen, encRndB, true, true, IV);
|
||||
|
||||
memcpy(both + rndlen, encRndB, rndlen);
|
||||
} else if (secureChannel == DACEV1) {
|
||||
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));
|
||||
}
|
||||
PrintAndLogEx(DEBUG, "Both : %s", sprint_hex(tmp, 32));
|
||||
}
|
||||
DesfireCryptoEncDecEx(dctx, DCOMainKey, tmp, rndlen * 2, both, true, true, IV);
|
||||
}
|
||||
|
||||
uint32_t bothlen = 16;
|
||||
|
@ -1174,31 +1078,15 @@ static int DesfireAuthenticateEV1(DesfireContext *dctx, DesfireSecureChannel sec
|
|||
// Part 4
|
||||
memcpy(encRndA, recv_data, rndlen);
|
||||
|
||||
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));
|
||||
//PrintAndLogEx(INFO, "IV : %s", sprint_hex(IV, rndlen));
|
||||
if (dctx->keyType == T_DES) {
|
||||
if (secureChannel == DACd40)
|
||||
des_decrypt(encRndA, encRndA, key->data);
|
||||
if (secureChannel == DACEV1)
|
||||
des_decrypt_cbc(encRndA, encRndA, rndlen, key->data, IV);
|
||||
} else if (dctx->keyType == T_3DES)
|
||||
if (secureChannel == DACd40)
|
||||
des3_decrypt(encRndA, encRndA, key->data, 2);
|
||||
else
|
||||
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);
|
||||
}
|
||||
|
||||
if (secureChannel == DACd40)
|
||||
memset(IV, 0, DESFIRE_MAX_CRYPTO_BLOCK_SIZE);
|
||||
DesfireCryptoEncDecEx(dctx, DCOMainKey, encRndA, rndlen, encRndA, false, false, IV);
|
||||
|
||||
// generate session key from rnda and rndb. before rol(RndA)!
|
||||
DesfireGenSessionKeyEV1(RndA, RndB, dctx->keyType, dctx->sessionKeyEnc);
|
||||
|
||||
rol(RndA, rndlen);
|
||||
//PrintAndLogEx(INFO, "Expected_RndA : %s", sprint_hex(RndA, rndlen));
|
||||
|
@ -1212,20 +1100,14 @@ static int DesfireAuthenticateEV1(DesfireContext *dctx, DesfireSecureChannel sec
|
|||
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)
|
||||
if (memcmp(dctx->key, &dctx->key[8], 8) == 0)
|
||||
memcpy(&dctx->sessionKeyEnc[8], dctx->sessionKeyEnc, 8);
|
||||
}
|
||||
|
||||
if (secureChannel == 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));
|
||||
}
|
||||
|
||||
memset(dctx->IV, 0, DESFIRE_MAX_KEY_SIZE);
|
||||
dctx->secureChannel = secureChannel;
|
||||
memcpy(dctx->sessionKeyMAC, dctx->sessionKeyEnc, desfire_get_key_length(dctx->keyType));
|
||||
|
@ -1420,6 +1302,22 @@ static int DesfireAuthenticateISO(DesfireContext *dctx, DesfireSecureChannel sec
|
|||
}
|
||||
|
||||
int DesfireAuthenticate(DesfireContext *dctx, DesfireSecureChannel secureChannel, bool verbose) {
|
||||
if (dctx->kdfAlgo == MFDES_KDF_ALGO_AN10922) {
|
||||
MifareKdfAn10922(dctx, DCOMasterKey, dctx->kdfInput, dctx->kdfInputLen);
|
||||
PrintAndLogEx(DEBUG, " Derrived key: " _GREEN_("%s"), sprint_hex(dctx->key, desfire_get_key_block_length(dctx->keyType)));
|
||||
} 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(dctx->uid, dctx->uidlen, dctx->keyNum, dctx->selectedAID, dctx->kdfInput, &dctx->kdfInputLen) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(FAILED, "Could not generate Gallagher KDF input");
|
||||
}
|
||||
PrintAndLogEx(DEBUG, " KDF Input: " _YELLOW_("%s"), sprint_hex(dctx->kdfInput, dctx->kdfInputLen));
|
||||
|
||||
MifareKdfAn10922(dctx, DCOMasterKey, dctx->kdfInput, dctx->kdfInputLen);
|
||||
PrintAndLogEx(DEBUG, " Derrived key: " _GREEN_("%s"), sprint_hex(dctx->key, desfire_get_key_block_length(dctx->keyType)));
|
||||
}
|
||||
|
||||
if (dctx->cmdSet == DCCISO && secureChannel != DACEV2)
|
||||
return DesfireAuthenticateISO(dctx, secureChannel, verbose);
|
||||
|
||||
|
@ -2642,6 +2540,7 @@ int DesfireISOSelectEx(DesfireContext *dctx, bool fieldon, DesfireISOSelectContr
|
|||
|
||||
DesfireClearSession(dctx);
|
||||
dctx->appSelected = !((cntr == ISSMFDFEF && datalen == 0) || (cntr == ISSEFByFileID && datalen == 2 && data[0] == 0 && data[1] == 0));
|
||||
dctx->selectedAID = 0;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
@ -2751,6 +2650,26 @@ int DesfireISOAppendRecord(DesfireContext *dctx, uint8_t fileid, uint8_t *data,
|
|||
return res;
|
||||
}
|
||||
|
||||
int DesfireGetCardUID(DesfireContext *ctx) {
|
||||
iso14a_card_select_t card = {0};
|
||||
|
||||
SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT, 0, 0, NULL, 0);
|
||||
PacketResponseNG resp;
|
||||
WaitForResponse(CMD_ACK, &resp);
|
||||
|
||||
memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t));
|
||||
uint64_t select_status = resp.oldarg[0];
|
||||
|
||||
if (select_status == 0 || select_status == 2 || select_status == 3) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
memcpy(ctx->uid, card.uid, card.uidlen);
|
||||
ctx->uidlen = card.uidlen;
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int DesfireSelectEx(DesfireContext *ctx, bool fieldon, DesfireISOSelectWay way, uint32_t id, char *dfname) {
|
||||
uint8_t resp[250] = {0};
|
||||
size_t resplen = 0;
|
||||
|
|
|
@ -16,8 +16,6 @@
|
|||
#include "common.h"
|
||||
#include "cliparser.h"
|
||||
#include "mifare/desfirecrypto.h"
|
||||
#include "mifare/desfire_crypto.h"
|
||||
#include "mifare/mifare4.h"
|
||||
|
||||
#define DESFIRE_TX_FRAME_MAX_LEN 54
|
||||
|
||||
|
@ -168,6 +166,8 @@ int DesfireSelectAIDHex(DesfireContext *ctx, uint32_t aid1, bool select_two, uin
|
|||
int DesfireSelectAIDHexNoFieldOn(DesfireContext *ctx, uint32_t aid);
|
||||
void DesfirePrintAIDFunctions(uint32_t appid);
|
||||
|
||||
int DesfireGetCardUID(DesfireContext *ctx);
|
||||
|
||||
int DesfireSelectEx(DesfireContext *ctx, bool fieldon, DesfireISOSelectWay way, uint32_t id, char *dfname);
|
||||
int DesfireSelect(DesfireContext *ctx, DesfireISOSelectWay way, uint32_t id, char *dfname);
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
#include "crc16.h" // crc16 ccitt
|
||||
#include "crc32.h"
|
||||
#include "commonutil.h"
|
||||
#include "mifare/desfire_crypto.h"
|
||||
#include "crypto/libpcrypto.h"
|
||||
|
||||
void DesfireClearContext(DesfireContext *ctx) {
|
||||
ctx->keyNum = 0;
|
||||
|
@ -43,6 +43,10 @@ void DesfireClearContext(DesfireContext *ctx) {
|
|||
ctx->commMode = DCMNone;
|
||||
|
||||
ctx->appSelected = false;
|
||||
ctx->selectedAID = 0;
|
||||
|
||||
memset(ctx->uid, 0, sizeof(ctx->uid));
|
||||
ctx->uidlen = 0;
|
||||
|
||||
ctx->kdfAlgo = 0;
|
||||
ctx->kdfInputLen = 0;
|
||||
|
@ -74,6 +78,7 @@ void DesfireSetKey(DesfireContext *ctx, uint8_t keyNum, enum DESFIRE_CRYPTOALGO
|
|||
ctx->keyNum = keyNum;
|
||||
ctx->keyType = keyType;
|
||||
memcpy(ctx->key, key, desfire_get_key_length(keyType));
|
||||
memcpy(ctx->masterKey, key, desfire_get_key_length(keyType));
|
||||
}
|
||||
|
||||
void DesfireSetCommandSet(DesfireContext *ctx, DesfireCommandSet cmdSet) {
|
||||
|
@ -96,7 +101,7 @@ bool DesfireIsAuthenticated(DesfireContext *dctx) {
|
|||
}
|
||||
|
||||
size_t DesfireGetMACLength(DesfireContext *ctx) {
|
||||
size_t mac_length = MAC_LENGTH;
|
||||
size_t mac_length = DESFIRE_MAC_LENGTH;
|
||||
switch (ctx->secureChannel) {
|
||||
case DACNone:
|
||||
mac_length = 0;
|
||||
|
@ -151,6 +156,19 @@ size_t DesfireSearchCRCPos(uint8_t *data, size_t datalen, uint8_t respcode, uint
|
|||
return crcposfound;
|
||||
}
|
||||
|
||||
uint8_t *DesfireGetKey(DesfireContext *ctx, DesfireCryptoOpKeyType key_type) {
|
||||
if (key_type == DCOSessionKeyMac) {
|
||||
return ctx->sessionKeyMAC;
|
||||
} else if (key_type == DCOSessionKeyEnc) {
|
||||
return ctx->sessionKeyEnc;
|
||||
} else if (key_type == DCOMasterKey) {
|
||||
return ctx->masterKey;
|
||||
}
|
||||
|
||||
return ctx->key;
|
||||
}
|
||||
|
||||
|
||||
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};
|
||||
|
@ -232,15 +250,14 @@ void DesfireCryptoEncDecEx(DesfireContext *ctx, DesfireCryptoOpKeyType key_type,
|
|||
else
|
||||
memcpy(xiv, iv, block_size);
|
||||
|
||||
uint8_t *key = DesfireGetKey(ctx, key_type);
|
||||
if (key == NULL)
|
||||
return;
|
||||
|
||||
size_t offset = 0;
|
||||
while (offset < srcdatalen) {
|
||||
if (key_type == DCOSessionKeyMac) {
|
||||
DesfireCryptoEncDecSingleBlock(ctx->sessionKeyMAC, ctx->keyType, srcdata + offset, data + offset, xiv, dir_to_send, encode);
|
||||
} 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(key, ctx->keyType, srcdata + offset, data + offset, xiv, dir_to_send, encode);
|
||||
|
||||
offset += block_size;
|
||||
}
|
||||
|
||||
|
@ -262,7 +279,7 @@ void DesfireCryptoEncDec(DesfireContext *ctx, DesfireCryptoOpKeyType key_type, u
|
|||
DesfireCryptoEncDecEx(ctx, key_type, srcdata, srcdatalen, dstdata, dir_to_send, xencode, NULL);
|
||||
}
|
||||
|
||||
static void DesfireCMACGenerateSubkeys(DesfireContext *ctx, uint8_t *sk1, uint8_t *sk2) {
|
||||
void DesfireCMACGenerateSubkeys(DesfireContext *ctx, DesfireCryptoOpKeyType key_type, uint8_t *sk1, uint8_t *sk2) {
|
||||
int kbs = desfire_get_key_block_length(ctx->keyType);
|
||||
const uint8_t R = (kbs == 8) ? 0x1B : 0x87;
|
||||
|
||||
|
@ -272,7 +289,7 @@ static void DesfireCMACGenerateSubkeys(DesfireContext *ctx, uint8_t *sk1, uint8_
|
|||
uint8_t ivect[kbs];
|
||||
memset(ivect, 0, kbs);
|
||||
|
||||
DesfireCryptoEncDecEx(ctx, DCOSessionKeyMac, l, kbs, l, true, true, ivect);
|
||||
DesfireCryptoEncDecEx(ctx, key_type, l, kbs, l, true, true, ivect);
|
||||
|
||||
bool txor = false;
|
||||
|
||||
|
@ -293,23 +310,23 @@ static void DesfireCMACGenerateSubkeys(DesfireContext *ctx, uint8_t *sk1, uint8_
|
|||
}
|
||||
}
|
||||
|
||||
void DesfireCryptoCMAC(DesfireContext *ctx, uint8_t *data, size_t len, uint8_t *cmac) {
|
||||
void DesfireCryptoCMACEx(DesfireContext *ctx, DesfireCryptoOpKeyType key_type, uint8_t *data, size_t len, size_t minlen, uint8_t *cmac) {
|
||||
int kbs = desfire_get_key_block_length(ctx->keyType);
|
||||
if (kbs == 0)
|
||||
return;
|
||||
|
||||
uint8_t buffer[padded_data_length(len, kbs)];
|
||||
uint8_t buffer[padded_data_length(MAX(minlen, len) + 1, kbs)];
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
|
||||
uint8_t sk1[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0};
|
||||
uint8_t sk2[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0};
|
||||
DesfireCMACGenerateSubkeys(ctx, sk1, sk2);
|
||||
DesfireCMACGenerateSubkeys(ctx, key_type, sk1, sk2);
|
||||
|
||||
memcpy(buffer, data, len);
|
||||
|
||||
if ((!len) || (len % kbs)) {
|
||||
if ((!len) || (len % kbs) || (len < minlen)) {
|
||||
buffer[len++] = 0x80;
|
||||
while (len % kbs) {
|
||||
while (len % kbs || len < minlen) {
|
||||
buffer[len++] = 0x00;
|
||||
}
|
||||
bin_xor(buffer + len - kbs, sk2, kbs);
|
||||
|
@ -317,12 +334,73 @@ void DesfireCryptoCMAC(DesfireContext *ctx, uint8_t *data, size_t len, uint8_t *
|
|||
bin_xor(buffer + len - kbs, sk1, kbs);
|
||||
}
|
||||
|
||||
DesfireCryptoEncDec(ctx, DCOSessionKeyMac, buffer, len, NULL, true);
|
||||
DesfireCryptoEncDec(ctx, key_type, buffer, len, NULL, true);
|
||||
|
||||
if (cmac != NULL)
|
||||
memcpy(cmac, ctx->IV, kbs);
|
||||
}
|
||||
|
||||
void DesfireCryptoCMAC(DesfireContext *ctx, uint8_t *data, size_t len, uint8_t *cmac) {
|
||||
DesfireCryptoCMACEx(ctx, DCOSessionKeyMac, data, len, 0, cmac);
|
||||
}
|
||||
|
||||
// This function is almot like cmac(...). but with some key differences.
|
||||
void MifareKdfAn10922(DesfireContext *ctx, DesfireCryptoOpKeyType key_type, const uint8_t *data, size_t len) {
|
||||
int kbs = desfire_get_key_block_length(ctx->keyType); // 8 or 16
|
||||
if (ctx == NULL || kbs == 0 || data == NULL || len < 1 || len > 31) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t cmac[DESFIRE_MAX_CRYPTO_BLOCK_SIZE * 3] = {0};
|
||||
uint8_t buffer[DESFIRE_MAX_CRYPTO_BLOCK_SIZE * 3] = {0};
|
||||
|
||||
if (ctx->keyType == T_AES) {
|
||||
// AES uses 16 byte IV
|
||||
if (kbs < CRYPTO_AES_BLOCK_SIZE)
|
||||
kbs = CRYPTO_AES_BLOCK_SIZE;
|
||||
|
||||
buffer[0] = 0x01;
|
||||
memcpy(&buffer[1], data, len);
|
||||
|
||||
DesfireCryptoCMACEx(ctx, key_type, buffer, len + 1, kbs * 2, cmac);
|
||||
memcpy(ctx->key, cmac, kbs);
|
||||
} else if (ctx->keyType == T_3DES) {
|
||||
buffer[0] = 0x21;
|
||||
memcpy(&buffer[1], data, len);
|
||||
|
||||
DesfireClearIV(ctx);
|
||||
DesfireCryptoCMACEx(ctx, key_type, buffer, len + 1, kbs * 2, cmac);
|
||||
|
||||
buffer[0] = 0x22;
|
||||
memcpy(&buffer[1], data, len);
|
||||
|
||||
DesfireClearIV(ctx);
|
||||
DesfireCryptoCMACEx(ctx, key_type, buffer, len + 1, kbs * 2, &cmac[kbs]);
|
||||
|
||||
memcpy(ctx->key, cmac, kbs * 2);
|
||||
} else if (ctx->keyType == T_3K3DES) {
|
||||
buffer[0] = 0x31;
|
||||
memcpy(&buffer[1], data, len);
|
||||
|
||||
DesfireClearIV(ctx);
|
||||
DesfireCryptoCMACEx(ctx, key_type, buffer, len + 1, kbs * 2, cmac);
|
||||
|
||||
buffer[0] = 0x32;
|
||||
memcpy(&buffer[1], data, len);
|
||||
|
||||
DesfireClearIV(ctx);
|
||||
DesfireCryptoCMACEx(ctx, key_type, buffer, len + 1, kbs * 2, &cmac[kbs]);
|
||||
|
||||
buffer[0] = 0x33;
|
||||
memcpy(&buffer[1], data, len);
|
||||
|
||||
DesfireClearIV(ctx);
|
||||
DesfireCryptoCMACEx(ctx, key_type, buffer, len + 1, kbs * 2, &cmac[kbs * 2]);
|
||||
|
||||
memcpy(ctx->key, cmac, kbs * 3);
|
||||
}
|
||||
}
|
||||
|
||||
void DesfireDESKeySetVersion(uint8_t *key, DesfireCryptoAlgorythm keytype, uint8_t version) {
|
||||
if (keytype == T_AES)
|
||||
return;
|
||||
|
@ -536,6 +614,45 @@ int DesfireEV2CalcCMAC(DesfireContext *ctx, uint8_t cmd, uint8_t *data, size_t d
|
|||
return aes_cmac8(NULL, ctx->sessionKeyMAC, mdata, mac, mdatalen);
|
||||
}
|
||||
|
||||
int desfire_get_key_length(DesfireCryptoAlgorythm key_type) {
|
||||
switch (key_type) {
|
||||
case T_DES:
|
||||
return 8;
|
||||
case T_3DES:
|
||||
return 16;
|
||||
case T_3K3DES:
|
||||
return 24;
|
||||
case T_AES:
|
||||
return 16;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t desfire_get_key_block_length(DesfireCryptoAlgorythm key_type) {
|
||||
size_t block_size = 8;
|
||||
switch (key_type) {
|
||||
case T_DES:
|
||||
case T_3DES:
|
||||
case T_3K3DES:
|
||||
block_size = 8;
|
||||
break;
|
||||
case T_AES:
|
||||
block_size = 16;
|
||||
break;
|
||||
}
|
||||
return block_size;
|
||||
}
|
||||
|
||||
/*
|
||||
* Size required to store nbytes of data in a buffer of size n*block_size.
|
||||
*/
|
||||
size_t padded_data_length(const size_t nbytes, const size_t block_size) {
|
||||
if ((!nbytes) || (nbytes % block_size))
|
||||
return ((nbytes / block_size) + 1) * block_size;
|
||||
else
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
void desfire_crc32(const uint8_t *data, const size_t len, uint8_t *crc) {
|
||||
crc32_ex(data, len, crc);
|
||||
}
|
||||
|
|
|
@ -22,12 +22,14 @@
|
|||
#define __DESFIRECRYPTO_H
|
||||
|
||||
#include "common.h"
|
||||
#include "mifare/mifare4.h"
|
||||
#include "crypto/libpcrypto.h"
|
||||
|
||||
#define CRYPTO_AES_BLOCK_SIZE 16
|
||||
#define MAX_CRYPTO_BLOCK_SIZE 16
|
||||
#define DESFIRE_MAX_CRYPTO_BLOCK_SIZE 16
|
||||
#define DESFIRE_MAX_KEY_SIZE 24
|
||||
#define DESFIRE_MAC_LENGTH 4
|
||||
#define DESFIRE_CMAC_LENGTH 8
|
||||
|
||||
#define DESFIRE_GET_ISO_STATUS(x) ( ((uint16_t)(0x91<<8)) + (uint16_t)x )
|
||||
|
||||
|
@ -63,6 +65,7 @@ typedef enum {
|
|||
} DesfireCommunicationMode;
|
||||
|
||||
typedef enum {
|
||||
DCOMasterKey,
|
||||
DCOMainKey,
|
||||
DCOSessionKeyMac,
|
||||
DCOSessionKeyEnc
|
||||
|
@ -72,6 +75,7 @@ typedef struct DesfireContextS {
|
|||
uint8_t keyNum;
|
||||
DesfireCryptoAlgorythm keyType; // des/2tdea/3tdea/aes
|
||||
uint8_t key[DESFIRE_MAX_KEY_SIZE];
|
||||
uint8_t masterKey[DESFIRE_MAX_KEY_SIZE]; // source for kdf
|
||||
|
||||
// KDF finction
|
||||
uint8_t kdfAlgo;
|
||||
|
@ -83,6 +87,10 @@ typedef struct DesfireContextS {
|
|||
DesfireCommunicationMode commMode; // plain/mac/enc
|
||||
|
||||
bool appSelected; // for iso auth
|
||||
uint32_t selectedAID;
|
||||
|
||||
uint8_t uid[10];
|
||||
uint8_t uidlen;
|
||||
|
||||
uint8_t IV[DESFIRE_MAX_KEY_SIZE];
|
||||
uint8_t sessionKeyMAC[DESFIRE_MAX_KEY_SIZE];
|
||||
|
@ -106,10 +114,14 @@ size_t DesfireGetMACLength(DesfireContext *ctx);
|
|||
|
||||
size_t DesfireSearchCRCPos(uint8_t *data, size_t datalen, uint8_t respcode, uint8_t crclen);
|
||||
|
||||
uint8_t *DesfireGetKey(DesfireContext *ctx, DesfireCryptoOpKeyType key_type);
|
||||
void DesfireCryptoEncDec(DesfireContext *ctx, DesfireCryptoOpKeyType key_type, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool encode);
|
||||
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 DesfireCMACGenerateSubkeys(DesfireContext *ctx, DesfireCryptoOpKeyType key_type, uint8_t *sk1, uint8_t *sk2);
|
||||
void DesfireCryptoCMAC(DesfireContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t *cmac);
|
||||
|
||||
void DesfireCryptoCMACEx(DesfireContext *ctx, DesfireCryptoOpKeyType key_type, uint8_t *data, size_t len, size_t minlen, uint8_t *cmac);
|
||||
void MifareKdfAn10922(DesfireContext *ctx, DesfireCryptoOpKeyType key_type, const uint8_t *data, size_t len);
|
||||
|
||||
void DesfireDESKeySetVersion(uint8_t *key, DesfireCryptoAlgorythm keytype, uint8_t version);
|
||||
uint8_t DesfireDESKeyGetVersion(uint8_t *key);
|
||||
|
||||
|
@ -125,6 +137,10 @@ void DesfireGenSessionKeyEV2(uint8_t *key, uint8_t *rndA, uint8_t *rndB, bool en
|
|||
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);
|
||||
|
||||
int desfire_get_key_length(DesfireCryptoAlgorythm key_type);
|
||||
size_t desfire_get_key_block_length(DesfireCryptoAlgorythm key_type);
|
||||
size_t padded_data_length(const size_t nbytes, const size_t block_size);
|
||||
|
||||
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);
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include "crc32.h"
|
||||
#include "commonutil.h"
|
||||
#include "protocols.h"
|
||||
#include "mifare/desfire_crypto.h"
|
||||
|
||||
static const uint8_t CommandsCanUseAnyChannel[] = {
|
||||
MFDES_S_ADDITIONAL_FRAME,
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#include "common.h"
|
||||
#include "mifare/desfirecore.h"
|
||||
#include "mifare/desfirecrypto.h"
|
||||
#include "mifare/desfire_crypto.h"
|
||||
#include "mifare/mifare4.h"
|
||||
|
||||
typedef struct {
|
||||
|
|
|
@ -78,6 +78,126 @@ static bool TestCRC32(void) {
|
|||
return res;
|
||||
}
|
||||
|
||||
// https://www.nxp.com/docs/en/application-note/AN10922.pdf
|
||||
static bool TestCMACSubkeys(void) {
|
||||
bool res = true;
|
||||
|
||||
uint8_t key[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF};
|
||||
|
||||
uint8_t sk1[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0};
|
||||
uint8_t sk2[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0};
|
||||
DesfireContext dctx;
|
||||
// AES
|
||||
DesfireSetKey(&dctx, 0, T_AES, key);
|
||||
|
||||
DesfireCMACGenerateSubkeys(&dctx, DCOMainKey, sk1, sk2);
|
||||
|
||||
uint8_t sk1test[] = {0xFB, 0xC9, 0xF7, 0x5C, 0x94, 0x13, 0xC0, 0x41, 0xDF, 0xEE, 0x45, 0x2D, 0x3F, 0x07, 0x06, 0xD1};
|
||||
uint8_t sk2test[] = {0xF7, 0x93, 0xEE, 0xB9, 0x28, 0x27, 0x80, 0x83, 0xBF, 0xDC, 0x8A, 0x5A, 0x7E, 0x0E, 0x0D, 0x25};
|
||||
|
||||
res = res && (memcmp(sk1, sk1test, sizeof(sk1test)) == 0);
|
||||
res = res && (memcmp(sk2, sk2test, sizeof(sk2test)) == 0);
|
||||
|
||||
// 2tdea
|
||||
DesfireSetKey(&dctx, 0, T_3DES, key);
|
||||
|
||||
DesfireCMACGenerateSubkeys(&dctx, DCOMainKey, sk1, sk2);
|
||||
|
||||
uint8_t sk1_2tdea[] = {0xF6, 0x12, 0xEB, 0x32, 0xE4, 0x60, 0x35, 0xF3};
|
||||
uint8_t sk2_2tdea[] = {0xEC, 0x25, 0xD6, 0x65, 0xC8, 0xC0, 0x6B, 0xFD};
|
||||
|
||||
res = res && (memcmp(sk1, sk1_2tdea, sizeof(sk1_2tdea)) == 0);
|
||||
res = res && (memcmp(sk2, sk2_2tdea, sizeof(sk2_2tdea)) == 0);
|
||||
|
||||
// 3tdea
|
||||
uint8_t key3[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
|
||||
DesfireSetKey(&dctx, 0, T_3K3DES, key3);
|
||||
|
||||
DesfireCMACGenerateSubkeys(&dctx, DCOMainKey, sk1, sk2);
|
||||
|
||||
uint8_t sk1_3tdea[] = {0xA3, 0xED, 0x58, 0xF8, 0xE6, 0x94, 0x1B, 0xCA};
|
||||
uint8_t sk2_3tdea[] = {0x47, 0xDA, 0xB1, 0xF1, 0xCD, 0x28, 0x37, 0x8F};
|
||||
|
||||
res = res && (memcmp(sk1, sk1_3tdea, sizeof(sk1_3tdea)) == 0);
|
||||
res = res && (memcmp(sk2, sk2_3tdea, sizeof(sk2_3tdea)) == 0);
|
||||
|
||||
if (res)
|
||||
PrintAndLogEx(INFO, "CMAC subkeys...... " _GREEN_("passed"));
|
||||
else
|
||||
PrintAndLogEx(ERR, "CMAC subkeys...... " _RED_("fail"));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// https://www.nxp.com/docs/en/application-note/AN10922.pdf
|
||||
// page 8
|
||||
static bool TestAn10922KDFAES(void) {
|
||||
bool res = true;
|
||||
|
||||
uint8_t key[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF};
|
||||
|
||||
DesfireContext dctx;
|
||||
DesfireSetKey(&dctx, 0, T_AES, key);
|
||||
|
||||
uint8_t kdfInput[] = {0x04, 0x78, 0x2E, 0x21, 0x80, 0x1D, 0x80, 0x30, 0x42, 0xF5, 0x4E, 0x58, 0x50, 0x20, 0x41, 0x62, 0x75};
|
||||
MifareKdfAn10922(&dctx, DCOMainKey, kdfInput, sizeof(kdfInput));
|
||||
|
||||
uint8_t dkey[] = {0xA8, 0xDD, 0x63, 0xA3, 0xB8, 0x9D, 0x54, 0xB3, 0x7C, 0xA8, 0x02, 0x47, 0x3F, 0xDA, 0x91, 0x75};
|
||||
res = res && (memcmp(dctx.key, dkey, sizeof(dkey)) == 0);
|
||||
|
||||
if (res)
|
||||
PrintAndLogEx(INFO, "An10922 AES....... " _GREEN_("passed"));
|
||||
else
|
||||
PrintAndLogEx(ERR, "An10922 AES....... " _RED_("fail"));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static bool TestAn10922KDF2TDEA(void) {
|
||||
bool res = true;
|
||||
|
||||
uint8_t key[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF};
|
||||
|
||||
DesfireContext dctx;
|
||||
DesfireSetKey(&dctx, 0, T_3DES, key);
|
||||
|
||||
uint8_t kdfInput[] = {0x04, 0x78, 0x2E, 0x21, 0x80, 0x1D, 0x80, 0x30, 0x42, 0xF5, 0x4E, 0x58, 0x50, 0x20, 0x41};
|
||||
MifareKdfAn10922(&dctx, DCOMainKey, kdfInput, sizeof(kdfInput));
|
||||
|
||||
uint8_t dkey[] = {0x16, 0xF8, 0x59, 0x7C, 0x9E, 0x89, 0x10, 0xC8, 0x6B, 0x96, 0x48, 0xD0, 0x06, 0x10, 0x7D, 0xD7};
|
||||
res = res && (memcmp(dctx.key, dkey, sizeof(dkey)) == 0);
|
||||
|
||||
if (res)
|
||||
PrintAndLogEx(INFO, "An10922 2TDEA..... " _GREEN_("passed"));
|
||||
else
|
||||
PrintAndLogEx(ERR, "An10922 2TDEA..... " _RED_("fail"));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static bool TestAn10922KDF3TDEA(void) {
|
||||
bool res = true;
|
||||
|
||||
uint8_t key[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
|
||||
|
||||
DesfireContext dctx;
|
||||
DesfireSetKey(&dctx, 0, T_3K3DES, key);
|
||||
|
||||
uint8_t kdfInput[] = {0x04, 0x78, 0x2E, 0x21, 0x80, 0x1D, 0x80, 0x30, 0x42, 0xF5, 0x4E, 0x58, 0x50};
|
||||
MifareKdfAn10922(&dctx, DCOMainKey, kdfInput, sizeof(kdfInput));
|
||||
|
||||
uint8_t dkey[] = {0x2F, 0x0D, 0xD0, 0x36, 0x75, 0xD3, 0xFB, 0x9A, 0x57, 0x05, 0xAB, 0x0B, 0xDA, 0x91, 0xCA, 0x0B,
|
||||
0x55, 0xB8, 0xE0, 0x7F, 0xCD, 0xBF, 0x10, 0xEC};
|
||||
res = res && (memcmp(dctx.key, dkey, sizeof(dkey)) == 0);
|
||||
|
||||
if (res)
|
||||
PrintAndLogEx(INFO, "An10922 3TDEA..... " _GREEN_("passed"));
|
||||
else
|
||||
PrintAndLogEx(ERR, "An10922 3TDEA..... " _RED_("fail"));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/TDES_CMAC.pdf
|
||||
static bool TestCMAC3TDEA(void) {
|
||||
bool res = true;
|
||||
|
@ -336,6 +456,10 @@ bool DesfireTest(bool verbose) {
|
|||
|
||||
res = res && TestCRC16();
|
||||
res = res && TestCRC32();
|
||||
res = res && TestCMACSubkeys();
|
||||
res = res && TestAn10922KDFAES();
|
||||
res = res && TestAn10922KDF2TDEA();
|
||||
res = res && TestAn10922KDF3TDEA();
|
||||
res = res && TestCMAC3TDEA();
|
||||
res = res && TestCMAC2TDEA();
|
||||
res = res && TestCMACDES();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue