mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-20 21:33:47 -07:00
Reorder function definitions
Order is roughly: - exported helpers - helpers - read -> create -> delete - exported commands
This commit is contained in:
parent
02e5fb6b1c
commit
82cd44e99f
1 changed files with 210 additions and 211 deletions
|
@ -32,42 +32,6 @@ static const uint8_t DEFAULT_SITE_KEY[] = {
|
||||||
0x34, 0x30, 0x2E, 0xB2, 0x99, 0xAA, 0xB4, 0x56,
|
0x34, 0x30, 0x2E, 0xB2, 0x99, 0xAA, 0xB4, 0x56,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Reverses the bytes in AID. Used when parsing CLI args
|
|
||||||
* (because Proxmark displays AIDs in reverse byte order).
|
|
||||||
*/
|
|
||||||
static void reverse_aid(uint8_t *aid) {
|
|
||||||
uint8_t tmp = aid[0];
|
|
||||||
aid[0] = aid[2];
|
|
||||||
aid[2] = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Converts a Card Application Directory format application ID to an integer.
|
|
||||||
* Note that the CAD stores AIDs in reverse order, so this function is different to DesfireAIDByteToUint().
|
|
||||||
*/
|
|
||||||
static uint32_t cad_aid_byte_to_uint(uint8_t *data) {
|
|
||||||
return data[2] + (data[1] << 8) + (data[0] << 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Converts an integer application ID to Card Application Directory format.
|
|
||||||
* Note that the CAD stores AIDs in reverse order, so this function is different to DesfireAIDUintToByte().
|
|
||||||
*/
|
|
||||||
static void cad_aid_uint_to_byte(uint32_t aid, uint8_t *data) {
|
|
||||||
data[2] = aid & 0xff;
|
|
||||||
data[1] = (aid >> 8) & 0xff;
|
|
||||||
data[0] = (aid >> 16) & 0xff;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns true if the Card Application Directory entry
|
|
||||||
* is for the specified region & facility, false otherwise.
|
|
||||||
*/
|
|
||||||
static bool cad_facility_match(uint8_t *entry, uint8_t region_code, uint16_t facility_code) {
|
|
||||||
return entry[0] == region_code && (entry[1] << 8) + entry[2] == facility_code;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create Gallagher Application Master Key by diversifying
|
* @brief Create Gallagher Application Master Key by diversifying
|
||||||
* the MIFARE Site Key with card UID, key number, and application ID.
|
* the MIFARE Site Key with card UID, key number, and application ID.
|
||||||
|
@ -104,6 +68,42 @@ int hfgal_diversify_key(uint8_t *site_key, uint8_t *uid, uint8_t uid_len,
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reverses the bytes in AID. Used when parsing CLI args
|
||||||
|
* (because Proxmark displays AIDs in reverse byte order).
|
||||||
|
*/
|
||||||
|
static void reverse_aid(uint8_t *aid) {
|
||||||
|
uint8_t tmp = aid[0];
|
||||||
|
aid[0] = aid[2];
|
||||||
|
aid[2] = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Converts a Card Application Directory format application ID to an integer.
|
||||||
|
* Note that the CAD stores AIDs in reverse order, so this function is different to DesfireAIDByteToUint().
|
||||||
|
*/
|
||||||
|
static uint32_t cad_aid_byte_to_uint(uint8_t *data) {
|
||||||
|
return data[2] + (data[1] << 8) + (data[0] << 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Converts an integer application ID to Card Application Directory format.
|
||||||
|
* Note that the CAD stores AIDs in reverse order, so this function is different to DesfireAIDUintToByte().
|
||||||
|
*/
|
||||||
|
static void cad_aid_uint_to_byte(uint32_t aid, uint8_t *data) {
|
||||||
|
data[2] = aid & 0xff;
|
||||||
|
data[1] = (aid >> 8) & 0xff;
|
||||||
|
data[0] = (aid >> 16) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns true if the Card Application Directory entry
|
||||||
|
* is for the specified region & facility, false otherwise.
|
||||||
|
*/
|
||||||
|
static bool cad_facility_match(uint8_t *entry, uint8_t region_code, uint16_t facility_code) {
|
||||||
|
return entry[0] == region_code && (entry[1] << 8) + entry[2] == facility_code;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Select application ID.
|
* @brief Select application ID.
|
||||||
*/
|
*/
|
||||||
|
@ -195,51 +195,25 @@ static uint32_t find_available_gallagher_aid(DesfireContext_t *ctx, bool verbose
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read Gallagher Card Application Directory from card.
|
* @brief Delete the CAD or an application that contains cardholder credentials.
|
||||||
*
|
*
|
||||||
* @param dest_buf Buffer to copy Card Application Directory into.
|
* @param site_key MIFARE site key.
|
||||||
* @param dest_buf_len Size of dest_buf. Must be at least 108 bytes.
|
* @param aid Application ID to remove.
|
||||||
* @param num_entries Will be set to the number of entries in the Card Application Directory.
|
|
||||||
*/
|
*/
|
||||||
static int hfgal_read_cad(DesfireContext_t *ctx, uint8_t *dest_buf,
|
static int hfgal_delete_app(DesfireContext_t *ctx, uint8_t *site_key,
|
||||||
uint8_t dest_buf_len, uint8_t *num_entries, bool verbose) {
|
uint32_t aid, bool verbose) {
|
||||||
if (dest_buf_len < 3 * 36) {
|
// Select application & authenticate
|
||||||
PrintAndLogEx(ERR, "hfgal_read_cad destination buffer is incorrectly sized. "
|
DesfireSetKeyNoClear(ctx, 0, T_AES, site_key);
|
||||||
"Received length %d, must be at least %d", dest_buf_len, 3 * 36);
|
DesfireSetKdf(ctx, MFDES_KDF_ALGO_GALLAGHER, NULL, 0);
|
||||||
return PM3_EINVARG;
|
int res = select_aid_and_authenticate(ctx, aid, verbose);
|
||||||
}
|
HFGAL_RET_IF_ERR(res);
|
||||||
|
|
||||||
// Get card AIDs from Card Application Directory (which contains 1 to 3 files)
|
// Delete application
|
||||||
int res = select_aid(ctx, CAD_AID, verbose);
|
DesfireSetCommMode(ctx, DCMMACed);
|
||||||
HFGAL_RET_IF_ERR_WITH_MSG(res, "Failed selecting Card Application Directory, does AID %06X exist?", CAD_AID);
|
res = DesfireDeleteApplication(ctx, aid);
|
||||||
|
HFGAL_RET_IF_ERR_WITH_MSG(res, "Failed deleting AID %06X", aid);
|
||||||
// Read up to 3 files with 6x 6-byte entries each
|
|
||||||
for (uint8_t i = 0; i < 3; i++) {
|
|
||||||
size_t read_len;
|
|
||||||
res = DesfireReadFile(ctx, i, 0, 36, &dest_buf[i * 36], &read_len);
|
|
||||||
if (res != PM3_SUCCESS && res != PM3_EAPDU_FAIL)
|
|
||||||
HFGAL_RET_ERR(res, "Failed reading file %d in Card Application Directory (AID %06X)", i, CAD_AID);
|
|
||||||
|
|
||||||
// end if the last entry is NULL
|
|
||||||
if (memcmp(&dest_buf[36 * i + 30], "\0\0\0\0\0\0", 6) == 0) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Count number of entries (i.e. count until we hit a NULL entry)
|
|
||||||
*num_entries = 0;
|
|
||||||
for (uint8_t i = 0; i < dest_buf_len; i += 6) {
|
|
||||||
if (memcmp(&dest_buf[i], "\0\0\0\0\0\0", 6) == 0) break;
|
|
||||||
*num_entries += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (verbose) {
|
|
||||||
// Print what we found
|
|
||||||
PrintAndLogEx(SUCCESS, "Card Application Directory contains:" NOLF);
|
|
||||||
for (int i = 0; i < *num_entries; i++)
|
|
||||||
PrintAndLogEx(NORMAL, "%s %06X" NOLF, (i == 0) ? "" : ",",
|
|
||||||
cad_aid_byte_to_uint(&dest_buf[i * 6 + 3]));
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
PrintAndLogEx(INFO, "Successfully deleted AID %06X", aid);
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,7 +224,7 @@ static int hfgal_read_cad(DesfireContext_t *ctx, uint8_t *dest_buf,
|
||||||
* @param site_key MIFARE site key.
|
* @param site_key MIFARE site key.
|
||||||
* @param creds Decoded credentials will be stored in this structure.
|
* @param creds Decoded credentials will be stored in this structure.
|
||||||
*/
|
*/
|
||||||
static int hfgal_read_app_creds(DesfireContext_t *ctx, uint32_t aid, uint8_t *site_key,
|
static int hfgal_read_creds_app(DesfireContext_t *ctx, uint32_t aid, uint8_t *site_key,
|
||||||
GallagherCredentials_t *creds, bool verbose) {
|
GallagherCredentials_t *creds, bool verbose) {
|
||||||
// Check that card UID has been set
|
// Check that card UID has been set
|
||||||
if (ctx->uidlen == 0)
|
if (ctx->uidlen == 0)
|
||||||
|
@ -287,137 +261,6 @@ static int hfgal_read_app_creds(DesfireContext_t *ctx, uint32_t aid, uint8_t *si
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Read credentials from a Gallagher card.
|
|
||||||
*
|
|
||||||
* @param aid Application ID to read. If 0, then the Card Application Directory will be queried and all entries will be read.
|
|
||||||
* @param site_key MIFARE site key.
|
|
||||||
* @param quiet Suppress error messages. Used when in continuous reader mode.
|
|
||||||
*/
|
|
||||||
static int hfgal_read_card(uint32_t aid, uint8_t *site_key, bool verbose, bool quiet) {
|
|
||||||
DropField();
|
|
||||||
clearCommandBuffer();
|
|
||||||
|
|
||||||
// Set up context
|
|
||||||
DesfireContext_t dctx = {0};
|
|
||||||
DesfireClearContext(&dctx);
|
|
||||||
|
|
||||||
// Get card UID (for key diversification)
|
|
||||||
int res = DesfireGetCardUID(&dctx);
|
|
||||||
HFGAL_RET_IF_ERR_MAYBE_MSG(res, !quiet, "Failed retrieving card UID");
|
|
||||||
|
|
||||||
// Find AIDs to process (from CLI args or the Card Application Directory)
|
|
||||||
uint8_t cad[36 * 3] = {0};
|
|
||||||
uint8_t num_entries = 0;
|
|
||||||
if (aid != 0) {
|
|
||||||
cad_aid_uint_to_byte(aid, &cad[3]);
|
|
||||||
num_entries = 1;
|
|
||||||
} else {
|
|
||||||
res = hfgal_read_cad(&dctx, cad, ARRAYLEN(cad), &num_entries, verbose);
|
|
||||||
HFGAL_RET_IF_ERR_MAYBE_MSG(res, !quiet, "Failed reading Card Application Directory");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Loop through each application in the CAD
|
|
||||||
for (uint8_t i = 0; i < num_entries * 6; i += 6) {
|
|
||||||
uint16_t region_code = cad[i + 0];
|
|
||||||
uint16_t facility_code = (cad[i + 1] << 8) + cad[i + 2];
|
|
||||||
uint32_t current_aid = cad_aid_byte_to_uint(&cad[i + 3]);
|
|
||||||
|
|
||||||
if (verbose) {
|
|
||||||
if (region_code > 0 || facility_code > 0)
|
|
||||||
PrintAndLogEx(INFO, "Reading AID: %06X, region: %u, facility: %u", current_aid, region_code, facility_code);
|
|
||||||
else
|
|
||||||
PrintAndLogEx(INFO, "Reading AID: %06X", current_aid);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read & decode credentials
|
|
||||||
GallagherCredentials_t creds = {0};
|
|
||||||
res = hfgal_read_app_creds(&dctx, current_aid, site_key, &creds, verbose);
|
|
||||||
HFGAL_RET_IF_ERR_MAYBE_MSG(res, !quiet, "Failed reading card application credentials");
|
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, "GALLAGHER (AID %06X) - Region: " _GREEN_("%u") ", Facility: " _GREEN_("%u")
|
|
||||||
", Card No.: " _GREEN_("%u") ", Issue Level: " _GREEN_("%u"), current_aid,
|
|
||||||
creds.region_code, creds.facility_code, creds.card_number, creds.issue_level);
|
|
||||||
}
|
|
||||||
|
|
||||||
return PM3_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int CmdGallagherReader(const char *cmd) {
|
|
||||||
CLIParserContext *ctx;
|
|
||||||
CLIParserInit(&ctx, "hf gallagher reader",
|
|
||||||
"Read a GALLAGHER tag",
|
|
||||||
"hf gallagher reader --aid 2081f4 --sitekey 00112233445566778899aabbccddeeff"
|
|
||||||
" -> act as a reader that skips reading the Card Application Directory and uses a non-default site key\n"
|
|
||||||
"hf gallagher reader -@ -> continuous reader mode"
|
|
||||||
);
|
|
||||||
|
|
||||||
void *argtable[] = {
|
|
||||||
arg_param_begin,
|
|
||||||
arg_str0(NULL, "aid", "<hex>", "Application ID to read (3 bytes)"),
|
|
||||||
arg_str0("k", "sitekey", "<hex>", "Master site key to compute diversified keys (16 bytes) [default=3112B738D8862CCD34302EB299AAB456]"),
|
|
||||||
arg_lit0(NULL, "apdu", "Show APDU requests and responses"),
|
|
||||||
arg_lit0("v", "verbose", "Verbose mode"),
|
|
||||||
arg_lit0("@", "continuous", "Continuous reader mode"),
|
|
||||||
arg_param_end
|
|
||||||
};
|
|
||||||
CLIExecWithReturn(ctx, cmd, argtable, true);
|
|
||||||
|
|
||||||
int aid_len = 0;
|
|
||||||
uint8_t aid_buf[3] = {0};
|
|
||||||
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);
|
|
||||||
|
|
||||||
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);
|
|
||||||
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);
|
|
||||||
bool continuous_mode = arg_get_lit(ctx, 5);
|
|
||||||
CLIParserFree(ctx);
|
|
||||||
|
|
||||||
if (!continuous_mode)
|
|
||||||
// Read single card
|
|
||||||
return hfgal_read_card(aid, site_key, verbose, false);
|
|
||||||
|
|
||||||
// Loop until <Enter> is pressed
|
|
||||||
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
|
|
||||||
while (!kbd_enter_pressed())
|
|
||||||
hfgal_read_card(aid, site_key, verbose, !verbose);
|
|
||||||
return PM3_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Delete the CAD or an application that contains cardholder credentials.
|
|
||||||
*
|
|
||||||
* @param site_key MIFARE site key.
|
|
||||||
* @param aid Application ID to remove.
|
|
||||||
*/
|
|
||||||
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);
|
|
||||||
HFGAL_RET_IF_ERR(res);
|
|
||||||
|
|
||||||
// Delete application
|
|
||||||
DesfireSetCommMode(ctx, DCMMACed);
|
|
||||||
res = DesfireDeleteApplication(ctx, aid);
|
|
||||||
HFGAL_RET_IF_ERR_WITH_MSG(res, "Failed deleting AID %06X", aid);
|
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "Successfully deleted AID %06X", aid);
|
|
||||||
return PM3_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create a new application to store Gallagher cardholder credentials.
|
* @brief Create a new application to store Gallagher cardholder credentials.
|
||||||
*
|
*
|
||||||
|
@ -535,6 +378,55 @@ static int hfgal_create_creds_file(DesfireContext_t *ctx, uint8_t *site_key, uin
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read Gallagher Card Application Directory from card.
|
||||||
|
*
|
||||||
|
* @param dest_buf Buffer to copy Card Application Directory into.
|
||||||
|
* @param dest_buf_len Size of dest_buf. Must be at least 108 bytes.
|
||||||
|
* @param num_entries Will be set to the number of entries in the Card Application Directory.
|
||||||
|
*/
|
||||||
|
static int hfgal_read_cad(DesfireContext_t *ctx, uint8_t *dest_buf,
|
||||||
|
uint8_t dest_buf_len, uint8_t *num_entries, bool verbose) {
|
||||||
|
if (dest_buf_len < 3 * 36) {
|
||||||
|
PrintAndLogEx(ERR, "hfgal_read_cad destination buffer is incorrectly sized. "
|
||||||
|
"Received length %d, must be at least %d", dest_buf_len, 3 * 36);
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get card AIDs from Card Application Directory (which contains 1 to 3 files)
|
||||||
|
int res = select_aid(ctx, CAD_AID, verbose);
|
||||||
|
HFGAL_RET_IF_ERR_WITH_MSG(res, "Failed selecting Card Application Directory, does AID %06X exist?", CAD_AID);
|
||||||
|
|
||||||
|
// Read up to 3 files with 6x 6-byte entries each
|
||||||
|
for (uint8_t i = 0; i < 3; i++) {
|
||||||
|
size_t read_len;
|
||||||
|
res = DesfireReadFile(ctx, i, 0, 36, &dest_buf[i * 36], &read_len);
|
||||||
|
if (res != PM3_SUCCESS && res != PM3_EAPDU_FAIL)
|
||||||
|
HFGAL_RET_ERR(res, "Failed reading file %d in Card Application Directory (AID %06X)", i, CAD_AID);
|
||||||
|
|
||||||
|
// end if the last entry is NULL
|
||||||
|
if (memcmp(&dest_buf[36 * i + 30], "\0\0\0\0\0\0", 6) == 0) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count number of entries (i.e. count until we hit a NULL entry)
|
||||||
|
*num_entries = 0;
|
||||||
|
for (uint8_t i = 0; i < dest_buf_len; i += 6) {
|
||||||
|
if (memcmp(&dest_buf[i], "\0\0\0\0\0\0", 6) == 0) break;
|
||||||
|
*num_entries += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
// Print what we found
|
||||||
|
PrintAndLogEx(SUCCESS, "Card Application Directory contains:" NOLF);
|
||||||
|
for (int i = 0; i < *num_entries; i++)
|
||||||
|
PrintAndLogEx(NORMAL, "%s %06X" NOLF, (i == 0) ? "" : ",",
|
||||||
|
cad_aid_byte_to_uint(&dest_buf[i * 6 + 3]));
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create the Gallagher Card Application Directory.
|
* @brief Create the Gallagher Card Application Directory.
|
||||||
*
|
*
|
||||||
|
@ -698,8 +590,7 @@ static int hfgal_remove_aid_from_cad(DesfireContext_t *ctx, uint8_t *site_key,
|
||||||
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(
|
int res = hfgal_read_cad(ctx, cad, ARRAYLEN(cad), &num_entries, verbose);
|
||||||
ctx, cad, ARRAYLEN(cad), &num_entries, verbose);
|
|
||||||
HFGAL_RET_IF_ERR(res);
|
HFGAL_RET_IF_ERR(res);
|
||||||
|
|
||||||
// Check if facility already exists in CAD
|
// Check if facility already exists in CAD
|
||||||
|
@ -764,6 +655,114 @@ static int hfgal_remove_aid_from_cad(DesfireContext_t *ctx, uint8_t *site_key,
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read credentials from a Gallagher card.
|
||||||
|
*
|
||||||
|
* @param aid Application ID to read. If 0, then the Card Application Directory will be queried and all entries will be read.
|
||||||
|
* @param site_key MIFARE site key.
|
||||||
|
* @param quiet Suppress error messages. Used when in continuous reader mode.
|
||||||
|
*/
|
||||||
|
static int hfgal_read_card(uint32_t aid, uint8_t *site_key, bool verbose, bool quiet) {
|
||||||
|
DropField();
|
||||||
|
clearCommandBuffer();
|
||||||
|
|
||||||
|
// Set up context
|
||||||
|
DesfireContext_t dctx = {0};
|
||||||
|
DesfireClearContext(&dctx);
|
||||||
|
|
||||||
|
// Get card UID (for key diversification)
|
||||||
|
int res = DesfireGetCardUID(&dctx);
|
||||||
|
HFGAL_RET_IF_ERR_MAYBE_MSG(res, !quiet, "Failed retrieving card UID");
|
||||||
|
|
||||||
|
// Find AIDs to process (from CLI args or the Card Application Directory)
|
||||||
|
uint8_t cad[36 * 3] = {0};
|
||||||
|
uint8_t num_entries = 0;
|
||||||
|
if (aid != 0) {
|
||||||
|
cad_aid_uint_to_byte(aid, &cad[3]);
|
||||||
|
num_entries = 1;
|
||||||
|
} else {
|
||||||
|
res = hfgal_read_cad(&dctx, cad, ARRAYLEN(cad), &num_entries, verbose);
|
||||||
|
HFGAL_RET_IF_ERR_MAYBE_MSG(res, !quiet, "Failed reading Card Application Directory");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop through each application in the CAD
|
||||||
|
for (uint8_t i = 0; i < num_entries * 6; i += 6) {
|
||||||
|
uint16_t region_code = cad[i + 0];
|
||||||
|
uint16_t facility_code = (cad[i + 1] << 8) + cad[i + 2];
|
||||||
|
uint32_t current_aid = cad_aid_byte_to_uint(&cad[i + 3]);
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
if (region_code > 0 || facility_code > 0)
|
||||||
|
PrintAndLogEx(INFO, "Reading AID: %06X, region: %u, facility: %u", current_aid, region_code, facility_code);
|
||||||
|
else
|
||||||
|
PrintAndLogEx(INFO, "Reading AID: %06X", current_aid);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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");
|
||||||
|
|
||||||
|
PrintAndLogEx(SUCCESS, "GALLAGHER (AID %06X) - Region: " _GREEN_("%u") ", Facility: " _GREEN_("%u")
|
||||||
|
", Card No.: " _GREEN_("%u") ", Issue Level: " _GREEN_("%u"), current_aid,
|
||||||
|
creds.region_code, creds.facility_code, creds.card_number, creds.issue_level);
|
||||||
|
}
|
||||||
|
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int CmdGallagherReader(const char *cmd) {
|
||||||
|
CLIParserContext *ctx;
|
||||||
|
CLIParserInit(&ctx, "hf gallagher reader",
|
||||||
|
"Read a GALLAGHER tag",
|
||||||
|
"hf gallagher reader --aid 2081f4 --sitekey 00112233445566778899aabbccddeeff"
|
||||||
|
" -> act as a reader that skips reading the Card Application Directory and uses a non-default site key\n"
|
||||||
|
"hf gallagher reader -@ -> continuous reader mode"
|
||||||
|
);
|
||||||
|
|
||||||
|
void *argtable[] = {
|
||||||
|
arg_param_begin,
|
||||||
|
arg_str0(NULL, "aid", "<hex>", "Application ID to read (3 bytes)"),
|
||||||
|
arg_str0("k", "sitekey", "<hex>", "Master site key to compute diversified keys (16 bytes) [default=3112B738D8862CCD34302EB299AAB456]"),
|
||||||
|
arg_lit0(NULL, "apdu", "Show APDU requests and responses"),
|
||||||
|
arg_lit0("v", "verbose", "Verbose mode"),
|
||||||
|
arg_lit0("@", "continuous", "Continuous reader mode"),
|
||||||
|
arg_param_end
|
||||||
|
};
|
||||||
|
CLIExecWithReturn(ctx, cmd, argtable, true);
|
||||||
|
|
||||||
|
int aid_len = 0;
|
||||||
|
uint8_t aid_buf[3] = {0};
|
||||||
|
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);
|
||||||
|
|
||||||
|
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);
|
||||||
|
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);
|
||||||
|
bool continuous_mode = arg_get_lit(ctx, 5);
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
|
if (!continuous_mode)
|
||||||
|
// Read single card
|
||||||
|
return hfgal_read_card(aid, site_key, verbose, false);
|
||||||
|
|
||||||
|
// Loop until <Enter> is pressed
|
||||||
|
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
|
||||||
|
while (!kbd_enter_pressed())
|
||||||
|
hfgal_read_card(aid, site_key, verbose, !verbose);
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static int CmdGallagherClone(const char *cmd) {
|
static int CmdGallagherClone(const char *cmd) {
|
||||||
CLIParserContext *ctx;
|
CLIParserContext *ctx;
|
||||||
CLIParserInit(&ctx, "hf gallagher clone",
|
CLIParserInit(&ctx, "hf gallagher clone",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue