Skip to content

Commit

Permalink
Merge pull request #329 from tomaspre/Gallagher-selfprog
Browse files Browse the repository at this point in the history
Self-programming support for Gallagher
  • Loading branch information
tomaspre authored May 1, 2023
2 parents 328d4a7 + 727a363 commit 6756802
Show file tree
Hide file tree
Showing 10 changed files with 781 additions and 3 deletions.
54 changes: 54 additions & 0 deletions Doc/DESFireGallagherReadme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Emulating Gallagher on MIFARE DESFire
As of November 2022, Chameleon supports emulation of Gallagher on top of MIFARE DESFire cards. However, there are few limitations.
Namely, only the AES encryption was tested. Other encryption modes (such as 3K tripple DES) may work if written on the Chameleon using a Proxmark or another reader.
They will, however, NOT work when using the commands below.

Mainly, there is now support for Gallagher self-programming using terminal commands. The supported actions are the following:
* Create a new DESFire card with a Gallagher application
* Select a Gallagher application to perform tasks over
* Create a Gallagher application
* Update a Gallagher application
* Update the card ID of a Gallagher application

However, these things are missing:
* Create a standalone Gallagher application directory app (however, it can be created as a part of creating the whole card)
* Changing the site key (the default site key is used)

For performing all the following commands, you first need to select the current slot to appear as a DESFire card. Eg ``CONFIG=MF_DESFIRE_4KEV1``.

## Create a new DESFire card with a Gallagher application (DF_SETUP_GALL)
This command sets up a new Gallagher encoded DESFire card with a single application. This is usually enough to emulate a personal access card.
If you just need a card copy, this is the only Gallagher command you need. If you need to change the UID of the Chameleon, remember to do it before running this command.

The syntax is: ``DF_SETUP_GALL=C<cardNumber>F<facilityId>I<issuieLevel>R<regionCode>`` eg ``DF_SETUP_GALL=C123456F1234I1R2``.

Card ID is a 32bit unsigned integer, facility ID is a 16bit unsigned integer and issue level as well as region code are 8bit unsigned integers.

## Select a Gallagher application to perform tasks over (DF_SEL_GALLAPP)
Selects the AID of the Gallagher app to perform operations over. This is needed for ``DF_CRE_GALLAPP``, ``DF_UP_GALLAPP``, and ``DF_UP_GALL_CID``. You do not need to run this command if you ran ``DF_SETUP_GALL`` previously as the default value is the last app an operation was executed over.

The syntax is: ``DF_SEL_GALLAPP=<AID>`` eg ``DF_SEL_GALLAPP=<A1B2C3>`` or ``DF_SEL_GALLAPP=<000100>``.

The AID has three bytes and all six hexadecimal digits need to be present when running this command.

## Create a Gallagher application (DF_CRE_GALLAPP)
Run ``DF_SEL_GALLAPP`` or ``DF_SETUP_GALL`` first!

This command sets up the Gallagher application only. It does not set up or update the application directory app. The syntax is the same as with ``DF_SETUP_GAL``. If you want to update data in an already existiing application, use ``DF_UP_GALLAPP``.

Warning! You need to set up the Gallagher application directory app yoursef. However, the DESFire card application directory will be updated for you.

## Update a Gallagher application (DF_UP_GALLAPP)
Run ``DF_SEL_GALLAPP`` or ``DF_SETUP_GALL`` first!

This command lets you update the contents of a Gallagher application. The syntax is the same as with ``DF_SETUP_GAL``. If you want to create a new application, use ``DF_CRE_GALLAPP``.

## Update the card ID of a Gallagher application (DF_UP_GALL_CID)
Run ``DF_SEL_GALLAPP`` or ``DF_SETUP_GALL`` first!

This command lets you update the Gallagher card ID of a already existing Gallagher app. The facility ID, region and issue level are taken from the last operation. The AID is either taken from the last app create operation or from ``DF_SEL_GALLAPP``.

The syntax is ``DF_UP_GALL_CIDP=<cardId>``. Eg. ``DF_UP_GALL_CIDP=123456``. The card ID is a 32bit unsigned integer.

## Change the site key (DF_SET_GALLKEY)
This command will return OK WITH TEXT - NOT IMPLEMENTED
10 changes: 7 additions & 3 deletions Firmware/Chameleon-Mini/Application/CryptoCMAC.c
Original file line number Diff line number Diff line change
Expand Up @@ -199,8 +199,12 @@ bool DesfireCMACGenerateSubkeys(uint8_t cryptoType, const uint8_t *keyData, uint
return true;
}

bool DesfireCryptoCMAC(uint8_t cryptoType, const uint8_t *keyData, uint8_t *bufferDataIn, uint16_t bufferSize, uint8_t *IV, uint8_t *cmac){
return DesfireCryptoCMACEx(cryptoType, keyData, bufferDataIn, bufferSize, IV, cmac, 0);
}

//Taken from https://github.com/RfidResearchGroup/proxmark3/blob/master/client/src/mifare/desfirecrypto.c
bool DesfireCryptoCMAC(uint8_t cryptoType, const uint8_t *keyData, uint8_t *bufferDataIn, uint16_t bufferSize, uint8_t *IV, uint8_t *cmac) {
bool DesfireCryptoCMACEx(uint8_t cryptoType, const uint8_t *keyData, uint8_t *bufferDataIn, uint16_t bufferSize, uint8_t *IV, uint8_t *cmac, uint16_t minlen) {
uint8_t kbs;
uint8_t len = bufferSize;
uint8_t * bufferData = bufferDataIn + bufferSize;
Expand All @@ -223,9 +227,9 @@ bool DesfireCryptoCMAC(uint8_t cryptoType, const uint8_t *keyData, uint8_t *buff

DesfireCMACGenerateSubkeys(cryptoType, keyData, sk1, sk2);

if ((!len) || (len % kbs)) {
if ((!len) || (len % kbs) || (len < minlen)) {
bufferData[len++] = 0x80;
while (len % kbs) {
while (len % kbs || len < minlen) {
bufferData[len++] = 0x00;
}
bin_xor(bufferData + len - kbs, sk2, kbs);
Expand Down
1 change: 1 addition & 0 deletions Firmware/Chameleon-Mini/Application/CryptoCMAC.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,6 @@ uint16_t appendBufferMAC(const uint8_t *keyData, uint8_t *bufferData, uint16_t b
bool checkBufferCMAC(uint8_t *bufferData, uint16_t bufferSize, uint16_t checksumSize);

bool DesfireCryptoCMAC(uint8_t cryptoType, const uint8_t *keyData, uint8_t *bufferDataIn, uint16_t bufferSize, uint8_t *IV, uint8_t *cmac);
bool DesfireCryptoCMACEx(uint8_t cryptoType, const uint8_t *keyData, uint8_t *bufferDataIn, uint16_t bufferSize, uint8_t *IV, uint8_t *cmac, uint16_t minlen);

#endif
149 changes: 149 additions & 0 deletions Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ This notice must be retained at the top of all source files where indicated.
/*
* DESFireChameleonTerminal.c
* Maxie D. Schmidt (github.com/maxieds)
*
* Part of this file was added by Tomas Preucil (github.com/tomaspre)
* This part is indicated in the code below
*/

#if defined(CONFIG_MF_DESFIRE_SUPPORT) && !defined(DISABLE_DESFIRE_TERMINAL_COMMANDS)
Expand All @@ -34,6 +37,11 @@ This notice must be retained at the top of all source files where indicated.
#include "DESFirePICCControl.h"
#include "DESFireMemoryOperations.h"
#include "DESFireLogging.h"
#include "DESFireGallagher.h"

#include <inttypes.h>

extern DESFireAidType selectedGallagherAID;

bool IsDESFireConfiguration(void) {
return GlobalSettings.ActiveSettingPtr->Configuration == CONFIG_MF_DESFIRE ||
Expand Down Expand Up @@ -151,6 +159,7 @@ CommandStatusIdType CommandDESFireSetHeaderProperty(char *OutParam, const char *
MemoryStoreDesfireHeaderBytes();
return COMMAND_INFO_OK_ID;
}

#endif /* DISABLE_PERMISSIVE_DESFIRE_SETTINGS */

CommandStatusIdType CommandDESFireSetCommMode(char *OutParam, const char *InParams) {
Expand Down Expand Up @@ -224,4 +233,144 @@ CommandStatusIdType CommandDESFireSetEncryptionMode(char *OutParam, const char *
return COMMAND_INFO_OK;
}

//The rest of the file was added by tomaspre
CommandStatusIdType CommandDESFireSetupGallagher(char *OutMessage, const char *InParams) {
if (!IsDESFireConfiguration()) {
return COMMAND_ERR_INVALID_USAGE_ID;
}

uint32_t cardId = 0xFFFFFFFF;
uint16_t facilityId = 0xFFFF;
uint8_t issueLevel = 0xFF;
uint8_t regionCode = 0xFF;

if (sscanf_P(InParams, PSTR("C%"SCNu32"F%"SCNu16"I%"SCNu8"R%"SCNu8), &cardId, &facilityId, &issueLevel, &regionCode) != 4) {
return COMMAND_ERR_INVALID_PARAM_ID;
}

bool ret = CreateGallagherCard(cardId, facilityId, issueLevel, regionCode);

if (!ret) {
return COMMAND_ERR_INVALID_USAGE_ID;
}

return COMMAND_INFO_OK_ID;
}

CommandStatusIdType CommandDESFireCreateGallagherApp(char *OutMessage, const char *InParams) {
if (!IsDESFireConfiguration()) {
return COMMAND_ERR_INVALID_USAGE_ID;
}

if (selectedGallagherAID[0] == 0xFF && selectedGallagherAID[1] == 0xFF && selectedGallagherAID[2] == 0xFF) {
snprintf_P(OutMessage, TERMINAL_BUFFER_SIZE, PSTR("SET AID FIRST"));
return COMMAND_ERR_INVALID_USAGE_ID;
}

DESFireAidType AID;
uint32_t cardId = 0xFFFFFFFF;
uint16_t facilityId = 0xFFFF;
uint8_t issueLevel = 0xFF;
uint8_t regionCode = 0xFF;

if (sscanf_P(InParams, PSTR("C%"SCNu32"F%"SCNu16"I%"SCNu8"R%"SCNu8),
&cardId, &facilityId, &issueLevel, &regionCode
) != 4) {
return COMMAND_ERR_INVALID_PARAM_ID;
}

bool ret = CreateGallagherAppWithAID(cardId, facilityId, issueLevel, regionCode, selectedGallagherAID);

if (!ret) {
return COMMAND_ERR_INVALID_USAGE_ID;
}

return COMMAND_INFO_OK_ID;
}

CommandStatusIdType CommandDESFireUpdateGallagherApp(char *OutMessage, const char *InParams) {
if (!IsDESFireConfiguration()) {
return COMMAND_ERR_INVALID_USAGE_ID;
}

if (selectedGallagherAID[0] == 0xFF && selectedGallagherAID[1] == 0xFF && selectedGallagherAID[2] == 0xFF) {
snprintf_P(OutMessage, TERMINAL_BUFFER_SIZE, PSTR("SET AID FIRST"));
return COMMAND_ERR_INVALID_USAGE_ID;
}

DESFireAidType AID;
uint32_t cardId = 0xFFFFFFFF;
uint16_t facilityId = 0xFFFF;
uint8_t issueLevel = 0xFF;
uint8_t regionCode = 0xFF;

if (sscanf_P(InParams, PSTR("C%"SCNu32"F%"SCNu16"I%"SCNu8"R%"SCNu8),
&cardId, &facilityId, &issueLevel, &regionCode
) != 4) {
return COMMAND_ERR_INVALID_PARAM_ID;
}

bool ret = UpdateGallagherFile(cardId, facilityId, issueLevel, regionCode, selectedGallagherAID);

if (!ret) {
return COMMAND_ERR_INVALID_USAGE_ID;
}

return COMMAND_INFO_OK_ID;
}

CommandStatusIdType CommandDESFireUpdateGallagherCardId(char *OutMessage, const char *InParams) {
if (!IsDESFireConfiguration()) {
return COMMAND_ERR_INVALID_USAGE_ID;
}

if (selectedGallagherAID[0] == 0xFF && selectedGallagherAID[1] == 0xFF && selectedGallagherAID[2] == 0xFF) {
snprintf_P(OutMessage, TERMINAL_BUFFER_SIZE, PSTR("SET AID FIRST"));
return COMMAND_ERR_INVALID_USAGE_ID;
}

uint32_t cardId;

if (sscanf_P(InParams, PSTR("%"SCNu32), &cardId) != 1) {
return COMMAND_ERR_INVALID_PARAM_ID;
}

bool ret = UpdateGallagherAppCardID(cardId);

if (!ret) {
return COMMAND_ERR_INVALID_USAGE_ID;
}

return COMMAND_INFO_OK_ID;
}

CommandStatusIdType CommandDESFireSelectGallagherApp(char *OutMessage, const char *InParams) {
if (!IsDESFireConfiguration()) {
return COMMAND_ERR_INVALID_USAGE_ID;
}

DESFireAidType AID;

if (sscanf_P(InParams, PSTR("%2"SCNx8"%2"SCNx8"%2"SCNx8),
&AID[0], &AID[1], &AID[2]) != 3) {
return COMMAND_ERR_INVALID_PARAM_ID;
}

SelectGallagherAID(AID);

return COMMAND_INFO_OK_ID;
}

CommandStatusIdType CommandDESFireSetGallagherSiteKey(char *OutMessage, const char *InParams) {
if (!IsDESFireConfiguration()) {
return COMMAND_ERR_INVALID_USAGE_ID;
}

//Use the SetGallagherSiteKey and ResetGallagherSiteKey fucntions

snprintf_P(OutMessage, TERMINAL_BUFFER_SIZE, PSTR("NOT IMPLEMENTED"));
return COMMAND_INFO_OK_WITH_TEXT_ID;
}

#endif /* CONFIG_MF_DESFIRE_SUPPORT */

Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ This notice must be retained at the top of all source files where indicated.
/*
* DESFireChameleonTerminal.h
* Maxie D. Schmidt (github.com/maxieds)
*
* Part of this file was added by Tomas Preucil (github.com/tomaspre)
* This part is indicated in the code below
*/

#ifndef __DESFIRE_CHAMELEON_TERMINAL_H__
Expand All @@ -47,6 +50,25 @@ CommandStatusIdType CommandDESFireSetCommMode(char *OutMessage, const char *InPa
#define DFCOMMAND_SET_ENCMODE "DF_ENCMODE"
CommandStatusIdType CommandDESFireSetEncryptionMode(char *OutMessage, const char *InParams);

//The rest of the file was added by tomaspre
#define DFCOMMAND_SETUP_GALLAGHER "DF_SETUP_GALL"
CommandStatusIdType CommandDESFireSetupGallagher(char *OutMessage, const char *InParams);

#define DFCOMMAND_CREATE_GALLAGHER_APP "DF_CRE_GALLAPP"
CommandStatusIdType CommandDESFireCreateGallagherApp(char *OutMessage, const char *InParams);

#define DFCOMMAND_UPDATE_GALLAGHER_APP "DF_UP_GALLAPP"
CommandStatusIdType CommandDESFireUpdateGallagherApp(char *OutMessage, const char *InParams);

#define DFCOMMAND_UPDATE_GALLAGHER_CARD_ID "DF_UP_GALL_CID"
CommandStatusIdType CommandDESFireUpdateGallagherCardId(char *OutMessage, const char *InParams);

#define DFCOMMAND_SELECT_GALLAGHER_APP "DF_SEL_GALLAPP"
CommandStatusIdType CommandDESFireSelectGallagherApp(char *OutMessage, const char *InParams);

#define DFCOMMAND_SET_GALLAGHER_SITE_KEY "DF_SET_GALLKEY"
CommandStatusIdType CommandDESFireSetGallagherSiteKey(char *OutMessage, const char *InParams);

#endif /* DESFire Support */

#endif /* __DESFIRE_CHAMELEON_TERMINAL_H__ */
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ This notice must be retained at the top of all source files where indicated.
/*
* DESFireChameleonTerminalInclude.c
* Maxie D. Schmidt (github.com/maxieds)
*
* Part of this file was added by Tomas Preucil (github.com/tomaspre)
* This part is indicated in the code below
*/

#ifdef CONFIG_MF_DESFIRE_SUPPORT
Expand All @@ -46,8 +49,46 @@ This notice must be retained at the top of all source files where indicated.
.ExecParamFunc = NO_FUNCTION,
.SetFunc = CommandDESFireSetEncryptionMode,
.GetFunc = NO_FUNCTION
}, {//The rest of the file was added by tomaspre
.Command = DFCOMMAND_SETUP_GALLAGHER,
.ExecFunc = NO_FUNCTION,
.ExecParamFunc = NO_FUNCTION,
.SetFunc = CommandDESFireSetupGallagher,
.GetFunc = NO_FUNCTION
}, {
.Command = DFCOMMAND_CREATE_GALLAGHER_APP,
.ExecFunc = NO_FUNCTION,
.ExecParamFunc = NO_FUNCTION,
.SetFunc = CommandDESFireCreateGallagherApp,
.GetFunc = NO_FUNCTION
}, {
.Command = DFCOMMAND_UPDATE_GALLAGHER_APP,
.ExecFunc = NO_FUNCTION,
.ExecParamFunc = NO_FUNCTION,
.SetFunc = CommandDESFireUpdateGallagherApp,
.GetFunc = NO_FUNCTION
}, {
.Command = DFCOMMAND_UPDATE_GALLAGHER_CARD_ID,
.ExecFunc = NO_FUNCTION,
.ExecParamFunc = NO_FUNCTION,
.SetFunc = CommandDESFireUpdateGallagherCardId,
.GetFunc = NO_FUNCTION
}, {
.Command = DFCOMMAND_SELECT_GALLAGHER_APP,
.ExecFunc = NO_FUNCTION,
.ExecParamFunc = NO_FUNCTION,
.SetFunc = CommandDESFireSelectGallagherApp,
.GetFunc = NO_FUNCTION
}, {
.Command = DFCOMMAND_SET_GALLAGHER_SITE_KEY,
.ExecFunc = NO_FUNCTION,
.ExecParamFunc = NO_FUNCTION,
.SetFunc = CommandDESFireSetGallagherSiteKey,
.GetFunc = NO_FUNCTION
},



#endif

#endif /* CONFIG_MF_DESFIRE_SUPPORT */
Loading

0 comments on commit 6756802

Please sign in to comment.