mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 22:03:42 -07:00
rework iclass dump
This commit is contained in:
parent
7aedd9c7fe
commit
52e9d7a750
2 changed files with 102 additions and 85 deletions
|
@ -1112,7 +1112,7 @@ static int CmdHFiClassEncryptBlk(const char *Cmd) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Calc_wb_mac(uint8_t blockno, uint8_t *data, uint8_t *div_key, uint8_t MAC[4]) {
|
static void calc_wb_mac(uint8_t blockno, uint8_t *data, uint8_t *div_key, uint8_t *MAC) {
|
||||||
uint8_t wb[9];
|
uint8_t wb[9];
|
||||||
wb[0] = blockno;
|
wb[0] = blockno;
|
||||||
memcpy(wb + 1, data, 8);
|
memcpy(wb + 1, data, 8);
|
||||||
|
@ -1120,24 +1120,25 @@ static void Calc_wb_mac(uint8_t blockno, uint8_t *data, uint8_t *div_key, uint8_
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool select_only(uint8_t *CSN, uint8_t *CCNR, bool use_credit_key, bool verbose) {
|
static bool select_only(uint8_t *CSN, uint8_t *CCNR, bool use_credit_key, bool verbose) {
|
||||||
PacketResponseNG resp;
|
|
||||||
uint8_t flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE);
|
|
||||||
|
|
||||||
|
uint8_t flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE);
|
||||||
if (use_credit_key)
|
if (use_credit_key)
|
||||||
flags |= FLAG_ICLASS_READER_CEDITKEY;
|
flags |= FLAG_ICLASS_READER_CEDITKEY;
|
||||||
|
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
|
PacketResponseNG resp;
|
||||||
SendCommandMIX(CMD_HF_ICLASS_READER, flags, 0, 0, NULL, 0);
|
SendCommandMIX(CMD_HF_ICLASS_READER, flags, 0, 0, NULL, 0);
|
||||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 2000) == false) {
|
if (WaitForResponseTimeout(CMD_ACK, &resp, 2000) == false) {
|
||||||
PrintAndLogEx(WARNING, "command execute timeout");
|
PrintAndLogEx(WARNING, "command execute timeout");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t isOK = resp.oldarg[0] & 0xff;
|
uint8_t isok = resp.oldarg[0] & 0xff;
|
||||||
|
|
||||||
if (isOK == 0xFF) {
|
// no tag found or button pressed
|
||||||
|
if ((isok == 0) || isok == 0xFF) {
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
PrintAndLogEx(FAILED, "failed tag-select, aborting... (%d)", isOK);
|
PrintAndLogEx(FAILED, "failed tag-select, aborting... (%d)", isok);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1159,17 +1160,12 @@ static bool select_only(uint8_t *CSN, uint8_t *CCNR, bool use_credit_key, bool v
|
||||||
|
|
||||||
static bool select_and_auth(uint8_t *KEY, uint8_t *MAC, uint8_t *div_key, bool use_credit_key, bool elite, bool rawkey, bool verbose) {
|
static bool select_and_auth(uint8_t *KEY, uint8_t *MAC, uint8_t *div_key, bool use_credit_key, bool elite, bool rawkey, bool verbose) {
|
||||||
|
|
||||||
struct {
|
iclass_auth_req_t payload = {
|
||||||
uint8_t key[8];
|
.use_raw = rawkey,
|
||||||
bool use_raw;
|
.use_elite = elite,
|
||||||
bool use_elite;
|
.use_credit_key = use_credit_key
|
||||||
bool use_credit_key;
|
};
|
||||||
} PACKED payload;
|
|
||||||
|
|
||||||
memcpy(payload.key, KEY, 8);
|
memcpy(payload.key, KEY, 8);
|
||||||
payload.use_raw = rawkey;
|
|
||||||
payload.use_elite = elite;
|
|
||||||
payload.use_credit_key = use_credit_key;
|
|
||||||
|
|
||||||
SendCommandNG(CMD_HF_ICLASS_AUTH, (uint8_t*)&payload, sizeof(payload));
|
SendCommandNG(CMD_HF_ICLASS_AUTH, (uint8_t*)&payload, sizeof(payload));
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
|
@ -1184,12 +1180,7 @@ static bool select_and_auth(uint8_t *KEY, uint8_t *MAC, uint8_t *div_key, bool u
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct p {
|
iclass_auth_resp_t *packet = (iclass_auth_resp_t *)resp.data.asBytes;
|
||||||
bool isOK;
|
|
||||||
uint8_t div_key[8];
|
|
||||||
uint8_t mac[4];
|
|
||||||
} PACKED;
|
|
||||||
struct p *packet = (struct p *)resp.data.asBytes;
|
|
||||||
|
|
||||||
if (packet->isOK == 0) {
|
if (packet->isOK == 0) {
|
||||||
if (verbose) PrintAndLogEx(FAILED, "authentication error");
|
if (verbose) PrintAndLogEx(FAILED, "authentication error");
|
||||||
|
@ -1206,7 +1197,7 @@ static bool select_and_auth(uint8_t *KEY, uint8_t *MAC, uint8_t *div_key, bool u
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int CmdHFiClassReader_Dump(const char *Cmd) {
|
static int CmdHFiClassDump(const char *Cmd) {
|
||||||
|
|
||||||
uint8_t MAC[4] = {0x00, 0x00, 0x00, 0x00};
|
uint8_t MAC[4] = {0x00, 0x00, 0x00, 0x00};
|
||||||
uint8_t div_key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
uint8_t div_key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
@ -1245,6 +1236,7 @@ static int CmdHFiClassReader_Dump(const char *Cmd) {
|
||||||
keyNbr = param_get8(Cmd, cmdp + 1);
|
keyNbr = param_get8(Cmd, cmdp + 1);
|
||||||
if (keyNbr < ICLASS_KEYS_MAX) {
|
if (keyNbr < ICLASS_KEYS_MAX) {
|
||||||
memcpy(CreditKEY, iClass_Key_Table[keyNbr], 8);
|
memcpy(CreditKEY, iClass_Key_Table[keyNbr], 8);
|
||||||
|
PrintAndLogEx(INFO, "AA2 (credit) index %u", keyNbr);
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(WARNING, "\nERROR: Credit KeyNbr is invalid\n");
|
PrintAndLogEx(WARNING, "\nERROR: Credit KeyNbr is invalid\n");
|
||||||
errors = true;
|
errors = true;
|
||||||
|
@ -1277,6 +1269,7 @@ static int CmdHFiClassReader_Dump(const char *Cmd) {
|
||||||
keyNbr = param_get8(Cmd, cmdp + 1);
|
keyNbr = param_get8(Cmd, cmdp + 1);
|
||||||
if (keyNbr < ICLASS_KEYS_MAX) {
|
if (keyNbr < ICLASS_KEYS_MAX) {
|
||||||
memcpy(KEY, iClass_Key_Table[keyNbr], 8);
|
memcpy(KEY, iClass_Key_Table[keyNbr], 8);
|
||||||
|
PrintAndLogEx(INFO, "AA1 (debit) index %u", keyNbr);
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(WARNING, "\nERROR: Credit KeyNbr is invalid\n");
|
PrintAndLogEx(WARNING, "\nERROR: Credit KeyNbr is invalid\n");
|
||||||
errors = true;
|
errors = true;
|
||||||
|
@ -1307,12 +1300,7 @@ static int CmdHFiClassReader_Dump(const char *Cmd) {
|
||||||
// if no debit key given try credit key on AA1 (not for iclass but for some picopass this will work)
|
// if no debit key given try credit key on AA1 (not for iclass but for some picopass this will work)
|
||||||
if (!have_debit_key && have_credit_key) use_credit_key = true;
|
if (!have_debit_key && have_credit_key) use_credit_key = true;
|
||||||
|
|
||||||
uint32_t flags = (
|
uint32_t flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE);
|
||||||
FLAG_ICLASS_READER_INIT |
|
|
||||||
FLAG_ICLASS_READER_CLEARTRACE |
|
|
||||||
FLAG_ICLASS_READER_ONLY_ONCE
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
//get config and first 3 blocks
|
//get config and first 3 blocks
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
|
@ -1320,7 +1308,7 @@ static int CmdHFiClassReader_Dump(const char *Cmd) {
|
||||||
|
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandMIX(CMD_HF_ICLASS_READER, flags, 0, 0, NULL, 0);
|
SendCommandMIX(CMD_HF_ICLASS_READER, flags, 0, 0, NULL, 0);
|
||||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 4500)) {
|
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
||||||
PrintAndLogEx(WARNING, "command execute timeout");
|
PrintAndLogEx(WARNING, "command execute timeout");
|
||||||
DropField();
|
DropField();
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
|
@ -1346,21 +1334,22 @@ static int CmdHFiClassReader_Dump(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// authenticate debit key and get div_key - later store in dump block 3
|
// authenticate debit key and get div_key - later store in dump block 3
|
||||||
int numberAuthRetries = ICLASS_AUTH_RETRY;
|
if (select_and_auth(KEY, MAC, div_key, use_credit_key, elite, rawkey, verbose) == false) {
|
||||||
do {
|
|
||||||
if (select_and_auth(KEY, MAC, div_key, use_credit_key, elite, rawkey, verbose))
|
|
||||||
break;
|
|
||||||
} while (numberAuthRetries--);
|
|
||||||
|
|
||||||
if (numberAuthRetries <= 0) {
|
|
||||||
PrintAndLogEx(WARNING, "failed authenticating with debit key");
|
PrintAndLogEx(WARNING, "failed authenticating with debit key");
|
||||||
DropField();
|
DropField();
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
// begin dump
|
struct {
|
||||||
|
uint8_t start_blockno;
|
||||||
|
uint8_t numblks;
|
||||||
|
} PACKED payload;
|
||||||
|
payload.start_blockno = blockno;
|
||||||
|
payload.numblks = numblks - blockno + 1;
|
||||||
|
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandMIX(CMD_HF_ICLASS_DUMP, blockno, numblks - blockno + 1, 0, NULL, 0);
|
SendCommandNG(CMD_HF_ICLASS_DUMP, (uint8_t*)&payload, sizeof(payload));
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
printf(".");
|
printf(".");
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
@ -1371,47 +1360,53 @@ static int CmdHFiClassReader_Dump(const char *Cmd) {
|
||||||
return PM3_EOPABORTED;
|
return PM3_EOPABORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 2000))
|
if (WaitForResponseTimeout(CMD_HF_ICLASS_DUMP, &resp, 2000))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (resp.status != PM3_SUCCESS) {
|
||||||
|
PrintAndLogEx(ERR, "failed to communicate with card");
|
||||||
|
return resp.status;
|
||||||
|
}
|
||||||
|
|
||||||
// dump cmd switch off at device when finised.
|
// dump cmd switch off at device when finised.
|
||||||
|
|
||||||
uint32_t blocksRead = resp.oldarg[1];
|
struct p_resp {
|
||||||
uint8_t isOK = resp.oldarg[0] & 0xff;
|
bool isOK;
|
||||||
if (!isOK && !blocksRead) {
|
uint8_t block_cnt;
|
||||||
|
uint32_t bb_offset;
|
||||||
|
} PACKED;
|
||||||
|
struct p_resp *packet = (struct p_resp *)resp.data.asBytes;
|
||||||
|
|
||||||
|
uint32_t blocks_read = packet->block_cnt;
|
||||||
|
|
||||||
|
if (packet->isOK == false) {
|
||||||
PrintAndLogEx(WARNING, "read block failed");
|
PrintAndLogEx(WARNING, "read block failed");
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t startindex = resp.oldarg[2];
|
uint32_t startindex = packet->bb_offset;
|
||||||
if (blocksRead * 8 > sizeof(tag_data) - (blockno * 8)) {
|
|
||||||
|
if (blocks_read * 8 > sizeof(tag_data) - (blockno * 8)) {
|
||||||
PrintAndLogEx(FAILED, "data exceeded buffer size!");
|
PrintAndLogEx(FAILED, "data exceeded buffer size!");
|
||||||
blocksRead = (sizeof(tag_data) / 8) - blockno;
|
blocks_read = (sizeof(tag_data) / 8) - blockno;
|
||||||
}
|
}
|
||||||
|
|
||||||
// response ok - now get bigbuf content of the dump
|
// response ok - now get bigbuf content of the dump
|
||||||
if (!GetFromDevice(BIG_BUF, tag_data + (blockno * 8), blocksRead * 8, startindex, NULL, 0, NULL, 2500, false)) {
|
if (!GetFromDevice(BIG_BUF, tag_data + (blockno * 8), blocks_read * 8, startindex, NULL, 0, NULL, 2500, false)) {
|
||||||
PrintAndLogEx(WARNING, "command execution time out");
|
PrintAndLogEx(WARNING, "command execution time out");
|
||||||
return PM3_ETIMEOUT;
|
return PM3_ETIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t gotBytes = blocksRead * 8 + blockno * 8;
|
size_t gotBytes = blocks_read * 8 + blockno * 8;
|
||||||
|
|
||||||
// try AA2
|
// try AA2 Kc, Credit
|
||||||
if (have_credit_key) {
|
if (have_credit_key) {
|
||||||
//turn off hf field before authenticating with different key
|
|
||||||
DropField();
|
|
||||||
|
|
||||||
memset(MAC, 0, 4);
|
memset(MAC, 0, 4);
|
||||||
|
|
||||||
// AA2 authenticate credit key and git c_div_key - later store in dump block 4
|
// AA2 authenticate credit key and git c_div_key - later store in dump block 4
|
||||||
numberAuthRetries = ICLASS_AUTH_RETRY;
|
if (select_and_auth(CreditKEY, MAC, c_div_key, true, elite, rawkey, verbose) == false) {
|
||||||
do {
|
|
||||||
if (select_and_auth(CreditKEY, MAC, c_div_key, true, elite, rawkey, verbose))
|
|
||||||
break;
|
|
||||||
} while (numberAuthRetries--);
|
|
||||||
|
|
||||||
if (numberAuthRetries <= 0) {
|
|
||||||
PrintAndLogEx(WARNING, "failed authenticating with credit key");
|
PrintAndLogEx(WARNING, "failed authenticating with credit key");
|
||||||
DropField();
|
DropField();
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
|
@ -1419,32 +1414,43 @@ static int CmdHFiClassReader_Dump(const char *Cmd) {
|
||||||
|
|
||||||
// do we still need to read more block? (aa2 enabled?)
|
// do we still need to read more block? (aa2 enabled?)
|
||||||
if (maxBlk > blockno + numblks + 1) {
|
if (maxBlk > blockno + numblks + 1) {
|
||||||
// setup dump and start
|
|
||||||
|
payload.start_blockno = blockno + blocks_read;
|
||||||
|
payload.numblks = maxBlk - (blockno + blocks_read);
|
||||||
|
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandMIX(CMD_HF_ICLASS_DUMP, blockno + blocksRead, maxBlk - (blockno + blocksRead), 0, NULL, 0);
|
SendCommandNG(CMD_HF_ICLASS_DUMP, (uint8_t*)&payload, sizeof(payload));
|
||||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 4500)) {
|
|
||||||
|
if (!WaitForResponseTimeout(CMD_HF_ICLASS_DUMP, &resp, 2000)) {
|
||||||
PrintAndLogEx(WARNING, "command execute timeout 2");
|
PrintAndLogEx(WARNING, "command execute timeout 2");
|
||||||
return PM3_ETIMEOUT;
|
return PM3_ETIMEOUT;
|
||||||
}
|
}
|
||||||
isOK = resp.oldarg[0] & 0xff;
|
|
||||||
blocksRead = resp.oldarg[1];
|
if (resp.status != PM3_SUCCESS) {
|
||||||
if (!isOK && !blocksRead) {
|
PrintAndLogEx(ERR, "failed to communicate with card");
|
||||||
PrintAndLogEx(WARNING, "read block failed 2");
|
return resp.status;
|
||||||
|
}
|
||||||
|
|
||||||
|
packet = (struct p_resp *)resp.data.asBytes;
|
||||||
|
if (packet->isOK == false) {
|
||||||
|
PrintAndLogEx(WARNING, "read block failed using credit key");
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
startindex = resp.oldarg[2];
|
blocks_read = packet->block_cnt;
|
||||||
if (blocksRead * 8 > sizeof(tag_data) - gotBytes) {
|
startindex = packet->bb_offset;
|
||||||
|
|
||||||
|
if (blocks_read * 8 > sizeof(tag_data) - gotBytes) {
|
||||||
PrintAndLogEx(FAILED, "data exceeded buffer size!");
|
PrintAndLogEx(FAILED, "data exceeded buffer size!");
|
||||||
blocksRead = (sizeof(tag_data) - gotBytes) / 8;
|
blocks_read = (sizeof(tag_data) - gotBytes) / 8;
|
||||||
}
|
}
|
||||||
// get dumped data from bigbuf
|
// get dumped data from bigbuf
|
||||||
if (!GetFromDevice(BIG_BUF, tag_data + gotBytes, blocksRead * 8, startindex, NULL, 0, NULL, 2500, false)) {
|
if (!GetFromDevice(BIG_BUF, tag_data + gotBytes, blocks_read * 8, startindex, NULL, 0, NULL, 2500, false)) {
|
||||||
PrintAndLogEx(WARNING, "command execution time out");
|
PrintAndLogEx(WARNING, "command execution time out");
|
||||||
return PM3_ETIMEOUT;
|
return PM3_ETIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
gotBytes += blocksRead * 8;
|
gotBytes += blocks_read * 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1485,13 +1491,13 @@ static int WriteBlock(uint8_t blockno, uint8_t *bldata, uint8_t *KEY, bool use_c
|
||||||
|
|
||||||
uint8_t MAC[4] = {0x00, 0x00, 0x00, 0x00};
|
uint8_t MAC[4] = {0x00, 0x00, 0x00, 0x00};
|
||||||
uint8_t div_key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
uint8_t div_key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
if (!select_and_auth(KEY, MAC, div_key, use_credit_key, elite, rawkey, verbose)) {
|
if (select_and_auth(KEY, MAC, div_key, use_credit_key, elite, rawkey, verbose) == false) {
|
||||||
numberAuthRetries--;
|
numberAuthRetries--;
|
||||||
DropField();
|
DropField();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Calc_wb_mac(blockno, bldata, div_key, MAC);
|
calc_wb_mac(blockno, bldata, div_key, MAC);
|
||||||
|
|
||||||
struct p {
|
struct p {
|
||||||
uint8_t blockno;
|
uint8_t blockno;
|
||||||
|
@ -1506,7 +1512,7 @@ static int WriteBlock(uint8_t blockno, uint8_t *bldata, uint8_t *KEY, bool use_c
|
||||||
SendCommandNG(CMD_HF_ICLASS_WRITEBL, (uint8_t *)&payload, sizeof(payload));
|
SendCommandNG(CMD_HF_ICLASS_WRITEBL, (uint8_t *)&payload, sizeof(payload));
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
|
|
||||||
if (WaitForResponseTimeout(CMD_HF_ICLASS_WRITEBL, &resp, 4000) == 0) {
|
if (WaitForResponseTimeout(CMD_HF_ICLASS_WRITEBL, &resp, 2000) == 0) {
|
||||||
if (verbose) PrintAndLogEx(WARNING, "Command execute timeout");
|
if (verbose) PrintAndLogEx(WARNING, "Command execute timeout");
|
||||||
DropField();
|
DropField();
|
||||||
return PM3_ETIMEOUT;
|
return PM3_ETIMEOUT;
|
||||||
|
@ -1767,7 +1773,7 @@ static int CmdHFiClassCloneTag(const char *Cmd) {
|
||||||
// calculate all mac for every the block we will write
|
// calculate all mac for every the block we will write
|
||||||
for (i = startblock; i <= endblock; i++) {
|
for (i = startblock; i <= endblock; i++) {
|
||||||
|
|
||||||
Calc_wb_mac(i, tag_data[i - startblock].d, div_key, MAC);
|
calc_wb_mac(i, tag_data[i - startblock].d, div_key, MAC);
|
||||||
// usb command d start pointer = d + (i - 6) * 12
|
// usb command d start pointer = d + (i - 6) * 12
|
||||||
// memcpy(pointer,tag_data[i - 6],8) 8 bytes
|
// memcpy(pointer,tag_data[i - 6],8) 8 bytes
|
||||||
// memcpy(pointer + 8,mac,sizoof(mac) 4 bytes;
|
// memcpy(pointer + 8,mac,sizoof(mac) 4 bytes;
|
||||||
|
@ -1806,7 +1812,7 @@ static int CmdHFiClassCloneTag(const char *Cmd) {
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandNG(CMD_HF_ICLASS_CLONE, (uint8_t *)&payload, total_bytes + 2);
|
SendCommandNG(CMD_HF_ICLASS_CLONE, (uint8_t *)&payload, total_bytes + 2);
|
||||||
|
|
||||||
if (WaitForResponseTimeout(CMD_HF_ICLASS_CLONE, &resp, 4500) == 0) {
|
if (WaitForResponseTimeout(CMD_HF_ICLASS_CLONE, &resp, 2000) == 0) {
|
||||||
PrintAndLogEx(WARNING, "command execute timeout");
|
PrintAndLogEx(WARNING, "command execute timeout");
|
||||||
DropField();
|
DropField();
|
||||||
return PM3_ETIMEOUT;
|
return PM3_ETIMEOUT;
|
||||||
|
@ -1829,7 +1835,6 @@ static int ReadBlock(uint8_t *KEY, uint8_t blockno, uint8_t keyType, bool elite,
|
||||||
bool isOK;
|
bool isOK;
|
||||||
uint8_t blockdata[8];
|
uint8_t blockdata[8];
|
||||||
} PACKED;
|
} PACKED;
|
||||||
|
|
||||||
struct p *result = NULL;
|
struct p *result = NULL;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
@ -1837,7 +1842,7 @@ static int ReadBlock(uint8_t *KEY, uint8_t blockno, uint8_t keyType, bool elite,
|
||||||
if (auth || blockno >= 2) {
|
if (auth || blockno >= 2) {
|
||||||
uint8_t MAC[4] = {0x00, 0x00, 0x00, 0x00};
|
uint8_t MAC[4] = {0x00, 0x00, 0x00, 0x00};
|
||||||
uint8_t div_key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
uint8_t div_key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
if (!select_and_auth(KEY, MAC, div_key, (keyType == 0x18), elite, rawkey, verbose)) {
|
if (select_and_auth(KEY, MAC, div_key, (keyType == 0x18), elite, rawkey, verbose) == false) {
|
||||||
numberAuthRetries--;
|
numberAuthRetries--;
|
||||||
DropField();
|
DropField();
|
||||||
continue;
|
continue;
|
||||||
|
@ -1845,7 +1850,7 @@ static int ReadBlock(uint8_t *KEY, uint8_t blockno, uint8_t keyType, bool elite,
|
||||||
} else {
|
} else {
|
||||||
uint8_t CSN[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
uint8_t CSN[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
uint8_t CCNR[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
uint8_t CCNR[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
if (!select_only(CSN, CCNR, (keyType == 0x18), verbose)) {
|
if (select_only(CSN, CCNR, (keyType == 0x18), verbose) == false) {
|
||||||
numberAuthRetries--;
|
numberAuthRetries--;
|
||||||
DropField();
|
DropField();
|
||||||
continue;
|
continue;
|
||||||
|
@ -2156,6 +2161,7 @@ static int CmdHFiClassCalcNewKey(const char *Cmd) {
|
||||||
bool elite = false;
|
bool elite = false;
|
||||||
bool errors = false;
|
bool errors = false;
|
||||||
uint8_t cmdp = 0;
|
uint8_t cmdp = 0;
|
||||||
|
|
||||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||||
case 'h':
|
case 'h':
|
||||||
|
@ -2217,9 +2223,9 @@ static int CmdHFiClassCalcNewKey(const char *Cmd) {
|
||||||
}
|
}
|
||||||
if (errors || cmdp < 4) return usage_hf_iclass_calc_newkey();
|
if (errors || cmdp < 4) return usage_hf_iclass_calc_newkey();
|
||||||
|
|
||||||
if (!givenCSN) {
|
if (givenCSN == false) {
|
||||||
uint8_t CCNR[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
uint8_t CCNR[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
if (!select_only(CSN, CCNR, false, true)) {
|
if (select_only(CSN, CCNR, false, true) == false) {
|
||||||
DropField();
|
DropField();
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
@ -2512,7 +2518,7 @@ static int CmdHFiClassCheckKeys(const char *Cmd) {
|
||||||
SendCommandOLD(CMD_HF_ICLASS_CHKKEYS, flags, keys, 0, pre + key_offset, 4 * keys);
|
SendCommandOLD(CMD_HF_ICLASS_CHKKEYS, flags, keys, 0, pre + key_offset, 4 * keys);
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
|
|
||||||
while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
while (!WaitForResponseTimeout(CMD_HF_ICLASS_CHKKEYS, &resp, 2000)) {
|
||||||
timeout++;
|
timeout++;
|
||||||
printf(".");
|
printf(".");
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
@ -2927,7 +2933,7 @@ static command_t CommandTable[] = {
|
||||||
{"chk", CmdHFiClassCheckKeys, AlwaysAvailable, "[options..] Check keys"},
|
{"chk", CmdHFiClassCheckKeys, AlwaysAvailable, "[options..] Check keys"},
|
||||||
{"clone", CmdHFiClassCloneTag, IfPm3Iclass, "[options..] Restore a dump file onto a iClass tag"},
|
{"clone", CmdHFiClassCloneTag, IfPm3Iclass, "[options..] Restore a dump file onto a iClass tag"},
|
||||||
{"decrypt", CmdHFiClassDecrypt, AlwaysAvailable, "[options..] Decrypt given block data or tag dump file" },
|
{"decrypt", CmdHFiClassDecrypt, AlwaysAvailable, "[options..] Decrypt given block data or tag dump file" },
|
||||||
{"dump", CmdHFiClassReader_Dump, IfPm3Iclass, "[options..] Dump iClass tag to file"},
|
{"dump", CmdHFiClassDump, IfPm3Iclass, "[options..] Dump iClass tag to file"},
|
||||||
{"eload", CmdHFiClassELoad, IfPm3Iclass, "[f <fname>] Load iClass dump file into emulator memory"},
|
{"eload", CmdHFiClassELoad, IfPm3Iclass, "[f <fname>] Load iClass dump file into emulator memory"},
|
||||||
{"encrypt", CmdHFiClassEncryptBlk, AlwaysAvailable, "[options..] Encrypt given block data"},
|
{"encrypt", CmdHFiClassEncryptBlk, AlwaysAvailable, "[options..] Encrypt given block data"},
|
||||||
{"info", CmdHFiClassInfo, AlwaysAvailable, " Tag information"},
|
{"info", CmdHFiClassInfo, AlwaysAvailable, " Tag information"},
|
||||||
|
@ -2979,8 +2985,6 @@ int readIclass(bool loop, bool verbose) {
|
||||||
|
|
||||||
uint8_t readStatus = resp.oldarg[0] & 0xff;
|
uint8_t readStatus = resp.oldarg[0] & 0xff;
|
||||||
|
|
||||||
// PrintAndLogEx(NORMAL, "ICE: %x", readStatus);
|
|
||||||
|
|
||||||
// no tag found or button pressed
|
// no tag found or button pressed
|
||||||
if ((readStatus == 0 && !loop) || readStatus == 0xFF) {
|
if ((readStatus == 0 && !loop) || readStatus == 0xFF) {
|
||||||
DropField();
|
DropField();
|
||||||
|
|
|
@ -27,6 +27,19 @@ typedef struct iclass_prekey {
|
||||||
uint8_t key[8];
|
uint8_t key[8];
|
||||||
} iclass_prekey_t;
|
} iclass_prekey_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t key[8];
|
||||||
|
bool use_raw;
|
||||||
|
bool use_elite;
|
||||||
|
bool use_credit_key;
|
||||||
|
} PACKED iclass_auth_req_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool isOK;
|
||||||
|
uint8_t div_key[8];
|
||||||
|
uint8_t mac[4];
|
||||||
|
} PACKED iclass_auth_resp_t;
|
||||||
|
|
||||||
int CmdHFiClass(const char *Cmd);
|
int CmdHFiClass(const char *Cmd);
|
||||||
|
|
||||||
int readIclass(bool loop, bool verbose);
|
int readIclass(bool loop, bool verbose);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue