mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-20 13:23:51 -07: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]
|
## [unreleased][unreleased]
|
||||||
- Changed `hf mf supercard` - Support editing UID and recovery of keys from second generation card (@AloneLiberty)
|
- 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)
|
- Changed magic note to include a section about GDM tags (@iceman1001)
|
||||||
- Added `hf mf gdmsetblk` - Support Gen4 GDM write block (@iceman1001)
|
- Added `hf mf gdmsetblk` - Support Gen4 GDM write block (@iceman1001)
|
||||||
- Changed `hf 14a info` - detect Gen GDM magic tags (@iceman1001)
|
- Changed `hf 14a info` - detect Gen GDM magic tags (@iceman1001)
|
||||||
|
|
|
@ -1743,6 +1743,14 @@ static void PacketReceived(PacketCommandNG *packet) {
|
||||||
MifareReadConfigBlockGDM(payload->key);
|
MifareReadConfigBlockGDM(payload->key);
|
||||||
break;
|
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: {
|
case CMD_HF_MIFARE_G4_GDM_WRBL: {
|
||||||
struct p {
|
struct p {
|
||||||
uint8_t blockno;
|
uint8_t blockno;
|
||||||
|
|
|
@ -253,7 +253,7 @@ void MifareReadConfigBlockGDM(uint8_t *key) {
|
||||||
goto OUT;
|
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;
|
retval = PM3_ESOFT;
|
||||||
goto OUT;
|
goto OUT;
|
||||||
};
|
};
|
||||||
|
@ -453,7 +453,6 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
|
||||||
memcpy(blockdata, datain + 10, 16);
|
memcpy(blockdata, datain + 10, 16);
|
||||||
|
|
||||||
// variables
|
// variables
|
||||||
uint8_t isOK = 0;
|
|
||||||
uint8_t uid[10] = {0x00};
|
uint8_t uid[10] = {0x00};
|
||||||
uint32_t cuid = 0;
|
uint32_t cuid = 0;
|
||||||
struct Crypto1State mpcs = {0, 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_B_OFF();
|
||||||
LED_C_OFF();
|
LED_C_OFF();
|
||||||
|
|
||||||
while (true) {
|
uint8_t retval = 0;
|
||||||
if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
|
|
||||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("Can't select card");
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) {
|
if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
|
||||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("Auth error");
|
if (g_dbglevel >= DBG_ERROR) Dbprintf("Can't select card");
|
||||||
break;
|
goto OUT;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (mifare_classic_writeblock(pcs, cuid, blockNo, blockdata)) {
|
if (mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) {
|
||||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("Write block error");
|
if (g_dbglevel >= DBG_ERROR) Dbprintf("Auth error");
|
||||||
break;
|
goto OUT;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (mifare_classic_halt(pcs, cuid)) {
|
int res = mifare_classic_writeblock(pcs, cuid, blockNo, blockdata);
|
||||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("Halt error");
|
if (res == PM3_ETEAROFF) {
|
||||||
break;
|
retval = PM3_ETEAROFF;
|
||||||
};
|
goto OUT;
|
||||||
|
} else if (res) {
|
||||||
isOK = 1;
|
if (g_dbglevel >= DBG_ERROR) Dbprintf("Write block error");
|
||||||
break;
|
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);
|
crypto1_deinit(pcs);
|
||||||
|
|
||||||
if (g_dbglevel >= 2) DbpString("WRITE BLOCK FINISHED");
|
reply_mix(CMD_ACK, retval, 0, 0, 0, 0);
|
||||||
|
|
||||||
reply_mix(CMD_ACK, isOK, 0, 0, 0, 0);
|
|
||||||
|
|
||||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||||
LEDsoff();
|
LEDsoff();
|
||||||
set_tracing(false);
|
set_tracing(false);
|
||||||
|
@ -549,18 +550,20 @@ void MifareWriteBlockGDM(uint8_t blockno, uint8_t keytype, uint8_t *key, uint8_t
|
||||||
goto OUT;
|
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;
|
retval = PM3_ESOFT;
|
||||||
goto OUT;
|
goto OUT;
|
||||||
};
|
}
|
||||||
|
|
||||||
if (mifare_classic_halt(pcs, cuid)) {
|
if (mifare_classic_halt(pcs, cuid)) {
|
||||||
retval = PM3_ESOFT;
|
retval = PM3_ESOFT;
|
||||||
goto OUT;
|
goto OUT;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (g_dbglevel >= 2) DbpString("WRITE BLOCK FINISHED");
|
|
||||||
|
|
||||||
OUT:
|
OUT:
|
||||||
crypto1_deinit(pcs);
|
crypto1_deinit(pcs);
|
||||||
|
|
||||||
|
@ -571,6 +574,73 @@ OUT:
|
||||||
BigBuf_free();
|
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) {
|
void MifareValue(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
|
||||||
// params
|
// params
|
||||||
|
@ -2484,7 +2554,7 @@ void MifareCIdent(bool is_mfc) {
|
||||||
uint8_t rats[4] = {ISO14443A_CMD_RATS, 0x80, 0x31, 0x73};
|
uint8_t rats[4] = {ISO14443A_CMD_RATS, 0x80, 0x31, 0x73};
|
||||||
uint8_t rdblf0[4] = {ISO14443A_CMD_READBLOCK, 0xF0, 0x8D, 0x5f};
|
uint8_t rdblf0[4] = {ISO14443A_CMD_READBLOCK, 0xF0, 0x8D, 0x5f};
|
||||||
uint8_t rdbl00[4] = {ISO14443A_CMD_READBLOCK, 0x00, 0x02, 0xa8};
|
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 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 superGen1[9] = {0x0A, 0x00, 0x00, 0xA6, 0xB0, 0x00, 0x10, 0x14, 0x1D};
|
||||||
uint8_t *par = BigBuf_malloc(MAX_PARITY_SIZE);
|
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
|
// MFC GEN4 GDM
|
||||||
void MifareReadConfigBlockGDM(uint8_t *key);
|
void MifareReadConfigBlockGDM(uint8_t *key);
|
||||||
|
void MifareWriteConfigBlockGDM(uint8_t *datain);
|
||||||
void MifareWriteBlockGDM(uint8_t blockno, uint8_t keytype, uint8_t *key, uint8_t *datain);
|
void MifareWriteBlockGDM(uint8_t blockno, uint8_t keytype, uint8_t *key, uint8_t *datain);
|
||||||
|
|
||||||
// MFC GEN4 GTU
|
// MFC GEN4 GTU
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
#include "mifareutil.h"
|
#include "mifareutil.h"
|
||||||
|
|
||||||
|
#include "appmain.h" // tearoff hook
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
#include "BigBuf.h"
|
#include "BigBuf.h"
|
||||||
#include "iso14443a.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);
|
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 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
|
// "random" reader nonce:
|
||||||
uint8_t par[1] = {0x00};
|
|
||||||
uint8_t nr[4];
|
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 receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00};
|
||||||
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_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
|
// 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);
|
uint8_t cmdbyte = (is_gdm) ? MIFARE_MAGIC_GDM_AUTH_KEY : MIFARE_AUTH_KEYA + (keyType & 0x01);
|
||||||
len = mifare_sendcmd_short(pcs, isNested, cmdbyte, blockNo, receivedAnswer, receivedAnswerPar, timing);
|
int len = mifare_sendcmd_short(pcs, isNested, cmdbyte, blockNo, receivedAnswer, receivedAnswerPar, timing);
|
||||||
if (len != 4) return 1;
|
if (len != 4) return 1;
|
||||||
|
|
||||||
// Save the tag nonce (nt)
|
// Save the tag nonce (nt)
|
||||||
nt = bytes_to_num(receivedAnswer, 4);
|
uint32_t nt = bytes_to_num(receivedAnswer, 4);
|
||||||
|
|
||||||
// ----------------------------- crypto1 create
|
// ----------------------------- crypto1 create
|
||||||
if (isNested)
|
if (isNested)
|
||||||
|
@ -184,7 +182,9 @@ int mifare_classic_authex_2(struct Crypto1State *pcs, uint32_t uid, uint8_t bloc
|
||||||
*ntptr = nt;
|
*ntptr = nt;
|
||||||
|
|
||||||
// Generate (encrypted) nr+parity by loading it into the cipher (Nr)
|
// 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++) {
|
for (pos = 0; pos < 4; pos++) {
|
||||||
mf_nr_ar[pos] = crypto1_byte(pcs, nr[pos], 0) ^ nr[pos];
|
mf_nr_ar[pos] = crypto1_byte(pcs, nr[pos], 0) ^ nr[pos];
|
||||||
par[0] |= (((filter(pcs->odd) ^ oddparity8(nr[pos])) & 0x01) << (7 - 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;
|
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 (ntpp != bytes_to_num(receivedAnswer, 4)) {
|
||||||
if (g_dbglevel >= DBG_EXTENDED) Dbprintf("Authentication failed. Error card response");
|
if (g_dbglevel >= DBG_EXTENDED) Dbprintf("Authentication failed. Error card response");
|
||||||
return 3;
|
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);
|
ReaderTransmitPar(d_block_enc, sizeof(d_block_enc), par, NULL);
|
||||||
|
|
||||||
// Receive the response
|
// tearoff occurred
|
||||||
len = ReaderReceive(receivedAnswer, receivedAnswerPar);
|
if (tearoff_hook() == PM3_ETEAROFF) {
|
||||||
|
return PM3_ETEAROFF;
|
||||||
|
} else {
|
||||||
|
// Receive the response
|
||||||
|
len = ReaderReceive(receivedAnswer, receivedAnswerPar);
|
||||||
|
|
||||||
uint8_t res = 0;
|
uint8_t res = 0;
|
||||||
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 0)) << 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], 1)) << 1;
|
||||||
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 2)) << 2;
|
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 2)) << 2;
|
||||||
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 3)) << 3;
|
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 3)) << 3;
|
||||||
|
|
||||||
if ((len != 1) || (res != 0x0A)) {
|
if ((len != 1) || (res != 0x0A)) {
|
||||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd send data2 Error: %02x", res);
|
if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd send data2 Error: %02x", res);
|
||||||
return 2;
|
return 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
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) {
|
int mifare_classic_value(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData, uint8_t action) {
|
||||||
// variables
|
// 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(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_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_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...
|
// Ultralight/NTAG...
|
||||||
int mifare_ul_ev1_auth(uint8_t *keybytes, uint8_t *pack);
|
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]);
|
snprintf(exp, size, "AUTH-B(" _MAGENTA_("%d") ")", cmd[1]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MIFARE_MAGIC_GDM_AUTH_KEYA: {
|
case MIFARE_MAGIC_GDM_AUTH_KEY: {
|
||||||
if (cmdsize > 3) {
|
if (cmdsize > 3) {
|
||||||
snprintf(exp, size, "MAGIC AUTH-A(" _MAGENTA_("%d") ")", cmd[1]);
|
snprintf(exp, size, "MAGIC AUTH (" _MAGENTA_("%d") ")", cmd[1]);
|
||||||
MifareAuthState = masNt;
|
MifareAuthState = masNt;
|
||||||
}
|
}
|
||||||
break;
|
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: {
|
case MIFARE_MAGIC_GDM_WRITEBLOCK: {
|
||||||
snprintf(exp, size, "MAGIC WRITEBLOCK(" _MAGENTA_("%d") ")", cmd[1]);
|
snprintf(exp, size, "MAGIC WRITEBLOCK(" _MAGENTA_("%d") ")", cmd[1]);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -628,10 +628,12 @@ static int CmdHF14AMfWrBl(const char *Cmd) {
|
||||||
return PM3_ETIMEOUT;
|
return PM3_ETIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t isok = resp.oldarg[0] & 0xff;
|
int status = resp.oldarg[0];
|
||||||
if (isok) {
|
if (status) {
|
||||||
PrintAndLogEx(SUCCESS, "Write ( " _GREEN_("ok") " )");
|
PrintAndLogEx(SUCCESS, "Write ( " _GREEN_("ok") " )");
|
||||||
PrintAndLogEx(HINT, "try `" _YELLOW_("hf mf rdbl") "` to verify");
|
PrintAndLogEx(HINT, "try `" _YELLOW_("hf mf rdbl") "` to verify");
|
||||||
|
} else if (status == PM3_ETEAROFF) {
|
||||||
|
return status;
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(FAILED, "Write ( " _RED_("fail") " )");
|
PrintAndLogEx(FAILED, "Write ( " _RED_("fail") " )");
|
||||||
// suggest the opposite keytype than what was used.
|
// suggest the opposite keytype than what was used.
|
||||||
|
@ -7669,11 +7671,11 @@ static int CmdHF14AGen4Save(const char *Cmd) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int CmdHF14AGen4_GDM_ConfigBlk(const char *Cmd) {
|
static int CmdHF14AGen4_GDM_Cfg(const char *Cmd) {
|
||||||
CLIParserContext *ctx;
|
CLIParserContext *ctx;
|
||||||
CLIParserInit(&ctx, "hf mf gdmconfig",
|
CLIParserInit(&ctx, "hf mf gdmcfg",
|
||||||
"Get configuration data from magic gen4 GDM card.",
|
"Get configuration data from magic gen4 GDM card.",
|
||||||
"hf mf gdmconfig\n"
|
"hf mf gdmcfg\n"
|
||||||
);
|
);
|
||||||
void *argtable[] = {
|
void *argtable[] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
|
@ -7715,6 +7717,52 @@ static int CmdHF14AGen4_GDM_ConfigBlk(const char *Cmd) {
|
||||||
return resp.status;
|
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) {
|
static int CmdHF14AGen4_GDM_SetBlk(const char *Cmd) {
|
||||||
|
|
||||||
CLIParserContext *ctx;
|
CLIParserContext *ctx;
|
||||||
|
@ -7805,6 +7853,8 @@ static int CmdHF14AGen4_GDM_SetBlk(const char *Cmd) {
|
||||||
if (resp.status == PM3_SUCCESS) {
|
if (resp.status == PM3_SUCCESS) {
|
||||||
PrintAndLogEx(SUCCESS, "Write ( " _GREEN_("ok") " )");
|
PrintAndLogEx(SUCCESS, "Write ( " _GREEN_("ok") " )");
|
||||||
PrintAndLogEx(HINT, "try `" _YELLOW_("hf mf rdbl") "` to verify");
|
PrintAndLogEx(HINT, "try `" _YELLOW_("hf mf rdbl") "` to verify");
|
||||||
|
} else if (resp.status == PM3_ETEAROFF) {
|
||||||
|
return resp.status;
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(FAILED, "Write ( " _RED_("fail") " )");
|
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');
|
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) {
|
if (action < 3) {
|
||||||
uint8_t isok = true;
|
|
||||||
if (g_session.pm3_present == false)
|
if (g_session.pm3_present == false)
|
||||||
return PM3_ENOTTY;
|
return PM3_ENOTTY;
|
||||||
|
|
||||||
|
@ -7955,7 +8005,15 @@ static int CmdHF14AMfValue(const char *Cmd) {
|
||||||
PrintAndLogEx(FAILED, "Command execute timeout");
|
PrintAndLogEx(FAILED, "Command execute timeout");
|
||||||
return PM3_ETIMEOUT;
|
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
|
} else { // set value
|
||||||
// To set a value block (or setup) we can use the normal mifare classic write block
|
// 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
|
// 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");
|
PrintAndLogEx(FAILED, "Command execute timeout");
|
||||||
return PM3_ETIMEOUT;
|
return PM3_ETIMEOUT;
|
||||||
}
|
}
|
||||||
isok = resp.oldarg[0] & 0xff;
|
int status = resp.oldarg[0];
|
||||||
}
|
if (status) {
|
||||||
|
// all ok so set flag to read current value
|
||||||
if (isok) {
|
getval = true;
|
||||||
PrintAndLogEx(SUCCESS, "Update ... : " _GREEN_("success"));
|
PrintAndLogEx(SUCCESS, "Update ( " _GREEN_("success") " )");
|
||||||
getval = true; // all ok so set flag to read current value
|
} else if (status == PM3_ETEAROFF) {
|
||||||
} else {
|
// all ok so set flag to read current value
|
||||||
PrintAndLogEx(FAILED, "Update ... : " _RED_("failed"));
|
getval = true;
|
||||||
|
} else {
|
||||||
|
PrintAndLogEx(FAILED, "Update ( " _RED_("failed") " )");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8077,8 +8138,9 @@ static command_t CommandTable[] = {
|
||||||
{"gsetblk", CmdHF14AGen4SetBlk, IfPm3Iso14443a, "Write block to card"},
|
{"gsetblk", CmdHF14AGen4SetBlk, IfPm3Iso14443a, "Write block to card"},
|
||||||
{"gview", CmdHF14AGen4View, IfPm3Iso14443a, "View card"},
|
{"gview", CmdHF14AGen4View, IfPm3Iso14443a, "View card"},
|
||||||
{"-----------", CmdHelp, IfPm3Iso14443a, "-------------------- " _CYAN_("magic gen4 GDM") " --------------------------"},
|
{"-----------", 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"},
|
||||||
{"gdmsetblk", CmdHF14AGen4_GDM_SetBlk, IfPm3Iso14443a, "Write block to card"},
|
{"gdmsetcfg", CmdHF14AGen4_GDM_SetCfg, IfPm3Iso14443a, "Write config block to card"},
|
||||||
|
{"gdmsetblk", CmdHF14AGen4_GDM_SetBlk, IfPm3Iso14443a, "Write block to card"},
|
||||||
{"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("ndef") " -----------------------"},
|
{"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("ndef") " -----------------------"},
|
||||||
// {"ice", CmdHF14AMfice, IfPm3Iso14443a, "collect MIFARE Classic nonces to file"},
|
// {"ice", CmdHF14AMfice, IfPm3Iso14443a, "collect MIFARE Classic nonces to file"},
|
||||||
{"ndefformat", CmdHFMFNDEFFormat, IfPm3Iso14443a, "Format MIFARE Classic Tag as NFC Tag"},
|
{"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.
|
Then send the data to be written.
|
||||||
|
|
||||||
This tag has simular commands to the [UFUID](#mifare-classic-directwrite-ufuid-version)
|
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**
|
**OBS**
|
||||||
|
|
||||||
|
@ -560,8 +560,8 @@ hf 14a info
|
||||||
|
|
||||||
* Auth: `80xx`+crc
|
* Auth: `80xx`+crc
|
||||||
* Write: `A8xx`+crc, `xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`+crc
|
* Write: `A8xx`+crc, `xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`+crc
|
||||||
* Read config: `E000`+crc (unidentified)
|
* Read config: `E000`+crc
|
||||||
* Write config: `E100`+crc
|
* Write config: `E100`+crc, `xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`+crc
|
||||||
|
|
||||||
### Characteristics
|
### Characteristics
|
||||||
^[Top](#top)
|
^[Top](#top)
|
||||||
|
@ -598,9 +598,11 @@ It is unknown what kind of block 0 changes the tag supports
|
||||||
# Write to persistent memory
|
# Write to persistent memory
|
||||||
hf mf gdmsetblk
|
hf mf gdmsetblk
|
||||||
|
|
||||||
# Read 0xE0 configuration:
|
# Read configuration (0xE0):
|
||||||
hf mf gdmconfig
|
hf mf gdmcfg
|
||||||
|
|
||||||
|
# Write configuration (0xE1):
|
||||||
|
hf mf gdmsetcfg
|
||||||
```
|
```
|
||||||
|
|
||||||
### libnfc commands
|
### libnfc commands
|
||||||
|
@ -612,7 +614,7 @@ No implemented commands today
|
||||||
|
|
||||||
**TODO**
|
**TODO**
|
||||||
|
|
||||||
* ZXUID, EUID, ICUID ?
|
* ZXUID, EUID, ICUID, KUID, HUID, RFUID ?
|
||||||
* Some cards exhibit a specific SAK=28 ??
|
* Some cards exhibit a specific SAK=28 ??
|
||||||
|
|
||||||
## MIFARE Classic Super
|
## MIFARE Classic Super
|
||||||
|
|
|
@ -690,6 +690,7 @@ typedef struct {
|
||||||
#define CMD_HF_MIFARE_G4_GDM_RDBL 0x0870
|
#define CMD_HF_MIFARE_G4_GDM_RDBL 0x0870
|
||||||
#define CMD_HF_MIFARE_G4_GDM_WRBL 0x0871
|
#define CMD_HF_MIFARE_G4_GDM_WRBL 0x0871
|
||||||
#define CMD_HF_MIFARE_G4_GDM_CONFIG 0x0872
|
#define CMD_HF_MIFARE_G4_GDM_CONFIG 0x0872
|
||||||
|
#define CMD_HF_MIFARE_G4_GDM_WRCFG 0x0873
|
||||||
|
|
||||||
#define CMD_UNKNOWN 0xFFFF
|
#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_RESTORE 0xC2
|
||||||
#define MIFARE_CMD_TRANSFER 0xB0
|
#define MIFARE_CMD_TRANSFER 0xB0
|
||||||
|
|
||||||
#define MIFARE_MAGIC_GDM_AUTH_KEYA 0x80
|
#define MIFARE_MAGIC_GDM_AUTH_KEY 0x80
|
||||||
#define MIFARE_MAGIC_GDM_AUTH_KEYB 0x81
|
|
||||||
#define MIFARE_MAGIC_GDM_WRITEBLOCK 0xA8
|
#define MIFARE_MAGIC_GDM_WRITEBLOCK 0xA8
|
||||||
#define MIFARE_MAGIC_GDM_READBLOCK 0xE0
|
#define MIFARE_MAGIC_GDM_READ_CFG 0xE0
|
||||||
#define MIFARE_MAGIC_GDM_READBLOCK_1 0xE1
|
#define MIFARE_MAGIC_GDM_WRITE_CFG 0xE1
|
||||||
|
|
||||||
#define MIFARE_EV1_PERSONAL_UID 0x40
|
#define MIFARE_EV1_PERSONAL_UID 0x40
|
||||||
#define MIFARE_EV1_SETMODE 0x43
|
#define MIFARE_EV1_SETMODE 0x43
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue