Add hf iclass creditepurse command to allow crediting the epurse debit value.

This commit is contained in:
nvx 2023-09-10 22:56:46 +10:00
commit 186308cb4a
10 changed files with 318 additions and 6 deletions

View file

@ -1902,13 +1902,13 @@ void iClass_WriteBlock(uint8_t *msg) {
// verify write
uint8_t all_ff[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
if (payload->req.blockno == 2) {
if (pagemap == PICOPASS_SECURE_PAGEMODE && payload->req.blockno == 2) {
// check response. e-purse update swaps first and second half
if (memcmp(payload->data + 4, resp, 4) || memcmp(payload->data, resp + 4, 4)) {
res = false;
goto out;
}
} else if (payload->req.blockno == 3 || payload->req.blockno == 4) {
} else if (pagemap == PICOPASS_SECURE_PAGEMODE && (payload->req.blockno == 3 || payload->req.blockno == 4)) {
// check response. Key updates always return 0xffffffffffffffff
if (memcmp(all_ff, resp, 8)) {
res = false;
@ -1929,6 +1929,159 @@ out:
reply_ng(CMD_HF_ICLASS_WRITEBL, PM3_SUCCESS, (uint8_t *)&res, sizeof(uint8_t));
}
void iclass_credit_epurse(iclass_credit_epurse_t *payload) {
LED_A_ON();
bool shallow_mod = payload->req.shallow_mod;
Iso15693InitReader();
// select tag.
uint32_t eof_time = 0;
picopass_hdr_t hdr = {0};
uint8_t res = select_iclass_tag(&hdr, payload->req.use_credit_key, &eof_time, shallow_mod);
if (res == false) {
goto out;
}
uint32_t start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
uint8_t mac[4] = {0};
// authenticate
if (payload->req.do_auth) {
res = authenticate_iclass_tag(&payload->req, &hdr, &start_time, &eof_time, mac);
if (res == false) {
goto out;
}
}
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
uint8_t cmd_read[] = {ICLASS_CMD_READ_OR_IDENTIFY, payload->req.blockno, 0x00, 0x00};
AddCrc(cmd_read + 1, 1);
uint8_t epurse[10];
res = iclass_send_cmd_with_retries(cmd_read, sizeof(cmd_read), epurse, sizeof(epurse), 10, 3, &start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time, shallow_mod);
if (!res) {
switch_off();
if (payload->req.send_reply)
reply_ng(CMD_HF_ICLASS_CREDIT_EPURSE, PM3_ETIMEOUT, (uint8_t *)&res, sizeof(uint8_t));
return;
}
uint8_t write[14] = { 0x80 | ICLASS_CMD_UPDATE, payload->req.blockno };
uint8_t write_len = 14;
uint8_t epurse_offset = 0;
const uint8_t empty_epurse[] = {0xff, 0xff, 0xff, 0xff};
if (!memcmp(epurse, empty_epurse, 4)) {
// epurse data in stage 2
epurse_offset = 4;
}
memcpy(epurse + epurse_offset, payload->epurse, 4);
// blank out debiting value as per the first step of the crediting procedure
epurse[epurse_offset + 0] = 0xFF;
epurse[epurse_offset + 1] = 0xFF;
// initial epurse write for credit
memcpy(write + 2, epurse, 8);
doMAC_N(write + 1, 9, payload->req.use_credit_key ? hdr.key_c : hdr.key_d, mac);
memcpy(write + 10, mac, sizeof(mac));
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
uint8_t resp[10] = {0};
uint8_t tries = 3;
while (tries-- > 0) {
iclass_send_as_reader(write, write_len, &start_time, &eof_time, shallow_mod);
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred
res = false;
switch_off();
if (payload->req.send_reply)
reply_ng(CMD_HF_ICLASS_CREDIT_EPURSE, PM3_ETEAROFF, (uint8_t *)&res, sizeof(uint8_t));
return;
} else {
uint16_t resp_len = 0;
int res2 = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_UPDATE, &eof_time, false, true, &resp_len);
if (res2 == PM3_SUCCESS && resp_len == 10) {
res = true;
break;
}
}
}
if (tries == 0) {
res = false;
goto out;
}
// check response. e-purse update swaps first and second half
if (memcmp(write + 2 + 4, resp, 4) || memcmp(write + 2, resp + 4, 4)) {
res = false;
goto out;
}
// new epurse write
// epurse offset is now flipped after the first write
epurse_offset ^= 4;
memcpy(resp + epurse_offset, payload->epurse, 4);
memcpy(write + 2, resp, 8);
doMAC_N(write + 1, 9, payload->req.use_credit_key ? hdr.key_c : hdr.key_d, mac);
memcpy(write + 10, mac, sizeof(mac));
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
tries = 3;
while (tries-- > 0) {
iclass_send_as_reader(write, write_len, &start_time, &eof_time, shallow_mod);
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred
res = false;
switch_off();
if (payload->req.send_reply)
reply_ng(CMD_HF_ICLASS_CREDIT_EPURSE, PM3_ETEAROFF, (uint8_t *)&res, sizeof(uint8_t));
return;
} else {
uint16_t resp_len = 0;
int res2 = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_UPDATE, &eof_time, false, true, &resp_len);
if (res2 == PM3_SUCCESS && resp_len == 10) {
res = true;
break;
}
}
}
if (tries == 0) {
res = false;
goto out;
}
// check response. e-purse update swaps first and second half
if (memcmp(write + 2 + 4, resp, 4) || memcmp(write + 2, resp + 4, 4)) {
res = false;
goto out;
}
out:
switch_off();
if (payload->req.send_reply)
reply_ng(CMD_HF_ICLASS_CREDIT_EPURSE, PM3_SUCCESS, (uint8_t *)&res, sizeof(uint8_t));
}
void iClass_Restore(iclass_restore_req_t *msg) {
// sanitation