From 6d88224a12fb86858048a2e75a4e64363861fc69 Mon Sep 17 00:00:00 2001 From: Matt Moran Date: Fri, 7 Jan 2022 19:29:55 +1300 Subject: [PATCH 01/13] Update changelog for `hf gallagher` commands --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b6622413..4ac6081a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -58,6 +58,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Fixed `SimulateTagLowFrequencyEx` ignoring the `ledcontrol` argument (@zabszk) - Added ledcontrol argument to LF operations (@zabszk) - Added new standalone mode `dankarmulti` - select and run multiple standalone modes (@dankar) + - Added `hf gallagher` commands for read/writing DESFire cards (@DarkMatterMatt) ## [crimson.4.14434][2021-09-18] - Fixed `hf mf staticnested` - flashmem / non loop now works (@horrordash) From 69049a6621c707b04c09bf9b1748bb544338d1e1 Mon Sep 17 00:00:00 2001 From: Matt Moran Date: Fri, 7 Jan 2022 19:31:36 +1300 Subject: [PATCH 02/13] Remove incorrect AID validation --- client/src/cmdhfgallagher.c | 35 ++++++----------------------------- common/generator.c | 8 -------- 2 files changed, 6 insertions(+), 37 deletions(-) diff --git a/client/src/cmdhfgallagher.c b/client/src/cmdhfgallagher.c index e95e25bcc..f3085ed3b 100644 --- a/client/src/cmdhfgallagher.c +++ b/client/src/cmdhfgallagher.c @@ -758,7 +758,6 @@ static int CmdGallagherReader(const char *cmd) { CLIGetHexWithReturn(ctx, 1, aid_buf, &aid_len); if (aid_len > 0 && aid_len != 3) HFGAL_RET_ERR(PM3_EINVARG, "--aid must be 3 bytes"); - reverse_aid(aid_buf); // PM3 displays AIDs backwards uint32_t aid = DesfireAIDByteToUint(aid_buf); @@ -832,19 +831,11 @@ static int CmdGallagherClone(const char *cmd) { int aid_len = 0; uint8_t aid_buf[3] = {0}; - uint32_t aid = 0; CLIGetHexWithReturn(ctx, 8, aid_buf, &aid_len); - if (aid_len > 0) { - if (aid_len != 3) - HFGAL_RET_ERR(PM3_EINVARG, "--aid must be 3 bytes"); - reverse_aid(aid_buf); // PM3 displays AIDs backwards - aid = DesfireAIDByteToUint(aid_buf); - - // Check that the AID is in the expected range - if (memcmp(aid_buf, "\xF4\x81", 2) != 0 || aid_buf[2] < 0x20 || aid_buf[2] > 0x2B) - // TODO: this should probably be a warning, but key diversification will throw an error later even if we don't - HFGAL_RET_ERR(PM3_EINVARG, "Invalid Gallagher AID %06X, expected 2?81F4, where 0 <= ? <= 0xB", aid); - } + if (aid_len > 0 && aid_len != 3) + HFGAL_RET_ERR(PM3_EINVARG, "--aid must be 3 bytes"); + reverse_aid(aid_buf); // PM3 displays AIDs backwards + uint32_t aid = DesfireAIDByteToUint(aid_buf); int site_key_len = 0; uint8_t site_key[16] = {0}; @@ -925,18 +916,11 @@ static int CmdGallagherDelete(const char *cmd) { int aid_len = 0; uint8_t aid_buf[3] = {0}; - uint32_t aid = 0; CLIGetHexWithReturn(ctx, 1, aid_buf, &aid_len); - if (aid_len != 3) HFGAL_RET_ERR(PM3_EINVARG, "--aid must be 3 bytes"); reverse_aid(aid_buf); // PM3 displays AIDs backwards - aid = DesfireAIDByteToUint(aid_buf); - - // Check that the AID is in the expected range - if (memcmp(aid_buf, "\xF4\x81", 2) != 0 || aid_buf[2] < 0x20 || aid_buf[2] > 0x2B) - // TODO: this should probably be a warning, but key diversification will throw an error later even if we don't - HFGAL_RET_ERR(PM3_EINVARG, "Invalid Gallagher AID %06X, expected 2?81F4, where 0 <= ? <= 0xB", aid); + uint32_t aid = DesfireAIDByteToUint(aid_buf); int site_key_len = 0; uint8_t site_key[16] = {0}; @@ -992,18 +976,11 @@ static int CmdGallagherDiversify(const char *cmd) { int aid_len = 0; uint8_t aid_buf[3] = {0}; - uint32_t aid = 0; CLIGetHexWithReturn(ctx, 1, aid_buf, &aid_len); - if (aid_len != 3) HFGAL_RET_ERR(PM3_EINVARG, "--aid must be 3 bytes"); reverse_aid(aid_buf); // PM3 displays AIDs backwards - aid = DesfireAIDByteToUint(aid_buf); - - // Check that the AID is in the expected range - if (memcmp(aid_buf, "\xF4\x81", 2) != 0 || aid_buf[2] < 0x20 || aid_buf[2] > 0x2B) - // TODO: this should probably be a warning, but key diversification will throw an error later even if we don't - HFGAL_RET_ERR(PM3_EINVARG, "Invalid Gallagher AID %06X, expected 2?81F4, where 0 <= ? <= 0xB", aid); + uint32_t aid = DesfireAIDByteToUint(aid_buf); int key_num = arg_get_int_def(ctx, 2, 0); diff --git a/common/generator.c b/common/generator.c index 8b259a79c..425587527 100644 --- a/common/generator.c +++ b/common/generator.c @@ -441,14 +441,6 @@ int mfdes_kdf_input_gallagher(uint8_t *uid, uint8_t uidLen, uint8_t keyNo, uint3 return PM3_EINVARG; } - // Verify the AppID is a valid Gallagher AppID - if ((aid & 0xF0FFFF) != 0x2081F4) { - if (g_debugMode) { - PrintAndLogEx(WARNING, "Invalid Gallagher AID %06X", aid); - } - return PM3_EINVARG; - } - int len = 0; // If the keyNo == 1, then omit the UID. if (keyNo != 1) { From beefc97995fa19d85231db66155b756b9bde49da Mon Sep 17 00:00:00 2001 From: Matt Moran Date: Fri, 7 Jan 2022 23:21:35 +1300 Subject: [PATCH 03/13] Add ability to use custom CAD key, add ability to skip some actions For cloning & deleting: - Add ability to use custom Card Application Directory key (`--cadkey`) - Add ability to skip updating the CAD (`--noupdatecad`) - Add ability to skip creating/deleting the app and only update the CAD (`--nocreateapp`, `--nodeleteapp`) --- client/src/cmdhfgallagher.c | 151 +++++++++++++++++++++++++----------- doc/commands.json | 20 +++-- 2 files changed, 117 insertions(+), 54 deletions(-) diff --git a/client/src/cmdhfgallagher.c b/client/src/cmdhfgallagher.c index f3085ed3b..86dc614ba 100644 --- a/client/src/cmdhfgallagher.c +++ b/client/src/cmdhfgallagher.c @@ -446,9 +446,11 @@ static int hfgal_read_cad(DesfireContext_t *ctx, uint8_t *dest_buf, /** * @brief Create the Gallagher Card Application Directory. * - * @param site_key MIFARE site key. + * @param site_key MIFARE site key. Not used if cad_key is provided. + * @param cad_key Custom AES key 0 for the CAD (if not using the site_key). */ -static int hfgal_create_cad(DesfireContext_t *ctx, uint8_t *site_key, bool verbose) { +static int hfgal_create_cad(DesfireContext_t *ctx, uint8_t *site_key, + uint8_t *cad_key, bool verbose) { // Check that card UID has been set if (ctx->uidlen == 0) HFGAL_RET_ERR(PM3_EINVARG, "Card UID must be set in DesfireContext " @@ -479,23 +481,30 @@ static int hfgal_create_cad(DesfireContext_t *ctx, uint8_t *site_key, bool verbo "currently has empty contents & blank keys)", CAD_AID); // Select application & authenticate - uint8_t blank_key[DESFIRE_MAX_KEY_SIZE] = {0}; + uint8_t blank_key[CRYPTO_AES128_KEY_SIZE] = {0}; DesfireSetKeyNoClear(ctx, 0, T_AES, blank_key); DesfireSetKdf(ctx, MFDES_KDF_ALGO_NONE, NULL, 0); res = select_aid_and_authenticate(ctx, CAD_AID, verbose); HFGAL_RET_IF_ERR(res); - // Diversify key uint8_t buf[CRYPTO_AES128_KEY_SIZE] = {0}; - res = hfgal_diversify_key(site_key, ctx->uid, ctx->uidlen, 0, CAD_AID, buf); - HFGAL_RET_IF_ERR_WITH_MSG(res, "Failed diversifying key 0 for AID %06X", CAD_AID); + if (cad_key != NULL) { + if (verbose) + PrintAndLogEx(INFO, "Using provided key 0 for CAD (AID %06X): " _GREEN_("%s"), + CAD_AID, sprint_hex_inrow(cad_key, CRYPTO_AES128_KEY_SIZE)); + } else { + // Diversify key + res = hfgal_diversify_key(site_key, ctx->uid, ctx->uidlen, 0, CAD_AID, buf); + HFGAL_RET_IF_ERR_WITH_MSG(res, "Failed diversifying key 0 for AID %06X", CAD_AID); - PrintAndLogEx(INFO, "Diversified key 0 for CAD (AID %06X): " _GREEN_("%s"), - CAD_AID, sprint_hex_inrow(buf, ARRAYLEN(buf))); + PrintAndLogEx(INFO, "Diversified key 0 for CAD (AID %06X): " _GREEN_("%s"), + CAD_AID, sprint_hex_inrow(buf, ARRAYLEN(buf))); + cad_key = buf; + } // Change key DesfireSetCommMode(ctx, DCMEncryptedPlain); - res = DesfireChangeKey(ctx, false, 0, app_algo, 1, buf, app_algo, blank_key, verbose); + res = DesfireChangeKey(ctx, false, 0, app_algo, 1, cad_key, app_algo, blank_key, verbose); HFGAL_RET_IF_ERR_WITH_MSG(res, "Failed setting key 0 for CAD"); if (verbose) @@ -509,12 +518,13 @@ static int hfgal_create_cad(DesfireContext_t *ctx, uint8_t *site_key, bool verbo /** * @brief Update the Gallagher Card Application Directory with a new entry. * - * @param site_key MIFARE site key. + * @param site_key MIFARE site key. Not used if cad_key is provided. + * @param cad_key Custom AES key 0 for the CAD (if not using the site_key). * @param aid Application ID to add to the CAD. * @param creds Gallagher cardholder credentials (region_code & facility_code are required). */ -static int hfgal_add_aid_to_cad(DesfireContext_t *ctx, uint8_t *site_key, uint32_t aid, - GallagherCredentials_t *creds, bool verbose) { +static int hfgal_add_aid_to_cad(DesfireContext_t *ctx, uint8_t *site_key, uint8_t *cad_key, + uint32_t aid, GallagherCredentials_t *creds, bool verbose) { // Check if CAD exists uint8_t cad[36 * 3] = {0}; uint8_t num_entries = 0; @@ -533,7 +543,7 @@ static int hfgal_add_aid_to_cad(DesfireContext_t *ctx, uint8_t *site_key, uint32 if (verbose) PrintAndLogEx(INFO, "Card Application Directory does not exist, creating it now..."); - int res = hfgal_create_cad(ctx, site_key, verbose); + int res = hfgal_create_cad(ctx, site_key, cad_key, verbose); HFGAL_RET_IF_ERR(res); } @@ -559,8 +569,13 @@ static int hfgal_add_aid_to_cad(DesfireContext_t *ctx, uint8_t *site_key, uint32 entry_num, file_id, sprint_hex_inrow(entry, 6)); // Select application & authenticate - DesfireSetKeyNoClear(ctx, 0, T_AES, site_key); - DesfireSetKdf(ctx, MFDES_KDF_ALGO_GALLAGHER, NULL, 0); + if (cad_key != NULL) { + DesfireSetKeyNoClear(ctx, 0, T_AES, cad_key); + DesfireSetKdf(ctx, MFDES_KDF_ALGO_NONE, NULL, 0); + } else { + DesfireSetKeyNoClear(ctx, 0, T_AES, site_key); + DesfireSetKdf(ctx, MFDES_KDF_ALGO_GALLAGHER, NULL, 0); + } int res = select_aid_and_authenticate(ctx, CAD_AID, verbose); HFGAL_RET_IF_ERR(res); @@ -607,11 +622,12 @@ static int hfgal_add_aid_to_cad(DesfireContext_t *ctx, uint8_t *site_key, uint32 /** * @brief Remove an entry from the Gallagher Card Application Directory. * - * @param site_key MIFARE site key. - * @param aid Application ID to add to the CAD. + * @param site_key MIFARE site key. Not used if cad_key is provided. + * @param cad_key Custom AES key 0 for the CAD (if not using the site_key). + * @param aid Application ID to remove from the CAD. */ static int hfgal_remove_aid_from_cad(DesfireContext_t *ctx, uint8_t *site_key, - uint32_t aid, bool verbose) { + uint8_t *cad_key, uint32_t aid, bool verbose) { // Check if CAD exists uint8_t cad[36 * 3] = {0}; uint8_t num_entries = 0; @@ -638,8 +654,13 @@ static int hfgal_remove_aid_from_cad(DesfireContext_t *ctx, uint8_t *site_key, memset(&cad[ARRAYLEN(cad) - 6], 0, 6); // Select application & authenticate - DesfireSetKeyNoClear(ctx, 0, T_AES, site_key); - DesfireSetKdf(ctx, MFDES_KDF_ALGO_GALLAGHER, NULL, 0); + if (cad_key != NULL) { + DesfireSetKeyNoClear(ctx, 0, T_AES, cad_key); + DesfireSetKdf(ctx, MFDES_KDF_ALGO_NONE, NULL, 0); + } else { + DesfireSetKeyNoClear(ctx, 0, T_AES, site_key); + DesfireSetKdf(ctx, MFDES_KDF_ALGO_GALLAGHER, NULL, 0); + } res = select_aid_and_authenticate(ctx, CAD_AID, verbose); HFGAL_RET_IF_ERR(res); @@ -803,35 +824,39 @@ static int CmdGallagherClone(const char *cmd) { arg_u64_1(NULL, "il", "", "Issue level. 4 bits max"), arg_str0(NULL, "aid", "", "Application ID to write (3 bytes) [default finds lowest available in range 0x2?81F4, where 0 <= ? <= 0xB]"), arg_str0(NULL, "sitekey", "", "MIFARE site key to compute diversified keys (16 bytes, required if using non-default key)"), + arg_str0(NULL, "cadkey", "", "Custom AES key 0 to modify the Card Application Directory (16 bytes)"), + arg_lit0(NULL, "nocadupdate", "Don't modify the Card Application Directory (only creates the app)"), + arg_lit0(NULL, "noappcreate", "Don't create the application (only modifies the CAD)"), arg_lit0(NULL, "apdu", "Show APDU requests and responses"), arg_lit0("v", "verbose", "Verbose mode"), arg_param_end }; CLIExecWithReturn(ctx, cmd, argtable, false); + uint8_t arg = 1; - int key_num = arg_get_int_def(ctx, 1, 0); + int key_num = arg_get_int_def(ctx, arg++, 0); int key_algo = T_DES; - if (CLIGetOptionList(arg_get_str(ctx, 2), DesfireAlgoOpts, &key_algo)) return PM3_ESOFT; + if (CLIGetOptionList(arg_get_str(ctx, arg++), DesfireAlgoOpts, &key_algo)) return PM3_ESOFT; int key_len = 0; uint8_t key[DESFIRE_MAX_KEY_SIZE] = {0}; - CLIGetHexWithReturn(ctx, 3, key, &key_len); + CLIGetHexWithReturn(ctx, arg++, key, &key_len); if (key_len && key_len != desfire_get_key_length(key_algo)) HFGAL_RET_ERR(PM3_EINVARG, "%s key must have %d bytes length instead of %d", CLIGetOptionListStr(DesfireAlgoOpts, key_algo), desfire_get_key_length(key_algo), key_len); if (key_len == 0) // Default to a key of all zeros key_len = desfire_get_key_length(key_algo); - uint64_t region_code = arg_get_u64(ctx, 4); // uint4, input will be validated later - uint64_t facility_code = arg_get_u64(ctx, 5); // uint16 - uint64_t card_number = arg_get_u64(ctx, 6); // uint24 - uint64_t issue_level = arg_get_u64(ctx, 7); // uint4 + uint64_t region_code = arg_get_u64(ctx, arg++); // uint4, input will be validated later + uint64_t facility_code = arg_get_u64(ctx, arg++); // uint16 + uint64_t card_number = arg_get_u64(ctx, arg++); // uint24 + uint64_t issue_level = arg_get_u64(ctx, arg++); // uint4 int aid_len = 0; uint8_t aid_buf[3] = {0}; - CLIGetHexWithReturn(ctx, 8, aid_buf, &aid_len); + CLIGetHexWithReturn(ctx, arg++, aid_buf, &aid_len); if (aid_len > 0 && aid_len != 3) HFGAL_RET_ERR(PM3_EINVARG, "--aid must be 3 bytes"); reverse_aid(aid_buf); // PM3 displays AIDs backwards @@ -840,12 +865,21 @@ static int CmdGallagherClone(const char *cmd) { int site_key_len = 0; uint8_t site_key[16] = {0}; memcpy(site_key, DEFAULT_SITE_KEY, ARRAYLEN(site_key)); - CLIGetHexWithReturn(ctx, 9, site_key, &site_key_len); + CLIGetHexWithReturn(ctx, arg++, site_key, &site_key_len); if (site_key_len > 0 && site_key_len != 16) HFGAL_RET_ERR(PM3_EINVARG, "--sitekey must be 16 bytes"); - SetAPDULogging(arg_get_lit(ctx, 10)); - bool verbose = arg_get_lit(ctx, 11); + int cad_key_len = 0; + uint8_t cad_key[16] = {0}; + CLIGetHexWithReturn(ctx, arg++, cad_key, &cad_key_len); + if (cad_key_len > 0 && cad_key_len != 16) + HFGAL_RET_ERR(PM3_EINVARG, "--cadkey must be 16 bytes"); + + bool no_cad_update = arg_get_lit(ctx, arg++); + bool no_app_create = arg_get_lit(ctx, arg++); + + SetAPDULogging(arg_get_lit(ctx, arg++)); + bool verbose = arg_get_lit(ctx, arg++); CLIParserFree(ctx); if (!gallagher_is_valid_creds(region_code, facility_code, card_number, issue_level)) @@ -875,16 +909,21 @@ static int CmdGallagherClone(const char *cmd) { } // Update Card Application Directory - DesfireSetKeyNoClear(&dctx, key_num, key_algo, key); - DesfireSetKdf(&dctx, MFDES_KDF_ALGO_NONE, NULL, 0); - res = hfgal_add_aid_to_cad(&dctx, site_key, aid, &creds, verbose); - HFGAL_RET_IF_ERR_WITH_MSG(res, "Failed updating Gallagher Card Application Directory"); + if (!no_cad_update) { + DesfireSetKeyNoClear(&dctx, key_num, key_algo, key); + DesfireSetKdf(&dctx, MFDES_KDF_ALGO_NONE, NULL, 0); + uint8_t *cad_key_ = cad_key_len > 0 ? cad_key : NULL; + res = hfgal_add_aid_to_cad(&dctx, site_key, cad_key_, aid, &creds, verbose); + HFGAL_RET_IF_ERR_WITH_MSG(res, "Failed updating Gallagher Card Application Directory"); + } // Create application - DesfireSetKeyNoClear(&dctx, key_num, key_algo, key); - DesfireSetKdf(&dctx, MFDES_KDF_ALGO_NONE, NULL, 0); - res = hfgal_create_creds_app(&dctx, site_key, aid, verbose); - HFGAL_RET_IF_ERR_WITH_MSG(res, "Failed creating Gallagher application"); + if (!no_app_create) { + DesfireSetKeyNoClear(&dctx, key_num, key_algo, key); + DesfireSetKdf(&dctx, MFDES_KDF_ALGO_NONE, NULL, 0); + res = hfgal_create_creds_app(&dctx, site_key, aid, verbose); + HFGAL_RET_IF_ERR_WITH_MSG(res, "Failed creating Gallagher application"); + } // Create credential files // Don't need to set keys here, they're generated automatically @@ -907,16 +946,20 @@ static int CmdGallagherDelete(const char *cmd) { arg_param_begin, arg_str1(NULL, "aid", "", "Application ID to delete (3 bytes)"), arg_str0(NULL, "sitekey", "", "MIFARE site key to compute diversified keys (16 bytes, required if using non-default key)"), + arg_str0(NULL, "cadkey", "", "Custom AES key 0 to modify the Card Application Directory (16 bytes)"), + arg_lit0(NULL, "nocadupdate", "Don't modify the Card Application Directory (only deletes the app)"), + arg_lit0(NULL, "noappdelete", "Don't delete the application (only modifies the CAD)"), arg_lit0(NULL, "apdu", "Show APDU requests and responses"), arg_lit0("v", "verbose", "Verbose mode"), arg_param_end }; CLIExecWithReturn(ctx, cmd, argtable, false); + uint8_t arg = 1; int aid_len = 0; uint8_t aid_buf[3] = {0}; - CLIGetHexWithReturn(ctx, 1, aid_buf, &aid_len); + CLIGetHexWithReturn(ctx, arg++, aid_buf, &aid_len); if (aid_len != 3) HFGAL_RET_ERR(PM3_EINVARG, "--aid must be 3 bytes"); reverse_aid(aid_buf); // PM3 displays AIDs backwards @@ -925,12 +968,21 @@ static int CmdGallagherDelete(const char *cmd) { int site_key_len = 0; uint8_t site_key[16] = {0}; memcpy(site_key, DEFAULT_SITE_KEY, ARRAYLEN(site_key)); - CLIGetHexWithReturn(ctx, 2, site_key, &site_key_len); + CLIGetHexWithReturn(ctx, arg++, site_key, &site_key_len); if (site_key_len > 0 && site_key_len != 16) HFGAL_RET_ERR(PM3_EINVARG, "--sitekey must be 16 bytes"); - SetAPDULogging(arg_get_lit(ctx, 3)); - bool verbose = arg_get_lit(ctx, 4); + int cad_key_len = 0; + uint8_t cad_key[16] = {0}; + CLIGetHexWithReturn(ctx, arg++, cad_key, &cad_key_len); + if (cad_key_len > 0 && cad_key_len != 16) + HFGAL_RET_ERR(PM3_EINVARG, "--cadkey must be 16 bytes"); + + bool no_cad_update = arg_get_lit(ctx, arg++); + bool no_app_delete = arg_get_lit(ctx, arg++); + + SetAPDULogging(arg_get_lit(ctx, arg++)); + bool verbose = arg_get_lit(ctx, arg++); CLIParserFree(ctx); // Set up context @@ -943,12 +995,17 @@ static int CmdGallagherDelete(const char *cmd) { HFGAL_RET_IF_ERR_WITH_MSG(res, "Failed retrieving card UID"); // Update Card Application Directory - res = hfgal_remove_aid_from_cad(&dctx, site_key, aid, verbose); - HFGAL_RET_IF_ERR_WITH_MSG(res, "Failed removing %06X from the Card Application Directory"); + if (!no_cad_update) { + uint8_t *cad_key_ = cad_key_len > 0 ? cad_key : NULL; + res = hfgal_remove_aid_from_cad(&dctx, site_key, cad_key_, aid, verbose); + HFGAL_RET_IF_ERR_WITH_MSG(res, "Failed removing %06X from the Card Application Directory"); + } // Delete application - res = hfgal_delete_app(&dctx, site_key, aid, verbose); - HFGAL_RET_IF_ERR_WITH_MSG(res, "Failed deleting Gallagher application"); + if (!no_app_delete) { + res = hfgal_delete_app(&dctx, site_key, aid, verbose); + HFGAL_RET_IF_ERR_WITH_MSG(res, "Failed deleting Gallagher application"); + } PrintAndLogEx(SUCCESS, "Done"); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf gallagher reader`") " to verify"); diff --git a/doc/commands.json b/doc/commands.json index d5fd002c0..f741f0edb 100644 --- a/doc/commands.json +++ b/doc/commands.json @@ -2329,19 +2329,22 @@ "offline": false, "options": [ "-h, --help this help", - "-n, --keynum key number [default=0]", - "-t, --algo crypt algo: des, 2tdea, 3tdea, aes", - "-k, --key key for authentication to the picc (hex 8(des), 16(2tdea or aes) or 24(3tdea) bytes)", + "-n, --keynum picc key number [default=0]", + "-t, --algo picc key algo: des, 2tdea, 3tdea, aes", + "-k, --key key for authentication to the picc to create applications (hex 8(des), 16(2tdea or aes) or 24(3tdea) bytes)", "--rc region code. 4 bits max", "--fc facility code. 2 bytes max", "--cn card number. 3 bytes max", "--il issue level. 4 bits max", - "--aid application id to write (3 bytes) [default finds lowest available in range 0x2?81f4, where 0 <= ? <= 0xb]", + "--aid application id to write (3 bytes) [default automatically chooses an aid]", "--sitekey mifare site key to compute diversified keys (16 bytes, required if using non-default key)", + "--cadkey custom aes key 0 to modify the card application directory (16 bytes)", + "--nocadupdate don't modify the card application directory (only creates the app)", + "--noappcreate don't create the application (only modifies the cad)", "--apdu show apdu requests and responses", "-v, --verbose verbose mode" ], - "usage": "hf gallagher clone [-hv] [-n ] [-t ] [-k ] --rc --fc --cn --il [--aid ] [--sitekey ] [--apdu]" + "usage": "hf gallagher clone [-hv] [-n ] [-t ] [-k ] --rc --fc --cn --il [--aid ] [--sitekey ] [--cadkey ] [--nocadupdate] [--noappcreate] [--apdu]" }, "hf gallagher delete": { "command": "hf gallagher delete", @@ -2354,10 +2357,13 @@ "-h, --help this help", "--aid application id to delete (3 bytes)", "--sitekey mifare site key to compute diversified keys (16 bytes, required if using non-default key)", + "--cadkey custom aes key 0 to modify the card application directory (16 bytes)", + "--nocadupdate don't modify the card application directory (only deletes the app)", + "--noappdelete don't delete the application (only modifies the cad)", "--apdu show apdu requests and responses", "-v, --verbose verbose mode" ], - "usage": "hf gallagher delete [-hv] --aid [--sitekey ] [--apdu]" + "usage": "hf gallagher delete [-hv] --aid [--sitekey ] [--cadkey ] [--nocadupdate] [--noappdelete] [--apdu]" }, "hf gallagher diversifykey": { "command": "hf gallagher diversifykey", @@ -10237,6 +10243,6 @@ "metadata": { "commands_extracted": 601, "extracted_by": "PM3Help2JSON v1.00", - "extracted_on": "2022-01-06T19:05:01" + "extracted_on": "2022-01-07T10:53:54" } } \ No newline at end of file From b3dc6f62abe1fc8525b3b77627f0cad82842171c Mon Sep 17 00:00:00 2001 From: Matt Moran Date: Fri, 7 Jan 2022 23:59:46 +1300 Subject: [PATCH 04/13] Refactor, adds `select_aid_and_auth_with_key` --- client/src/cmdhfgallagher.c | 157 ++++++++++++++++++------------------ 1 file changed, 80 insertions(+), 77 deletions(-) diff --git a/client/src/cmdhfgallagher.c b/client/src/cmdhfgallagher.c index 86dc614ba..079630ad9 100644 --- a/client/src/cmdhfgallagher.c +++ b/client/src/cmdhfgallagher.c @@ -153,7 +153,7 @@ static int authenticate(DesfireContext_t *ctx, bool verbose) { * @brief Select application ID & authenticate. * Uses existing authentication keys in context. */ -static int select_aid_and_authenticate(DesfireContext_t *ctx, uint32_t aid, bool verbose) { +static int select_aid_and_auth(DesfireContext_t *ctx, uint32_t aid, bool verbose) { int res = select_aid(ctx, aid, verbose); HFGAL_RET_IF_ERR(res); @@ -163,6 +163,25 @@ static int select_aid_and_authenticate(DesfireContext_t *ctx, uint32_t aid, bool return PM3_SUCCESS; } +/** + * @brief Select application ID & authenticate with specified AES key. + */ +static int select_aid_and_auth_with_key(DesfireContext_t *ctx, uint32_t aid, uint8_t *key, + uint8_t key_num, bool should_diversify, bool verbose) { + int res = select_aid(ctx, aid, verbose); + HFGAL_RET_IF_ERR(res); + + // Set key & diversification algorithm. + uint8_t kdf_algo = should_diversify ? MFDES_KDF_ALGO_GALLAGHER : MFDES_KDF_ALGO_NONE; + DesfireSetKeyNoClear(ctx, key_num, T_AES, key); + DesfireSetKdf(ctx, kdf_algo, NULL, 0); + + res = authenticate(ctx, verbose); + HFGAL_RET_IF_ERR(res); + + return PM3_SUCCESS; +} + /** * @brief Returns true if the specified application exists, false otherwise. */ @@ -193,6 +212,7 @@ static uint32_t find_available_gallagher_aid(DesfireContext_t *ctx, bool verbose if (!aid_exists(ctx, aid, verbose)) return aid; } + //DesfireGetAIDList return 0; } @@ -205,9 +225,7 @@ static uint32_t find_available_gallagher_aid(DesfireContext_t *ctx, bool verbose static int hfgal_delete_app(DesfireContext_t *ctx, uint8_t *site_key, uint32_t aid, bool verbose) { // Select application & authenticate - DesfireSetKeyNoClear(ctx, 0, T_AES, site_key); - DesfireSetKdf(ctx, MFDES_KDF_ALGO_GALLAGHER, NULL, 0); - int res = select_aid_and_authenticate(ctx, aid, verbose); + int res = select_aid_and_auth_with_key(ctx, aid, site_key, 0, true, verbose); HFGAL_RET_IF_ERR(res); // Delete application @@ -234,9 +252,7 @@ static int hfgal_read_creds_app(DesfireContext_t *ctx, uint32_t aid, uint8_t *si "(required for key diversification)"); // Select application & authenticate - DesfireSetKeyNoClear(ctx, 2, T_AES, site_key); - DesfireSetKdf(ctx, MFDES_KDF_ALGO_GALLAGHER, NULL, 0); - int res = select_aid_and_authenticate(ctx, aid, verbose); + int res = select_aid_and_auth_with_key(ctx, aid, site_key, 0, true, verbose); HFGAL_RET_IF_ERR_WITH_MSG(res, "Failed selecting/authenticating to AID %06X", aid); // Read file 0 (contains credentials) @@ -274,7 +290,7 @@ static int hfgal_read_creds_app(DesfireContext_t *ctx, uint32_t aid, uint8_t *si */ static int hfgal_create_creds_app(DesfireContext_t *ctx, uint8_t *site_key, uint32_t aid, bool verbose) { // Select application & authenticate - int res = select_aid_and_authenticate(ctx, 0x000000, verbose); + int res = select_aid_and_auth(ctx, 0x000000, verbose); HFGAL_RET_IF_ERR(res); // UID is required for key diversification @@ -347,9 +363,7 @@ static int hfgal_create_creds_app(DesfireContext_t *ctx, uint8_t *site_key, uint static int hfgal_create_creds_file(DesfireContext_t *ctx, uint8_t *site_key, uint32_t aid, GallagherCredentials_t *creds, bool verbose) { // Select application & authenticate - DesfireSetKeyNoClear(ctx, 0, T_AES, site_key); - DesfireSetKdf(ctx, MFDES_KDF_ALGO_GALLAGHER, NULL, 0); - int res = select_aid_and_authenticate(ctx, aid, verbose); + int res = select_aid_and_auth_with_key(ctx, aid, site_key, 0, true, verbose); HFGAL_RET_IF_ERR(res); // Prepare create file command @@ -446,18 +460,18 @@ static int hfgal_read_cad(DesfireContext_t *ctx, uint8_t *dest_buf, /** * @brief Create the Gallagher Card Application Directory. * - * @param site_key MIFARE site key. Not used if cad_key is provided. - * @param cad_key Custom AES key 0 for the CAD (if not using the site_key). + * @param key MIFARE site key, or custom CAD key. + * @param should_diversify True if using a site_key, false if using a custom CAD key. */ -static int hfgal_create_cad(DesfireContext_t *ctx, uint8_t *site_key, - uint8_t *cad_key, bool verbose) { +static int hfgal_create_cad(DesfireContext_t *ctx, uint8_t *key, + bool should_diversify, bool verbose) { // Check that card UID has been set if (ctx->uidlen == 0) HFGAL_RET_ERR(PM3_EINVARG, "Card UID must be set in DesfireContext " "(required for key diversification)"); // Select application & authenticate - int res = select_aid_and_authenticate(ctx, 0x000000, verbose); + int res = select_aid_and_auth(ctx, 0x000000, verbose); HFGAL_RET_IF_ERR(res); // Create application @@ -482,29 +496,25 @@ static int hfgal_create_cad(DesfireContext_t *ctx, uint8_t *site_key, // Select application & authenticate uint8_t blank_key[CRYPTO_AES128_KEY_SIZE] = {0}; - DesfireSetKeyNoClear(ctx, 0, T_AES, blank_key); - DesfireSetKdf(ctx, MFDES_KDF_ALGO_NONE, NULL, 0); - res = select_aid_and_authenticate(ctx, CAD_AID, verbose); + res = select_aid_and_auth_with_key(ctx, CAD_AID, blank_key, 0, false, verbose); HFGAL_RET_IF_ERR(res); uint8_t buf[CRYPTO_AES128_KEY_SIZE] = {0}; - if (cad_key != NULL) { - if (verbose) - PrintAndLogEx(INFO, "Using provided key 0 for CAD (AID %06X): " _GREEN_("%s"), - CAD_AID, sprint_hex_inrow(cad_key, CRYPTO_AES128_KEY_SIZE)); - } else { + if (should_diversify) { // Diversify key - res = hfgal_diversify_key(site_key, ctx->uid, ctx->uidlen, 0, CAD_AID, buf); + res = hfgal_diversify_key(key, ctx->uid, ctx->uidlen, 0, CAD_AID, buf); HFGAL_RET_IF_ERR_WITH_MSG(res, "Failed diversifying key 0 for AID %06X", CAD_AID); PrintAndLogEx(INFO, "Diversified key 0 for CAD (AID %06X): " _GREEN_("%s"), - CAD_AID, sprint_hex_inrow(buf, ARRAYLEN(buf))); - cad_key = buf; - } + CAD_AID, sprint_hex_inrow(buf, ARRAYLEN(buf))); + key = buf; + } else if (verbose) + PrintAndLogEx(INFO, "Using provided key 0 for CAD (AID %06X): " _GREEN_("%s"), + CAD_AID, sprint_hex_inrow(key, CRYPTO_AES128_KEY_SIZE)); // Change key DesfireSetCommMode(ctx, DCMEncryptedPlain); - res = DesfireChangeKey(ctx, false, 0, app_algo, 1, cad_key, app_algo, blank_key, verbose); + res = DesfireChangeKey(ctx, false, 0, app_algo, 1, key, app_algo, blank_key, verbose); HFGAL_RET_IF_ERR_WITH_MSG(res, "Failed setting key 0 for CAD"); if (verbose) @@ -518,12 +528,12 @@ static int hfgal_create_cad(DesfireContext_t *ctx, uint8_t *site_key, /** * @brief Update the Gallagher Card Application Directory with a new entry. * - * @param site_key MIFARE site key. Not used if cad_key is provided. - * @param cad_key Custom AES key 0 for the CAD (if not using the site_key). + * @param key MIFARE site key, or custom CAD key. + * @param should_diversify True if using a site_key, false if using a custom CAD key. * @param aid Application ID to add to the CAD. * @param creds Gallagher cardholder credentials (region_code & facility_code are required). */ -static int hfgal_add_aid_to_cad(DesfireContext_t *ctx, uint8_t *site_key, uint8_t *cad_key, +static int hfgal_add_aid_to_cad(DesfireContext_t *ctx, uint8_t *key, bool should_diversify, uint32_t aid, GallagherCredentials_t *creds, bool verbose) { // Check if CAD exists uint8_t cad[36 * 3] = {0}; @@ -543,7 +553,7 @@ static int hfgal_add_aid_to_cad(DesfireContext_t *ctx, uint8_t *site_key, uint8_ if (verbose) PrintAndLogEx(INFO, "Card Application Directory does not exist, creating it now..."); - int res = hfgal_create_cad(ctx, site_key, cad_key, verbose); + int res = hfgal_create_cad(ctx, key, should_diversify, verbose); HFGAL_RET_IF_ERR(res); } @@ -569,14 +579,7 @@ static int hfgal_add_aid_to_cad(DesfireContext_t *ctx, uint8_t *site_key, uint8_ entry_num, file_id, sprint_hex_inrow(entry, 6)); // Select application & authenticate - if (cad_key != NULL) { - DesfireSetKeyNoClear(ctx, 0, T_AES, cad_key); - DesfireSetKdf(ctx, MFDES_KDF_ALGO_NONE, NULL, 0); - } else { - DesfireSetKeyNoClear(ctx, 0, T_AES, site_key); - DesfireSetKdf(ctx, MFDES_KDF_ALGO_GALLAGHER, NULL, 0); - } - int res = select_aid_and_authenticate(ctx, CAD_AID, verbose); + int res = select_aid_and_auth_with_key(ctx, aid, key, 0, should_diversify, verbose); HFGAL_RET_IF_ERR(res); // Create file if necessary @@ -622,16 +625,15 @@ static int hfgal_add_aid_to_cad(DesfireContext_t *ctx, uint8_t *site_key, uint8_ /** * @brief Remove an entry from the Gallagher Card Application Directory. * - * @param site_key MIFARE site key. Not used if cad_key is provided. - * @param cad_key Custom AES key 0 for the CAD (if not using the site_key). + * @param key MIFARE site key, or custom CAD key. + * @param should_diversify True if using a site_key, false if using a custom CAD key. * @param aid Application ID to remove from the CAD. */ -static int hfgal_remove_aid_from_cad(DesfireContext_t *ctx, uint8_t *site_key, - uint8_t *cad_key, uint32_t aid, bool verbose) { - // Check if CAD exists +static int hfgal_remove_aid_from_cad(DesfireContext_t *ctx, uint8_t *key, + bool should_diversify, uint32_t aid, bool verbose) { + // Read CAD uint8_t cad[36 * 3] = {0}; uint8_t num_entries = 0; - int res = hfgal_read_cad(ctx, cad, ARRAYLEN(cad), &num_entries, verbose); HFGAL_RET_IF_ERR(res); @@ -654,14 +656,7 @@ static int hfgal_remove_aid_from_cad(DesfireContext_t *ctx, uint8_t *site_key, memset(&cad[ARRAYLEN(cad) - 6], 0, 6); // Select application & authenticate - if (cad_key != NULL) { - DesfireSetKeyNoClear(ctx, 0, T_AES, cad_key); - DesfireSetKdf(ctx, MFDES_KDF_ALGO_NONE, NULL, 0); - } else { - DesfireSetKeyNoClear(ctx, 0, T_AES, site_key); - DesfireSetKdf(ctx, MFDES_KDF_ALGO_GALLAGHER, NULL, 0); - } - res = select_aid_and_authenticate(ctx, CAD_AID, verbose); + res = select_aid_and_auth_with_key(ctx, CAD_AID, key, 0, should_diversify, verbose); HFGAL_RET_IF_ERR(res); // Determine what files we need to update @@ -814,15 +809,15 @@ static int CmdGallagherClone(const char *cmd) { void *argtable[] = { arg_param_begin, - arg_int0("n", "keynum", "", "Key number [default=0]"), - arg_str0("t", "algo", "", "Crypt algo: DES, 2TDEA, 3TDEA, AES"), - arg_str0("k", "key", "", "Key for authentication to the PICC (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"), + arg_int0("n", "keynum", "", "PICC key number [default=0]"), + arg_str0("t", "algo", "", "PICC key algo: DES, 2TDEA, 3TDEA, AES"), + arg_str0("k", "key", "", "Key for authentication to the PICC to create applications (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"), arg_u64_1(NULL, "rc", "", "Region code. 4 bits max"), arg_u64_1(NULL, "fc", "", "Facility code. 2 bytes max"), arg_u64_1(NULL, "cn", "", "Card number. 3 bytes max"), arg_u64_1(NULL, "il", "", "Issue level. 4 bits max"), - arg_str0(NULL, "aid", "", "Application ID to write (3 bytes) [default finds lowest available in range 0x2?81F4, where 0 <= ? <= 0xB]"), + arg_str0(NULL, "aid", "", "Application ID to write (3 bytes) [default automatically chooses an AID]"), arg_str0(NULL, "sitekey", "", "MIFARE site key to compute diversified keys (16 bytes, required if using non-default key)"), arg_str0(NULL, "cadkey", "", "Custom AES key 0 to modify the Card Application Directory (16 bytes)"), arg_lit0(NULL, "nocadupdate", "Don't modify the Card Application Directory (only creates the app)"), @@ -835,19 +830,19 @@ static int CmdGallagherClone(const char *cmd) { CLIExecWithReturn(ctx, cmd, argtable, false); uint8_t arg = 1; - int key_num = arg_get_int_def(ctx, arg++, 0); + int picc_key_num = arg_get_int_def(ctx, arg++, 0); - int key_algo = T_DES; - if (CLIGetOptionList(arg_get_str(ctx, arg++), DesfireAlgoOpts, &key_algo)) return PM3_ESOFT; + int picc_key_algo = T_DES; + if (CLIGetOptionList(arg_get_str(ctx, arg++), DesfireAlgoOpts, &picc_key_algo)) return PM3_ESOFT; - int key_len = 0; - uint8_t key[DESFIRE_MAX_KEY_SIZE] = {0}; - CLIGetHexWithReturn(ctx, arg++, key, &key_len); - if (key_len && key_len != desfire_get_key_length(key_algo)) - HFGAL_RET_ERR(PM3_EINVARG, "%s key must have %d bytes length instead of %d", CLIGetOptionListStr(DesfireAlgoOpts, key_algo), desfire_get_key_length(key_algo), key_len); - if (key_len == 0) + int picc_key_len = 0; + uint8_t picc_key[DESFIRE_MAX_KEY_SIZE] = {0}; + CLIGetHexWithReturn(ctx, arg++, picc_key, &picc_key_len); + if (picc_key_len && picc_key_len != desfire_get_key_length(picc_key_algo)) + HFGAL_RET_ERR(PM3_EINVARG, "%s key must have %d bytes length instead of %d", CLIGetOptionListStr(DesfireAlgoOpts, picc_key_algo), desfire_get_key_length(picc_key_algo), picc_key_len); + if (picc_key_len == 0) // Default to a key of all zeros - key_len = desfire_get_key_length(key_algo); + picc_key_len = desfire_get_key_length(picc_key_algo); uint64_t region_code = arg_get_u64(ctx, arg++); // uint4, input will be validated later uint64_t facility_code = arg_get_u64(ctx, arg++); // uint16 @@ -874,7 +869,7 @@ static int CmdGallagherClone(const char *cmd) { CLIGetHexWithReturn(ctx, arg++, cad_key, &cad_key_len); if (cad_key_len > 0 && cad_key_len != 16) HFGAL_RET_ERR(PM3_EINVARG, "--cadkey must be 16 bytes"); - + bool no_cad_update = arg_get_lit(ctx, arg++); bool no_app_create = arg_get_lit(ctx, arg++); @@ -910,17 +905,24 @@ static int CmdGallagherClone(const char *cmd) { // Update Card Application Directory if (!no_cad_update) { - DesfireSetKeyNoClear(&dctx, key_num, key_algo, key); + // Set keys so that hfgal_add_aid_to_cad can auth to 0x000000 + // if it needs to create the CAD application. + DesfireSetKeyNoClear(&dctx, picc_key_num, picc_key_algo, picc_key); DesfireSetKdf(&dctx, MFDES_KDF_ALGO_NONE, NULL, 0); - uint8_t *cad_key_ = cad_key_len > 0 ? cad_key : NULL; - res = hfgal_add_aid_to_cad(&dctx, site_key, cad_key_, aid, &creds, verbose); + + bool should_diversify = cad_key_len == 0; + uint8_t *key = should_diversify ? site_key : cad_key; + res = hfgal_add_aid_to_cad(&dctx, key, should_diversify, aid, &creds, verbose); HFGAL_RET_IF_ERR_WITH_MSG(res, "Failed updating Gallagher Card Application Directory"); } // Create application if (!no_app_create) { - DesfireSetKeyNoClear(&dctx, key_num, key_algo, key); + // Set keys so that hfgal_create_creds_app can auth to 0x000000 + // when it creates the application. + DesfireSetKeyNoClear(&dctx, picc_key_num, picc_key_algo, picc_key); DesfireSetKdf(&dctx, MFDES_KDF_ALGO_NONE, NULL, 0); + res = hfgal_create_creds_app(&dctx, site_key, aid, verbose); HFGAL_RET_IF_ERR_WITH_MSG(res, "Failed creating Gallagher application"); } @@ -977,7 +979,7 @@ static int CmdGallagherDelete(const char *cmd) { CLIGetHexWithReturn(ctx, arg++, cad_key, &cad_key_len); if (cad_key_len > 0 && cad_key_len != 16) HFGAL_RET_ERR(PM3_EINVARG, "--cadkey must be 16 bytes"); - + bool no_cad_update = arg_get_lit(ctx, arg++); bool no_app_delete = arg_get_lit(ctx, arg++); @@ -996,8 +998,9 @@ static int CmdGallagherDelete(const char *cmd) { // Update Card Application Directory if (!no_cad_update) { - uint8_t *cad_key_ = cad_key_len > 0 ? cad_key : NULL; - res = hfgal_remove_aid_from_cad(&dctx, site_key, cad_key_, aid, verbose); + bool should_diversify = cad_key_len == 0; + uint8_t *key = should_diversify ? site_key : cad_key; + res = hfgal_remove_aid_from_cad(&dctx, key, should_diversify, aid, verbose); HFGAL_RET_IF_ERR_WITH_MSG(res, "Failed removing %06X from the Card Application Directory"); } From 1f8217ec2e740d084bd4626c5ed319c8d510357e Mon Sep 17 00:00:00 2001 From: Matt Moran Date: Sat, 8 Jan 2022 00:36:26 +1300 Subject: [PATCH 05/13] Use `DesfireGetAIDList` to find an available AID ... and check that user-specified AID is available (before writing to the CAD) --- client/src/cmdhfgallagher.c | 59 ++++++++++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 10 deletions(-) diff --git a/client/src/cmdhfgallagher.c b/client/src/cmdhfgallagher.c index 079630ad9..f9765f37f 100644 --- a/client/src/cmdhfgallagher.c +++ b/client/src/cmdhfgallagher.c @@ -204,16 +204,49 @@ static bool aid_exists(DesfireContext_t *ctx, uint32_t aid, bool verbose) { /** * @brief Returns the lowest available Gallagher application ID. - * @return 0 if no AID is available, or an AID in the range 0x2?81F4, where 0 <= ? <= 0xB. + * @return The lowest AID in the range 0x??81F4, where 0x20 <= ?? <= 0xFE. */ static uint32_t find_available_gallagher_aid(DesfireContext_t *ctx, bool verbose) { - for (uint8_t i = 0x0; i <= 0xB; i++) { - uint32_t aid = 0x2081F4 | (i << 16); - if (!aid_exists(ctx, aid, verbose)) - return aid; + // Select PICC + select_aid(ctx, 0x000000, verbose); + + // Retrieve the AID list + uint8_t aid_buf[0xFF] = {0}; + size_t aid_buf_len = 0; + int res = DesfireGetAIDList(ctx, aid_buf, &aid_buf_len); + if (res != PM3_SUCCESS) + HFGAL_RET_ERR(0, "Failed retrieving AID list"); + + if (verbose) { + // Print what we got + PrintAndLogEx(INFO, "Retrieved AID list:" NOLF); + for (int i = 0; i < aid_buf_len; i += 3) + PrintAndLogEx(NORMAL, "%s %06X" NOLF, (i == 0) ? "" : ",", + DesfireAIDByteToUint(&aid_buf[i])); + PrintAndLogEx(NORMAL, ""); } - //DesfireGetAIDList - return 0; + + // Find lowest available in range F48120 -> F481FE, excluding the CAD + for (uint8_t aid_increment = 0x20; aid_increment < 0xFF; aid_increment++) { + uint32_t aid = 0x0081F4 | (aid_increment << 16); + if (aid == CAD_AID) + continue; + + // Check if AID exists in aid_buf + bool aid_exists = false; + for (uint8_t idx = 0; idx < aid_buf_len; idx += 3) { + if (DesfireAIDByteToUint(&aid_buf[idx]) == aid) { + aid_exists = true; + break; + } + } + if (!aid_exists) + return aid; + } + + // Failed to find an available AID. This shouldn't be possible since + // we check 255 different AIDs and cards don't hold that many. + HFGAL_RET_ERR(0, "All AIDs exist. This shouldn't be possible."); } /** @@ -579,7 +612,7 @@ static int hfgal_add_aid_to_cad(DesfireContext_t *ctx, uint8_t *key, bool should entry_num, file_id, sprint_hex_inrow(entry, 6)); // Select application & authenticate - int res = select_aid_and_auth_with_key(ctx, aid, key, 0, should_diversify, verbose); + int res = select_aid_and_auth_with_key(ctx, CAD_AID, key, 0, should_diversify, verbose); HFGAL_RET_IF_ERR(res); // Create file if necessary @@ -896,11 +929,17 @@ static int CmdGallagherClone(const char *cmd) { int res = DesfireGetCardUID(&dctx); HFGAL_RET_IF_ERR_WITH_MSG(res, "Failed retrieving card UID"); - // Find available Gallagher AID if the user did not specify one if (aid_len == 0) { + // Find available Gallagher AID if the user did not specify one aid = find_available_gallagher_aid(&dctx, verbose); if (aid == 0) - HFGAL_RET_ERR(PM3_EFATAL, "Could not find an available AID, card is full"); + HFGAL_RET_ERR(PM3_EFATAL, "Could not find an available AID, please specify with --aid"); + if (verbose) + PrintAndLogEx(INFO, "Using available AID: %06X", aid); + } else { + // Check that AID is available + if (aid_exists(&dctx, aid, verbose)) + HFGAL_RET_ERR(PM3_EINVARG, "AID already exists: %06X", aid); } // Update Card Application Directory From cb6a1db85215731aa808cad81c084564362773cf Mon Sep 17 00:00:00 2001 From: Matt Moran Date: Sat, 8 Jan 2022 18:13:29 +1300 Subject: [PATCH 06/13] Continue reading credentials if one fails (e.g. when using different site keys) --- client/src/cmdhfgallagher.c | 7 ++++++- client/src/cmdhfgallagher.h | 4 ++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/client/src/cmdhfgallagher.c b/client/src/cmdhfgallagher.c index f9765f37f..5e653708b 100644 --- a/client/src/cmdhfgallagher.c +++ b/client/src/cmdhfgallagher.c @@ -771,7 +771,12 @@ static int hfgal_read_card(uint32_t aid, uint8_t *site_key, bool verbose, bool q // Read & decode credentials GallagherCredentials_t creds = {0}; res = hfgal_read_creds_app(&dctx, current_aid, site_key, &creds, verbose); - HFGAL_RET_IF_ERR_MAYBE_MSG(res, !quiet, "Failed reading card application credentials"); + if (res != PM3_SUCCESS && res != HFGAL_AUTH_FAIL) + HFGAL_RET_IF_ERR_MAYBE_MSG(res, !quiet, "Failed reading card application credentials"); + if (res == HFGAL_AUTH_FAIL) { + PrintAndLogEx(WARNING, "Invalid site key for AID %06X", current_aid); + continue; + } PrintAndLogEx(SUCCESS, "GALLAGHER (AID %06X) - Region: " _GREEN_("%u") ", Facility: " _GREEN_("%u") ", Card No.: " _GREEN_("%u") ", Issue Level: " _GREEN_("%u"), current_aid, diff --git a/client/src/cmdhfgallagher.h b/client/src/cmdhfgallagher.h index c4ed31784..087ad9364 100644 --- a/client/src/cmdhfgallagher.h +++ b/client/src/cmdhfgallagher.h @@ -40,4 +40,8 @@ int hfgal_diversify_key(uint8_t *site_key, uint8_t *uid, uint8_t uid_len, #define HFGAL_RET_IF_ERR_WITH_MSG(res, ...) if (res != PM3_SUCCESS) { PrintAndLogEx(ERR, __VA_ARGS__); return res; } #define HFGAL_RET_IF_ERR_MAYBE_MSG(res, verbose, ...) if (res != PM3_SUCCESS) { if (verbose) PrintAndLogEx(ERR, __VA_ARGS__); return res; } +// The response code when an invalid key is used for authentication +// Returned in /client/src/mifare/desfirecore.c, line 1185 (if DesfireExchangeEx fails) +#define HFGAL_AUTH_FAIL 7 + #endif From aa6b74a08d60959c2743778e490b5bdbe1b4c648 Mon Sep 17 00:00:00 2001 From: Matt Moran Date: Thu, 13 Jan 2022 21:06:21 +1300 Subject: [PATCH 07/13] Fix was attempting to credential file when --noappcreate was passed --- client/src/cmdhfgallagher.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/client/src/cmdhfgallagher.c b/client/src/cmdhfgallagher.c index 5e653708b..40d95db81 100644 --- a/client/src/cmdhfgallagher.c +++ b/client/src/cmdhfgallagher.c @@ -209,7 +209,7 @@ static bool aid_exists(DesfireContext_t *ctx, uint32_t aid, bool verbose) { static uint32_t find_available_gallagher_aid(DesfireContext_t *ctx, bool verbose) { // Select PICC select_aid(ctx, 0x000000, verbose); - + // Retrieve the AID list uint8_t aid_buf[0xFF] = {0}; size_t aid_buf_len = 0; @@ -241,7 +241,7 @@ static uint32_t find_available_gallagher_aid(DesfireContext_t *ctx, bool verbose } } if (!aid_exists) - return aid; + return aid; } // Failed to find an available AID. This shouldn't be possible since @@ -941,11 +941,10 @@ static int CmdGallagherClone(const char *cmd) { HFGAL_RET_ERR(PM3_EFATAL, "Could not find an available AID, please specify with --aid"); if (verbose) PrintAndLogEx(INFO, "Using available AID: %06X", aid); - } else { - // Check that AID is available - if (aid_exists(&dctx, aid, verbose)) - HFGAL_RET_ERR(PM3_EINVARG, "AID already exists: %06X", aid); } + // Check that AID is available + else if (!no_app_create && aid_exists(&dctx, aid, verbose)) + HFGAL_RET_ERR(PM3_EINVARG, "AID already exists: %06X", aid); // Update Card Application Directory if (!no_cad_update) { @@ -969,12 +968,12 @@ static int CmdGallagherClone(const char *cmd) { res = hfgal_create_creds_app(&dctx, site_key, aid, verbose); HFGAL_RET_IF_ERR_WITH_MSG(res, "Failed creating Gallagher application"); - } - // Create credential files - // Don't need to set keys here, they're generated automatically - res = hfgal_create_creds_file(&dctx, site_key, aid, &creds, verbose); - HFGAL_RET_IF_ERR_WITH_MSG(res, "Failed creating Gallagher credential file"); + // Create credential files + // Don't need to set keys here, they're generated automatically + res = hfgal_create_creds_file(&dctx, site_key, aid, &creds, verbose); + HFGAL_RET_IF_ERR_WITH_MSG(res, "Failed creating Gallagher credential file"); + } PrintAndLogEx(SUCCESS, "Done"); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf gallagher reader`") " to verify"); From f057184ee313457db83a7043d893ce65de2a31b7 Mon Sep 17 00:00:00 2001 From: Matt Moran Date: Sat, 15 Jan 2022 13:10:00 +1300 Subject: [PATCH 08/13] Fix styles (missing braces) --- client/src/cmdhfgallagher.c | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/client/src/cmdhfgallagher.c b/client/src/cmdhfgallagher.c index 6eed216c3..33104266e 100644 --- a/client/src/cmdhfgallagher.c +++ b/client/src/cmdhfgallagher.c @@ -134,8 +134,9 @@ static int select_aid(DesfireContext_t *ctx, uint32_t aid, bool verbose) { return 202; } - if (verbose) + if (verbose) { PrintAndLogEx(INFO, "Selected AID %06X", aid); + } return PM3_SUCCESS; } @@ -364,9 +365,10 @@ static int hfgal_create_creds_app(DesfireContext_t *ctx, uint8_t *site_key, uint PM3_RET_IF_ERR(res); // UID is required for key diversification - if (ctx->uidlen == 0) + if (ctx->uidlen == 0) { PM3_RET_ERR(PM3_EINVARG, "UID is required for key diversification. " "Please fetch it before calling `hfgal_create_creds_app`"); + } // Create application DesfireCryptoAlgorithm app_algo = T_AES; @@ -548,8 +550,9 @@ static int hfgal_read_cad(DesfireContext_t *ctx, uint8_t *dest_buf, static int hfgal_create_cad(DesfireContext_t *ctx, uint8_t *key, bool should_diversify, bool verbose) { // Check that card UID has been set - if (ctx->uidlen == 0) + if (ctx->uidlen == 0) { PM3_RET_ERR(PM3_EINVARG, "Card UID must be set in DesfireContext (required for key div)"); + } // Select application & authenticate int res = select_aid_and_auth(ctx, 0x000000, verbose); @@ -604,8 +607,9 @@ static int hfgal_create_cad(DesfireContext_t *ctx, uint8_t *key, res = DesfireChangeKey(ctx, false, 0, app_algo, 1, buf, app_algo, blank_key, verbose); PM3_RET_IF_ERR_WITH_MSG(res, "Failed setting key 0 for CAD"); - if (verbose) + if (verbose) { PrintAndLogEx(INFO, "Successfully set key " _YELLOW_("0") " for CAD"); + } PrintAndLogEx(INFO, "Successfully created Card Application Directory (AID " _YELLOW_("%06X") ")", CAD_AID); return PM3_SUCCESS; @@ -653,10 +657,11 @@ static int hfgal_add_aid_to_cad(DesfireContext_t *ctx, uint8_t *key, bool should // Check if facility already exists in CAD. for (uint8_t i = 0; i < ARRAYLEN(cad); i += 6) { - if (cad_facility_match(&cad[i], creds->region_code, creds->facility_code)) + if (cad_facility_match(&cad[i], creds->region_code, creds->facility_code)) { PM3_RET_ERR(PM3_EFATAL, "Facility already exists in CAD, delete or update AID %06X", cad_aid_byte_to_uint(&cad[i + 3]) ); + } } // Create entry @@ -701,14 +706,16 @@ static int hfgal_add_aid_to_cad(DesfireContext_t *ctx, uint8_t *key, bool should res = DesfireCreateFile(ctx, file_type, data, ARRAYLEN(data), false); PM3_RET_IF_ERR_WITH_MSG(res, "Failed creating file %d in CAD (AID %06X)", file_id, CAD_AID); - if (verbose) + if (verbose) { PrintAndLogEx(INFO, "Created file " _YELLOW_("%d") " in CAD (empty contents)", file_id); + } // Write file res = DesfireWriteFile(ctx, file_id, 0, 36, &cad[file_id * 36]); - } else + } else { // Write file res = DesfireWriteFile(ctx, file_id, entry_num * 6, 6, entry); + } PM3_RET_IF_ERR_WITH_MSG(res, "Failed writing data to file %d in CAD AID %06X)", file_id, CAD_AID); PrintAndLogEx(INFO, "Successfully added new entry for " _YELLOW_("%06X") " to the Card Application Directory", aid); @@ -999,8 +1006,9 @@ static int CmdGallagherClone(const char *cmd) { int cad_key_len = 0; uint8_t cad_key[16] = {0}; CLIGetHexWithReturn(ctx, arg++, cad_key, &cad_key_len); - if (cad_key_len > 0 && cad_key_len != 16) + if (cad_key_len > 0 && cad_key_len != 16) { PM3_RET_ERR(PM3_EINVARG, "--cadkey must be 16 bytes"); + } bool no_cad_update = arg_get_lit(ctx, arg++); bool no_app_create = arg_get_lit(ctx, arg++); @@ -1009,8 +1017,9 @@ static int CmdGallagherClone(const char *cmd) { bool verbose = arg_get_lit(ctx, arg++); CLIParserFree(ctx); - if (gallagher_is_valid_creds(region_code, facility_code, card_number, issue_level) == false) + if (gallagher_is_valid_creds(region_code, facility_code, card_number, issue_level) == false) { return PM3_EINVARG; + } GallagherCredentials_t creds = { .region_code = region_code, @@ -1039,8 +1048,9 @@ static int CmdGallagherClone(const char *cmd) { } } // Check that AID is available - else if (!no_app_create && aid_exists(&dctx, aid, verbose)) + else if (!no_app_create && aid_exists(&dctx, aid, verbose)) { PM3_RET_ERR(PM3_EINVARG, "AID already exists: %06X", aid); + } // Update Card Application Directory if (!no_cad_update) { @@ -1102,8 +1112,9 @@ static int CmdGallagherDelete(const char *cmd) { int aid_len = 0; uint8_t aid_buf[3] = {0}; CLIGetHexWithReturn(ctx, arg++, aid_buf, &aid_len); - if (aid_len != 3) + if (aid_len != 3) { PM3_RET_ERR_FREE(PM3_EINVARG, "--aid must be 3 bytes"); + } reverse_aid(aid_buf); // PM3 displays AIDs backwards uint32_t aid = DesfireAIDByteToUint(aid_buf); @@ -1118,8 +1129,9 @@ static int CmdGallagherDelete(const char *cmd) { int cad_key_len = 0; uint8_t cad_key[16] = {0}; CLIGetHexWithReturn(ctx, arg++, cad_key, &cad_key_len); - if (cad_key_len > 0 && cad_key_len != 16) + if (cad_key_len > 0 && cad_key_len != 16) { PM3_RET_ERR(PM3_EINVARG, "--cadkey must be 16 bytes"); + } bool no_cad_update = arg_get_lit(ctx, arg++); bool no_app_delete = arg_get_lit(ctx, arg++); From 4c9d167966c92d73bbb63cf5f07a601ce7f2261c Mon Sep 17 00:00:00 2001 From: Matt Moran Date: Sat, 15 Jan 2022 13:44:16 +1300 Subject: [PATCH 09/13] Update styles to match changes --- client/src/cmdhfgallagher.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/client/src/cmdhfgallagher.c b/client/src/cmdhfgallagher.c index 33104266e..bd1a347c2 100644 --- a/client/src/cmdhfgallagher.c +++ b/client/src/cmdhfgallagher.c @@ -49,7 +49,7 @@ static const uint8_t DEFAULT_SITE_KEY[] = { * @param uid Card unique ID (4 or 7 bytes). * @param uid_len Length of UID. * @param key_num Key number (0 <= key_num <= 2). - * @param aid Application ID (0x2?81F4 where 0 <= ? <= 0xB). + * @param aid Application ID (3 bytes, e.g. 0x2081F4). * @param key_output Buffer to copy the diversified key into (must be 16 bytes). * @return PM3_SUCCESS if successful, PM3_EINVARG if an argument is invalid. */ @@ -228,7 +228,7 @@ static bool aid_exists(DesfireContext_t *ctx, uint32_t aid, bool verbose) { /** * @brief Returns the lowest available Gallagher application ID. - * @return The lowest AID in the range 0x??81F4, where 0x20 <= ?? <= 0xFE. + * @return The lowest AID in the range 0x??81F4, where ?? >= 0x20. */ static uint32_t find_available_gallagher_aid(DesfireContext_t *ctx, bool verbose) { // Select PICC @@ -357,7 +357,7 @@ static int hfgal_read_creds_app(DesfireContext_t *ctx, uint32_t aid, uint8_t *si * @brief Create a new application to store Gallagher cardholder credentials. * * @param site_key MIFARE site key. - * @param aid New application ID. Should be 0x2?81F4, where 0 <= ? <= 0xB. + * @param aid New application ID. 3 bytes, e.g. 0x2081F4. */ static int hfgal_create_creds_app(DesfireContext_t *ctx, uint8_t *site_key, uint32_t aid, bool verbose) { // Select application & authenticate @@ -933,21 +933,21 @@ static int CmdGallagherClone(const char *cmd) { " DES 8 bytes\n" " 2TDEA or AES 16 bytes\n" " 3TDEA 24 bytes\n" - "AID id, default finds lowest available in range 0x2?81F4, where 0 <= ? <= 0xB.", + "AID, default finds lowest available in range 0x??81F4, where ?? >= 0x20.", "hf gallagher clone --rc 1 --fc 22 --cn 3333 --il 4 --sitekey 00112233445566778899aabbccddeeff" ); void *argtable[] = { arg_param_begin, - arg_int0("n", "keynum", "", "PICC key number [default=0]"), - arg_str0("t", "algo", "", "PICC key algo: DES, 2TDEA, 3TDEA, AES"), + arg_int0("n", "keynum", "", "PICC key number [default = 0]"), + arg_str0("t", "algo", "", "PICC crypt algo: DES, 2TDEA, 3TDEA, AES"), arg_str0("k", "key", "", "Key for authentication to the PICC to create applications (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"), arg_u64_1(NULL, "rc", "", "Region code. 4 bits max"), arg_u64_1(NULL, "fc", "", "Facility code. 2 bytes max"), arg_u64_1(NULL, "cn", "", "Card number. 3 bytes max"), arg_u64_1(NULL, "il", "", "Issue level. 4 bits max"), arg_str0(NULL, "aid", "", "Application ID to write (3 bytes) [default automatically chooses an AID]"), - arg_str0(NULL, "sitekey", "", "MIFARE site key to compute diversified keys (16 bytes, required if using non-default key)"), + arg_str0(NULL, "sitekey", "", "Site key to compute diversified keys (16 bytes)"), arg_str0(NULL, "cadkey", "", "Custom AES key 0 to modify the Card Application Directory (16 bytes)"), arg_lit0(NULL, "nocadupdate", "Don't modify the Card Application Directory (only creates the app)"), arg_lit0(NULL, "noappcreate", "Don't create the application (only modifies the CAD)"), @@ -1046,14 +1046,13 @@ static int CmdGallagherClone(const char *cmd) { if (verbose) { PrintAndLogEx(INFO, "Using available AID: %06X", aid); } - } - // Check that AID is available - else if (!no_app_create && aid_exists(&dctx, aid, verbose)) { + } else if (no_app_create == false && aid_exists(&dctx, aid, verbose)) { + // AID was specified but is not available PM3_RET_ERR(PM3_EINVARG, "AID already exists: %06X", aid); } // Update Card Application Directory - if (!no_cad_update) { + if (no_cad_update == false) { // Set keys so that hfgal_add_aid_to_cad can auth to 0x000000 // if it needs to create the CAD application. DesfireSetKeyNoClear(&dctx, picc_key_num, picc_key_algo, picc_key); @@ -1066,7 +1065,7 @@ static int CmdGallagherClone(const char *cmd) { } // Create application - if (!no_app_create) { + if (no_app_create == false) { // Set keys so that hfgal_create_creds_app can auth to 0x000000 // when it creates the application. DesfireSetKeyNoClear(&dctx, picc_key_num, picc_key_algo, picc_key); @@ -1097,7 +1096,7 @@ static int CmdGallagherDelete(const char *cmd) { void *argtable[] = { arg_param_begin, arg_str1(NULL, "aid", "", "Application ID to delete (3 bytes)"), - arg_str0(NULL, "sitekey", "", "MIFARE site key to compute diversified keys (16 bytes, required if using non-default key)"), + arg_str0(NULL, "sitekey", "", "Site key to compute diversified keys (16 bytes)"), arg_str0(NULL, "cadkey", "", "Custom AES key 0 to modify the Card Application Directory (16 bytes)"), arg_lit0(NULL, "nocadupdate", "Don't modify the Card Application Directory (only deletes the app)"), arg_lit0(NULL, "noappdelete", "Don't delete the application (only modifies the CAD)"), @@ -1150,7 +1149,7 @@ static int CmdGallagherDelete(const char *cmd) { PM3_RET_IF_ERR_WITH_MSG(res, "Failed retrieving card UID"); // Update Card Application Directory - if (!no_cad_update) { + if (no_cad_update == false) { bool should_diversify = cad_key_len == 0; uint8_t *key = should_diversify ? site_key : cad_key; res = hfgal_remove_aid_from_cad(&dctx, key, should_diversify, aid, verbose); @@ -1158,7 +1157,7 @@ static int CmdGallagherDelete(const char *cmd) { } // Delete application - if (!no_app_delete) { + if (no_app_delete == false) { res = hfgal_delete_app(&dctx, site_key, aid, verbose); PM3_RET_IF_ERR_WITH_MSG(res, "Failed deleting Gallagher application"); } From 8118ab538c17a200b7571ec99ae106558f1bbf26 Mon Sep 17 00:00:00 2001 From: Matt Moran Date: Sat, 15 Jan 2022 14:03:00 +1300 Subject: [PATCH 10/13] Update commands.json/.md --- client/src/pm3line_vocabulory.h | 1 - doc/commands.json | 39 ++++++++++++++------------------- doc/commands.md | 1 - 3 files changed, 16 insertions(+), 25 deletions(-) diff --git a/client/src/pm3line_vocabulory.h b/client/src/pm3line_vocabulory.h index d71e90895..4ef0c0771 100644 --- a/client/src/pm3line_vocabulory.h +++ b/client/src/pm3line_vocabulory.h @@ -63,7 +63,6 @@ const static vocabulory_t vocabulory[] = { { 1, "analyse crc" }, { 1, "analyse chksum" }, { 1, "analyse dates" }, - { 1, "analyse tea" }, { 1, "analyse lfsr" }, { 1, "analyse a" }, { 1, "analyse nuid" }, diff --git a/doc/commands.json b/doc/commands.json index ca5b13fb5..56e392eaf 100644 --- a/doc/commands.json +++ b/doc/commands.json @@ -97,7 +97,7 @@ }, "analyse help": { "command": "analyse help", - "description": "help this help lcr generate final byte for xor lrc crc stub method for crc evaluations chksum checksum with adding, masking and one's complement dates look for datestamps in a given array of bytes tea crypto tea test lfsr lfsr tests a num bits test nuid create nuid from 7byte uid demodbuff load binary string to demodbuffer freq calc wave lengths foo muxer units convert etu <> us <> ssp_clk (3.39mhz) --------------------------------------------------------------------------------------- analyse lcr available offline: yes specifying the bytes of a uid with a known lrc will find the last byte value needed to generate that lrc with a rolling xor. all bytes should be specified in hex.", + "description": "help this help lcr generate final byte for xor lrc crc stub method for crc evaluations chksum checksum with adding, masking and one's complement dates look for datestamps in a given array of bytes lfsr lfsr tests a num bits test nuid create nuid from 7byte uid demodbuff load binary string to demodbuffer freq calc wave lengths foo muxer units convert etu <> us <> ssp_clk (3.39mhz) --------------------------------------------------------------------------------------- analyse lcr available offline: yes specifying the bytes of a uid with a known lrc will find the last byte value needed to generate that lrc with a rolling xor. all bytes should be specified in hex.", "notes": [ "analyse lcr -d 04008064ba -> target (ba) requires final lrc xor byte value: 5a" ], @@ -136,19 +136,6 @@ ], "usage": "analyse nuid [-ht] [-d ]" }, - "analyse tea": { - "command": "analyse tea", - "description": "crypto tea self tests", - "notes": [ - "analyse tea -d 1122334455667788" - ], - "offline": true, - "options": [ - "-h, --help this help", - "-d, --data bytes to encrypt ( 8 hex bytes )" - ], - "usage": "analyse tea [-h] -d " - }, "analyse units": { "command": "analyse units", "description": "experiments of unit conversions found in hf. etu (1/13.56mhz), us or ssp_clk (1/3.39mhz)", @@ -2322,26 +2309,29 @@ }, "hf gallagher clone": { "command": "hf gallagher clone", - "description": "clone gallagher credentials to a writable desfire card specify site key is required if using non-default key key, lengths for the different crypto: des 8 bytes 2tdea or aes 16 bytes 3tdea 24 bytes aid id, default finds lowest available in range 0x2?81f4, where 0 <= ? <= 0xb.", + "description": "clone gallagher credentials to a writable desfire card specify site key is required if using non-default key key, lengths for the different crypto: des 8 bytes 2tdea or aes 16 bytes 3tdea 24 bytes aid, default finds lowest available in range 0x??81f4, where ?? >= 0x20.", "notes": [ "hf gallagher clone --rc 1 --fc 22 --cn 3333 --il 4 --sitekey 00112233445566778899aabbccddeeff" ], "offline": false, "options": [ "-h, --help this help", - "-n, --keynum key number [default = 0]", - "-t, --algo crypt algo: des, 2tdea, 3tdea, aes", - "-k, --key key for authentication to the picc", + "-n, --keynum picc key number [default = 0]", + "-t, --algo picc crypt algo: des, 2tdea, 3tdea, aes", + "-k, --key key for authentication to the picc to create applications (hex 8(des), 16(2tdea or aes) or 24(3tdea) bytes)", "--rc region code. 4 bits max", "--fc facility code. 2 bytes max", "--cn card number. 3 bytes max", "--il issue level. 4 bits max", - "--aid application id to write (3 bytes)", + "--aid application id to write (3 bytes) [default automatically chooses an aid]", "--sitekey site key to compute diversified keys (16 bytes)", + "--cadkey custom aes key 0 to modify the card application directory (16 bytes)", + "--nocadupdate don't modify the card application directory (only creates the app)", + "--noappcreate don't create the application (only modifies the cad)", "--apdu show apdu requests and responses", "-v, --verbose verbose mode" ], - "usage": "hf gallagher clone [-hv] [-n ] [-t ] [-k ] --rc --fc --cn --il [--aid ] [--sitekey ] [--apdu]" + "usage": "hf gallagher clone [-hv] [-n ] [-t ] [-k ] --rc --fc --cn --il [--aid ] [--sitekey ] [--cadkey ] [--nocadupdate] [--noappcreate] [--apdu]" }, "hf gallagher delete": { "command": "hf gallagher delete", @@ -2354,10 +2344,13 @@ "-h, --help this help", "--aid application id to delete (3 bytes)", "--sitekey site key to compute diversified keys (16 bytes)", + "--cadkey custom aes key 0 to modify the card application directory (16 bytes)", + "--nocadupdate don't modify the card application directory (only deletes the app)", + "--noappdelete don't delete the application (only modifies the cad)", "--apdu show apdu requests and responses", "-v, --verbose verbose mode" ], - "usage": "hf gallagher delete [-hv] --aid [--sitekey ] [--apdu]" + "usage": "hf gallagher delete [-hv] --aid [--sitekey ] [--cadkey ] [--nocadupdate] [--noappdelete] [--apdu]" }, "hf gallagher diversifykey": { "command": "hf gallagher diversifykey", @@ -10210,8 +10203,8 @@ } }, "metadata": { - "commands_extracted": 599, + "commands_extracted": 598, "extracted_by": "PM3Help2JSON v1.00", - "extracted_on": "2022-01-11T01:15:20" + "extracted_on": "2022-01-15T01:07:16" } } \ No newline at end of file diff --git a/doc/commands.md b/doc/commands.md index f585b71da..86eca7c06 100644 --- a/doc/commands.md +++ b/doc/commands.md @@ -74,7 +74,6 @@ Check column "offline" for their availability. |`analyse crc `|Y |`Stub method for CRC evaluations` |`analyse chksum `|Y |`Checksum with adding, masking and one's complement` |`analyse dates `|Y |`Look for datestamps in a given array of bytes` -|`analyse tea `|Y |`Crypto TEA test` |`analyse lfsr `|Y |`LFSR tests` |`analyse a `|Y |`num bits test` |`analyse nuid `|Y |`create NUID from 7byte UID` From 2805b8f7ffb509ffff47ab5d9a199d1cac0cde7a Mon Sep 17 00:00:00 2001 From: Matt Moran Date: Sat, 15 Jan 2022 14:10:37 +1300 Subject: [PATCH 11/13] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index eaf6cf2a6..cf6a64184 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file. This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... ## [unreleased][unreleased] + - Remove AID limitations when using Gallagher key diversification (@DarkMatterMatt) ## [Frostbit.4.14831] [2022-01-11] - Changed Wiegand format lookup - now case-insensitive (@iceman1001) From 072e97998ffe61ad826f0413648b313dcdab66fb Mon Sep 17 00:00:00 2001 From: Matt Moran Date: Sat, 15 Jan 2022 14:40:40 +1300 Subject: [PATCH 12/13] Fix wasn't freeing arg ctx, improve comments --- client/src/cmdhfgallagher.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/client/src/cmdhfgallagher.c b/client/src/cmdhfgallagher.c index bd1a347c2..511fb47cb 100644 --- a/client/src/cmdhfgallagher.c +++ b/client/src/cmdhfgallagher.c @@ -228,14 +228,14 @@ static bool aid_exists(DesfireContext_t *ctx, uint32_t aid, bool verbose) { /** * @brief Returns the lowest available Gallagher application ID. - * @return The lowest AID in the range 0x??81F4, where ?? >= 0x20. + * @return The lowest available AID in the range 0x??81F4, where ?? >= 0x20. */ static uint32_t find_available_gallagher_aid(DesfireContext_t *ctx, bool verbose) { // Select PICC select_aid(ctx, 0x000000, verbose); // Retrieve the AID list - uint8_t aid_buf[0xFF] = {0}; + uint8_t aid_buf[DESFIRE_BUFFER_SIZE] = {0}; size_t aid_buf_len = 0; int res = DesfireGetAIDList(ctx, aid_buf, &aid_buf_len); if (res != PM3_SUCCESS) { @@ -274,9 +274,9 @@ static uint32_t find_available_gallagher_aid(DesfireContext_t *ctx, bool verbose } } - // Failed to find an available AID. This shouldn't be possible since - // we check 255 different AIDs and cards don't hold that many. - PM3_RET_ERR(0, "All AIDs exist. This shouldn't be possible."); + // Failed to find an available AID. This is very unlikely to occur as + // DESFire cards rarely have more than 1 application on them + PM3_RET_ERR(0, "Checked 200+ AIDs and all exist, abandoning search"); } /** @@ -1007,7 +1007,7 @@ static int CmdGallagherClone(const char *cmd) { uint8_t cad_key[16] = {0}; CLIGetHexWithReturn(ctx, arg++, cad_key, &cad_key_len); if (cad_key_len > 0 && cad_key_len != 16) { - PM3_RET_ERR(PM3_EINVARG, "--cadkey must be 16 bytes"); + PM3_RET_ERR_FREE(PM3_EINVARG, "--cadkey must be 16 bytes"); } bool no_cad_update = arg_get_lit(ctx, arg++); @@ -1100,7 +1100,6 @@ static int CmdGallagherDelete(const char *cmd) { arg_str0(NULL, "cadkey", "", "Custom AES key 0 to modify the Card Application Directory (16 bytes)"), arg_lit0(NULL, "nocadupdate", "Don't modify the Card Application Directory (only deletes the app)"), arg_lit0(NULL, "noappdelete", "Don't delete the application (only modifies the CAD)"), - arg_lit0(NULL, "apdu", "Show APDU requests and responses"), arg_lit0("v", "verbose", "Verbose mode"), arg_param_end @@ -1129,7 +1128,7 @@ static int CmdGallagherDelete(const char *cmd) { uint8_t cad_key[16] = {0}; CLIGetHexWithReturn(ctx, arg++, cad_key, &cad_key_len); if (cad_key_len > 0 && cad_key_len != 16) { - PM3_RET_ERR(PM3_EINVARG, "--cadkey must be 16 bytes"); + PM3_RET_ERR_FREE(PM3_EINVARG, "--cadkey must be 16 bytes"); } bool no_cad_update = arg_get_lit(ctx, arg++); @@ -1177,11 +1176,11 @@ static int CmdGallagherDiversify(const char *cmd) { void *argtable[] = { arg_param_begin, - arg_str1(NULL, "aid", "", "Application ID for diversification (3 bytes)"), - arg_int0(NULL, "keynum", "", "Key number [default = 0]"), - arg_str0(NULL, "uid", "", "Card UID to delete (4 or 7 bytes)"), - arg_str0(NULL, "sitekey", "", "Site key to compute diversified keys (16 bytes)"), - arg_lit0(NULL, "apdu", "Show APDU requests and responses"), + arg_str1(NULL, "aid", "", "Application ID for diversification (3 bytes)"), + arg_int0(NULL, "keynum", "", "Key number [default = 0]"), + arg_str0(NULL, "uid", "", "Card UID to delete (4 or 7 bytes)"), + arg_str0(NULL, "sitekey", "", "Site key to compute diversified keys (16 bytes)"), + arg_lit0(NULL, "apdu", "Show APDU requests and responses"), arg_param_end }; CLIExecWithReturn(ctx, cmd, argtable, false); From 750fd646c1e17e2ca36a80d7e33e9e12f9a161b4 Mon Sep 17 00:00:00 2001 From: Matt Moran Date: Mon, 17 Jan 2022 23:38:00 +1300 Subject: [PATCH 13/13] Shorten command help text, reorder changelog --- CHANGELOG.md | 2 +- client/src/cmdhfgallagher.c | 4 ++-- doc/commands.json | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a8cd8220..0e86025fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac ## [Frostbit.4.14831] [2022-01-11] - Changed Wiegand format lookup - now case-insensitive (@iceman1001) - Added new standalone mode `hf_15SNIFF` - Same as `hf_14ASNIFF` standalone mode for RDV4 - flashmem (@startrk1995) + - Added `hf gallagher` commands for read/writing DESFire cards (@DarkMatterMatt) - Added support for MIFARE DESFire application creation without authentication (@joswr1ght) - Changed drastically Hitag S ARM code to remove state machines and ease way to build new commands (@doegox) - Fixed Hitag S crypto mode with key or NrAr, fixed `lf hitag cc`, fixed pwd dump in hitagS dump with LKP (@doegox) @@ -64,7 +65,6 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Fixed `SimulateTagLowFrequencyEx` ignoring the `ledcontrol` argument (@zabszk) - Added ledcontrol argument to LF operations (@zabszk) - Added new standalone mode `dankarmulti` - select and run multiple standalone modes (@dankar) - - Added `hf gallagher` commands for read/writing DESFire cards (@DarkMatterMatt) ## [crimson.4.14434][2021-09-18] - Fixed `hf mf staticnested` - flashmem / non loop now works (@horrordash) diff --git a/client/src/cmdhfgallagher.c b/client/src/cmdhfgallagher.c index 511fb47cb..7d46953ef 100644 --- a/client/src/cmdhfgallagher.c +++ b/client/src/cmdhfgallagher.c @@ -941,12 +941,12 @@ static int CmdGallagherClone(const char *cmd) { arg_param_begin, arg_int0("n", "keynum", "", "PICC key number [default = 0]"), arg_str0("t", "algo", "", "PICC crypt algo: DES, 2TDEA, 3TDEA, AES"), - arg_str0("k", "key", "", "Key for authentication to the PICC to create applications (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"), + arg_str0("k", "key", "", "Key for authentication to the PICC to create applications"), arg_u64_1(NULL, "rc", "", "Region code. 4 bits max"), arg_u64_1(NULL, "fc", "", "Facility code. 2 bytes max"), arg_u64_1(NULL, "cn", "", "Card number. 3 bytes max"), arg_u64_1(NULL, "il", "", "Issue level. 4 bits max"), - arg_str0(NULL, "aid", "", "Application ID to write (3 bytes) [default automatically chooses an AID]"), + arg_str0(NULL, "aid", "", "Application ID to write (3 bytes) [default automatically chooses]"), arg_str0(NULL, "sitekey", "", "Site key to compute diversified keys (16 bytes)"), arg_str0(NULL, "cadkey", "", "Custom AES key 0 to modify the Card Application Directory (16 bytes)"), arg_lit0(NULL, "nocadupdate", "Don't modify the Card Application Directory (only creates the app)"), diff --git a/doc/commands.json b/doc/commands.json index 56e392eaf..ad96cf2ea 100644 --- a/doc/commands.json +++ b/doc/commands.json @@ -2318,12 +2318,12 @@ "-h, --help this help", "-n, --keynum picc key number [default = 0]", "-t, --algo picc crypt algo: des, 2tdea, 3tdea, aes", - "-k, --key key for authentication to the picc to create applications (hex 8(des), 16(2tdea or aes) or 24(3tdea) bytes)", + "-k, --key key for authentication to the picc to create applications", "--rc region code. 4 bits max", "--fc facility code. 2 bytes max", "--cn card number. 3 bytes max", "--il issue level. 4 bits max", - "--aid application id to write (3 bytes) [default automatically chooses an aid]", + "--aid application id to write (3 bytes) [default automatically chooses]", "--sitekey site key to compute diversified keys (16 bytes)", "--cadkey custom aes key 0 to modify the card application directory (16 bytes)", "--nocadupdate don't modify the card application directory (only creates the app)", @@ -10205,6 +10205,6 @@ "metadata": { "commands_extracted": 598, "extracted_by": "PM3Help2JSON v1.00", - "extracted_on": "2022-01-15T01:07:16" + "extracted_on": "2022-01-17T10:37:00" } } \ No newline at end of file