From 53c7e47e75eb1503bb93a66a1300a08ec5dc2e84 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 14 Oct 2020 17:41:34 +0200 Subject: [PATCH] fix: hf iclass restore - now uses NG and better reporting and works :) --- armsrc/Standalone/hf_iceclass.c | 8 +- armsrc/appmain.c | 12 +-- armsrc/iclass.c | 115 ++++++++++++++++------- armsrc/iclass.h | 5 +- client/src/cmdhficlass.c | 161 +++++++++----------------------- include/pm3_cmd.h | 17 ++-- 6 files changed, 143 insertions(+), 175 deletions(-) diff --git a/armsrc/Standalone/hf_iceclass.c b/armsrc/Standalone/hf_iceclass.c index 00de115e6..0c06bc90b 100644 --- a/armsrc/Standalone/hf_iceclass.c +++ b/armsrc/Standalone/hf_iceclass.c @@ -302,15 +302,17 @@ static int reader_dump_mode(void) { Iso15693InitReader(); set_tracing(false); + + picopass_hdr *hdr = (picopass_hdr *)card_data; + // select tag. uint32_t eof_time = 0; - bool res = select_iclass_tag(card_data, auth.use_credit_key, &eof_time); + bool res = select_iclass_tag(hdr, auth.use_credit_key, &eof_time); if (res == false) { switch_off(); continue; } - picopass_hdr *hdr = (picopass_hdr *)card_data; // sanity check of CSN. if (hdr->csn[7] != 0xE0 && hdr->csn[6] != 0x12) { switch_off(); @@ -366,7 +368,7 @@ static int reader_dump_mode(void) { auth.use_credit_key = true; memcpy(auth.key, aa2_key, sizeof(auth.key)); - res = select_iclass_tag(card_data, auth.use_credit_key, &eof_time); + res = select_iclass_tag(hdr, auth.use_credit_key, &eof_time); if (res) { // sanity check of CSN. diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 0b274f654..6b40a3909 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1553,18 +1553,8 @@ static void PacketReceived(PacketCommandNG *packet) { iClass_Dump(packet->data.asBytes); break; } - case CMD_HF_ICLASS_CLONE: { - struct p { - uint8_t startblock; - uint8_t endblock; - uint8_t data[]; - } PACKED; - struct p *payload = (struct p *)packet->data.asBytes; - iClass_Clone(payload->startblock, payload->endblock, payload->data); - break; - } case CMD_HF_ICLASS_RESTORE: { - iClass_Restore(packet->data.asBytes); + iClass_Restore( (iclass_restore_req_t *)packet->data.asBytes); break; } #endif diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 00e88f405..36ba0706b 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -1276,7 +1276,7 @@ static bool iclass_send_cmd_with_retries(uint8_t *cmd, size_t cmdsize, uint8_t * * @return false = fail * true = Got all. */ -static bool select_iclass_tag_ex(uint8_t *card_data, bool use_credit_key, uint32_t *eof_time, uint8_t *status) { +static bool select_iclass_tag_ex(picopass_hdr *hdr, bool use_credit_key, uint32_t *eof_time, uint8_t *status) { static uint8_t act_all[] = { ICLASS_CMD_ACTALL }; static uint8_t identify[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x00, 0x73, 0x33 }; @@ -1286,8 +1286,6 @@ static bool select_iclass_tag_ex(uint8_t *card_data, bool use_credit_key, uint32 uint8_t read_check_cc[] = { 0x80 | ICLASS_CMD_READCHECK, 0x02 }; uint8_t resp[ICLASS_BUFFER_SIZE] = {0}; - picopass_hdr *hdr = (picopass_hdr *)card_data; - // Bit 4: K.If this bit equals to one, the READCHECK will use the Credit Key (Kc); if equals to zero, Debit Key (Kd) will be used // bit 7: parity. if (use_credit_key) @@ -1369,6 +1367,8 @@ static bool select_iclass_tag_ex(uint8_t *card_data, bool use_credit_key, uint32 *status |= FLAG_ICLASS_CC; } else { + + // on NON_SECURE_PAGEMODE cards, AIA is on block2.. // read App Issuer Area block 2 read_aia[1] = 0x02; @@ -1385,23 +1385,23 @@ static bool select_iclass_tag_ex(uint8_t *card_data, bool use_credit_key, uint32 if (status) { *status |= FLAG_ICLASS_AIA; - memcpy(card_data + (8 * 2), resp, 8); + memcpy(hdr->epurse, resp, sizeof(hdr->epurse)); } } return true; } -bool select_iclass_tag(uint8_t *card_data, bool use_credit_key, uint32_t *eof_time) { +bool select_iclass_tag(picopass_hdr *hdr, bool use_credit_key, uint32_t *eof_time) { uint8_t result = 0; - return select_iclass_tag_ex(card_data, use_credit_key, eof_time, &result); + return select_iclass_tag_ex(hdr, use_credit_key, eof_time, &result); } // Reader iClass Anticollission // turn off afterwards void ReaderIClass(uint8_t flags) { - uint8_t card_data[6 * 8] = {0xFF}; + picopass_hdr hdr = {0}; // uint8_t last_csn[8] = {0, 0, 0, 0, 0, 0, 0, 0}; uint8_t resp[ICLASS_BUFFER_SIZE] = {0}; memset(resp, 0xFF, sizeof(resp)); @@ -1419,14 +1419,13 @@ void ReaderIClass(uint8_t flags) { uint8_t result_status = 0; uint32_t eof_time = 0; - bool status = select_iclass_tag_ex(card_data, use_credit_key, &eof_time, &result_status); + bool status = select_iclass_tag_ex(&hdr, use_credit_key, &eof_time, &result_status); if (status == false) { - reply_mix(CMD_ACK, 0xFF, 0, 0, card_data, 0); + reply_mix(CMD_ACK, 0xFF, 0, 0, NULL, 0); switch_off(); return; } - // Page mapping for secure mode // 0 : CSN // 1 : Configuration @@ -1444,7 +1443,7 @@ void ReaderIClass(uint8_t flags) { // with 0xFF:s in block 3 and 4. LED_B_ON(); - reply_mix(CMD_ACK, result_status, 0, 0, card_data, sizeof(card_data)); + reply_mix(CMD_ACK, result_status, 0, 0, (uint8_t*)&hdr, sizeof(hdr)); //Send back to client, but don't bother if we already sent this - // only useful if looping in arm (not try_once && not abort_after_read) @@ -1543,7 +1542,7 @@ void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain) { readcheck_cc[0] = 0x10 | ICLASS_CMD_READCHECK; // select card / e-purse - uint8_t card_data[6 * 8] = {0}; + picopass_hdr hdr = {0}; iclass_premac_t *keys = (iclass_premac_t *)datain; @@ -1557,7 +1556,7 @@ void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain) { uint32_t start_time = 0, eof_time = 0; - if (select_iclass_tag(card_data, use_credit_key, &eof_time) == false) + if (select_iclass_tag(&hdr, use_credit_key, &eof_time) == false) goto out; start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; @@ -1634,7 +1633,7 @@ void iClass_ReadBlock(uint8_t *msg) { // select tag. uint32_t eof_time = 0; picopass_hdr hdr = {0}; - bool res = select_iclass_tag((uint8_t *)&hdr, payload->use_credit_key, &eof_time); + bool res = select_iclass_tag(&hdr, payload->use_credit_key, &eof_time); if (res == false) { if (payload->send_reply) { response.isOK = res; @@ -1707,7 +1706,7 @@ void iClass_Dump(uint8_t *msg) { // select tag. uint32_t eof_time = 0; picopass_hdr hdr = {0}; - bool res = select_iclass_tag((uint8_t *)&hdr, req->use_credit_key, &eof_time); + bool res = select_iclass_tag(&hdr, req->use_credit_key, &eof_time); if (res == false) { if (req->send_reply) { reply_ng(CMD_HF_ICLASS_DUMP, PM3_ETIMEOUT, NULL, 0); @@ -1777,10 +1776,12 @@ void iClass_Dump(uint8_t *msg) { BigBuf_free(); } -static bool iclass_writeblock_ext(uint8_t blockno, uint8_t *data) { +static bool iclass_writeblock_ext(uint8_t blockno, uint8_t *data, uint8_t *mac) { + // write command: cmd, 1 blockno, 8 data, 4 mac uint8_t write[16] = { 0x80 | ICLASS_CMD_UPDATE, blockno }; - memcpy(write + 2, data, 12); // data + mac + memcpy(write + 2, data, 8); + memcpy(write + 10, mac, 4); AddCrc(write + 1, 13); uint8_t resp[10] = {0}; @@ -1825,7 +1826,7 @@ void iClass_WriteBlock(uint8_t *msg) { // select tag. uint32_t eof_time = 0; picopass_hdr hdr = {0}; - bool res = select_iclass_tag((uint8_t *)&hdr, payload->req.use_credit_key, &eof_time); + bool res = select_iclass_tag(&hdr, payload->req.use_credit_key, &eof_time); if (res == false) { goto out; } @@ -1924,29 +1925,75 @@ out: reply_ng(CMD_HF_ICLASS_WRITEBL, PM3_SUCCESS, (uint8_t *)&res, sizeof(uint8_t)); } -// turn off afterwards -void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t *data) { -} +void iClass_Restore(iclass_restore_req_t *msg) { -void iClass_Restore(uint8_t *msg) { + // sanitation + if (msg == NULL) { + reply_ng(CMD_HF_ICLASS_RESTORE, PM3_ESOFT, NULL, 0); + return; + } - iclass_restore_req_t *cmd = (iclass_restore_req_t *)msg; -// iclass_auth_req_t *req = &cmd->req; + if (msg->item_cnt == 0) { + if (msg->req.send_reply) { + reply_ng(CMD_HF_ICLASS_RESTORE, PM3_ESOFT, NULL, 0); + } + return; + } LED_A_ON(); - uint16_t written = 0; - uint16_t total_blocks = (cmd->end_block - cmd->start_block) + 1; - for (uint8_t b = cmd->start_block; b < total_blocks; b++) { + Iso15693InitReader(); - if (iclass_writeblock_ext(b, cmd->data + ((b - cmd->start_block) * 12))) { - Dbprintf("Write block [%02x] successful", b); - written++; - } else { - Dbprintf("Write block [%02x] failed", b); + uint16_t written = 0; + uint32_t eof_time = 0; + picopass_hdr hdr = {0}; + + // select + bool res = select_iclass_tag(&hdr, msg->req.use_credit_key, &eof_time); + if (res == false) { + goto out; + } + + // authenticate + uint8_t mac[4] = {0}; + uint32_t start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + + // authenticate + if (msg->req.do_auth) { + res = authenticate_iclass_tag(&msg->req, &hdr, &start_time, &eof_time, mac); + if (res == false) { + goto out; } } + // main loop + for (uint8_t i = 0; i < msg->item_cnt; i++) { + + iclass_restore_item_t item = msg->blocks[i]; + + // calc new mac for data, using 1b blockno, 8b data, + uint8_t wb[9] = {0}; + wb[0] = item.blockno; + memcpy(wb + 1, item.data, 8); + + if (msg->req.use_credit_key) + doMAC_N(wb, sizeof(wb), hdr.key_c, mac); + else + doMAC_N(wb, sizeof(wb), hdr.key_d, mac); + + // data + mac + if (iclass_writeblock_ext(item.blockno, item.data, mac)) { + Dbprintf("Write block [%02x] " _GREEN_("successful"), item.blockno); + written++; + } else { + Dbprintf("Write block [%02x] " _RED_("failed"), item.blockno); + } + } + +out: + switch_off(); - uint8_t isOK = (written == total_blocks) ? 1 : 0; - reply_ng(CMD_HF_ICLASS_CLONE, PM3_SUCCESS, (uint8_t *)&isOK, sizeof(uint8_t)); + if (msg->req.send_reply) { + int isOK = (written == msg->item_cnt) ? PM3_SUCCESS : PM3_ESOFT; + reply_ng(CMD_HF_ICLASS_RESTORE, isOK, NULL, 0); + } } diff --git a/armsrc/iclass.h b/armsrc/iclass.h index ec9ff7b15..1895ebbf6 100644 --- a/armsrc/iclass.h +++ b/armsrc/iclass.h @@ -21,8 +21,7 @@ void ReaderIClass(uint8_t arg0); void iClass_WriteBlock(uint8_t *msg); void iClass_Dump(uint8_t *msg); -void iClass_Restore(uint8_t *msg); -void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t *data); +void iClass_Restore(iclass_restore_req_t *msg); int do_iclass_simulation_nonsec(void); int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf); @@ -36,6 +35,6 @@ bool iclass_auth(iclass_auth_req_t *payload, uint8_t *out); void iClass_ReadBlock(uint8_t *msg); bool iclass_read_block(uint16_t blockno, uint8_t *data, uint32_t *start_time, uint32_t *eof_time); -bool select_iclass_tag(uint8_t *card_data, bool use_credit_key, uint32_t *eof_time); +bool select_iclass_tag(picopass_hdr *hdr, bool use_credit_key, uint32_t *eof_time); bool authenticate_iclass_tag(iclass_auth_req_t *payload, picopass_hdr *hdr, uint32_t *start_time, uint32_t *eof_time, uint8_t *mac_out); #endif diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index bf40e2d1e..57a231e2e 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -1431,13 +1431,6 @@ static int CmdHFiClassEncryptBlk(const char *Cmd) { return PM3_SUCCESS; } -static void calc_wb_mac(uint8_t blockno, uint8_t *data, uint8_t *div_key, uint8_t *MAC) { - uint8_t wb[9]; - wb[0] = blockno; - memcpy(wb + 1, data, 8); - doMAC_N(wb, sizeof(wb), div_key, MAC); -} - static bool select_only(uint8_t *CSN, uint8_t *CCNR, bool verbose) { uint8_t flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE); @@ -1475,47 +1468,6 @@ static bool select_only(uint8_t *CSN, uint8_t *CCNR, bool verbose) { return true; } -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) { - - iclass_auth_req_t payload = { - .use_raw = rawkey, - .use_elite = elite, - .use_credit_key = use_credit_key - }; - memcpy(payload.key, KEY, 8); - - SendCommandNG(CMD_HF_ICLASS_AUTH, (uint8_t *)&payload, sizeof(payload)); - PacketResponseNG resp; - clearCommandBuffer(); - if (WaitForResponseTimeout(CMD_HF_ICLASS_AUTH, &resp, 2000) == 0) { - if (verbose) PrintAndLogEx(WARNING, "Command execute timeout"); - return false; - } - - if (resp.status != PM3_SUCCESS) { - if (verbose) PrintAndLogEx(ERR, "failed to communicate with card"); - return false; - } - - iclass_readblock_resp_t *packet = (iclass_readblock_resp_t *)resp.data.asBytes; - - if (packet->isOK == 0) { - if (verbose) PrintAndLogEx(FAILED, "authentication error"); - return false; - } - - if (div_key) - memcpy(div_key, packet->div_key, sizeof(packet->div_key)); - - if (MAC) - memcpy(MAC, packet->mac, sizeof(packet->mac)); - - if (verbose) - PrintAndLogEx(SUCCESS, "authing with %s: %s", rawkey ? "raw key" : "diversified key", sprint_hex(div_key, 8)); - - return true; -} - static int CmdHFiClassDump(const char *Cmd) { uint8_t KEY[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; @@ -2026,11 +1978,6 @@ static int CmdHFiClass_WriteBlock(const char *Cmd) { return isok; } -/* -static int CmdHFiClassClone(const char *Cmd) { - return PM3_SUCCESS; -} -*/ static int CmdHFiClassRestore(const char *Cmd) { char filename[FILE_PATH_SIZE] = { 0x00 }; char tempStr[50] = {0}; @@ -2082,7 +2029,7 @@ static int CmdHFiClassRestore(const char *Cmd) { } else if (dataLen == 1) { keyNbr = param_get8(Cmd, cmdp + 1); if (keyNbr < ICLASS_KEYS_MAX) { - PrintAndLogEx(SUCCESS, "Using key[%d] %s", keyNbr, sprint_hex(iClass_Key_Table[keyNbr], 8)); + PrintAndLogEx(SUCCESS, "Using key[%d] " _GREEN_("%s"), keyNbr, sprint_hex(iClass_Key_Table[keyNbr], 8)); memcpy(KEY, iClass_Key_Table[keyNbr], 8); } else { PrintAndLogEx(WARNING, "\nERROR: Credit KeyNbr is invalid\n"); @@ -2119,14 +2066,19 @@ static int CmdHFiClassRestore(const char *Cmd) { if (errors || cmdp < 8) return usage_hf_iclass_restore(); + if (rawkey + elite > 1) { + PrintAndLogEx(FAILED, "Can not use both 'e', 'r'"); + return PM3_EINVARG; + } + if (startblock < 5) { PrintAndLogEx(WARNING, "you cannot write key blocks this way. yet... make your start block > 4"); return PM3_EINVARG; } - int total_bytes = (((endblock - startblock) + 1) * 12); + uint32_t payload_size = sizeof(iclass_restore_req_t) + (sizeof(iclass_restore_item_t) * (endblock - startblock + 1)); - if (total_bytes > PM3_CMD_DATA_SIZE - 2) { + if (payload_size > PM3_CMD_DATA_SIZE) { PrintAndLogEx(NORMAL, "Trying to write too many blocks at once. Max: %d", PM3_CMD_DATA_SIZE / 8); return PM3_EINVARG; } @@ -2144,93 +2096,68 @@ static int CmdHFiClassRestore(const char *Cmd) { return PM3_EFILE; } - if (bytes_read < sizeof(iclass_block_t) * (endblock - startblock + 1)) { - PrintAndLogEx(ERR, "file wrong size"); + if (bytes_read < ((endblock - startblock + 1) * 8 )) { + PrintAndLogEx(ERR, "file is smaller than your suggested block range ( " _RED_("0x%02x..0x%02x")" )", + startblock, endblock + ); free(dump); return PM3_EFILE; } + iclass_restore_req_t *payload = calloc(1, payload_size); + payload->req.use_raw = rawkey, + payload->req.use_elite = elite, + payload->req.use_credit_key = use_credit_key, + payload->req.use_replay = false, + payload->req.blockno = startblock, + payload->req.send_reply = true, + payload->req.do_auth = true, + memcpy(payload->req.key, KEY, 8); + + payload->item_cnt = (endblock - startblock + 1); + // read data from file from block 6 --- 19 // we will use this struct [data 8 bytes][MAC 4 bytes] for each block calculate all mac number for each data // then copy to usbcommand->asbytes; // max is 32 - 6 = 28 block. 28 x 12 bytes gives 336 bytes - iclass_block_t tag_data[PM3_CMD_DATA_SIZE / 12]; - memcpy(tag_data, dump + startblock * 8, sizeof(iclass_block_t) * (endblock - startblock + 1)); + for (uint8_t i = 0; i < payload->item_cnt; i++) { + payload->blocks[i].blockno = startblock + i; + memcpy(payload->blocks[i].data, dump + (startblock * 8) + (i * 8) , sizeof(payload->blocks[i].data)); + } free(dump); - uint8_t MAC[4] = {0x00, 0x00, 0x00, 0x00}; - uint8_t div_key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - - int i; - int numberAuthRetries = ICLASS_AUTH_RETRY; - do { - if (select_and_auth(KEY, MAC, div_key, use_credit_key, elite, rawkey, verbose)) - break; - } while (numberAuthRetries--); - - if (numberAuthRetries <= 0) { - PrintAndLogEx(ERR, "failed to authenticate"); - DropField(); - return PM3_ESOFT; - } - - uint8_t data[total_bytes]; - - // calculate all mac for every the block we will write - for (i = startblock; i <= endblock; i++) { - - calc_wb_mac(i, tag_data[i - startblock].d, div_key, MAC); - // usb command d start pointer = d + (i - 6) * 12 - // memcpy(pointer,tag_data[i - 6],8) 8 bytes - // memcpy(pointer + 8,mac,sizoof(mac) 4 bytes; - // next one - uint8_t *ptr = data + (i - startblock) * 12; - memcpy(ptr, &(tag_data[i - startblock].d[0]), 8); - memcpy(ptr + 8, MAC, 4); - } - if (verbose) { - PrintAndLogEx(INFO, "------+--------------------------+-------------"); - PrintAndLogEx(INFO, "block | data | mac"); - PrintAndLogEx(INFO, "------+--------------------------+-------------"); - uint8_t p[12]; - for (i = 0; i <= endblock - startblock; i++) { - memcpy(p, data + (i * 12), 12); - char *s = calloc(70, sizeof(uint8_t)); - snprintf(s, 70, "| %s ", sprint_hex(p, 8)); - snprintf(s + strlen(s), 70 - strlen(s), "| %s", sprint_hex(p + 8, 4)); - PrintAndLogEx(NORMAL, " %02X %s", i + startblock, s); - free(s); + PrintAndLogEx(INFO, "Preparing to restore block range 0x02x..0x%02x", startblock, endblock); + + PrintAndLogEx(INFO, "------+----------------------"); + PrintAndLogEx(INFO, "block | data"); + PrintAndLogEx(INFO, "------+----------------------"); + + for (uint8_t i = 0; i < payload->item_cnt; i++) { + iclass_restore_item_t item = payload->blocks[i]; + PrintAndLogEx(INFO, " %02X | %s", item.blockno, sprint_hex_inrow(item.data, sizeof(item.data))); } } - struct p { - uint8_t startblock; - uint8_t endblock; - uint8_t data[PM3_CMD_DATA_SIZE - 2]; - } PACKED payload; - - payload.startblock = startblock; - payload.endblock = endblock; - memcpy(payload.data, data, total_bytes); + PrintAndLogEx(INFO, "restore started..."); PacketResponseNG resp; clearCommandBuffer(); - SendCommandNG(CMD_HF_ICLASS_CLONE, (uint8_t *)&payload, total_bytes + 2); + SendCommandNG(CMD_HF_ICLASS_RESTORE, (uint8_t *)payload, payload_size); - if (WaitForResponseTimeout(CMD_HF_ICLASS_CLONE, &resp, 2000) == 0) { + if (WaitForResponseTimeout(CMD_HF_ICLASS_RESTORE, &resp, 2500) == 0) { PrintAndLogEx(WARNING, "command execute timeout"); DropField(); return PM3_ETIMEOUT; } if (resp.status == PM3_SUCCESS) { - if (resp.data.asBytes[0] == 1) - PrintAndLogEx(SUCCESS, "Restore successful"); - else - PrintAndLogEx(WARNING, "Restore failed"); + PrintAndLogEx(SUCCESS, "iCLASS restore " _GREEN_("successful")); + PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass rdbl ") "` to verify data on card"); + } else { + PrintAndLogEx(WARNING, "iCLASS restore " _RED_("failed")); } return resp.status; } diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index 141f51621..a473eb7f3 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -334,11 +334,15 @@ typedef struct { } PACKED iclass_writeblock_req_t; // iCLASS dump data structure +typedef struct { + uint8_t blockno; + uint8_t data[8]; +} PACKED iclass_restore_item_t; + typedef struct { iclass_auth_req_t req; - uint8_t start_block; - uint8_t end_block; - uint8_t data[]; + uint8_t item_cnt; + iclass_restore_item_t blocks[]; } PACKED iclass_restore_req_t; @@ -351,7 +355,7 @@ typedef struct { uint8_t mem_config; //[13] uint8_t eas; //[14] uint8_t fuses; //[15] -} picopass_conf_block_t; +} PACKED picopass_conf_block_t; // iCLASS secure mode memory mapping typedef struct { @@ -361,14 +365,14 @@ typedef struct { uint8_t key_d[8]; uint8_t key_c[8]; uint8_t app_issuer_area[8]; -} picopass_hdr; +} PACKED picopass_hdr; // iCLASS non-secure mode memory mapping typedef struct { uint8_t csn[8]; picopass_conf_block_t conf; uint8_t app_issuer_area[8]; -} picopass_ns_hdr; +} PACKED picopass_ns_hdr; // For the bootloader @@ -560,7 +564,6 @@ typedef struct { // iCLASS / Picopass #define CMD_HF_ICLASS_READCHECK 0x038F -#define CMD_HF_ICLASS_CLONE 0x0390 #define CMD_HF_ICLASS_DUMP 0x0391 #define CMD_HF_ICLASS_SNIFF 0x0392 #define CMD_HF_ICLASS_SIMULATE 0x0393