Merge pull request #1551 from DarkMatterMatt/feat/hf-gallagher

Add `hf gallagher` commands
This commit is contained in:
Iceman 2022-01-06 19:58:12 +01:00 committed by GitHub
commit 75c2462777
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 1449 additions and 133 deletions

View file

@ -234,6 +234,7 @@ set (TARGET_SOURCES
${PM3_ROOT}/client/src/mifare/desfiresecurechan.c ${PM3_ROOT}/client/src/mifare/desfiresecurechan.c
${PM3_ROOT}/client/src/mifare/desfirecore.c ${PM3_ROOT}/client/src/mifare/desfirecore.c
${PM3_ROOT}/client/src/mifare/desfiretest.c ${PM3_ROOT}/client/src/mifare/desfiretest.c
${PM3_ROOT}/client/src/mifare/gallaghercore.c
${PM3_ROOT}/client/src/uart/uart_posix.c ${PM3_ROOT}/client/src/uart/uart_posix.c
${PM3_ROOT}/client/src/uart/uart_win32.c ${PM3_ROOT}/client/src/uart/uart_win32.c
${PM3_ROOT}/client/src/ui/overlays.ui ${PM3_ROOT}/client/src/ui/overlays.ui
@ -254,6 +255,7 @@ set (TARGET_SOURCES
${PM3_ROOT}/client/src/cmdhfepa.c ${PM3_ROOT}/client/src/cmdhfepa.c
${PM3_ROOT}/client/src/cmdhffelica.c ${PM3_ROOT}/client/src/cmdhffelica.c
${PM3_ROOT}/client/src/cmdhffido.c ${PM3_ROOT}/client/src/cmdhffido.c
${PM3_ROOT}/client/src/cmdhfgallagher.c
${PM3_ROOT}/client/src/cmdhfcipurse.c ${PM3_ROOT}/client/src/cmdhfcipurse.c
${PM3_ROOT}/client/src/cmdhficlass.c ${PM3_ROOT}/client/src/cmdhficlass.c
${PM3_ROOT}/client/src/cmdhfjooki.c ${PM3_ROOT}/client/src/cmdhfjooki.c

View file

@ -506,6 +506,7 @@ SRCS = mifare/aiddesfire.c \
cmdhfemrtd.c \ cmdhfemrtd.c \
cmdhffelica.c \ cmdhffelica.c \
cmdhffido.c \ cmdhffido.c \
cmdhfgallagher.c \
cmdhfksx6924.c \ cmdhfksx6924.c \
cmdhfcipurse.c \ cmdhfcipurse.c \
cmdhficlass.c \ cmdhficlass.c \
@ -612,6 +613,7 @@ SRCS = mifare/aiddesfire.c \
mifare/desfirecore.c \ mifare/desfirecore.c \
mifare/desfiresecurechan.c \ mifare/desfiresecurechan.c \
mifare/desfiretest.c \ mifare/desfiretest.c \
mifare/gallaghercore.c \
mifare/mad.c \ mifare/mad.c \
mifare/mfkey.c \ mifare/mfkey.c \
mifare/mifare4.c \ mifare/mifare4.c \

View file

@ -99,6 +99,7 @@ add_library(pm3rrg_rdv4 SHARED
${PM3_ROOT}/client/src/mifare/desfiresecurechan.c ${PM3_ROOT}/client/src/mifare/desfiresecurechan.c
${PM3_ROOT}/client/src/mifare/desfirecore.c ${PM3_ROOT}/client/src/mifare/desfirecore.c
${PM3_ROOT}/client/src/mifare/desfiretest.c ${PM3_ROOT}/client/src/mifare/desfiretest.c
${PM3_ROOT}/client/src/mifare/gallaghercore.c
${PM3_ROOT}/client/src/uart/uart_posix.c ${PM3_ROOT}/client/src/uart/uart_posix.c
${PM3_ROOT}/client/src/uart/uart_win32.c ${PM3_ROOT}/client/src/uart/uart_win32.c
${PM3_ROOT}/client/src/ui/overlays.ui ${PM3_ROOT}/client/src/ui/overlays.ui
@ -119,6 +120,7 @@ add_library(pm3rrg_rdv4 SHARED
${PM3_ROOT}/client/src/cmdhfepa.c ${PM3_ROOT}/client/src/cmdhfepa.c
${PM3_ROOT}/client/src/cmdhffelica.c ${PM3_ROOT}/client/src/cmdhffelica.c
${PM3_ROOT}/client/src/cmdhffido.c ${PM3_ROOT}/client/src/cmdhffido.c
${PM3_ROOT}/client/src/cmdhfgallagher.c
${PM3_ROOT}/client/src/cmdhfcipurse.c ${PM3_ROOT}/client/src/cmdhfcipurse.c
${PM3_ROOT}/client/src/cmdhficlass.c ${PM3_ROOT}/client/src/cmdhficlass.c
${PM3_ROOT}/client/src/cmdhfjooki.c ${PM3_ROOT}/client/src/cmdhfjooki.c

View file

@ -233,6 +233,7 @@ set (TARGET_SOURCES
${PM3_ROOT}/client/src/mifare/desfiresecurechan.c ${PM3_ROOT}/client/src/mifare/desfiresecurechan.c
${PM3_ROOT}/client/src/mifare/desfirecore.c ${PM3_ROOT}/client/src/mifare/desfirecore.c
${PM3_ROOT}/client/src/mifare/desfiretest.c ${PM3_ROOT}/client/src/mifare/desfiretest.c
${PM3_ROOT}/client/src/mifare/gallaghercore.c
${PM3_ROOT}/client/src/uart/uart_posix.c ${PM3_ROOT}/client/src/uart/uart_posix.c
${PM3_ROOT}/client/src/uart/uart_win32.c ${PM3_ROOT}/client/src/uart/uart_win32.c
${PM3_ROOT}/client/src/ui/overlays.ui ${PM3_ROOT}/client/src/ui/overlays.ui
@ -253,6 +254,7 @@ set (TARGET_SOURCES
${PM3_ROOT}/client/src/cmdhfepa.c ${PM3_ROOT}/client/src/cmdhfepa.c
${PM3_ROOT}/client/src/cmdhffelica.c ${PM3_ROOT}/client/src/cmdhffelica.c
${PM3_ROOT}/client/src/cmdhffido.c ${PM3_ROOT}/client/src/cmdhffido.c
${PM3_ROOT}/client/src/cmdhfgallagher.c
${PM3_ROOT}/client/src/cmdhfcipurse.c ${PM3_ROOT}/client/src/cmdhfcipurse.c
${PM3_ROOT}/client/src/cmdhficlass.c ${PM3_ROOT}/client/src/cmdhficlass.c
${PM3_ROOT}/client/src/cmdhfjooki.c ${PM3_ROOT}/client/src/cmdhfjooki.c

View file

@ -33,6 +33,7 @@
#include "cmdhftopaz.h" // TOPAZ #include "cmdhftopaz.h" // TOPAZ
#include "cmdhffelica.h" // ISO18092 / FeliCa #include "cmdhffelica.h" // ISO18092 / FeliCa
#include "cmdhffido.h" // FIDO authenticators #include "cmdhffido.h" // FIDO authenticators
#include "cmdhfgallagher.h" // Gallagher DESFire cards
#include "cmdhfksx6924.h" // KS X 6924 #include "cmdhfksx6924.h" // KS X 6924
#include "cmdhfcipurse.h" // CIPURSE transport cards #include "cmdhfcipurse.h" // CIPURSE transport cards
#include "cmdhfthinfilm.h" // Thinfilm #include "cmdhfthinfilm.h" // Thinfilm
@ -414,6 +415,7 @@ static command_t CommandTable[] = {
{"emrtd", CmdHFeMRTD, AlwaysAvailable, "{ Machine Readable Travel Document... }"}, {"emrtd", CmdHFeMRTD, AlwaysAvailable, "{ Machine Readable Travel Document... }"},
{"felica", CmdHFFelica, AlwaysAvailable, "{ ISO18092 / FeliCa RFIDs... }"}, {"felica", CmdHFFelica, AlwaysAvailable, "{ ISO18092 / FeliCa RFIDs... }"},
{"fido", CmdHFFido, AlwaysAvailable, "{ FIDO and FIDO2 authenticators... }"}, {"fido", CmdHFFido, AlwaysAvailable, "{ FIDO and FIDO2 authenticators... }"},
{"gallagher", CmdHFGallagher, AlwaysAvailable, "{ Gallagher DESFire RFIDs... }"},
{"ksx6924", CmdHFKSX6924, AlwaysAvailable, "{ KS X 6924 (T-Money, Snapper+) RFIDs }"}, {"ksx6924", CmdHFKSX6924, AlwaysAvailable, "{ KS X 6924 (T-Money, Snapper+) RFIDs }"},
{"jooki", CmdHF_Jooki, AlwaysAvailable, "{ Jooki RFIDs... }"}, {"jooki", CmdHF_Jooki, AlwaysAvailable, "{ Jooki RFIDs... }"},
{"iclass", CmdHFiClass, AlwaysAvailable, "{ ICLASS RFIDs... }"}, {"iclass", CmdHFiClass, AlwaysAvailable, "{ ICLASS RFIDs... }"},

1075
client/src/cmdhfgallagher.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,42 @@
/**
* Matt Moran (@DarkMatterMatt), 2021
* -----------------------------------------------------------------------------
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
* -----------------------------------------------------------------------------
* High frequency GALLAGHER tag commands.
* MIFARE DESFire, AIDs 2081F4-2F81F4
*/
#ifndef CMDHFGALLAGHER_H__
#define CMDHFGALLAGHER_H__
#include "common.h"
#include <stdint.h>
int CmdHFGallagher(const char *Cmd);
/**
* @brief Create Gallagher Application Master Key by diversifying
* the MIFARE Site Key with card UID, key number, and application ID.
*
* @param sitekey MIFARE Site Key (16 bytes).
* @param uid Card unique ID (4 or 7 bytes).
* @param uidLen Length of UID.
* @param keyNum Key number (0 <= keyNum <= 2).
* @param aid Application ID (0x2?81F4 where 0 <= ? <= B).
* @param keyOut Buffer to copy the diversified key into (must be 16 bytes).
* @return PM3_SUCCESS if successful, PM3_EINVARG if an argument is invalid.
*/
int hfgal_diversify_key(uint8_t *sitekey, uint8_t *uid, uint8_t uidLen, uint8_t keyNum, uint32_t aid, uint8_t *keyOut);
// Return error
#define HFGAL_RET_ERR(err, ...) { PrintAndLogEx(ERR, __VA_ARGS__); return err; }
// HF GALlagher RETurn IF ERRor
#define HFGAL_RET_IF_ERR(res) if (res != PM3_SUCCESS) { return res; }
#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; }
#endif

View file

@ -155,6 +155,17 @@ typedef struct aidhdr {
uint8_t name[16]; uint8_t name[16];
} PACKED aidhdr_t; } PACKED aidhdr_t;
typedef struct {
const char *aid;
const char *comment;
} mfdesCommonAID_t;
static const mfdesCommonAID_t commonAids[] = {
// AID, name/comment
{ "\xf4\x81\x2f", "Gallagher card data application" },
{ "\xf4\x81\x20", "Gallagher card application directory" }, // Can be 0xF48120 - 0xF4812B, but I've only ever seen 0xF48120
};
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
static int CLIGetUint32Hex(CLIParserContext *ctx, uint8_t paramnum, uint32_t defaultValue, uint32_t *value, bool *valuePresent, uint8_t nlen, const char *lengthErrorStr) { static int CLIGetUint32Hex(CLIParserContext *ctx, uint8_t paramnum, uint32_t defaultValue, uint32_t *value, bool *valuePresent, uint8_t nlen, const char *lengthErrorStr) {
@ -244,6 +255,16 @@ static char *getVersionStr(uint8_t major, uint8_t minor) {
//04 01 01 01 00 1A 05 //04 01 01 01 00 1A 05
} }
static char noCommentStr[1] = { 0x00 };
static const char *getAidCommentStr(uint8_t *aid) {
for (int i = 0; i < ARRAYLEN(commonAids); i++) {
if (memcmp(aid, commonAids[i].aid, 3) == 0) {
return commonAids[i].comment;
}
}
return noCommentStr;
}
static nxp_cardtype_t getCardType(uint8_t major, uint8_t minor) { static nxp_cardtype_t getCardType(uint8_t major, uint8_t minor) {
if (major == 0x00) if (major == 0x00)
@ -3058,8 +3079,13 @@ static int CmdHF14ADesGetAIDs(const char *Cmd) {
if (buflen >= 3) { if (buflen >= 3) {
PrintAndLogEx(INFO, "---- " _CYAN_("AID list") " ----"); PrintAndLogEx(INFO, "---- " _CYAN_("AID list") " ----");
for (int i = 0; i < buflen; i += 3) for (int i = 0; i < buflen; i += 3) {
const char *commentStr = getAidCommentStr(&buf[i]);
if ((void *) commentStr == &noCommentStr)
PrintAndLogEx(INFO, "AID: %06x", DesfireAIDByteToUint(&buf[i])); PrintAndLogEx(INFO, "AID: %06x", DesfireAIDByteToUint(&buf[i]));
else
PrintAndLogEx(INFO, "AID: %06x (%s)", DesfireAIDByteToUint(&buf[i]), commentStr);
}
} else { } else {
PrintAndLogEx(INFO, "There is no applications on the card"); PrintAndLogEx(INFO, "There is no applications on the card");
} }

View file

@ -9,7 +9,10 @@
// ASK/MAN, RF/32, 96 bits long (unknown cs) (0x00088060) // ASK/MAN, RF/32, 96 bits long (unknown cs) (0x00088060)
// sample Q5 , ASK RF/32, STT, 96 bits (3blocks) ( 0x9000F006) // sample Q5 , ASK RF/32, STT, 96 bits (3blocks) ( 0x9000F006)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Modified by: Matt Moran (@DarkMatterMatt), 2021
#include "cmdlfgallagher.h" #include "cmdlfgallagher.h"
#include "mifare/gallaghercore.h"
#include <string.h> // memcpy #include <string.h> // memcpy
#include <ctype.h> // tolower #include <ctype.h> // tolower
#include <stdio.h> #include <stdio.h>
@ -29,56 +32,6 @@
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
static void scramble(uint8_t *arr, uint8_t len) {
const uint8_t lut[] = {
0xa3, 0xb0, 0x80, 0xc6, 0xb2, 0xf4, 0x5c, 0x6c, 0x81, 0xf1, 0xbb, 0xeb, 0x55, 0x67, 0x3c, 0x05,
0x1a, 0x0e, 0x61, 0xf6, 0x22, 0xce, 0xaa, 0x8f, 0xbd, 0x3b, 0x1f, 0x5e, 0x44, 0x04, 0x51, 0x2e,
0x4d, 0x9a, 0x84, 0xea, 0xf8, 0x66, 0x74, 0x29, 0x7f, 0x70, 0xd8, 0x31, 0x7a, 0x6d, 0xa4, 0x00,
0x82, 0xb9, 0x5f, 0xb4, 0x16, 0xab, 0xff, 0xc2, 0x39, 0xdc, 0x19, 0x65, 0x57, 0x7c, 0x20, 0xfa,
0x5a, 0x49, 0x13, 0xd0, 0xfb, 0xa8, 0x91, 0x73, 0xb1, 0x33, 0x18, 0xbe, 0x21, 0x72, 0x48, 0xb6,
0xdb, 0xa0, 0x5d, 0xcc, 0xe6, 0x17, 0x27, 0xe5, 0xd4, 0x53, 0x42, 0xf3, 0xdd, 0x7b, 0x24, 0xac,
0x2b, 0x58, 0x1e, 0xa7, 0xe7, 0x86, 0x40, 0xd3, 0x98, 0x97, 0x71, 0xcb, 0x3a, 0x0f, 0x01, 0x9b,
0x6e, 0x1b, 0xfc, 0x34, 0xa6, 0xda, 0x07, 0x0c, 0xae, 0x37, 0xca, 0x54, 0xfd, 0x26, 0xfe, 0x0a,
0x45, 0xa2, 0x2a, 0xc4, 0x12, 0x0d, 0xf5, 0x4f, 0x69, 0xe0, 0x8a, 0x77, 0x60, 0x3f, 0x99, 0x95,
0xd2, 0x38, 0x36, 0x62, 0xb7, 0x32, 0x7e, 0x79, 0xc0, 0x46, 0x93, 0x2f, 0xa5, 0xba, 0x5b, 0xaf,
0x52, 0x1d, 0xc3, 0x75, 0xcf, 0xd6, 0x4c, 0x83, 0xe8, 0x3d, 0x30, 0x4e, 0xbc, 0x08, 0x2d, 0x09,
0x06, 0xd9, 0x25, 0x9e, 0x89, 0xf2, 0x96, 0x88, 0xc1, 0x8c, 0x94, 0x0b, 0x28, 0xf0, 0x47, 0x63,
0xd5, 0xb3, 0x68, 0x56, 0x9c, 0xf9, 0x6f, 0x41, 0x50, 0x85, 0x8b, 0x9d, 0x59, 0xbf, 0x9f, 0xe2,
0x8e, 0x6a, 0x11, 0x23, 0xa1, 0xcd, 0xb5, 0x7d, 0xc7, 0xa9, 0xc8, 0xef, 0xdf, 0x02, 0xb8, 0x03,
0x6b, 0x35, 0x3e, 0x2c, 0x76, 0xc9, 0xde, 0x1c, 0x4b, 0xd1, 0xed, 0x14, 0xc5, 0xad, 0xe9, 0x64,
0x4a, 0xec, 0x8d, 0xf7, 0x10, 0x43, 0x78, 0x15, 0x87, 0xe4, 0xd7, 0x92, 0xe1, 0xee, 0xe3, 0x90
};
for (int i = 0; i < len; i++) {
arr[i] = lut[arr[i]];
}
}
static void descramble(uint8_t *arr, uint8_t len) {
const uint8_t lut[] = {
0x2f, 0x6e, 0xdd, 0xdf, 0x1d, 0x0f, 0xb0, 0x76, 0xad, 0xaf, 0x7f, 0xbb, 0x77, 0x85, 0x11, 0x6d,
0xf4, 0xd2, 0x84, 0x42, 0xeb, 0xf7, 0x34, 0x55, 0x4a, 0x3a, 0x10, 0x71, 0xe7, 0xa1, 0x62, 0x1a,
0x3e, 0x4c, 0x14, 0xd3, 0x5e, 0xb2, 0x7d, 0x56, 0xbc, 0x27, 0x82, 0x60, 0xe3, 0xae, 0x1f, 0x9b,
0xaa, 0x2b, 0x95, 0x49, 0x73, 0xe1, 0x92, 0x79, 0x91, 0x38, 0x6c, 0x19, 0x0e, 0xa9, 0xe2, 0x8d,
0x66, 0xc7, 0x5a, 0xf5, 0x1c, 0x80, 0x99, 0xbe, 0x4e, 0x41, 0xf0, 0xe8, 0xa6, 0x20, 0xab, 0x87,
0xc8, 0x1e, 0xa0, 0x59, 0x7b, 0x0c, 0xc3, 0x3c, 0x61, 0xcc, 0x40, 0x9e, 0x06, 0x52, 0x1b, 0x32,
0x8c, 0x12, 0x93, 0xbf, 0xef, 0x3b, 0x25, 0x0d, 0xc2, 0x88, 0xd1, 0xe0, 0x07, 0x2d, 0x70, 0xc6,
0x29, 0x6a, 0x4d, 0x47, 0x26, 0xa3, 0xe4, 0x8b, 0xf6, 0x97, 0x2c, 0x5d, 0x3d, 0xd7, 0x96, 0x28,
0x02, 0x08, 0x30, 0xa7, 0x22, 0xc9, 0x65, 0xf8, 0xb7, 0xb4, 0x8a, 0xca, 0xb9, 0xf2, 0xd0, 0x17,
0xff, 0x46, 0xfb, 0x9a, 0xba, 0x8f, 0xb6, 0x69, 0x68, 0x8e, 0x21, 0x6f, 0xc4, 0xcb, 0xb3, 0xce,
0x51, 0xd4, 0x81, 0x00, 0x2e, 0x9c, 0x74, 0x63, 0x45, 0xd9, 0x16, 0x35, 0x5f, 0xed, 0x78, 0x9f,
0x01, 0x48, 0x04, 0xc1, 0x33, 0xd6, 0x4f, 0x94, 0xde, 0x31, 0x9d, 0x0a, 0xac, 0x18, 0x4b, 0xcd,
0x98, 0xb8, 0x37, 0xa2, 0x83, 0xec, 0x03, 0xd8, 0xda, 0xe5, 0x7a, 0x6b, 0x53, 0xd5, 0x15, 0xa4,
0x43, 0xe9, 0x90, 0x67, 0x58, 0xc0, 0xa5, 0xfa, 0x2a, 0xb1, 0x75, 0x50, 0x39, 0x5c, 0xe6, 0xdc,
0x89, 0xfc, 0xcf, 0xfe, 0xf9, 0x57, 0x54, 0x64, 0xa8, 0xee, 0x23, 0x0b, 0xf1, 0xea, 0xfd, 0xdb,
0xbd, 0x09, 0xb5, 0x5b, 0x05, 0x86, 0x13, 0xf3, 0x24, 0xc5, 0x3f, 0x44, 0x72, 0x7c, 0x7e, 0x36
};
for (int i = 0; i < len; i++) {
arr[i] = lut[arr[i]];
}
}
//see ASK/MAN Demod for what args are accepted //see ASK/MAN Demod for what args are accepted
int demodGallagher(bool verbose) { int demodGallagher(bool verbose) {
(void) verbose; // unused so far (void) verbose; // unused so far
@ -113,6 +66,7 @@ int demodGallagher(bool verbose) {
// bytes // bytes
uint8_t arr[8] = {0}; uint8_t arr[8] = {0};
for (int i = 0, pos = 0; i < ARRAYLEN(arr); i++) { for (int i = 0, pos = 0; i < ARRAYLEN(arr); i++) {
// first 16 bits are the 7FEA prefix, then every 9th bit is a checksum-bit for the preceding byte
pos = 16 + (9 * i); pos = 16 + (9 * i);
arr[i] = bytebits_to_byte(g_DemodBuffer + pos, 8); arr[i] = bytebits_to_byte(g_DemodBuffer + pos, 8);
} }
@ -121,22 +75,12 @@ int demodGallagher(bool verbose) {
uint8_t crc = bytebits_to_byte(g_DemodBuffer + 16 + (9 * 8), 8); uint8_t crc = bytebits_to_byte(g_DemodBuffer + 16 + (9 * 8), 8);
uint8_t calc_crc = CRC8Cardx(arr, ARRAYLEN(arr)); uint8_t calc_crc = CRC8Cardx(arr, ARRAYLEN(arr));
descramble(arr, ARRAYLEN(arr)); GallagherCredentials_t creds = {0};
gallagher_decode_creds(arr, &creds);
// 4bit region code PrintAndLogEx(SUCCESS, "GALLAGHER - Region: " _GREEN_("%u") " Facility: " _GREEN_("%u") " Card No.: " _GREEN_("%u") " Issue Level: " _GREEN_("%u"),
uint8_t rc = (arr[3] & 0x1E) >> 1; creds.region_code, creds.facility_code, creds.card_number, creds.issue_level);
PrintAndLogEx(SUCCESS, " Displayed: " _GREEN_("%C%u"), creds.region_code + 'A', creds.facility_code);
// 16bit FC
uint16_t fc = (arr[5] & 0x0F) << 12 | arr[1] << 4 | ((arr[7] >> 4) & 0x0F);
// 24bit CN
uint32_t cn = arr[0] << 16 | (arr[4] & 0x1F) << 11 | arr[2] << 3 | (arr[3] & 0xE0) >> 5;
// 4bit issue level
uint8_t il = arr[7] & 0x0F;
PrintAndLogEx(SUCCESS, "GALLAGHER - Region: " _GREEN_("%u") " FC: " _GREEN_("%u") " CN: " _GREEN_("%u") " Issue Level: " _GREEN_("%u"), rc, fc, cn, il);
PrintAndLogEx(SUCCESS, " Displayed: " _GREEN_("%C%u"), rc + 'A', fc);
PrintAndLogEx(SUCCESS, " Raw: %08X%08X%08X", raw1, raw2, raw3); PrintAndLogEx(SUCCESS, " Raw: %08X%08X%08X", raw1, raw2, raw3);
PrintAndLogEx(SUCCESS, " CRC: %02X - %02X (%s)", crc, calc_crc, (crc == calc_crc) ? "ok" : "fail"); PrintAndLogEx(SUCCESS, " CRC: %02X - %02X (%s)", crc, calc_crc, (crc == calc_crc) ? "ok" : "fail");
return PM3_SUCCESS; return PM3_SUCCESS;
@ -185,34 +129,6 @@ static int CmdGallagherReader(const char *Cmd) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static bool isValidGallagherParams(int8_t rc, int32_t fc, int32_t cn, int8_t il) {
bool isValid = true;
// if one is set, all must be set
if (rc < 0 || fc < 0 || cn < 0 || il < 0) {
PrintAndLogEx(FAILED, "If rc/fc/cn/il is specified, all must be set");
isValid = false;
}
// validate input
if (rc > 0x0f) {
PrintAndLogEx(FAILED, "Region code must be less than 16 (4 bits)");
isValid = false;
}
if (fc > 0xffff) {
PrintAndLogEx(FAILED, "Facility code must be less than 65536 (2 bytes)");
isValid = false;
}
if (cn > 0xffffff) {
PrintAndLogEx(FAILED, "Card number must be less than 16777216 (3 bytes)");
isValid = false;
}
if (il > 0x0f) {
PrintAndLogEx(FAILED, "Issue level must be less than 16 (4 bits)");
isValid = false;
}
return isValid;
}
static void setBitsInBlocks(uint32_t *blocks, uint8_t *pos, uint32_t data, uint8_t data_len) { static void setBitsInBlocks(uint32_t *blocks, uint8_t *pos, uint32_t data, uint8_t data_len) {
for (int i = data_len - 1; i >= 0; i--) { for (int i = data_len - 1; i >= 0; i--) {
uint8_t blk = *pos / 32; uint8_t blk = *pos / 32;
@ -223,20 +139,10 @@ static void setBitsInBlocks(uint32_t *blocks, uint8_t *pos, uint32_t data, uint8
} }
} }
static void createBlocks(uint32_t *blocks, uint8_t rc, uint16_t fc, uint32_t cn, uint8_t il) { static void createBlocks(uint32_t *blocks, GallagherCredentials_t *creds) {
// put data into the correct places (Gallagher obfuscation) // put data into the correct places (Gallagher obfuscation)
uint8_t arr[8] = {0}; uint8_t arr[8] = {0};
arr[0] = (cn & 0xffffff) >> 16; gallagher_encode_creds(arr, creds);
arr[1] = (fc & 0xfff) >> 4;
arr[2] = (cn & 0x7ff) >> 3;
arr[3] = (cn & 0x7) << 5 | (rc & 0xf) << 1;
arr[4] = (cn & 0xffff) >> 11;
arr[5] = (fc & 0xffff) >> 12;
arr[6] = 0;
arr[7] = (fc & 0xf) << 4 | (il & 0xf);
// more obfuscation
scramble(arr, ARRAYLEN(arr));
blocks[0] = blocks[1] = blocks[2] = 0; blocks[0] = blocks[1] = blocks[2] = 0;
uint8_t pos = 0; uint8_t pos = 0;
@ -258,7 +164,6 @@ static void createBlocks(uint32_t *blocks, uint8_t rc, uint16_t fc, uint32_t cn,
} }
static int CmdGallagherClone(const char *Cmd) { static int CmdGallagherClone(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "lf gallagher clone", CLIParserInit(&ctx, "lf gallagher clone",
"clone a GALLAGHER tag to a T55x7, Q5/T5555 or EM4305/4469 tag.", "clone a GALLAGHER tag to a T55x7, Q5/T5555 or EM4305/4469 tag.",
@ -273,10 +178,10 @@ static int CmdGallagherClone(const char *Cmd) {
arg_str0("r", "raw", "<hex>", "raw hex data. 12 bytes max"), arg_str0("r", "raw", "<hex>", "raw hex data. 12 bytes max"),
arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"), arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"), arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
arg_int0(NULL, "rc", "<decimal>", "Region code. 4 bits max"), arg_u64_0(NULL, "rc", "<decimal>", "Region code. 4 bits max"),
arg_int0(NULL, "fc", "<decimal>", "Facility code. 2 bytes max"), arg_u64_0(NULL, "fc", "<decimal>", "Facility code. 2 bytes max"),
arg_int0(NULL, "cn", "<decimal>", "Card number. 3 bytes max"), arg_u64_0(NULL, "cn", "<decimal>", "Card number. 3 bytes max"),
arg_int0(NULL, "il", "<decimal>", "Issue level. 4 bits max"), arg_u64_0(NULL, "il", "<decimal>", "Issue level. 4 bits max"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, false); CLIExecWithReturn(ctx, Cmd, argtable, false);
@ -292,10 +197,10 @@ static int CmdGallagherClone(const char *Cmd) {
bool q5 = arg_get_lit(ctx, 2); bool q5 = arg_get_lit(ctx, 2);
bool em = arg_get_lit(ctx, 3); bool em = arg_get_lit(ctx, 3);
int16_t region_code = arg_get_int_def(ctx, 4, -1); uint64_t region_code = arg_get_u64_def(ctx, 4, -1); // uint4, input will be validated later
int32_t facility_code = arg_get_int_def(ctx, 5, -1); uint64_t facility_code = arg_get_u64_def(ctx, 5, -1); // uint16
int32_t card_number = arg_get_int_def(ctx, 6, -1); uint64_t card_number = arg_get_u64_def(ctx, 6, -1); // uint24
int32_t issue_level = arg_get_int_def(ctx, 7, -1); uint64_t issue_level = arg_get_u64_def(ctx, 7, -1); // uint4
CLIParserFree(ctx); CLIParserFree(ctx);
bool use_raw = raw_len > 0; bool use_raw = raw_len > 0;
@ -316,7 +221,7 @@ static int CmdGallagherClone(const char *Cmd) {
PrintAndLogEx(FAILED, "Can't specify both raw and rc/fc/cn/il at the same time"); PrintAndLogEx(FAILED, "Can't specify both raw and rc/fc/cn/il at the same time");
return PM3_EINVARG; return PM3_EINVARG;
} }
if (!isValidGallagherParams(region_code, facility_code, card_number, issue_level)) { if (!gallagher_is_valid_creds(region_code, facility_code, card_number, issue_level)) {
return PM3_EINVARG; return PM3_EINVARG;
} }
} }
@ -327,8 +232,14 @@ static int CmdGallagherClone(const char *Cmd) {
blocks[i] = bytes_to_num(raw + ((i - 1) * 4), sizeof(uint32_t)); blocks[i] = bytes_to_num(raw + ((i - 1) * 4), sizeof(uint32_t));
} }
} else { } else {
GallagherCredentials_t creds = {
.region_code = region_code,
.facility_code = facility_code,
.card_number = card_number,
.issue_level = issue_level,
};
// fill blocks 1 to 3 with Gallagher data // fill blocks 1 to 3 with Gallagher data
createBlocks(blocks + 1, region_code, facility_code, card_number, issue_level); createBlocks(blocks + 1, &creds);
} }
//Pac - compat mode, NRZ, data rate 40, 3 data blocks //Pac - compat mode, NRZ, data rate 40, 3 data blocks
@ -373,10 +284,10 @@ static int CmdGallagherSim(const char *Cmd) {
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_str0("r", "raw", "<hex>", "raw hex data. 12 bytes max"), arg_str0("r", "raw", "<hex>", "raw hex data. 12 bytes max"),
arg_int0(NULL, "rc", "<decimal>", "Region code. 4 bits max"), arg_u64_0(NULL, "rc", "<decimal>", "Region code. 4 bits max"),
arg_int0(NULL, "fc", "<decimal>", "Facility code. 2 bytes max"), arg_u64_0(NULL, "fc", "<decimal>", "Facility code. 2 bytes max"),
arg_int0(NULL, "cn", "<decimal>", "Card number. 3 bytes max"), arg_u64_0(NULL, "cn", "<decimal>", "Card number. 3 bytes max"),
arg_int0(NULL, "il", "<decimal>", "Issue level. 4 bits max"), arg_u64_0(NULL, "il", "<decimal>", "Issue level. 4 bits max"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, false); CLIExecWithReturn(ctx, Cmd, argtable, false);
@ -391,10 +302,10 @@ static int CmdGallagherSim(const char *Cmd) {
return PM3_EINVARG; return PM3_EINVARG;
} }
int16_t region_code = arg_get_int_def(ctx, 2, -1); uint64_t region_code = arg_get_u64_def(ctx, 2, -1); // uint4, input will be validated later
int32_t facility_code = arg_get_int_def(ctx, 3, -1); uint64_t facility_code = arg_get_u64_def(ctx, 3, -1); // uint16
int32_t card_number = arg_get_int_def(ctx, 4, -1); uint64_t card_number = arg_get_u64_def(ctx, 4, -1); // uint24
int32_t issue_level = arg_get_int_def(ctx, 5, -1); uint64_t issue_level = arg_get_u64_def(ctx, 5, -1); // uint4
CLIParserFree(ctx); CLIParserFree(ctx);
bool use_raw = raw_len > 0; bool use_raw = raw_len > 0;
@ -410,15 +321,21 @@ static int CmdGallagherSim(const char *Cmd) {
PrintAndLogEx(FAILED, "Can't specify both raw and rc/fc/cn/il at the same time"); PrintAndLogEx(FAILED, "Can't specify both raw and rc/fc/cn/il at the same time");
return PM3_EINVARG; return PM3_EINVARG;
} }
if (!isValidGallagherParams(region_code, facility_code, card_number, issue_level)) { if (!gallagher_is_valid_creds(region_code, facility_code, card_number, issue_level)) {
return PM3_EINVARG; return PM3_EINVARG;
} }
} }
if (!use_raw) { if (!use_raw) {
// generate Gallagher data // generate Gallagher data
GallagherCredentials_t creds = {
.region_code = region_code,
.facility_code = facility_code,
.card_number = card_number,
.issue_level = issue_level,
};
uint32_t blocks[3]; uint32_t blocks[3];
createBlocks(blocks, region_code, facility_code, card_number, issue_level); createBlocks(blocks, &creds);
// convert to the normal 'raw' format // convert to the normal 'raw' format
for (int i = 0; i < ARRAYLEN(blocks); i++) { for (int i = 0; i < ARRAYLEN(blocks); i++) {

View file

@ -0,0 +1,124 @@
/**
* Matt Moran (@DarkMatterMatt), 2021
* -----------------------------------------------------------------------------
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
* -----------------------------------------------------------------------------
* Common functionality for low/high-frequency GALLAGHER tag encoding & decoding.
*/
#include "gallaghercore.h"
#include "common.h"
#include "ui.h"
static void scramble(uint8_t *arr, uint8_t len) {
uint8_t lut[] = {
0xa3, 0xb0, 0x80, 0xc6, 0xb2, 0xf4, 0x5c, 0x6c, 0x81, 0xf1, 0xbb, 0xeb, 0x55, 0x67, 0x3c, 0x05,
0x1a, 0x0e, 0x61, 0xf6, 0x22, 0xce, 0xaa, 0x8f, 0xbd, 0x3b, 0x1f, 0x5e, 0x44, 0x04, 0x51, 0x2e,
0x4d, 0x9a, 0x84, 0xea, 0xf8, 0x66, 0x74, 0x29, 0x7f, 0x70, 0xd8, 0x31, 0x7a, 0x6d, 0xa4, 0x00,
0x82, 0xb9, 0x5f, 0xb4, 0x16, 0xab, 0xff, 0xc2, 0x39, 0xdc, 0x19, 0x65, 0x57, 0x7c, 0x20, 0xfa,
0x5a, 0x49, 0x13, 0xd0, 0xfb, 0xa8, 0x91, 0x73, 0xb1, 0x33, 0x18, 0xbe, 0x21, 0x72, 0x48, 0xb6,
0xdb, 0xa0, 0x5d, 0xcc, 0xe6, 0x17, 0x27, 0xe5, 0xd4, 0x53, 0x42, 0xf3, 0xdd, 0x7b, 0x24, 0xac,
0x2b, 0x58, 0x1e, 0xa7, 0xe7, 0x86, 0x40, 0xd3, 0x98, 0x97, 0x71, 0xcb, 0x3a, 0x0f, 0x01, 0x9b,
0x6e, 0x1b, 0xfc, 0x34, 0xa6, 0xda, 0x07, 0x0c, 0xae, 0x37, 0xca, 0x54, 0xfd, 0x26, 0xfe, 0x0a,
0x45, 0xa2, 0x2a, 0xc4, 0x12, 0x0d, 0xf5, 0x4f, 0x69, 0xe0, 0x8a, 0x77, 0x60, 0x3f, 0x99, 0x95,
0xd2, 0x38, 0x36, 0x62, 0xb7, 0x32, 0x7e, 0x79, 0xc0, 0x46, 0x93, 0x2f, 0xa5, 0xba, 0x5b, 0xaf,
0x52, 0x1d, 0xc3, 0x75, 0xcf, 0xd6, 0x4c, 0x83, 0xe8, 0x3d, 0x30, 0x4e, 0xbc, 0x08, 0x2d, 0x09,
0x06, 0xd9, 0x25, 0x9e, 0x89, 0xf2, 0x96, 0x88, 0xc1, 0x8c, 0x94, 0x0b, 0x28, 0xf0, 0x47, 0x63,
0xd5, 0xb3, 0x68, 0x56, 0x9c, 0xf9, 0x6f, 0x41, 0x50, 0x85, 0x8b, 0x9d, 0x59, 0xbf, 0x9f, 0xe2,
0x8e, 0x6a, 0x11, 0x23, 0xa1, 0xcd, 0xb5, 0x7d, 0xc7, 0xa9, 0xc8, 0xef, 0xdf, 0x02, 0xb8, 0x03,
0x6b, 0x35, 0x3e, 0x2c, 0x76, 0xc9, 0xde, 0x1c, 0x4b, 0xd1, 0xed, 0x14, 0xc5, 0xad, 0xe9, 0x64,
0x4a, 0xec, 0x8d, 0xf7, 0x10, 0x43, 0x78, 0x15, 0x87, 0xe4, 0xd7, 0x92, 0xe1, 0xee, 0xe3, 0x90
};
for (int i = 0; i < len; i++) {
arr[i] = lut[arr[i]];
}
}
static void descramble(uint8_t *arr, uint8_t len) {
uint8_t lut[] = {
0x2f, 0x6e, 0xdd, 0xdf, 0x1d, 0x0f, 0xb0, 0x76, 0xad, 0xaf, 0x7f, 0xbb, 0x77, 0x85, 0x11, 0x6d,
0xf4, 0xd2, 0x84, 0x42, 0xeb, 0xf7, 0x34, 0x55, 0x4a, 0x3a, 0x10, 0x71, 0xe7, 0xa1, 0x62, 0x1a,
0x3e, 0x4c, 0x14, 0xd3, 0x5e, 0xb2, 0x7d, 0x56, 0xbc, 0x27, 0x82, 0x60, 0xe3, 0xae, 0x1f, 0x9b,
0xaa, 0x2b, 0x95, 0x49, 0x73, 0xe1, 0x92, 0x79, 0x91, 0x38, 0x6c, 0x19, 0x0e, 0xa9, 0xe2, 0x8d,
0x66, 0xc7, 0x5a, 0xf5, 0x1c, 0x80, 0x99, 0xbe, 0x4e, 0x41, 0xf0, 0xe8, 0xa6, 0x20, 0xab, 0x87,
0xc8, 0x1e, 0xa0, 0x59, 0x7b, 0x0c, 0xc3, 0x3c, 0x61, 0xcc, 0x40, 0x9e, 0x06, 0x52, 0x1b, 0x32,
0x8c, 0x12, 0x93, 0xbf, 0xef, 0x3b, 0x25, 0x0d, 0xc2, 0x88, 0xd1, 0xe0, 0x07, 0x2d, 0x70, 0xc6,
0x29, 0x6a, 0x4d, 0x47, 0x26, 0xa3, 0xe4, 0x8b, 0xf6, 0x97, 0x2c, 0x5d, 0x3d, 0xd7, 0x96, 0x28,
0x02, 0x08, 0x30, 0xa7, 0x22, 0xc9, 0x65, 0xf8, 0xb7, 0xb4, 0x8a, 0xca, 0xb9, 0xf2, 0xd0, 0x17,
0xff, 0x46, 0xfb, 0x9a, 0xba, 0x8f, 0xb6, 0x69, 0x68, 0x8e, 0x21, 0x6f, 0xc4, 0xcb, 0xb3, 0xce,
0x51, 0xd4, 0x81, 0x00, 0x2e, 0x9c, 0x74, 0x63, 0x45, 0xd9, 0x16, 0x35, 0x5f, 0xed, 0x78, 0x9f,
0x01, 0x48, 0x04, 0xc1, 0x33, 0xd6, 0x4f, 0x94, 0xde, 0x31, 0x9d, 0x0a, 0xac, 0x18, 0x4b, 0xcd,
0x98, 0xb8, 0x37, 0xa2, 0x83, 0xec, 0x03, 0xd8, 0xda, 0xe5, 0x7a, 0x6b, 0x53, 0xd5, 0x15, 0xa4,
0x43, 0xe9, 0x90, 0x67, 0x58, 0xc0, 0xa5, 0xfa, 0x2a, 0xb1, 0x75, 0x50, 0x39, 0x5c, 0xe6, 0xdc,
0x89, 0xfc, 0xcf, 0xfe, 0xf9, 0x57, 0x54, 0x64, 0xa8, 0xee, 0x23, 0x0b, 0xf1, 0xea, 0xfd, 0xdb,
0xbd, 0x09, 0xb5, 0x5b, 0x05, 0x86, 0x13, 0xf3, 0x24, 0xc5, 0x3f, 0x44, 0x72, 0x7c, 0x7e, 0x36
};
for (int i = 0; i < len; i++) {
arr[i] = lut[arr[i]];
}
}
void gallagher_decode_creds(uint8_t *eight_bytes, GallagherCredentials_t *creds) {
uint8_t *arr = eight_bytes;
descramble(arr, 8);
// 4bit region code
creds->region_code = (arr[3] & 0x1E) >> 1;
// 16bit facility code
creds->facility_code = (arr[5] & 0x0F) << 12 | arr[1] << 4 | ((arr[7] >> 4) & 0x0F);
// 24bit card number
creds->card_number = arr[0] << 16 | (arr[4] & 0x1F) << 11 | arr[2] << 3 | (arr[3] & 0xE0) >> 5;
// 4bit issue level
creds->issue_level = arr[7] & 0x0F;
}
void gallagher_encode_creds(uint8_t *eight_bytes, GallagherCredentials_t *creds) {
uint8_t rc = creds->region_code;
uint16_t fc = creds->facility_code;
uint32_t cn = creds->card_number;
uint8_t il = creds->issue_level;
// put data into the correct places (Gallagher obfuscation)
eight_bytes[0] = (cn & 0xffffff) >> 16;
eight_bytes[1] = (fc & 0xfff) >> 4;
eight_bytes[2] = (cn & 0x7ff) >> 3;
eight_bytes[3] = (cn & 0x7) << 5 | (rc & 0xf) << 1;
eight_bytes[4] = (cn & 0xffff) >> 11;
eight_bytes[5] = (fc & 0xffff) >> 12;
eight_bytes[6] = 0;
eight_bytes[7] = (fc & 0xf) << 4 | (il & 0xf);
// more obfuscation
scramble(eight_bytes, 8);
}
bool gallagher_is_valid_creds(uint64_t region_code, uint64_t facility_code, uint64_t card_number, uint64_t issue_level) {
bool is_valid = true;
// validate input
if (region_code > 0x0f) {
PrintAndLogEx(ERR, "Region code must be 0 <= rc <= 15 (4 bits), received: %d", region_code);
is_valid = false;
}
if (facility_code > 0xffff) {
PrintAndLogEx(ERR, "Facility code must be 0 <= fc <= 65535 (2 bytes), received: %d", facility_code);
is_valid = false;
}
if (card_number > 0xffffff) {
PrintAndLogEx(ERR, "Card number must be 0 <= cn <= 16777215 (3 bytes), received: %d", card_number);
is_valid = false;
}
if (issue_level > 0x0f) {
PrintAndLogEx(ERR, "Issue level must be 0 <= il <= 15 (4 bits), received: %d", issue_level);
is_valid = false;
}
return is_valid;
}

View file

@ -0,0 +1,30 @@
/**
* Matt Moran (@DarkMatterMatt), 2021
* -----------------------------------------------------------------------------
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
* -----------------------------------------------------------------------------
* Common functionality for low/high-frequency GALLAGHER tag encoding & decoding.
*/
#ifndef MIFARE_GALLAGHERCORE_H__
#define MIFARE_GALLAGHERCORE_H__
#include "common.h"
#include <stdint.h>
typedef struct {
uint8_t region_code;
uint16_t facility_code;
uint32_t card_number;
uint8_t issue_level;
} GallagherCredentials_t;
void gallagher_encode_creds(uint8_t *eight_bytes, GallagherCredentials_t *creds);
void gallagher_decode_creds(uint8_t *eight_bytes, GallagherCredentials_t *creds);
bool gallagher_is_valid_creds(uint64_t region_code, uint64_t facility_code, uint64_t card_number, uint64_t issue_level);
#endif

View file

@ -216,6 +216,11 @@ const static vocabulory_t vocabulory[] = {
{ 0, "hf fido auth" }, { 0, "hf fido auth" },
{ 0, "hf fido make" }, { 0, "hf fido make" },
{ 0, "hf fido assert" }, { 0, "hf fido assert" },
{ 1, "hf gallagher help" },
{ 0, "hf gallagher reader" },
{ 0, "hf gallagher clone" },
{ 0, "hf gallagher delete" },
{ 1, "hf gallagher diversifykey" },
{ 1, "hf ksx6924 help" }, { 1, "hf ksx6924 help" },
{ 0, "hf ksx6924 balance" }, { 0, "hf ksx6924 balance" },
{ 0, "hf ksx6924 info" }, { 0, "hf ksx6924 info" },

View file

@ -2320,9 +2320,83 @@
], ],
"usage": "hf fido reg [-havt] [-f <fn>] [--cp <ascii>] [--ap <ascii>] [--cpx <hex>] [--apx <hex>]" "usage": "hf fido reg [-havt] [-f <fn>] [--cp <ascii>] [--ap <ascii>] [--cpx <hex>] [--apx <hex>]"
}, },
"hf gallagher clone": {
"command": "hf gallagher clone",
"description": "clone gallagher credentials to a writable desfire card",
"notes": [
"hf gallagher clone --rc 1 --fc 22 --cn 3333 --il 4 --sitekey 00112233445566778899aabbccddeeff"
],
"offline": false,
"options": [
"-h, --help this help",
"-n, --keynum <decimal> key number [default=0]",
"-t, --algo <des/2tdea/3tdea/aes> crypt algo: des, 2tdea, 3tdea, aes",
"-k, --key <hex> key for authentication to the picc (hex 8(des), 16(2tdea or aes) or 24(3tdea) bytes)",
"--rc <decimal> region code. 4 bits max",
"--fc <decimal> facility code. 2 bytes max",
"--cn <decimal> card number. 3 bytes max",
"--il <decimal> issue level. 4 bits max",
"--aid <hex> application id to write (3 bytes) [default finds lowest available in range 0x2?81f4, where 0 <= ? <= 0xb]",
"--sitekey <hex> mifare site key to compute diversified keys (16 bytes, required if using non-default key)",
"--apdu show apdu requests and responses",
"-v, --verbose verbose mode"
],
"usage": "hf gallagher clone [-hv] [-n <decimal>] [-t <des/2tdea/3tdea/aes>] [-k <hex>] --rc <decimal> --fc <decimal> --cn <decimal> --il <decimal> [--aid <hex>] [--sitekey <hex>] [--apdu]"
},
"hf gallagher delete": {
"command": "hf gallagher delete",
"description": "delete gallagher application from a desfire card",
"notes": [
"hf gallagher delete --aid 2081f4 --sitekey 00112233445566778899aabbccddeeff"
],
"offline": false,
"options": [
"-h, --help this help",
"--aid <hex> application id to delete (3 bytes)",
"--sitekey <hex> mifare site key to compute diversified keys (16 bytes, required if using non-default key)",
"--apdu show apdu requests and responses",
"-v, --verbose verbose mode"
],
"usage": "hf gallagher delete [-hv] --aid <hex> [--sitekey <hex>] [--apdu]"
},
"hf gallagher diversifykey": {
"command": "hf gallagher diversifykey",
"description": "diversify gallagher key",
"notes": [
"hf gallagher diversify --uid 11223344556677 --aid 2081f4"
],
"offline": true,
"options": [
"-h, --help this help",
"--aid <hex> application id for diversification (3 bytes)",
"--keynum <decimal> key number [default=0]",
"--uid <hex> card uid to delete (4 or 7 bytes)",
"--sitekey <hex> mifare site key to compute diversified keys (16 bytes, required if using non-default key)",
"--apdu show apdu requests and responses"
],
"usage": "hf gallagher diversify [-h] --aid <hex> [--keynum <decimal>] [--uid <hex>] [--sitekey <hex>] [--apdu]"
},
"hf gallagher help": {
"command": "hf gallagher help",
"description": "help this help diversifykey diversify gallagher key --------------------------------------------------------------------------------------- hf gallagher reader available offline: no read a gallagher desfire tag",
"notes": [
"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",
"hf gallagher reader -@ -> continuous reader mode"
],
"offline": true,
"options": [
"-h, --help this help",
"--aid <hex> application id to read (3 bytes). if specified, then the card application directory is not used",
"--sitekey <hex> mifare site key to compute diversified keys (16 bytes, required if using non-default key)",
"-@, --continuous continuous reader mode",
"--apdu show apdu requests and responses",
"-v, --verbose verbose mode"
],
"usage": "hf gallagher reader [-h@v] [--aid <hex>] [--sitekey <hex>] [--apdu]"
},
"hf help": { "hf help": {
"command": "hf help", "command": "hf help",
"description": "-------- ----------------------- high frequency ----------------------- 14a { iso14443a rfids... } 14b { iso14443b rfids... } 15 { iso15693 rfids... } cipurse { cipurse transport cards... } epa { german identification card... } emrtd { machine readable travel document... } felica { iso18092 / felica rfids... } fido { fido and fido2 authenticators... } ksx6924 { ks x 6924 (t-money, snapper+) rfids } jooki { jooki rfids... } iclass { iclass rfids... } legic { legic rfids... } lto { lto cartridge memory rfids... } mf { mifare rfids... } mfp { mifare plus rfids... } mfu { mifare ultralight rfids... } mfdes { mifare desfire rfids... } seos { seos rfids... } st25ta { st25ta rfids... } thinfilm { thinfilm rfids... } topaz { topaz (nfc type 1) rfids... } waveshare { waveshare nfc epaper... } ----------- --------------------- general --------------------- help this help list list protocol data in trace buffer search search for known hf tags --------------------------------------------------------------------------------------- hf list available offline: yes alias of `trace list -t raw` with selected protocol data to annotate trace buffer you can load a trace from file (see `trace load -h`) or it be downloaded from device by default it accepts all other arguments of `trace list`. note that some might not be relevant for this specific protocol", "description": "-------- ----------------------- high frequency ----------------------- 14a { iso14443a rfids... } 14b { iso14443b rfids... } 15 { iso15693 rfids... } cipurse { cipurse transport cards... } epa { german identification card... } emrtd { machine readable travel document... } felica { iso18092 / felica rfids... } fido { fido and fido2 authenticators... } gallagher { gallagher desfire rfids... } ksx6924 { ks x 6924 (t-money, snapper+) rfids } jooki { jooki rfids... } iclass { iclass rfids... } legic { legic rfids... } lto { lto cartridge memory rfids... } mf { mifare rfids... } mfp { mifare plus rfids... } mfu { mifare ultralight rfids... } mfdes { mifare desfire rfids... } seos { seos rfids... } st25ta { st25ta rfids... } thinfilm { thinfilm rfids... } topaz { topaz (nfc type 1) rfids... } waveshare { waveshare nfc epaper... } ----------- --------------------- general --------------------- help this help list list protocol data in trace buffer search search for known hf tags --------------------------------------------------------------------------------------- hf list available offline: yes alias of `trace list -t raw` with selected protocol data to annotate trace buffer you can load a trace from file (see `trace load -h`) or it be downloaded from device by default it accepts all other arguments of `trace list`. note that some might not be relevant for this specific protocol",
"notes": [ "notes": [
"hf list -f -> show frame delay times", "hf list -f -> show frame delay times",
"hf list -1 -> use trace buffer" "hf list -1 -> use trace buffer"
@ -5963,8 +6037,8 @@
"command": "hw connect", "command": "hw connect",
"description": "connects to a proxmark3 device via specified serial port. baudrate here is only for physical uart or uart-bt, not for usb-cdc or blue shark add-on", "description": "connects to a proxmark3 device via specified serial port. baudrate here is only for physical uart or uart-bt, not for usb-cdc or blue shark add-on",
"notes": [ "notes": [
"hw connect -p /dev/ttyacm0", "hw connect -p com3",
"hw connect -p /dev/ttyacm0 -b 115200" "hw connect -p com3 -b 115200"
], ],
"offline": true, "offline": true,
"options": [ "options": [
@ -10161,8 +10235,8 @@
} }
}, },
"metadata": { "metadata": {
"commands_extracted": 597, "commands_extracted": 601,
"extracted_by": "PM3Help2JSON v1.00", "extracted_by": "PM3Help2JSON v1.00",
"extracted_on": "2022-01-05T16:57:29" "extracted_on": "2022-01-06T12:03:19"
} }
} }

View file

@ -317,6 +317,19 @@ Check column "offline" for their availability.
|`hf fido assert `|N |`FIDO2 GetAssertion command.` |`hf fido assert `|N |`FIDO2 GetAssertion command.`
### hf gallagher
{ Gallagher DESFire RFIDs... }
|command |offline |description
|------- |------- |-----------
|`hf gallagher help `|Y |`This help`
|`hf gallagher reader `|N |`Read & decode all Gallagher credentials on a DESFire card`
|`hf gallagher clone `|N |`Add Gallagher credentials to a DESFire card`
|`hf gallagher delete `|N |`Delete Gallagher credentials from a DESFire card`
|`hf gallagher diversifykey`|Y |`Diversify Gallagher key`
### hf ksx6924 ### hf ksx6924
{ KS X 6924 (T-Money, Snapper+) RFIDs } { KS X 6924 (T-Money, Snapper+) RFIDs }