mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 22:03:42 -07:00
Merge pull request #1557 from DarkMatterMatt/feat/hf-gallagher-remove-aid-limits
Improve `hf gallagher` commands
This commit is contained in:
commit
795e604ddb
7 changed files with 260 additions and 182 deletions
|
@ -4,10 +4,12 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
|
||||||
|
|
||||||
## [unreleased][unreleased]
|
## [unreleased][unreleased]
|
||||||
- Add `nfc decode` - now NDEF vCard messages with a PHOTO in base64 format is shown (@iceman1001)
|
- Add `nfc decode` - now NDEF vCard messages with a PHOTO in base64 format is shown (@iceman1001)
|
||||||
|
- Remove AID limitations when using Gallagher key diversification (@DarkMatterMatt)
|
||||||
|
|
||||||
## [Frostbit.4.14831] [2022-01-11]
|
## [Frostbit.4.14831] [2022-01-11]
|
||||||
- Changed Wiegand format lookup - now case-insensitive (@iceman1001)
|
- 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 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)
|
- 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)
|
- 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)
|
- Fixed Hitag S crypto mode with key or NrAr, fixed `lf hitag cc`, fixed pwd dump in hitagS dump with LKP (@doegox)
|
||||||
|
|
|
@ -49,7 +49,7 @@ static const uint8_t DEFAULT_SITE_KEY[] = {
|
||||||
* @param uid Card unique ID (4 or 7 bytes).
|
* @param uid Card unique ID (4 or 7 bytes).
|
||||||
* @param uid_len Length of UID.
|
* @param uid_len Length of UID.
|
||||||
* @param key_num Key number (0 <= key_num <= 2).
|
* @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).
|
* @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.
|
* @return PM3_SUCCESS if successful, PM3_EINVARG if an argument is invalid.
|
||||||
*/
|
*/
|
||||||
|
@ -134,8 +134,9 @@ static int select_aid(DesfireContext_t *ctx, uint32_t aid, bool verbose) {
|
||||||
return 202;
|
return 202;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verbose)
|
if (verbose) {
|
||||||
PrintAndLogEx(INFO, "Selected AID %06X", aid);
|
PrintAndLogEx(INFO, "Selected AID %06X", aid);
|
||||||
|
}
|
||||||
|
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -173,7 +174,7 @@ static int authenticate(DesfireContext_t *ctx, bool verbose) {
|
||||||
* @brief Select application ID & authenticate.
|
* @brief Select application ID & authenticate.
|
||||||
* Uses existing authentication keys in context.
|
* 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);
|
int res = select_aid(ctx, aid, verbose);
|
||||||
PM3_RET_IF_ERR(res);
|
PM3_RET_IF_ERR(res);
|
||||||
|
|
||||||
|
@ -183,6 +184,25 @@ static int select_aid_and_authenticate(DesfireContext_t *ctx, uint32_t aid, bool
|
||||||
return PM3_SUCCESS;
|
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);
|
||||||
|
PM3_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);
|
||||||
|
PM3_RET_IF_ERR(res);
|
||||||
|
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns true if the specified application exists, false otherwise.
|
* @brief Returns true if the specified application exists, false otherwise.
|
||||||
*/
|
*/
|
||||||
|
@ -208,16 +228,55 @@ static bool aid_exists(DesfireContext_t *ctx, uint32_t aid, bool verbose) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns the lowest available Gallagher application ID.
|
* @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 available AID in the range 0x??81F4, where ?? >= 0x20.
|
||||||
*/
|
*/
|
||||||
static uint32_t find_available_gallagher_aid(DesfireContext_t *ctx, bool verbose) {
|
static uint32_t find_available_gallagher_aid(DesfireContext_t *ctx, bool verbose) {
|
||||||
for (uint8_t i = 0x0; i <= 0xB; i++) {
|
// Select PICC
|
||||||
uint32_t aid = 0x2081F4 | (i << 16);
|
select_aid(ctx, 0x000000, verbose);
|
||||||
if (aid_exists(ctx, aid, verbose) == false) {
|
|
||||||
|
// Retrieve the AID list
|
||||||
|
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) {
|
||||||
|
PM3_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, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 == false) {
|
||||||
return aid;
|
return aid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
|
// 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");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -229,9 +288,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,
|
static int hfgal_delete_app(DesfireContext_t *ctx, uint8_t *site_key,
|
||||||
uint32_t aid, bool verbose) {
|
uint32_t aid, bool verbose) {
|
||||||
// Select application & authenticate
|
// Select application & authenticate
|
||||||
DesfireSetKeyNoClear(ctx, 0, T_AES, site_key);
|
int res = select_aid_and_auth_with_key(ctx, aid, site_key, 0, true, verbose);
|
||||||
DesfireSetKdf(ctx, MFDES_KDF_ALGO_GALLAGHER, NULL, 0);
|
|
||||||
int res = select_aid_and_authenticate(ctx, aid, verbose);
|
|
||||||
PM3_RET_IF_ERR(res);
|
PM3_RET_IF_ERR(res);
|
||||||
|
|
||||||
// Delete application
|
// Delete application
|
||||||
|
@ -258,9 +315,7 @@ static int hfgal_read_creds_app(DesfireContext_t *ctx, uint32_t aid, uint8_t *si
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select application & authenticate
|
// Select application & authenticate
|
||||||
DesfireSetKeyNoClear(ctx, 2, T_AES, site_key);
|
int res = select_aid_and_auth_with_key(ctx, aid, site_key, 0, true, verbose);
|
||||||
DesfireSetKdf(ctx, MFDES_KDF_ALGO_GALLAGHER, NULL, 0);
|
|
||||||
int res = select_aid_and_authenticate(ctx, aid, verbose);
|
|
||||||
PM3_RET_IF_ERR_WITH_MSG(res, "Failed selecting/authenticating to AID %06X", aid);
|
PM3_RET_IF_ERR_WITH_MSG(res, "Failed selecting/authenticating to AID %06X", aid);
|
||||||
|
|
||||||
// Read file 0 (contains credentials)
|
// Read file 0 (contains credentials)
|
||||||
|
@ -302,17 +357,18 @@ 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.
|
* @brief Create a new application to store Gallagher cardholder credentials.
|
||||||
*
|
*
|
||||||
* @param site_key MIFARE site key.
|
* @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) {
|
static int hfgal_create_creds_app(DesfireContext_t *ctx, uint8_t *site_key, uint32_t aid, bool verbose) {
|
||||||
// Select application & authenticate
|
// Select application & authenticate
|
||||||
int res = select_aid_and_authenticate(ctx, 0x000000, verbose);
|
int res = select_aid_and_auth(ctx, 0x000000, verbose);
|
||||||
PM3_RET_IF_ERR(res);
|
PM3_RET_IF_ERR(res);
|
||||||
|
|
||||||
// UID is required for key diversification
|
// 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. "
|
PM3_RET_ERR(PM3_EINVARG, "UID is required for key diversification. "
|
||||||
"Please fetch it before calling `hfgal_create_creds_app`");
|
"Please fetch it before calling `hfgal_create_creds_app`");
|
||||||
|
}
|
||||||
|
|
||||||
// Create application
|
// Create application
|
||||||
DesfireCryptoAlgorithm app_algo = T_AES;
|
DesfireCryptoAlgorithm app_algo = T_AES;
|
||||||
|
@ -381,9 +437,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,
|
static int hfgal_create_creds_file(DesfireContext_t *ctx, uint8_t *site_key, uint32_t aid,
|
||||||
GallagherCredentials_t *creds, bool verbose) {
|
GallagherCredentials_t *creds, bool verbose) {
|
||||||
// Select application & authenticate
|
// Select application & authenticate
|
||||||
DesfireSetKeyNoClear(ctx, 0, T_AES, site_key);
|
int res = select_aid_and_auth_with_key(ctx, aid, site_key, 0, true, verbose);
|
||||||
DesfireSetKdf(ctx, MFDES_KDF_ALGO_GALLAGHER, NULL, 0);
|
|
||||||
int res = select_aid_and_authenticate(ctx, aid, verbose);
|
|
||||||
PM3_RET_IF_ERR(res);
|
PM3_RET_IF_ERR(res);
|
||||||
|
|
||||||
// Prepare create file command
|
// Prepare create file command
|
||||||
|
@ -490,15 +544,18 @@ static int hfgal_read_cad(DesfireContext_t *ctx, uint8_t *dest_buf,
|
||||||
/**
|
/**
|
||||||
* @brief Create the Gallagher Card Application Directory.
|
* @brief Create the Gallagher Card Application Directory.
|
||||||
*
|
*
|
||||||
* @param site_key MIFARE 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, 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
|
// 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)");
|
PM3_RET_ERR(PM3_EINVARG, "Card UID must be set in DesfireContext (required for key div)");
|
||||||
|
}
|
||||||
|
|
||||||
// Select application & authenticate
|
// Select application & authenticate
|
||||||
int res = select_aid_and_authenticate(ctx, 0x000000, verbose);
|
int res = select_aid_and_auth(ctx, 0x000000, verbose);
|
||||||
PM3_RET_IF_ERR(res);
|
PM3_RET_IF_ERR(res);
|
||||||
|
|
||||||
// Create application
|
// Create application
|
||||||
|
@ -524,28 +581,35 @@ static int hfgal_create_cad(DesfireContext_t *ctx, uint8_t *site_key, bool verbo
|
||||||
|
|
||||||
// Select application & authenticate
|
// Select application & authenticate
|
||||||
uint8_t blank_key[DESFIRE_MAX_KEY_SIZE] = {0};
|
uint8_t blank_key[DESFIRE_MAX_KEY_SIZE] = {0};
|
||||||
DesfireSetKeyNoClear(ctx, 0, T_AES, blank_key);
|
res = select_aid_and_auth_with_key(ctx, CAD_AID, blank_key, 0, false, verbose);
|
||||||
DesfireSetKdf(ctx, MFDES_KDF_ALGO_NONE, NULL, 0);
|
|
||||||
res = select_aid_and_authenticate(ctx, CAD_AID, verbose);
|
|
||||||
PM3_RET_IF_ERR(res);
|
PM3_RET_IF_ERR(res);
|
||||||
|
|
||||||
// Diversify key
|
|
||||||
uint8_t buf[CRYPTO_AES128_KEY_SIZE] = {0};
|
uint8_t buf[CRYPTO_AES128_KEY_SIZE] = {0};
|
||||||
res = hfgal_diversify_key(site_key, ctx->uid, ctx->uidlen, 0, CAD_AID, buf);
|
if (should_diversify) {
|
||||||
PM3_RET_IF_ERR_WITH_MSG(res, "Failed diversifying key 0 for AID %06X", CAD_AID);
|
// Diversify key
|
||||||
|
res = hfgal_diversify_key(key, ctx->uid, ctx->uidlen, 0, CAD_AID, buf);
|
||||||
|
PM3_RET_IF_ERR_WITH_MSG(res, "Failed diversifying key 0 for AID %06X", CAD_AID);
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "Diversified key " _YELLOW_("0") " for CAD (AID " _YELLOW_("%06X") "): " _GREEN_("%s"),
|
PrintAndLogEx(INFO, "Diversified key " _YELLOW_("0") " for CAD (AID " _YELLOW_("%06X") "): " _GREEN_("%s"),
|
||||||
CAD_AID,
|
CAD_AID,
|
||||||
sprint_hex_inrow(buf, ARRAYLEN(buf))
|
sprint_hex_inrow(buf, ARRAYLEN(buf))
|
||||||
);
|
);
|
||||||
|
key = buf;
|
||||||
|
} else if (verbose) {
|
||||||
|
PrintAndLogEx(INFO, "Using provided key " _YELLOW_("0") " for CAD (AID " _YELLOW_("%06X") "): " _GREEN_("%s"),
|
||||||
|
CAD_AID,
|
||||||
|
sprint_hex_inrow(key, CRYPTO_AES128_KEY_SIZE)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Change key
|
// Change key
|
||||||
DesfireSetCommMode(ctx, DCMEncryptedPlain);
|
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, buf, app_algo, blank_key, verbose);
|
||||||
PM3_RET_IF_ERR_WITH_MSG(res, "Failed setting key 0 for CAD");
|
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 set key " _YELLOW_("0") " for CAD");
|
||||||
|
}
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "Successfully created Card Application Directory (AID " _YELLOW_("%06X") ")", CAD_AID);
|
PrintAndLogEx(INFO, "Successfully created Card Application Directory (AID " _YELLOW_("%06X") ")", CAD_AID);
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
|
@ -554,12 +618,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.
|
* @brief Update the Gallagher Card Application Directory with a new entry.
|
||||||
*
|
*
|
||||||
* @param site_key MIFARE 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 aid Application ID to add to the CAD.
|
||||||
* @param creds Gallagher cardholder credentials (region_code & facility_code are required).
|
* @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,
|
static int hfgal_add_aid_to_cad(DesfireContext_t *ctx, uint8_t *key, bool should_diversify,
|
||||||
GallagherCredentials_t *creds, bool verbose) {
|
uint32_t aid, GallagherCredentials_t *creds, bool verbose) {
|
||||||
// Check if CAD exists
|
// Check if CAD exists
|
||||||
uint8_t cad[36 * 3] = {0};
|
uint8_t cad[36 * 3] = {0};
|
||||||
uint8_t num_entries = 0;
|
uint8_t num_entries = 0;
|
||||||
|
@ -582,7 +647,7 @@ static int hfgal_add_aid_to_cad(DesfireContext_t *ctx, uint8_t *site_key, uint32
|
||||||
PrintAndLogEx(INFO, "Card Application Directory does not exist, creating it now...");
|
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, key, should_diversify, verbose);
|
||||||
PM3_RET_IF_ERR(res);
|
PM3_RET_IF_ERR(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -592,10 +657,11 @@ static int hfgal_add_aid_to_cad(DesfireContext_t *ctx, uint8_t *site_key, uint32
|
||||||
|
|
||||||
// Check if facility already exists in CAD.
|
// Check if facility already exists in CAD.
|
||||||
for (uint8_t i = 0; i < ARRAYLEN(cad); i += 6) {
|
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",
|
PM3_RET_ERR(PM3_EFATAL, "Facility already exists in CAD, delete or update AID %06X",
|
||||||
cad_aid_byte_to_uint(&cad[i + 3])
|
cad_aid_byte_to_uint(&cad[i + 3])
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create entry
|
// Create entry
|
||||||
|
@ -614,9 +680,7 @@ static int hfgal_add_aid_to_cad(DesfireContext_t *ctx, uint8_t *site_key, uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select application & authenticate
|
// Select application & authenticate
|
||||||
DesfireSetKeyNoClear(ctx, 0, T_AES, site_key);
|
int res = select_aid_and_auth_with_key(ctx, CAD_AID, key, 0, should_diversify, verbose);
|
||||||
DesfireSetKdf(ctx, MFDES_KDF_ALGO_GALLAGHER, NULL, 0);
|
|
||||||
int res = select_aid_and_authenticate(ctx, CAD_AID, verbose);
|
|
||||||
PM3_RET_IF_ERR(res);
|
PM3_RET_IF_ERR(res);
|
||||||
|
|
||||||
// Create file if necessary
|
// Create file if necessary
|
||||||
|
@ -642,14 +706,16 @@ static int hfgal_add_aid_to_cad(DesfireContext_t *ctx, uint8_t *site_key, uint32
|
||||||
res = DesfireCreateFile(ctx, file_type, data, ARRAYLEN(data), false);
|
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);
|
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);
|
PrintAndLogEx(INFO, "Created file " _YELLOW_("%d") " in CAD (empty contents)", file_id);
|
||||||
|
}
|
||||||
|
|
||||||
// Write file
|
// Write file
|
||||||
res = DesfireWriteFile(ctx, file_id, 0, 36, &cad[file_id * 36]);
|
res = DesfireWriteFile(ctx, file_id, 0, 36, &cad[file_id * 36]);
|
||||||
} else
|
} else {
|
||||||
// Write file
|
// Write file
|
||||||
res = DesfireWriteFile(ctx, file_id, entry_num * 6, 6, entry);
|
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);
|
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);
|
PrintAndLogEx(INFO, "Successfully added new entry for " _YELLOW_("%06X") " to the Card Application Directory", aid);
|
||||||
|
@ -659,15 +725,15 @@ 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.
|
* @brief Remove an entry from the Gallagher Card Application Directory.
|
||||||
*
|
*
|
||||||
* @param site_key MIFARE site key.
|
* @param key MIFARE site key, or custom CAD key.
|
||||||
* @param aid Application ID to add to the CAD.
|
* @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,
|
static int hfgal_remove_aid_from_cad(DesfireContext_t *ctx, uint8_t *key,
|
||||||
uint32_t aid, bool verbose) {
|
bool should_diversify, uint32_t aid, bool verbose) {
|
||||||
// Check if CAD exists
|
// Read CAD
|
||||||
uint8_t cad[36 * 3] = {0};
|
uint8_t cad[36 * 3] = {0};
|
||||||
uint8_t num_entries = 0;
|
uint8_t num_entries = 0;
|
||||||
|
|
||||||
int res = hfgal_read_cad(ctx, cad, ARRAYLEN(cad), &num_entries, verbose);
|
int res = hfgal_read_cad(ctx, cad, ARRAYLEN(cad), &num_entries, verbose);
|
||||||
PM3_RET_IF_ERR(res);
|
PM3_RET_IF_ERR(res);
|
||||||
|
|
||||||
|
@ -691,9 +757,7 @@ static int hfgal_remove_aid_from_cad(DesfireContext_t *ctx, uint8_t *site_key,
|
||||||
memset(&cad[ARRAYLEN(cad) - 6], 0, 6);
|
memset(&cad[ARRAYLEN(cad) - 6], 0, 6);
|
||||||
|
|
||||||
// Select application & authenticate
|
// Select application & authenticate
|
||||||
DesfireSetKeyNoClear(ctx, 0, T_AES, site_key);
|
res = select_aid_and_auth_with_key(ctx, CAD_AID, key, 0, should_diversify, verbose);
|
||||||
DesfireSetKdf(ctx, MFDES_KDF_ALGO_GALLAGHER, NULL, 0);
|
|
||||||
res = select_aid_and_authenticate(ctx, CAD_AID, verbose);
|
|
||||||
PM3_RET_IF_ERR(res);
|
PM3_RET_IF_ERR(res);
|
||||||
|
|
||||||
// Determine what files we need to update
|
// Determine what files we need to update
|
||||||
|
@ -784,11 +848,15 @@ static int hfgal_read_card(uint32_t aid, uint8_t *site_key, bool verbose, bool q
|
||||||
// Read & decode credentials
|
// Read & decode credentials
|
||||||
GallagherCredentials_t creds = {0};
|
GallagherCredentials_t creds = {0};
|
||||||
res = hfgal_read_creds_app(&dctx, current_aid, site_key, &creds, verbose);
|
res = hfgal_read_creds_app(&dctx, current_aid, site_key, &creds, verbose);
|
||||||
|
if (res == HFGAL_AUTH_FAIL) {
|
||||||
|
PrintAndLogEx(WARNING, "Invalid site key for AID %06X", current_aid);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
PM3_RET_IF_ERR_MAYBE_MSG(res, !quiet, "Failed reading card application credentials");
|
PM3_RET_IF_ERR_MAYBE_MSG(res, !quiet, "Failed reading card application credentials");
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, "Gallagher (AID %06X) - region: " _GREEN_("%u")
|
PrintAndLogEx(SUCCESS, "Gallagher (AID %06X) - region: " _GREEN_("%u")
|
||||||
", fc: " _GREEN_("%u")
|
", facility: " _GREEN_("%u")
|
||||||
", cn: " _GREEN_("%u")
|
", card number: " _GREEN_("%u")
|
||||||
", issue level: " _GREEN_("%u"),
|
", issue level: " _GREEN_("%u"),
|
||||||
current_aid,
|
current_aid,
|
||||||
creds.region_code,
|
creds.region_code,
|
||||||
|
@ -865,89 +933,93 @@ static int CmdGallagherClone(const char *cmd) {
|
||||||
" DES 8 bytes\n"
|
" DES 8 bytes\n"
|
||||||
" 2TDEA or AES 16 bytes\n"
|
" 2TDEA or AES 16 bytes\n"
|
||||||
" 3TDEA 24 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"
|
"hf gallagher clone --rc 1 --fc 22 --cn 3333 --il 4 --sitekey 00112233445566778899aabbccddeeff"
|
||||||
);
|
);
|
||||||
|
|
||||||
void *argtable[] = {
|
void *argtable[] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
arg_int0("n", "keynum", "<dec>", "Key number [default = 0]"),
|
arg_int0("n", "keynum", "<dec>", "PICC key number [default = 0]"),
|
||||||
arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Crypt algo: DES, 2TDEA, 3TDEA, AES"),
|
arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "PICC crypt algo: DES, 2TDEA, 3TDEA, AES"),
|
||||||
arg_str0("k", "key", "<hex>", "Key for authentication to the PICC"),
|
arg_str0("k", "key", "<hex>", "Key for authentication to the PICC to create applications"),
|
||||||
arg_u64_1(NULL, "rc", "<dec>", "Region code. 4 bits max"),
|
arg_u64_1(NULL, "rc", "<dec>", "Region code. 4 bits max"),
|
||||||
arg_u64_1(NULL, "fc", "<dec>", "Facility code. 2 bytes max"),
|
arg_u64_1(NULL, "fc", "<dec>", "Facility code. 2 bytes max"),
|
||||||
arg_u64_1(NULL, "cn", "<dec>", "Card number. 3 bytes max"),
|
arg_u64_1(NULL, "cn", "<dec>", "Card number. 3 bytes max"),
|
||||||
arg_u64_1(NULL, "il", "<dec>", "Issue level. 4 bits max"),
|
arg_u64_1(NULL, "il", "<dec>", "Issue level. 4 bits max"),
|
||||||
arg_str0(NULL, "aid", "<hex>", "Application ID to write (3 bytes)"),
|
arg_str0(NULL, "aid", "<hex>", "Application ID to write (3 bytes) [default automatically chooses]"),
|
||||||
arg_str0(NULL, "sitekey", "<hex>", "Site key to compute diversified keys (16 bytes)"),
|
arg_str0(NULL, "sitekey", "<hex>", "Site key to compute diversified keys (16 bytes)"),
|
||||||
arg_lit0(NULL, "apdu", "Show APDU requests and responses"),
|
arg_str0(NULL, "cadkey", "<hex>", "Custom AES key 0 to modify the Card Application Directory (16 bytes)"),
|
||||||
arg_lit0("v", "verbose", "Verbose mode"),
|
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
|
arg_param_end
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, cmd, argtable, false);
|
CLIExecWithReturn(ctx, cmd, argtable, false);
|
||||||
|
uint8_t arg = 1;
|
||||||
|
|
||||||
int key_num = arg_get_int_def(ctx, 1, 0);
|
int picc_key_num = arg_get_int_def(ctx, arg++, 0);
|
||||||
|
|
||||||
int key_algo = T_DES;
|
int picc_key_algo = T_DES;
|
||||||
if (CLIGetOptionList(arg_get_str(ctx, 2), DesfireAlgoOpts, &key_algo)) {
|
if (CLIGetOptionList(arg_get_str(ctx, arg++), DesfireAlgoOpts, &picc_key_algo)) {
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
int key_len = 0;
|
int picc_key_len = 0;
|
||||||
uint8_t key[DESFIRE_MAX_KEY_SIZE] = {0};
|
uint8_t picc_key[DESFIRE_MAX_KEY_SIZE] = {0};
|
||||||
CLIGetHexWithReturn(ctx, 3, key, &key_len);
|
CLIGetHexWithReturn(ctx, arg++, picc_key, &picc_key_len);
|
||||||
if (key_len && key_len != desfire_get_key_length(key_algo)) {
|
if (picc_key_len && picc_key_len != desfire_get_key_length(picc_key_algo)) {
|
||||||
PM3_RET_ERR_FREE(PM3_EINVARG, "%s key must have %d bytes length instead of %d",
|
PM3_RET_ERR_FREE(PM3_EINVARG, "%s key must have %d bytes length instead of %d",
|
||||||
CLIGetOptionListStr(DesfireAlgoOpts, key_algo),
|
CLIGetOptionListStr(DesfireAlgoOpts, picc_key_algo),
|
||||||
desfire_get_key_length(key_algo),
|
desfire_get_key_length(picc_key_algo),
|
||||||
key_len
|
picc_key_len
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (key_len == 0) {
|
if (picc_key_len == 0) {
|
||||||
// Default to a key of all zeros
|
// 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, 4); // uint4, input will be validated later
|
uint64_t region_code = arg_get_u64(ctx, arg++); // uint4, input will be validated later
|
||||||
uint64_t facility_code = arg_get_u64(ctx, 5); // uint16
|
uint64_t facility_code = arg_get_u64(ctx, arg++); // uint16
|
||||||
uint64_t card_number = arg_get_u64(ctx, 6); // uint24
|
uint64_t card_number = arg_get_u64(ctx, arg++); // uint24
|
||||||
uint64_t issue_level = arg_get_u64(ctx, 7); // uint4
|
uint64_t issue_level = arg_get_u64(ctx, arg++); // uint4
|
||||||
|
|
||||||
int aid_len = 0;
|
int aid_len = 0;
|
||||||
uint8_t aid_buf[3] = {0};
|
uint8_t aid_buf[3] = {0};
|
||||||
uint32_t aid = 0;
|
CLIGetHexWithReturn(ctx, arg++, aid_buf, &aid_len);
|
||||||
CLIGetHexWithReturn(ctx, 8, aid_buf, &aid_len);
|
if (aid_len > 0 && aid_len != 3) {
|
||||||
if (aid_len > 0) {
|
PM3_RET_ERR_FREE(PM3_EINVARG, "--aid must be 3 bytes");
|
||||||
if (aid_len != 3) {
|
|
||||||
PM3_RET_ERR_FREE(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
|
|
||||||
PM3_RET_ERR_FREE(PM3_EINVARG, "Invalid Gallagher AID %06X, expected 2?81F4, where 0 <= ? <= 0xB", aid);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
reverse_aid(aid_buf); // PM3 displays AIDs backwards
|
||||||
|
uint32_t aid = DesfireAIDByteToUint(aid_buf);
|
||||||
|
|
||||||
int site_key_len = 0;
|
int site_key_len = 0;
|
||||||
uint8_t site_key[16] = {0};
|
uint8_t site_key[16] = {0};
|
||||||
memcpy(site_key, DEFAULT_SITE_KEY, ARRAYLEN(site_key));
|
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) {
|
if (site_key_len > 0 && site_key_len != 16) {
|
||||||
PM3_RET_ERR_FREE(PM3_EINVARG, "--sitekey must be 16 bytes");
|
PM3_RET_ERR_FREE(PM3_EINVARG, "--sitekey must be 16 bytes");
|
||||||
}
|
}
|
||||||
|
|
||||||
SetAPDULogging(arg_get_lit(ctx, 10));
|
int cad_key_len = 0;
|
||||||
bool verbose = arg_get_lit(ctx, 11);
|
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_FREE(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);
|
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;
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
GallagherCredentials_t creds = {
|
GallagherCredentials_t creds = {
|
||||||
.region_code = region_code,
|
.region_code = region_code,
|
||||||
|
@ -965,30 +1037,48 @@ static int CmdGallagherClone(const char *cmd) {
|
||||||
int res = DesfireGetCardUID(&dctx);
|
int res = DesfireGetCardUID(&dctx);
|
||||||
PM3_RET_IF_ERR_WITH_MSG(res, "Failed retrieving card UID");
|
PM3_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) {
|
if (aid_len == 0) {
|
||||||
|
// Find available Gallagher AID if the user did not specify one
|
||||||
aid = find_available_gallagher_aid(&dctx, verbose);
|
aid = find_available_gallagher_aid(&dctx, verbose);
|
||||||
if (aid == 0) {
|
if (aid == 0) {
|
||||||
PM3_RET_ERR(PM3_EFATAL, "Could not find an available AID, card is full");
|
PM3_RET_ERR(PM3_EFATAL, "Could not find an available AID, please specify with --aid");
|
||||||
}
|
}
|
||||||
|
if (verbose) {
|
||||||
|
PrintAndLogEx(INFO, "Using available AID: %06X", aid);
|
||||||
|
}
|
||||||
|
} 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
|
// Update Card Application Directory
|
||||||
DesfireSetKeyNoClear(&dctx, key_num, key_algo, key);
|
if (no_cad_update == false) {
|
||||||
DesfireSetKdf(&dctx, MFDES_KDF_ALGO_NONE, NULL, 0);
|
// Set keys so that hfgal_add_aid_to_cad can auth to 0x000000
|
||||||
res = hfgal_add_aid_to_cad(&dctx, site_key, aid, &creds, verbose);
|
// if it needs to create the CAD application.
|
||||||
PM3_RET_IF_ERR_WITH_MSG(res, "Failed updating Gallagher Card Application Directory");
|
DesfireSetKeyNoClear(&dctx, picc_key_num, picc_key_algo, picc_key);
|
||||||
|
DesfireSetKdf(&dctx, MFDES_KDF_ALGO_NONE, NULL, 0);
|
||||||
|
|
||||||
|
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);
|
||||||
|
PM3_RET_IF_ERR_WITH_MSG(res, "Failed updating Gallagher Card Application Directory");
|
||||||
|
}
|
||||||
|
|
||||||
// Create application
|
// Create application
|
||||||
DesfireSetKeyNoClear(&dctx, key_num, key_algo, key);
|
if (no_app_create == false) {
|
||||||
DesfireSetKdf(&dctx, MFDES_KDF_ALGO_NONE, NULL, 0);
|
// Set keys so that hfgal_create_creds_app can auth to 0x000000
|
||||||
res = hfgal_create_creds_app(&dctx, site_key, aid, verbose);
|
// when it creates the application.
|
||||||
PM3_RET_IF_ERR_WITH_MSG(res, "Failed creating Gallagher application");
|
DesfireSetKeyNoClear(&dctx, picc_key_num, picc_key_algo, picc_key);
|
||||||
|
DesfireSetKdf(&dctx, MFDES_KDF_ALGO_NONE, NULL, 0);
|
||||||
|
|
||||||
// Create credential files
|
res = hfgal_create_creds_app(&dctx, site_key, aid, verbose);
|
||||||
// Don't need to set keys here, they're generated automatically
|
PM3_RET_IF_ERR_WITH_MSG(res, "Failed creating Gallagher application");
|
||||||
res = hfgal_create_creds_file(&dctx, site_key, aid, &creds, verbose);
|
|
||||||
PM3_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);
|
||||||
|
PM3_RET_IF_ERR_WITH_MSG(res, "Failed creating Gallagher credential file");
|
||||||
|
}
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, "Done");
|
PrintAndLogEx(SUCCESS, "Done");
|
||||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf gallagher reader`") " to verify");
|
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf gallagher reader`") " to verify");
|
||||||
|
@ -1007,41 +1097,45 @@ static int CmdGallagherDelete(const char *cmd) {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
arg_str1(NULL, "aid", "<hex>", "Application ID to delete (3 bytes)"),
|
arg_str1(NULL, "aid", "<hex>", "Application ID to delete (3 bytes)"),
|
||||||
arg_str0(NULL, "sitekey", "<hex>", "Site key to compute diversified keys (16 bytes)"),
|
arg_str0(NULL, "sitekey", "<hex>", "Site key to compute diversified keys (16 bytes)"),
|
||||||
|
arg_str0(NULL, "cadkey", "<hex>", "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(NULL, "apdu", "Show APDU requests and responses"),
|
||||||
arg_lit0("v", "verbose", "Verbose mode"),
|
arg_lit0("v", "verbose", "Verbose mode"),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, cmd, argtable, false);
|
CLIExecWithReturn(ctx, cmd, argtable, false);
|
||||||
|
uint8_t arg = 1;
|
||||||
|
|
||||||
int aid_len = 0;
|
int aid_len = 0;
|
||||||
uint8_t aid_buf[3] = {0};
|
uint8_t aid_buf[3] = {0};
|
||||||
uint32_t aid = 0;
|
CLIGetHexWithReturn(ctx, arg++, aid_buf, &aid_len);
|
||||||
CLIGetHexWithReturn(ctx, 1, aid_buf, &aid_len);
|
|
||||||
|
|
||||||
if (aid_len != 3) {
|
if (aid_len != 3) {
|
||||||
PM3_RET_ERR_FREE(PM3_EINVARG, "--aid must be 3 bytes");
|
PM3_RET_ERR_FREE(PM3_EINVARG, "--aid must be 3 bytes");
|
||||||
}
|
}
|
||||||
reverse_aid(aid_buf); // PM3 displays AIDs backwards
|
reverse_aid(aid_buf); // PM3 displays AIDs backwards
|
||||||
aid = DesfireAIDByteToUint(aid_buf);
|
uint32_t 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
|
|
||||||
PM3_RET_ERR_FREE(PM3_EINVARG, "Invalid Gallagher AID %06X, expected 2?81F4, where 0 <= ? <= 0xB", aid);
|
|
||||||
}
|
|
||||||
|
|
||||||
int site_key_len = 0;
|
int site_key_len = 0;
|
||||||
uint8_t site_key[16] = {0};
|
uint8_t site_key[16] = {0};
|
||||||
memcpy(site_key, DEFAULT_SITE_KEY, ARRAYLEN(site_key));
|
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) {
|
if (site_key_len > 0 && site_key_len != 16) {
|
||||||
PM3_RET_ERR_FREE(PM3_EINVARG, "--sitekey must be 16 bytes");
|
PM3_RET_ERR_FREE(PM3_EINVARG, "--sitekey must be 16 bytes");
|
||||||
}
|
}
|
||||||
|
|
||||||
SetAPDULogging(arg_get_lit(ctx, 3));
|
int cad_key_len = 0;
|
||||||
bool verbose = arg_get_lit(ctx, 4);
|
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_FREE(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);
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
// Set up context
|
// Set up context
|
||||||
|
@ -1054,12 +1148,18 @@ static int CmdGallagherDelete(const char *cmd) {
|
||||||
PM3_RET_IF_ERR_WITH_MSG(res, "Failed retrieving card UID");
|
PM3_RET_IF_ERR_WITH_MSG(res, "Failed retrieving card UID");
|
||||||
|
|
||||||
// Update Card Application Directory
|
// Update Card Application Directory
|
||||||
res = hfgal_remove_aid_from_cad(&dctx, site_key, aid, verbose);
|
if (no_cad_update == false) {
|
||||||
PM3_RET_IF_ERR_WITH_MSG(res, "Failed removing %06X from the Card Application Directory", aid);
|
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);
|
||||||
|
PM3_RET_IF_ERR_WITH_MSG(res, "Failed removing %06X from the Card Application Directory", aid);
|
||||||
|
}
|
||||||
|
|
||||||
// Delete application
|
// Delete application
|
||||||
res = hfgal_delete_app(&dctx, site_key, aid, verbose);
|
if (no_app_delete == false) {
|
||||||
PM3_RET_IF_ERR_WITH_MSG(res, "Failed deleting Gallagher application");
|
res = hfgal_delete_app(&dctx, site_key, aid, verbose);
|
||||||
|
PM3_RET_IF_ERR_WITH_MSG(res, "Failed deleting Gallagher application");
|
||||||
|
}
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, "Done");
|
PrintAndLogEx(SUCCESS, "Done");
|
||||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf gallagher reader`") " to verify");
|
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf gallagher reader`") " to verify");
|
||||||
|
@ -1076,34 +1176,23 @@ static int CmdGallagherDiversify(const char *cmd) {
|
||||||
|
|
||||||
void *argtable[] = {
|
void *argtable[] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
arg_str1(NULL, "aid", "<hex>", "Application ID for diversification (3 bytes)"),
|
arg_str1(NULL, "aid", "<hex>", "Application ID for diversification (3 bytes)"),
|
||||||
arg_int0(NULL, "keynum", "<dec>", "Key number [default = 0]"),
|
arg_int0(NULL, "keynum", "<dec>", "Key number [default = 0]"),
|
||||||
arg_str0(NULL, "uid", "<hex>", "Card UID to delete (4 or 7 bytes)"),
|
arg_str0(NULL, "uid", "<hex>", "Card UID to delete (4 or 7 bytes)"),
|
||||||
arg_str0(NULL, "sitekey", "<hex>", "Site key to compute diversified keys (16 bytes)"),
|
arg_str0(NULL, "sitekey", "<hex>", "Site key to compute diversified keys (16 bytes)"),
|
||||||
arg_lit0(NULL, "apdu", "Show APDU requests and responses"),
|
arg_lit0(NULL, "apdu", "Show APDU requests and responses"),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, cmd, argtable, false);
|
CLIExecWithReturn(ctx, cmd, argtable, false);
|
||||||
|
|
||||||
int aid_len = 0;
|
int aid_len = 0;
|
||||||
uint8_t aid_buf[3] = {0};
|
uint8_t aid_buf[3] = {0};
|
||||||
uint32_t aid = 0;
|
|
||||||
CLIGetHexWithReturn(ctx, 1, aid_buf, &aid_len);
|
CLIGetHexWithReturn(ctx, 1, aid_buf, &aid_len);
|
||||||
|
|
||||||
if (aid_len != 3) {
|
if (aid_len != 3) {
|
||||||
PM3_RET_ERR_FREE(PM3_EINVARG, "--aid must be 3 bytes");
|
PM3_RET_ERR_FREE(PM3_EINVARG, "--aid must be 3 bytes");
|
||||||
}
|
}
|
||||||
|
|
||||||
reverse_aid(aid_buf); // PM3 displays AIDs backwards
|
reverse_aid(aid_buf); // PM3 displays AIDs backwards
|
||||||
aid = DesfireAIDByteToUint(aid_buf);
|
uint32_t 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
|
|
||||||
PM3_RET_ERR_FREE(PM3_EINVARG, "Invalid Gallagher AID %06X, expected 2?81F4, where 0 <= ? <= 0xB", aid);
|
|
||||||
}
|
|
||||||
|
|
||||||
int key_num = arg_get_int_def(ctx, 2, 0);
|
int key_num = arg_get_int_def(ctx, 2, 0);
|
||||||
|
|
||||||
|
|
|
@ -40,4 +40,8 @@ int CmdHFGallagher(const char *cmd);
|
||||||
int hfgal_diversify_key(uint8_t *site_key, uint8_t *uid, uint8_t uid_len,
|
int hfgal_diversify_key(uint8_t *site_key, uint8_t *uid, uint8_t uid_len,
|
||||||
uint8_t key_num, uint32_t aid, uint8_t *key_output);
|
uint8_t key_num, uint32_t aid, uint8_t *key_output);
|
||||||
|
|
||||||
|
// 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
|
#endif
|
||||||
|
|
|
@ -63,7 +63,6 @@ const static vocabulory_t vocabulory[] = {
|
||||||
{ 1, "analyse crc" },
|
{ 1, "analyse crc" },
|
||||||
{ 1, "analyse chksum" },
|
{ 1, "analyse chksum" },
|
||||||
{ 1, "analyse dates" },
|
{ 1, "analyse dates" },
|
||||||
{ 1, "analyse tea" },
|
|
||||||
{ 1, "analyse lfsr" },
|
{ 1, "analyse lfsr" },
|
||||||
{ 1, "analyse a" },
|
{ 1, "analyse a" },
|
||||||
{ 1, "analyse nuid" },
|
{ 1, "analyse nuid" },
|
||||||
|
|
|
@ -449,14 +449,6 @@ int mfdes_kdf_input_gallagher(uint8_t *uid, uint8_t uidLen, uint8_t keyNo, uint3
|
||||||
return PM3_EINVARG;
|
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;
|
int len = 0;
|
||||||
// If the keyNo == 1, then omit the UID.
|
// If the keyNo == 1, then omit the UID.
|
||||||
if (keyNo != 1) {
|
if (keyNo != 1) {
|
||||||
|
|
|
@ -97,7 +97,7 @@
|
||||||
},
|
},
|
||||||
"analyse help": {
|
"analyse help": {
|
||||||
"command": "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": [
|
"notes": [
|
||||||
"analyse lcr -d 04008064ba -> target (ba) requires final lrc xor byte value: 5a"
|
"analyse lcr -d 04008064ba -> target (ba) requires final lrc xor byte value: 5a"
|
||||||
],
|
],
|
||||||
|
@ -136,19 +136,6 @@
|
||||||
],
|
],
|
||||||
"usage": "analyse nuid [-ht] [-d <hex>]"
|
"usage": "analyse nuid [-ht] [-d <hex>]"
|
||||||
},
|
},
|
||||||
"analyse tea": {
|
|
||||||
"command": "analyse tea",
|
|
||||||
"description": "crypto tea self tests",
|
|
||||||
"notes": [
|
|
||||||
"analyse tea -d 1122334455667788"
|
|
||||||
],
|
|
||||||
"offline": true,
|
|
||||||
"options": [
|
|
||||||
"-h, --help this help",
|
|
||||||
"-d, --data <hex> bytes to encrypt ( 8 hex bytes )"
|
|
||||||
],
|
|
||||||
"usage": "analyse tea [-h] -d <hex>"
|
|
||||||
},
|
|
||||||
"analyse units": {
|
"analyse units": {
|
||||||
"command": "analyse units",
|
"command": "analyse units",
|
||||||
"description": "experiments of unit conversions found in hf. etu (1/13.56mhz), us or ssp_clk (1/3.39mhz)",
|
"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": {
|
"hf gallagher clone": {
|
||||||
"command": "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": [
|
"notes": [
|
||||||
"hf gallagher clone --rc 1 --fc 22 --cn 3333 --il 4 --sitekey 00112233445566778899aabbccddeeff"
|
"hf gallagher clone --rc 1 --fc 22 --cn 3333 --il 4 --sitekey 00112233445566778899aabbccddeeff"
|
||||||
],
|
],
|
||||||
"offline": false,
|
"offline": false,
|
||||||
"options": [
|
"options": [
|
||||||
"-h, --help this help",
|
"-h, --help this help",
|
||||||
"-n, --keynum <dec> key number [default = 0]",
|
"-n, --keynum <dec> picc key number [default = 0]",
|
||||||
"-t, --algo <des|2tdea|3tdea|aes> crypt algo: des, 2tdea, 3tdea, aes",
|
"-t, --algo <des|2tdea|3tdea|aes> picc crypt algo: des, 2tdea, 3tdea, aes",
|
||||||
"-k, --key <hex> key for authentication to the picc",
|
"-k, --key <hex> key for authentication to the picc to create applications",
|
||||||
"--rc <dec> region code. 4 bits max",
|
"--rc <dec> region code. 4 bits max",
|
||||||
"--fc <dec> facility code. 2 bytes max",
|
"--fc <dec> facility code. 2 bytes max",
|
||||||
"--cn <dec> card number. 3 bytes max",
|
"--cn <dec> card number. 3 bytes max",
|
||||||
"--il <dec> issue level. 4 bits max",
|
"--il <dec> issue level. 4 bits max",
|
||||||
"--aid <hex> application id to write (3 bytes)",
|
"--aid <hex> application id to write (3 bytes) [default automatically chooses]",
|
||||||
"--sitekey <hex> site key to compute diversified keys (16 bytes)",
|
"--sitekey <hex> site key to compute diversified keys (16 bytes)",
|
||||||
|
"--cadkey <hex> 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",
|
"--apdu show apdu requests and responses",
|
||||||
"-v, --verbose verbose mode"
|
"-v, --verbose verbose mode"
|
||||||
],
|
],
|
||||||
"usage": "hf gallagher clone [-hv] [-n <dec>] [-t <des|2tdea|3tdea|aes>] [-k <hex>] --rc <dec> --fc <dec> --cn <dec> --il <dec> [--aid <hex>] [--sitekey <hex>] [--apdu]"
|
"usage": "hf gallagher clone [-hv] [-n <dec>] [-t <des|2tdea|3tdea|aes>] [-k <hex>] --rc <dec> --fc <dec> --cn <dec> --il <dec> [--aid <hex>] [--sitekey <hex>] [--cadkey <hex>] [--nocadupdate] [--noappcreate] [--apdu]"
|
||||||
},
|
},
|
||||||
"hf gallagher delete": {
|
"hf gallagher delete": {
|
||||||
"command": "hf gallagher delete",
|
"command": "hf gallagher delete",
|
||||||
|
@ -2354,10 +2344,13 @@
|
||||||
"-h, --help this help",
|
"-h, --help this help",
|
||||||
"--aid <hex> application id to delete (3 bytes)",
|
"--aid <hex> application id to delete (3 bytes)",
|
||||||
"--sitekey <hex> site key to compute diversified keys (16 bytes)",
|
"--sitekey <hex> site key to compute diversified keys (16 bytes)",
|
||||||
|
"--cadkey <hex> 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",
|
"--apdu show apdu requests and responses",
|
||||||
"-v, --verbose verbose mode"
|
"-v, --verbose verbose mode"
|
||||||
],
|
],
|
||||||
"usage": "hf gallagher delete [-hv] --aid <hex> [--sitekey <hex>] [--apdu]"
|
"usage": "hf gallagher delete [-hv] --aid <hex> [--sitekey <hex>] [--cadkey <hex>] [--nocadupdate] [--noappdelete] [--apdu]"
|
||||||
},
|
},
|
||||||
"hf gallagher diversifykey": {
|
"hf gallagher diversifykey": {
|
||||||
"command": "hf gallagher diversifykey",
|
"command": "hf gallagher diversifykey",
|
||||||
|
@ -10210,8 +10203,8 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"commands_extracted": 599,
|
"commands_extracted": 598,
|
||||||
"extracted_by": "PM3Help2JSON v1.00",
|
"extracted_by": "PM3Help2JSON v1.00",
|
||||||
"extracted_on": "2022-01-11T01:15:20"
|
"extracted_on": "2022-01-17T10:37:00"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -74,7 +74,6 @@ Check column "offline" for their availability.
|
||||||
|`analyse crc `|Y |`Stub method for CRC evaluations`
|
|`analyse crc `|Y |`Stub method for CRC evaluations`
|
||||||
|`analyse chksum `|Y |`Checksum with adding, masking and one's complement`
|
|`analyse chksum `|Y |`Checksum with adding, masking and one's complement`
|
||||||
|`analyse dates `|Y |`Look for datestamps in a given array of bytes`
|
|`analyse dates `|Y |`Look for datestamps in a given array of bytes`
|
||||||
|`analyse tea `|Y |`Crypto TEA test`
|
|
||||||
|`analyse lfsr `|Y |`LFSR tests`
|
|`analyse lfsr `|Y |`LFSR tests`
|
||||||
|`analyse a `|Y |`num bits test`
|
|`analyse a `|Y |`num bits test`
|
||||||
|`analyse nuid `|Y |`create NUID from 7byte UID`
|
|`analyse nuid `|Y |`create NUID from 7byte UID`
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue