added "hf mf gdmsetcfg" to write GDM configuration

This commit is contained in:
iceman1001 2023-03-26 16:50:59 +02:00
commit 71ddee1386
10 changed files with 197 additions and 32 deletions

View file

@ -3,7 +3,8 @@ All notable changes to this project will be documented in this file.
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
## [unreleased][unreleased]
- Added `hf mf gdmgetblk` - Support Gen4 GDM read configuration block (@iceman1001)
- Added `hf mf gdmsetcfg` - Supprt Gen4 GDM write configuration block (@iceman1001)
- Added `hf mf gdmcfg` - Support Gen4 GDM read configuration block (@iceman1001)
- Changed magic note to include a section about GDM tags (@iceman1001)
- Added `hf mf gdmsetblk` - Support Gen4 GDM write block (@iceman1001)
- Changed `hf 14a info` - detect Gen GDM magic tags (@iceman1001)

View file

@ -1743,6 +1743,14 @@ static void PacketReceived(PacketCommandNG *packet) {
MifareReadConfigBlockGDM(payload->key);
break;
}
case CMD_HF_MIFARE_G4_GDM_WRCFG: {
struct p {
uint8_t data[16];
} PACKED;
struct p *payload = (struct p *) packet->data.asBytes;
MifareWriteConfigBlockGDM(payload->data);
break;
}
case CMD_HF_MIFARE_G4_GDM_WRBL: {
struct p {
uint8_t blockno;

View file

@ -253,7 +253,7 @@ void MifareReadConfigBlockGDM(uint8_t *key) {
goto OUT;
};
if (mifare_classic_readblock_ex(pcs, cuid, 0, outbuf, MIFARE_MAGIC_GDM_READBLOCK)) {
if (mifare_classic_readblock_ex(pcs, cuid, 0, outbuf, MIFARE_MAGIC_GDM_READ_CFG)) {
retval = PM3_ESOFT;
goto OUT;
};
@ -574,6 +574,73 @@ OUT:
BigBuf_free();
}
void MifareWriteConfigBlockGDM(uint8_t *datain) {
int retval = PM3_SUCCESS;
// check args
if (datain == NULL) {
retval = PM3_EINVARG;
goto OUT;
}
uint8_t *par = BigBuf_malloc(MAX_PARITY_SIZE);
if (par == NULL) {
retval = PM3_EMALLOC;
goto OUT;
}
uint8_t *uid = BigBuf_malloc(10);
if (uid == NULL) {
retval = PM3_EMALLOC;
goto OUT;
}
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
clear_trace();
set_tracing(true);
// variables
uint32_t cuid = 0;
struct Crypto1State mpcs = {0, 0};
struct Crypto1State *pcs;
pcs = &mpcs;
if (iso14443a_select_card(uid, NULL, &cuid, true, 0, true) == false) {
retval = PM3_ESOFT;
goto OUT;
}
uint64_t key = 0;
if (mifare_classic_authex_2(pcs, cuid, 0, 0, key, AUTH_FIRST, NULL, NULL, true)) {
retval = PM3_ESOFT;
goto OUT;
};
int res = mifare_classic_write_cfg_block_gdm(pcs, cuid, datain);
if (res == PM3_ETEAROFF) {
retval = PM3_ETEAROFF;
goto OUT;
} else if (res) {
retval = PM3_ESOFT;
goto OUT;
}
if (mifare_classic_halt(pcs, cuid)) {
retval = PM3_ESOFT;
goto OUT;
};
OUT:
crypto1_deinit(pcs);
reply_ng(CMD_HF_MIFARE_G4_GDM_WRCFG, retval, NULL, 0);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
set_tracing(false);
BigBuf_free();
}
void MifareValue(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
// params
@ -2487,7 +2554,7 @@ void MifareCIdent(bool is_mfc) {
uint8_t rats[4] = { ISO14443A_CMD_RATS, 0x80, 0x31, 0x73 };
uint8_t rdblf0[4] = { ISO14443A_CMD_READBLOCK, 0xF0, 0x8D, 0x5f};
uint8_t rdbl00[4] = { ISO14443A_CMD_READBLOCK, 0x00, 0x02, 0xa8};
uint8_t gen4gmd[4] = { MIFARE_MAGIC_GDM_AUTH_KEYA, 0x00, 0x6C, 0x92};
uint8_t gen4gmd[4] = { MIFARE_MAGIC_GDM_AUTH_KEY, 0x00, 0x6C, 0x92};
uint8_t gen4GetConf[8] = { GEN_4GTU_CMD, 0x00, 0x00, 0x00, 0x00, GEN_4GTU_GETCNF, 0, 0};
uint8_t *par = BigBuf_malloc(MAX_PARITY_SIZE);
uint8_t *buf = BigBuf_malloc(PM3_CMD_DATA_SIZE);

View file

@ -60,6 +60,7 @@ void MifareGen3Freez(void); // Gen 3 magic card lock further UID changes
// MFC GEN4 GDM
void MifareReadConfigBlockGDM(uint8_t *key);
void MifareWriteConfigBlockGDM(uint8_t *datain);
void MifareWriteBlockGDM(uint8_t blockno, uint8_t keytype, uint8_t *key, uint8_t *datain);
// MFC GEN4 GTU

View file

@ -142,24 +142,21 @@ int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockN
return mifare_classic_authex_2(pcs, uid, blockNo, keyType, ui64Key, isNested, NULL, NULL, false);
}
int mifare_classic_authex_2(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested, uint32_t *ntptr, uint32_t *timing, bool is_gdm) {
int len;
uint32_t pos, nt, ntpp; // Supplied tag nonce
uint8_t par[1] = {0x00};
// "random" reader nonce:
uint8_t nr[4];
uint8_t mf_nr_ar[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
num_to_bytes(prng_successor(GetTickCount(), 32), 4, nr);
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00};
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = {0x00};
// "random" reader nonce:
num_to_bytes(prng_successor(GetTickCount(), 32), 4, nr);
// Transmit MIFARE_CLASSIC_AUTH 0x60, 0x61 or GDM 0x80
uint8_t cmdbyte = (is_gdm) ? MIFARE_MAGIC_GDM_AUTH_KEYA + (keyType & 0x01) : MIFARE_AUTH_KEYA + (keyType & 0x01);
len = mifare_sendcmd_short(pcs, isNested, cmdbyte, blockNo, receivedAnswer, receivedAnswerPar, timing);
uint8_t cmdbyte = (is_gdm) ? MIFARE_MAGIC_GDM_AUTH_KEY : MIFARE_AUTH_KEYA + (keyType & 0x01);
int len = mifare_sendcmd_short(pcs, isNested, cmdbyte, blockNo, receivedAnswer, receivedAnswerPar, timing);
if (len != 4) return 1;
// Save the tag nonce (nt)
nt = bytes_to_num(receivedAnswer, 4);
uint32_t nt = bytes_to_num(receivedAnswer, 4);
// ----------------------------- crypto1 create
if (isNested)
@ -185,7 +182,9 @@ int mifare_classic_authex_2(struct Crypto1State *pcs, uint32_t uid, uint8_t bloc
*ntptr = nt;
// Generate (encrypted) nr+parity by loading it into the cipher (Nr)
par[0] = 0;
uint32_t pos;
uint8_t par[1] = {0x00};
uint8_t mf_nr_ar[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
for (pos = 0; pos < 4; pos++) {
mf_nr_ar[pos] = crypto1_byte(pcs, nr[pos], 0) ^ nr[pos];
par[0] |= (((filter(pcs->odd) ^ oddparity8(nr[pos])) & 0x01) << (7 - pos));
@ -221,8 +220,8 @@ int mifare_classic_authex_2(struct Crypto1State *pcs, uint32_t uid, uint8_t bloc
return 2;
}
ntpp = prng_successor(nt, 32) ^ crypto1_word(pcs, 0, 0);
// Supplied tag nonce
uint32_t ntpp = prng_successor(nt, 32) ^ crypto1_word(pcs, 0, 0);
if (ntpp != bytes_to_num(receivedAnswer, 4)) {
if (g_dbglevel >= DBG_EXTENDED) Dbprintf("Authentication failed. Error card response");
return 3;
@ -473,6 +472,52 @@ int mifare_classic_writeblock_ex(struct Crypto1State *pcs, uint32_t uid, uint8_t
return 0;
}
int mifare_classic_write_cfg_block_gdm(struct Crypto1State *pcs, uint32_t uid, uint8_t *blockData) {
// variables
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00};
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = {0x00};
uint16_t len = mifare_sendcmd_short(pcs, 1, MIFARE_MAGIC_GDM_WRITE_CFG, 0, receivedAnswer, receivedAnswerPar, NULL);
if ((len != 1) || (receivedAnswer[0] != 0x0A)) {
return 1;
}
uint8_t d_block[18], d_block_enc[18];
memcpy(d_block, blockData, 16);
AddCrc14A(d_block, 16);
// enough for 18 Bytes to send
uint8_t par[3] = {0x00, 0x00, 0x00};
// crypto
for (uint32_t pos = 0; pos < 18; pos++) {
d_block_enc[pos] = crypto1_byte(pcs, 0x00, 0) ^ d_block[pos];
par[pos >> 3] |= (((filter(pcs->odd) ^ oddparity8(d_block[pos])) & 0x01) << (7 - (pos & 0x0007)));
}
ReaderTransmitPar(d_block_enc, sizeof(d_block_enc), par, NULL);
// tearoff occurred
if (tearoff_hook() == PM3_ETEAROFF) {
return PM3_ETEAROFF;
} else {
// Receive the response
len = ReaderReceive(receivedAnswer, receivedAnswerPar);
uint8_t res = 0;
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 0)) << 0;
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 1)) << 1;
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 2)) << 2;
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 3)) << 3;
if ((len != 1) || (res != 0x0A)) {
return 2;
}
}
return 0;
}
int mifare_classic_value(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData, uint8_t action) {
// variables

View file

@ -82,6 +82,7 @@ int mifare_classic_halt_ex(struct Crypto1State *pcs);
int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData);
int mifare_classic_writeblock_ex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData, bool is_gdm);
int mifare_classic_value(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData, uint8_t action);
int mifare_classic_write_cfg_block_gdm(struct Crypto1State *pcs, uint32_t uid, uint8_t *blockData);
// Ultralight/NTAG...
int mifare_ul_ev1_auth(uint8_t *keybytes, uint8_t *pack);

