diff --git a/CHANGELOG.md b/CHANGELOG.md index ba2423d8f..8d12c6e25 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 969513d39..6901973f2 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -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; diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index 39aa166b8..feabf15a1 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -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); diff --git a/armsrc/mifarecmd.h b/armsrc/mifarecmd.h index 6363423fd..415e0333d 100644 --- a/armsrc/mifarecmd.h +++ b/armsrc/mifarecmd.h @@ -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 diff --git a/armsrc/mifareutil.c b/armsrc/mifareutil.c index 11009031b..b11625339 100644 --- a/armsrc/mifareutil.c +++ b/armsrc/mifareutil.c @@ -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 diff --git a/armsrc/mifareutil.h b/armsrc/mifareutil.h index bcc813d00..e5731ce36 100644 --- a/armsrc/mifareutil.h +++ b/armsrc/mifareutil.h @@ -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); diff --git a/client/src/cmdhflist.c b/client/src/cmdhflist.c index 263a4baa1..7207e50f9 100644 --- a/client/src/cmdhflist.c +++ b/client/src/cmdhflist.c @@ -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; diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c index 7c8c7235f..5aede7d00 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -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", "", "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"}, diff --git a/doc/magic_cards_notes.md b/doc/magic_cards_notes.md index 2d4cd259c..1b94dd5ba 100644 --- a/doc/magic_cards_notes.md +++ b/doc/magic_cards_notes.md @@ -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 diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index b99bb8430..7a19e6dbe 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -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 diff --git a/include/protocols.h b/include/protocols.h index 54a8ba446..f67ae1798 100644 --- a/include/protocols.h +++ b/include/protocols.h @@ -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