diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 41ed89238..2d71b41dd 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -64,6 +64,9 @@ typedef struct { uint8_t keyno; uint8_t keylen; uint8_t key[24]; + uint8_t kdfAlgo; + uint8_t kdfInputLen; + uint8_t kdfInput[31]; } PACKED mfdes_authinput_t; static mfdes_authinput_t currentauth[0xF] = {{.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}}; @@ -707,6 +710,13 @@ static int handler_desfire_auth(mfdes_authinput_t *payload, mfdes_auth_res_t *rp Desfire_3k3des_key_new_with_version(keybytes, key); } + if (payload->kdfAlgo == MFDES_KDF_ALGO_AN10922) { + mifare_kdf_an10922(key, payload->kdfInput, payload->kdfInputLen); + if (g_debugMode) { + PrintAndLogEx(INFO, " Derrived key: " _GREEN_("%s"), sprint_hex(key->data, key_block_size(key))); + } + } + uint8_t subcommand = MFDES_AUTHENTICATE; tag->authentication_scheme = AS_LEGACY; @@ -919,7 +929,7 @@ static int handler_desfire_auth(mfdes_authinput_t *payload, mfdes_auth_res_t *rp memset(tag->ivect, 0, MAX_CRYPTO_BLOCK_SIZE); tag->authenticated_key_no = payload->keyno; if (tag->authentication_scheme == AS_NEW) { - cmac_generate_subkeys(tag->session_key); + cmac_generate_subkeys(tag->session_key, MCD_RECEIVE); } return PM3_SUCCESS; } @@ -1988,7 +1998,7 @@ static void swap16(uint8_t *data) { data[1] = tmp; }; -static int desfire_authenticate(int cmdAuthMode, int cmdAuthAlgo, uint8_t *aid, uint8_t *key, int cmdKeyNo, mfdes_auth_res_t *rpayload) { +static int desfire_authenticate(int cmdAuthMode, int cmdAuthAlgo, uint8_t *aid, uint8_t *key, int cmdKeyNo, uint8_t cmdKdfAlgo, uint8_t kdfInputLen, uint8_t *kdfInput, mfdes_auth_res_t *rpayload) { switch (cmdAuthMode) { case MFDES_AUTH_DES: if (cmdAuthAlgo != MFDES_ALGO_DES && cmdAuthAlgo != MFDES_ALGO_3DES) { @@ -2037,6 +2047,25 @@ static int desfire_authenticate(int cmdAuthMode, int cmdAuthAlgo, uint8_t *aid, break; } + switch (cmdKdfAlgo) { + case MFDES_KDF_ALGO_AN10922: + // TODO: 2TDEA and 3TDEA keys use an input length of 1-15 bytes + if (cmdAuthAlgo != MFDES_ALGO_AES) { + PrintAndLogEx(FAILED, "Crypto algo not valid for the KDF AN10922 algo."); + return PM3_EINVARG; + } + if (kdfInputLen < 1 || kdfInputLen > 31) { + PrintAndLogEx(FAILED, "KDF AN10922 algo requires an input of length 1-31 bytes."); + return PM3_EINVARG; + } + case MFDES_KDF_ALGO_NONE: + break; + default: + PrintAndLogEx(WARNING, "KDF algo %d is not supported.", cmdKdfAlgo); + return PM3_EINVARG; + break; + } + // KEY int res = handler_desfire_select_application(aid); if (res != PM3_SUCCESS) return res; @@ -2054,6 +2083,9 @@ static int desfire_authenticate(int cmdAuthMode, int cmdAuthAlgo, uint8_t *aid, payload.mode = cmdAuthMode; payload.algo = cmdAuthAlgo; payload.keyno = cmdKeyNo; + payload.kdfAlgo = cmdKdfAlgo; + payload.kdfInputLen = kdfInputLen; + memcpy(payload.kdfInput, kdfInput, kdfInputLen); int error = handler_desfire_auth(&payload, rpayload); if (error == PM3_SUCCESS) { @@ -3879,6 +3911,8 @@ static int CmdHF14ADesAuth(const char *Cmd) { arg_strx0("a", "aid", "", "AID used for authentification (HEX 3 bytes)"), arg_int0("n", "keyno", "", "Key number used for authentification"), arg_str0("k", "key", "", "Key for checking (HEX 8-24 bytes)"), + arg_int0("d", "kdf", "", "Key Derivation Function (KDF) (0=None, 1=AN10922)"), + arg_str0("i", "kdfi", "", "KDF input (HEX 1-31 bytes)"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -3895,6 +3929,13 @@ static int CmdHF14ADesAuth(const char *Cmd) { uint8_t key[24] = {0}; int keylen = 0; CLIGetHexWithReturn(ctx, 5, key, &keylen); + + // Get KDF input + uint8_t kdfInput[31] = {0}; + int kdfInputLen = 0; + uint8_t cmdKDFAlgo = arg_get_int_def(ctx, 6, 0); + CLIGetHexWithReturn(ctx, 7, kdfInput, &kdfInputLen); + CLIParserFree(ctx); if (cmdAuthAlgo == MFDES_ALGO_AES) { @@ -3940,7 +3981,7 @@ static int CmdHF14ADesAuth(const char *Cmd) { } mfdes_auth_res_t rpayload; - int error = desfire_authenticate(cmdAuthMode, cmdAuthAlgo, aid, key, cmdKeyNo, &rpayload); + int error = desfire_authenticate(cmdAuthMode, cmdAuthAlgo, aid, key, cmdKeyNo, cmdKDFAlgo, kdfInputLen, kdfInput, &rpayload); if (error == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, " Key : " _GREEN_("%s"), sprint_hex(key, keylength)); PrintAndLogEx(SUCCESS, " SESSION : " _GREEN_("%s"), sprint_hex(rpayload.sessionkey, keylength)); @@ -4087,7 +4128,7 @@ static int AuthCheckDesfire(uint8_t *aid, if (usedkeys[keyno] == 1 && foundKeys[0][keyno][0] == 0) { for (uint32_t curkey = 0; curkey < deskeyListLen; curkey++) { mfdes_auth_res_t rpayload; - error = desfire_authenticate(MFDES_AUTH_DES, MFDES_ALGO_DES, aid, deskeyList[curkey], keyno, &rpayload); + error = desfire_authenticate(MFDES_AUTH_DES, MFDES_ALGO_DES, aid, deskeyList[curkey], keyno, 0, 0, NULL, &rpayload); if (error == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "AID 0x%06X, Found DES Key %u : " _GREEN_("%s"), curaid, keyno, sprint_hex(deskeyList[curkey], 8)); foundKeys[0][keyno][0] = 0x01; @@ -4119,7 +4160,7 @@ static int AuthCheckDesfire(uint8_t *aid, if (usedkeys[keyno] == 1 && foundKeys[1][keyno][0] == 0) { for (uint32_t curkey = 0; curkey < aeskeyListLen; curkey++) { mfdes_auth_res_t rpayload; - error = desfire_authenticate(MFDES_AUTH_DES, MFDES_ALGO_3DES, aid, aeskeyList[curkey], keyno, &rpayload); + error = desfire_authenticate(MFDES_AUTH_DES, MFDES_ALGO_3DES, aid, aeskeyList[curkey], keyno, 0, 0, NULL, &rpayload); if (error == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "AID 0x%06X, Found 3DES Key %u : " _GREEN_("%s"), curaid, keyno, sprint_hex(aeskeyList[curkey], 16)); foundKeys[1][keyno][0] = 0x01; @@ -4151,7 +4192,7 @@ static int AuthCheckDesfire(uint8_t *aid, if (usedkeys[keyno] == 1 && foundKeys[2][keyno][0] == 0) { for (uint32_t curkey = 0; curkey < aeskeyListLen; curkey++) { mfdes_auth_res_t rpayload; - error = desfire_authenticate(MFDES_AUTH_AES, MFDES_ALGO_AES, aid, aeskeyList[curkey], keyno, &rpayload); + error = desfire_authenticate(MFDES_AUTH_AES, MFDES_ALGO_AES, aid, aeskeyList[curkey], keyno, 0, 0, NULL, &rpayload); if (error == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "AID 0x%06X, Found AES Key %u : " _GREEN_("%s"), curaid, keyno, sprint_hex(aeskeyList[curkey], 16)); foundKeys[2][keyno][0] = 0x01; @@ -4183,7 +4224,7 @@ static int AuthCheckDesfire(uint8_t *aid, if (usedkeys[keyno] == 1 && foundKeys[3][keyno][0] == 0) { for (uint32_t curkey = 0; curkey < k3kkeyListLen; curkey++) { mfdes_auth_res_t rpayload; - error = desfire_authenticate(MFDES_AUTH_ISO, MFDES_ALGO_3K3DES, aid, k3kkeyList[curkey], keyno, &rpayload); + error = desfire_authenticate(MFDES_AUTH_ISO, MFDES_ALGO_3K3DES, aid, k3kkeyList[curkey], keyno, 0, 0, NULL, &rpayload); if (error == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "AID 0x%06X, Found 3K3 Key %u : " _GREEN_("%s"), curaid, keyno, sprint_hex(k3kkeyList[curkey], 24)); foundKeys[3][keyno][0] = 0x01; diff --git a/client/src/mifare/desfire_crypto.c b/client/src/mifare/desfire_crypto.c index 9eca32e44..3e87236ea 100644 --- a/client/src/mifare/desfire_crypto.c +++ b/client/src/mifare/desfire_crypto.c @@ -251,7 +251,7 @@ static void xor(const uint8_t *ivect, uint8_t *data, const size_t len) { } } -void cmac_generate_subkeys(desfirekey_t key) { +void cmac_generate_subkeys(desfirekey_t key, MifareCryptoDirection direction) { int kbs = key_block_size(key); const uint8_t R = (kbs == 8) ? 0x1B : 0x87; @@ -261,7 +261,7 @@ void cmac_generate_subkeys(desfirekey_t key) { uint8_t ivect[kbs]; memset(ivect, 0, kbs); - mifare_cypher_blocks_chained(NULL, key, ivect, l, kbs, MCD_RECEIVE, MCO_ENCYPHER); + mifare_cypher_blocks_chained(NULL, key, ivect, l, kbs, direction, MCO_ENCYPHER); bool xor = false; @@ -306,6 +306,45 @@ void cmac(const desfirekey_t key, uint8_t *ivect, const uint8_t *data, size_t le free(buffer); } +// 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; + } + + cmac_generate_subkeys(key, MCD_SEND); + + uint8_t *buffer = malloc(kbs2); + uint8_t *ivect = malloc(kbs); + + memset(ivect, 0, kbs); + + buffer[0] = 0x01; + memcpy(&buffer[1], data, len++); + + if (len != (kbs2)) { + buffer[len++] = 0x80; + while (len % kbs2) { + buffer[len++] = 0x00; + } + xor(key->cmac_sk2, buffer + kbs, kbs); + } else { + xor(key->cmac_sk1, buffer + kbs, kbs); + } + + mbedtls_aes_context actx; + mbedtls_aes_init(&actx); + mbedtls_aes_setkey_enc(&actx, key->data, kbs * 8); + mbedtls_aes_crypt_cbc(&actx, MBEDTLS_AES_ENCRYPT, kbs2, ivect, buffer, buffer); + mbedtls_aes_free(&actx); + + memcpy(key->data, buffer + kbs, kbs); + free(ivect); + free(buffer); +} + size_t key_block_size(const desfirekey_t key) { if (key == NULL) return 0; diff --git a/client/src/mifare/desfire_crypto.h b/client/src/mifare/desfire_crypto.h index fb36ea991..a1d514507 100644 --- a/client/src/mifare/desfire_crypto.h +++ b/client/src/mifare/desfire_crypto.h @@ -126,9 +126,11 @@ 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); +void cmac_generate_subkeys(desfirekey_t key, MifareCryptoDirection direction); void cmac(const desfirekey_t key, uint8_t *ivect, const uint8_t *data, size_t len, uint8_t *cmac); +void mifare_kdf_an10922(const desfirekey_t key, const uint8_t *data, size_t dataLen); + 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 iso14443a_crc_append(uint8_t *data, size_t len); diff --git a/include/mifare.h b/include/mifare.h index 476a4e28b..50dbdc3b0 100644 --- a/include/mifare.h +++ b/include/mifare.h @@ -94,6 +94,11 @@ typedef enum { MFDES_ALGO_AES = 4 } mifare_des_authalgo_t; +typedef enum { + MFDES_KDF_ALGO_NONE = 0, + MFDES_KDF_ALGO_AN10922 = 1, +} mifare_des_kdf_algo_t; + //----------------------------------------------------------------------------- // "hf 14a sim x", "hf mf sim x" attacks //-----------------------------------------------------------------------------