mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2024-12-31 04:39:49 +08:00
Merge branch 'master' into mf-supercard
Signed-off-by: AloneLiberty <111039319+AloneLiberty@users.noreply.github.com>
This commit is contained in:
commit
f3a3707c06
11 changed files with 282 additions and 91 deletions
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,6 +7853,8 @@ 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 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") " )");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8077,8 +8138,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"},
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue