Merge branch 'master' into mf-supercard

Signed-off-by: AloneLiberty <111039319+AloneLiberty@users.noreply.github.com>
This commit is contained in:
AloneLiberty 2023-03-26 14:58:33 +00:00 committed by GitHub
commit f3a3707c06
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 282 additions and 91 deletions

View file

@ -4,7 +4,8 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
## [unreleased][unreleased]
- Changed `hf mf supercard` - Support editing UID and recovery of keys from second generation card (@AloneLiberty)
- 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;
};
@ -453,7 +453,6 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
memcpy(blockdata, datain + 10, 16);
// variables
uint8_t isOK = 0;
uint8_t uid[10] = {0x00};
uint32_t cuid = 0;
struct Crypto1State mpcs = {0, 0};
@ -469,37 +468,39 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
LED_B_OFF();
LED_C_OFF();
while (true) {
if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Can't select card");
break;
};
uint8_t retval = 0;
if (mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Auth error");
break;
};
if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Can't select card");
goto OUT;
};
if (mifare_classic_writeblock(pcs, cuid, blockNo, blockdata)) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Write block error");
break;
};
if (mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Auth error");
goto OUT;
};
if (mifare_classic_halt(pcs, cuid)) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Halt error");
break;
};
isOK = 1;
break;
int res = mifare_classic_writeblock(pcs, cuid, blockNo, blockdata);
if (res == PM3_ETEAROFF) {
retval = PM3_ETEAROFF;
goto OUT;
} else if (res) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Write block error");
retval = PM3_ESOFT;
goto OUT;
}
if (mifare_classic_halt(pcs, cuid)) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Halt error");
goto OUT;
};
retval = 1;
OUT:
crypto1_deinit(pcs);
if (g_dbglevel >= 2) DbpString("WRITE BLOCK FINISHED");
reply_mix(CMD_ACK, isOK, 0, 0, 0, 0);
reply_mix(CMD_ACK, retval, 0, 0, 0, 0);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
set_tracing(false);
@ -549,18 +550,20 @@ void MifareWriteBlockGDM(uint8_t blockno, uint8_t keytype, uint8_t *key, uint8_t
goto OUT;
};
if (mifare_classic_writeblock_ex(pcs, cuid, blockno, datain, true)) {
int res = mifare_classic_writeblock_ex(pcs, cuid, blockno, datain, true);
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;
};
if (g_dbglevel >= 2) DbpString("WRITE BLOCK FINISHED");
OUT:
crypto1_deinit(pcs);
@ -571,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
@ -2484,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 superGen1[9] = {0x0A, 0x00, 0x00, 0xA6, 0xB0, 0x00, 0x10, 0x14, 0x1D};
uint8_t *par = BigBuf_malloc(MAX_PARITY_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

@ -18,6 +18,7 @@
//-----------------------------------------------------------------------------
#include "mifareutil.h"
#include "appmain.h" // tearoff hook
#include "string.h"
#include "BigBuf.h"
#include "iso14443a.h"
@ -141,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)
@ -184,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));
@ -220,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;
@ -451,22 +451,73 @@ int mifare_classic_writeblock_ex(struct Crypto1State *pcs, uint32_t uid, uint8_t
ReaderTransmitPar(d_block_enc, sizeof(d_block_enc), par, NULL);
// Receive the response
len = ReaderReceive(receivedAnswer, receivedAnswerPar);
// 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;
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)) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd send data2 Error: %02x", res);
return 2;
if ((len != 1) || (res != 0x0A)) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd send data2 Error: %02x", res);
return 2;
}
}
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

