mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-19 21:03:48 -07:00
added "hf mf gdmsetcfg" to write GDM configuration
This commit is contained in:
parent
82f5c8512d
commit
71ddee1386
10 changed files with 197 additions and 32 deletions
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,7 +8041,8 @@ 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"},
|
||||
{"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"},
|
||||
|
|
|
@ -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…
Add table
Add a link
Reference in a new issue