View file

@ -318,18 +318,13 @@ int applyIso14443a(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool i
snprintf(exp, size, "AUTH-B(" _MAGENTA_("%d") ")", cmd[1]);
break;
}
case MIFARE_MAGIC_GDM_AUTH_KEYA: {
case MIFARE_MAGIC_GDM_AUTH_KEY: {
if (cmdsize > 3) {
snprintf(exp, size, "MAGIC AUTH-A(" _MAGENTA_("%d") ")", cmd[1]);
snprintf(exp, size, "MAGIC AUTH (" _MAGENTA_("%d") ")", cmd[1]);
MifareAuthState = masNt;
}
break;
}
case MIFARE_MAGIC_GDM_AUTH_KEYB: {
MifareAuthState = masNt;
snprintf(exp, size, "MAGIC AUTH-B(" _MAGENTA_("%d") ")", cmd[1]);
break;
}
case MIFARE_MAGIC_GDM_WRITEBLOCK: {
snprintf(exp, size, "MAGIC WRITEBLOCK(" _MAGENTA_("%d") ")", cmd[1]);
break;

View file

@ -7574,11 +7574,11 @@ static int CmdHF14AGen4Save(const char *Cmd) {
return PM3_SUCCESS;
}
static int CmdHF14AGen4_GDM_ConfigBlk(const char *Cmd) {
static int CmdHF14AGen4_GDM_Cfg(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mf gdmconfig",
CLIParserInit(&ctx, "hf mf gdmcfg",
"Get configuration data from magic gen4 GDM card.",
"hf mf gdmconfig\n"
"hf mf gdmcfg\n"
);
void *argtable[] = {
arg_param_begin,
@ -7620,6 +7620,52 @@ static int CmdHF14AGen4_GDM_ConfigBlk(const char *Cmd) {
return resp.status;
}
static int CmdHF14AGen4_GDM_SetCfg(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mf gdmsetcfg",
"Set configuration data on a magic gen4 GDM card",
"hf mf gdmsetcfg -d 850000000000000000005A5A00000008"
);
void *argtable[] = {
arg_param_begin,
arg_str1("d", "data", "<hex>", "bytes to write, 16 hex bytes"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
uint8_t block[MFBLOCK_SIZE] = {0x00};
int blen = 0;
CLIGetHexWithReturn(ctx, 1, block, &blen);
CLIParserFree(ctx);
if (blen != MFBLOCK_SIZE) {
PrintAndLogEx(WARNING, "expected %u HEX bytes. got %i", MFBLOCK_SIZE, blen);
return PM3_EINVARG;
}
struct p {
uint8_t data[MFBLOCK_SIZE];
} PACKED payload;
memcpy(payload.data, block, sizeof(payload.data));
clearCommandBuffer();
SendCommandNG(CMD_HF_MIFARE_G4_GDM_WRCFG, (uint8_t *)&payload, sizeof(payload));
PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_HF_MIFARE_G4_GDM_WRCFG, &resp, 1500) == false) {
PrintAndLogEx(WARNING, "command execute timeout");
return PM3_ETIMEOUT;
}
if (resp.status == PM3_SUCCESS) {
PrintAndLogEx(SUCCESS, "Write ( " _GREEN_("ok") " )");
PrintAndLogEx(HINT, "try `" _YELLOW_("hf mf gdmcfg") "` to verify");
} else {
PrintAndLogEx(FAILED, "Write ( " _RED_("fail") " )");
}
return PM3_SUCCESS;
}
static int CmdHF14AGen4_GDM_SetBlk(const char *Cmd) {
CLIParserContext *ctx;
@ -7995,8 +8041,9 @@ static command_t CommandTable[] = {
{"gsetblk", CmdHF14AGen4SetBlk, IfPm3Iso14443a, "Write block to card"},
{"gview", CmdHF14AGen4View, IfPm3Iso14443a, "View card"},
{"-----------", CmdHelp, IfPm3Iso14443a, "-------------------- " _CYAN_("magic gen4 GDM") " --------------------------"},
{"gdmconfig", CmdHF14AGen4_GDM_ConfigBlk, IfPm3Iso14443a, "Read config block from card"},
{"gdmsetblk", CmdHF14AGen4_GDM_SetBlk, IfPm3Iso14443a, "Write block to card"},
{"gdmcfg", CmdHF14AGen4_GDM_Cfg, IfPm3Iso14443a, "Read config block from card"},
{"gdmsetcfg", CmdHF14AGen4_GDM_SetCfg, IfPm3Iso14443a, "Write config block to card"},
{"gdmsetblk", CmdHF14AGen4_GDM_SetBlk, IfPm3Iso14443a, "Write block to card"},
{"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("ndef") " -----------------------"},
// {"ice", CmdHF14AMfice, IfPm3Iso14443a, "collect MIFARE Classic nonces to file"},
{"ndefformat", CmdHFMFNDEFFormat, IfPm3Iso14443a, "Format MIFARE Classic Tag as NFC Tag"},

View file

@ -690,6 +690,7 @@ typedef struct {
#define CMD_HF_MIFARE_G4_GDM_RDBL 0x0870
#define CMD_HF_MIFARE_G4_GDM_WRBL 0x0871
#define CMD_HF_MIFARE_G4_GDM_CONFIG 0x0872
#define CMD_HF_MIFARE_G4_GDM_WRCFG 0x0873
#define CMD_UNKNOWN 0xFFFF

View file

@ -190,11 +190,10 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
#define MIFARE_CMD_RESTORE 0xC2
#define MIFARE_CMD_TRANSFER 0xB0
#define MIFARE_MAGIC_GDM_AUTH_KEYA 0x80
#define MIFARE_MAGIC_GDM_AUTH_KEYB 0x81
#define MIFARE_MAGIC_GDM_AUTH_KEY 0x80
#define MIFARE_MAGIC_GDM_WRITEBLOCK 0xA8
#define MIFARE_MAGIC_GDM_READBLOCK 0xE0
#define MIFARE_MAGIC_GDM_READBLOCK_1 0xE1
#define MIFARE_MAGIC_GDM_READ_CFG 0xE0
#define MIFARE_MAGIC_GDM_WRITE_CFG 0xE1
#define MIFARE_EV1_PERSONAL_UID 0x40
#define MIFARE_EV1_SETMODE 0x43