@ -628,10 +628,12 @@ static int CmdHF14AMfWrBl(const char *Cmd) {
return PM3_ETIMEOUT;
}
uint8_t isok = resp.oldarg[0] & 0xff;
if (isok) {
int status = resp.oldarg[0];
if (status) {
PrintAndLogEx(SUCCESS, "Write ( " _GREEN_("ok") " )");
PrintAndLogEx(HINT, "try `" _YELLOW_("hf mf rdbl") "` to verify");
} else if (status == PM3_ETEAROFF) {
return status;
} else {
PrintAndLogEx(FAILED, "Write ( " _RED_("fail") " )");
// suggest the opposite keytype than what was used.
@ -7669,11 +7671,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,
@ -7715,6 +7717,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;
@ -7805,7 +7853,9 @@ static int CmdHF14AGen4_GDM_SetBlk(const char *Cmd) {
if (resp.status == PM3_SUCCESS) {
PrintAndLogEx(SUCCESS, "Write ( " _GREEN_("ok") " )");
PrintAndLogEx(HINT, "try `" _YELLOW_("hf mf rdbl") "` to verify");
} else {
} else if (resp.status == PM3_ETEAROFF) {
return resp.status;
} else {
PrintAndLogEx(FAILED, "Write ( " _RED_("fail") " )");
PrintAndLogEx(HINT, "Maybe access rights? Try specify keytype `" _YELLOW_("hf mf gdmsetblk -%c ...") "` instead", (keytype == MF_KEY_A) ? 'b' : 'a');
}
@ -7928,7 +7978,7 @@ static int CmdHF14AMfValue(const char *Cmd) {
}
if (action < 3) {
uint8_t isok = true;
if (g_session.pm3_present == false)
return PM3_ENOTTY;
@ -7955,7 +8005,15 @@ static int CmdHF14AMfValue(const char *Cmd) {
PrintAndLogEx(FAILED, "Command execute timeout");
return PM3_ETIMEOUT;
}
isok = resp.oldarg[0] & 0xff;
if (resp.oldarg[0] & 0xFF) {
// all ok so set flag to read current value
getval = true;
PrintAndLogEx(SUCCESS, "Update ( " _GREEN_("success") " )");
} else {
PrintAndLogEx(FAILED, "Update ( " _RED_("failed") " )");
}
} else { // set value
// To set a value block (or setup) we can use the normal mifare classic write block
// So build the command options can call CMD_HF_MIFARE_WRITEBL
@ -7980,14 +8038,17 @@ static int CmdHF14AMfValue(const char *Cmd) {
PrintAndLogEx(FAILED, "Command execute timeout");
return PM3_ETIMEOUT;
}
isok = resp.oldarg[0] & 0xff;
}
if (isok) {
PrintAndLogEx(SUCCESS, "Update ... : " _GREEN_("success"));
getval = true; // all ok so set flag to read current value
} else {
PrintAndLogEx(FAILED, "Update ... : " _RED_("failed"));
int status = resp.oldarg[0];
if (status) {
// all ok so set flag to read current value
getval = true;
PrintAndLogEx(SUCCESS, "Update ( " _GREEN_("success") " )");
} else if (status == PM3_ETEAROFF) {
// all ok so set flag to read current value
getval = true;
} else {
PrintAndLogEx(FAILED, "Update ( " _RED_("failed") " )");
}
}
}
@ -8076,9 +8137,10 @@ static command_t CommandTable[] = {
{"gsave", CmdHF14AGen4Save, IfPm3Iso14443a, "Save dump from card into file or emulator"},
{"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"},
{"-----------", CmdHelp, IfPm3Iso14443a, "-------------------- " _CYAN_("magic gen4 GDM") " --------------------------"},
{"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

@ -537,7 +537,7 @@ for example to write, you must use a customer authentication byte, 0x80, to aut
Then send the data to be written.
This tag has simular commands to the [UFUID](#mifare-classic-directwrite-ufuid-version)
It seems to be developed by the same person.
This indicates that both tagtypes are developed by the same person.
**OBS**
@ -560,8 +560,8 @@ hf 14a info
* Auth: `80xx`+crc
* Write: `A8xx`+crc, `xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`+crc
* Read config: `E000`+crc (unidentified)
* Write config: `E100`+crc
* Read config: `E000`+crc
* Write config: `E100`+crc, `xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`+crc
### Characteristics
^[Top](#top)
@ -598,9 +598,11 @@ It is unknown what kind of block 0 changes the tag supports
# Write to persistent memory
hf mf gdmsetblk
# Read 0xE0 configuration:
hf mf gdmconfig
# Read configuration (0xE0):
hf mf gdmcfg
# Write configuration (0xE1):
hf mf gdmsetcfg
```
### libnfc commands
@ -612,7 +614,7 @@ No implemented commands today
**TODO**
* ZXUID, EUID, ICUID ?
* ZXUID, EUID, ICUID, KUID, HUID, RFUID ?
* Some cards exhibit a specific SAK=28 ??
## MIFARE Classic Super

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