From d93364bc22ce782881bce3405048b510fbdf3106 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 3 Aug 2020 17:42:05 +0200 Subject: [PATCH] textual chk, loopup. Sim working on reva,b,c readers --- armsrc/appmain.c | 7 +- armsrc/iclass.c | 356 +++++++++++++++++++-------------------- armsrc/iso15693.c | 173 +++++++++++-------- client/src/cmdhficlass.c | 259 ++++++++++++++-------------- 4 files changed, 410 insertions(+), 385 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index d40d262f4..a8089cf5f 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1397,7 +1397,12 @@ static void PacketReceived(PacketCommandNG *packet) { break; } case CMD_HF_ICLASS_REPLAY: { - ReaderIClass_Replay(packet->oldarg[0], packet->data.asBytes); + struct p { + uint8_t reader; + uint8_t mac[4]; + } PACKED; + struct p *payload = (struct p *) packet->data.asBytes; + ReaderIClass_Replay(payload->reader, payload->mac); break; } case CMD_HF_ICLASS_EML_MEMSET: { diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 888dbb6c8..c0b0ca7d1 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -35,8 +35,16 @@ #include "ticks.h" #include "iso15693.h" +static bool is_se(picopass_hdr *hdr) { + return ( memcmp(hdr->app_issuer_area, "\xff\xff\xff\x00\x06\xff\xff\xff", 8) == 0); +} + +static uint8_t get_pagemap(const picopass_hdr *hdr) { + return (hdr->conf.fuses & (FUSE_CRYPT0 | FUSE_CRYPT1)) >> 3; +} + // The length of a received command will in most cases be no more than 18 bytes. -// we expect max 34 bytes as tag answer (response to READ4) +// we expect max 34 (32+2) bytes as tag answer (response to READ4) #ifndef ICLASS_BUFFER_SIZE #define ICLASS_BUFFER_SIZE 34 + 2 #endif @@ -57,11 +65,6 @@ #define AddCrc(data, len) compute_crc(CRC_ICLASS, (data), (len), (data)+(len), (data)+(len)+1) -/* -static uint8_t get_pagemap(const picopass_hdr *hdr) { - return (hdr->conf.fuses & (FUSE_CRYPT0 | FUSE_CRYPT1)) >> 3; -} -*/ /* * CARD TO READER @@ -102,7 +105,6 @@ static void CodeIClassTagSOF(void) { ts->max++; } - /* * SOF comprises 3 parts; * * An unmodulated time of 56.64 us @@ -138,7 +140,6 @@ static void CodeIClassTagSOF(void) { * */ - /** * @brief SimulateIClass simulates an iClass card. * @param arg0 type of simulation @@ -154,6 +155,8 @@ static void CodeIClassTagSOF(void) { // turn off afterwards void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain) { iclass_simulate(arg0, arg1, arg2, datain, NULL, NULL); + + DbpString("Button pressed"); } void iclass_simulate(uint8_t sim_type, uint8_t num_csns, bool send_reply, uint8_t *datain, uint8_t *dataout, uint16_t *dataoutlen) { @@ -215,14 +218,13 @@ void iclass_simulate(uint8_t sim_type, uint8_t num_csns, bool send_reply, uint8_ //This is 'full sim' mode, where we use the emulator storage for data. //ie: BigBuf_get_EM_addr should be previously filled with data from the "eload" command picopass_hdr *hdr = (picopass_hdr *)BigBuf_get_EM_addr(); - uint8_t pagemap = (hdr->conf.fuses & (FUSE_CRYPT0 | FUSE_CRYPT1)) >> 3; // 0x18 + uint8_t pagemap = get_pagemap(hdr); if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) { do_iclass_simulation_nonsec(); } else { do_iclass_simulation(ICLASS_SIM_MODE_FULL, NULL); } - } else if (sim_type == ICLASS_SIM_MODE_CONFIG_CARD) { // config card @@ -355,7 +357,6 @@ int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf) { // (iceman) this only works for 2KS / 16KS tags. // Use application data from block 5 memcpy(aia_data, emulator + (8 * 5), 8); - // older 2K / 16K tags has its application issuer data on block 2 } AddCrc(conf_block, 8); @@ -411,26 +412,26 @@ int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf) { int trace_data_size = 0; // Respond SOF -- takes 1 bytes - uint8_t *resp_sof = BigBuf_malloc(2); + uint8_t *resp_sof = BigBuf_malloc(1); int resp_sof_len; // Anticollision CSN (rotated CSN) // 22: Takes 2 bytes for SOF/EOF and 10 * 2 = 20 bytes (2 bytes/byte) - uint8_t *resp_anticoll = BigBuf_malloc(28); + uint8_t *resp_anticoll = BigBuf_malloc(22); int resp_anticoll_len; - // CSN + // CSN (block 0) // 22: Takes 2 bytes for SOF/EOF and 10 * 2 = 20 bytes (2 bytes/byte) - uint8_t *resp_csn = BigBuf_malloc(28); + uint8_t *resp_csn = BigBuf_malloc(22); int resp_csn_len; // configuration (blk 1) PICOPASS 2ks - uint8_t *resp_conf = BigBuf_malloc(28); + uint8_t *resp_conf = BigBuf_malloc(22); int resp_conf_len; // e-Purse (blk 2) // 18: Takes 2 bytes for SOF/EOF and 8 * 2 = 16 bytes (2 bytes/bit) - uint8_t *resp_cc = BigBuf_malloc(28); + uint8_t *resp_cc = BigBuf_malloc(18); int resp_cc_len; // Kd, Kc (blocks 3 and 4). Cannot be read. Always respond with 0xff bytes only @@ -440,7 +441,7 @@ int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf) { AddCrc(ff_data, 8); // Application Issuer Area (blk 5) - uint8_t *resp_aia = BigBuf_malloc(28); + uint8_t *resp_aia = BigBuf_malloc(22); int resp_aia_len; // receive command @@ -448,7 +449,6 @@ int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf) { // Prepare card messages tosend_t *ts = get_tosend(); - ts->max = 0; // First card answer: SOF CodeIClassTagSOF(); @@ -487,11 +487,11 @@ int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf) { //This is used for responding to READ-block commands or other data which is dynamically generated //First the 'trace'-data, not encoded for FPGA - uint8_t *data_generic_trace = BigBuf_malloc(32 + 2); // 32 bytes data + 2byte CRC is max tag answer + uint8_t *data_generic_trace = BigBuf_malloc(34); // 32 bytes data + 2byte CRC is max tag answer //Then storage for the modulated data //Each bit is doubled when modulated for FPGA, and we also have SOF and EOF (2 bytes) - uint8_t *data_response = BigBuf_malloc((32 + 2) * 2 + 2); + uint8_t *data_response = BigBuf_malloc((34 * 2) + 3); enum { IDLE, ACTIVATED, SELECTED, HALTED } chip_state = IDLE; @@ -502,6 +502,13 @@ int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf) { bool exit_loop = false; while (exit_loop == false) { WDT_HIT(); + + // Now look at the reader command and provide appropriate responses + // default is no response: + modulated_response = NULL; + modulated_response_size = 0; + trace_data = NULL; + trace_data_size = 0; uint32_t reader_eof_time = 0; len = GetIso15693CommandFromReader(receivedCmd, MAX_FRAME_SIZE, &reader_eof_time); @@ -510,13 +517,7 @@ int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf) { exit_loop = true; continue; } - - // Now look at the reader command and provide appropriate responses - // default is no response: - modulated_response = NULL; - modulated_response_size = 0; - trace_data = NULL; - trace_data_size = 0; + // extra response data cmd = receivedCmd[0] & 0xF; @@ -525,11 +526,9 @@ int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf) { if (cmd == ICLASS_CMD_ACTALL && len == 1) { // 0x0A // Reader in anti collision phase - if (chip_state != HALTED) { - modulated_response = resp_sof; - modulated_response_size = resp_sof_len; - chip_state = ACTIVATED; - } + modulated_response = resp_sof; + modulated_response_size = resp_sof_len; + chip_state = ACTIVATED; goto send; } else if (cmd == ICLASS_CMD_READ_OR_IDENTIFY && len == 1) { // 0x0C @@ -542,29 +541,29 @@ int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf) { } goto send; - } else if (cmd == ICLASS_CMD_SELECT && len == 9) { - // Reader selects anticollision CSN. - // Tag sends the corresponding real CSN - if (chip_state == ACTIVATED || chip_state == SELECTED) { - if (!memcmp(receivedCmd + 1, anticoll_data, 8)) { - modulated_response = resp_csn; - modulated_response_size = resp_csn_len; - trace_data = csn_data; - trace_data_size = sizeof(csn_data); - chip_state = SELECTED; - } else { - chip_state = IDLE; - } - } else if (chip_state == HALTED) { - // RESELECT with CSN - if (!memcmp(receivedCmd + 1, csn_data, 8)) { - modulated_response = resp_csn; - modulated_response_size = resp_csn_len; - trace_data = csn_data; - trace_data_size = sizeof(csn_data); - chip_state = SELECTED; - } - } + } else if (cmd == ICLASS_CMD_SELECT && len == 9) { + // Reader selects anticollision CSN. + // Tag sends the corresponding real CSN + if (chip_state == ACTIVATED || chip_state == SELECTED) { + if (!memcmp(receivedCmd + 1, anticoll_data, 8)) { + modulated_response = resp_csn; + modulated_response_size = resp_csn_len; + trace_data = csn_data; + trace_data_size = sizeof(csn_data); + chip_state = SELECTED; + } else { + chip_state = IDLE; + } + } else if (chip_state == HALTED || chip_state == IDLE) { + // RESELECT with CSN + if (!memcmp(receivedCmd + 1, csn_data, 8)) { + modulated_response = resp_csn; + modulated_response_size = resp_csn_len; + trace_data = csn_data; + trace_data_size = sizeof(csn_data); + chip_state = SELECTED; + } + } goto send; @@ -573,72 +572,79 @@ int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf) { if (chip_state != SELECTED) { goto send; } - // block0,1,2,5 is always readable. - switch (block) { - case 0: { // csn (0c 00) - modulated_response = resp_csn; - modulated_response_size = resp_csn_len; - trace_data = csn_data; - trace_data_size = sizeof(csn_data); - goto send; - } - case 1: { // configuration (0c 01) - modulated_response = resp_conf; - modulated_response_size = resp_conf_len; - trace_data = conf_block; - trace_data_size = sizeof(conf_block); - goto send; - } - case 2: {// e-purse (0c 02) - modulated_response = resp_cc; - modulated_response_size = resp_cc_len; - trace_data = card_challenge_data; - trace_data_size = sizeof(card_challenge_data); - // set epurse of sim2,4 attack - if (reader_mac_buf != NULL) { - memcpy(reader_mac_buf, card_challenge_data, 8); + if (simulationMode == ICLASS_SIM_MODE_EXIT_AFTER_MAC) { + // provide defaults for blocks 0 ... 5 + + // block0,1,2,5 is always readable. + switch (block) { + case 0: { // csn (0c 00) + modulated_response = resp_csn; + modulated_response_size = resp_csn_len; + trace_data = csn_data; + trace_data_size = sizeof(csn_data); + goto send; } - goto send; - } - case 3: - case 4: { // Kd, Kc, always respond with 0xff bytes + case 1: { // configuration (0c 01) + modulated_response = resp_conf; + modulated_response_size = resp_conf_len; + trace_data = conf_block; + trace_data_size = sizeof(conf_block); + goto send; + } + case 2: {// e-purse (0c 02) + modulated_response = resp_cc; + modulated_response_size = resp_cc_len; + trace_data = card_challenge_data; + trace_data_size = sizeof(card_challenge_data); + // set epurse of sim2,4 attack + if (reader_mac_buf != NULL) { + memcpy(reader_mac_buf, card_challenge_data, 8); + } + goto send; + } + case 3: + case 4: { // Kd, Kc, always respond with 0xff bytes + modulated_response = resp_ff; + modulated_response_size = resp_ff_len; + trace_data = ff_data; + trace_data_size = sizeof(ff_data); + goto send; + } + case 5: { // Application Issuer Area (0c 05) + modulated_response = resp_aia; + modulated_response_size = resp_aia_len; + trace_data = aia_data; + trace_data_size = sizeof(aia_data); + goto send; + } + } // switch + } else if (simulationMode == ICLASS_SIM_MODE_FULL) { + if (block == 3 || block == 4) { // Kd, Kc, always respond with 0xff bytes modulated_response = resp_ff; modulated_response_size = resp_ff_len; trace_data = ff_data; trace_data_size = sizeof(ff_data); - goto send; + } else { // use data from emulator memory + memcpy(data_generic_trace, emulator + current_page * page_size + 8 * block, 8); + AddCrc(data_generic_trace, 8); + trace_data = data_generic_trace; + trace_data_size = 10; + CodeIso15693AsTag(trace_data, trace_data_size); + memcpy(data_response, ts->buf, ts->max); + modulated_response = data_response; + modulated_response_size = ts->max; } - case 5: { // Application Issuer Area (0c 05) - modulated_response = resp_aia; - modulated_response_size = resp_aia_len; - trace_data = aia_data; - trace_data_size = sizeof(aia_data); - goto send; - } - default : { - if (simulationMode == ICLASS_SIM_MODE_FULL) { // 0x0C - //Read block - //Take the data... - memcpy(data_generic_trace, emulator + (block << 3), 8); - AddCrc(data_generic_trace, 8); - trace_data = data_generic_trace; - trace_data_size = 10; - CodeIso15693AsTag(trace_data, trace_data_size); - memcpy(data_response, ts->buf, ts->max); - modulated_response = data_response; - modulated_response_size = ts->max; - } - goto send; - } - } // swith + goto send; + } - } else if (cmd == ICLASS_CMD_READCHECK) { // 0x88 + } else if (cmd == ICLASS_CMD_READCHECK && block == 0x02 && len == 2) { // 0x88 // Read e-purse KD (88 02) KC (18 02) if (chip_state != SELECTED) { goto send; } - if ( ICLASS_DEBIT(cmd) ){ + // debit key + if ( receivedCmd[0] == 0x88 ){ cipher_state = &cipher_state_KD[current_page]; diversified_key = diversified_kd; } else { @@ -671,11 +677,6 @@ int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf) { modulated_response_size = ts->max; } else { // Not fullsim, we don't respond - // We do not know what to answer, so lets keep quiet - modulated_response = resp_sof; - modulated_response_size = 0; - trace_data = NULL; - trace_data_size = 0; chip_state = HALTED; if (simulationMode == ICLASS_SIM_MODE_EXIT_AFTER_MAC) { @@ -716,8 +717,8 @@ int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf) { goto send; } //Read block - memcpy(data_generic_trace, emulator + (current_page * page_size) + (block * 8), 8 * 4); - AddCrc(data_generic_trace, 8 * 4); + memcpy(data_generic_trace, emulator + (current_page * page_size) + (block * 8), 32); + AddCrc(data_generic_trace, 32); trace_data = data_generic_trace; trace_data_size = 34; CodeIso15693AsTag(trace_data, trace_data_size); @@ -946,7 +947,7 @@ int do_iclass_simulation_nonsec(void) { memcpy(resp_conf, ts->buf, ts->max); resp_conf_len = ts->max; - // Application Issuer Area (block 5) + // Application Issuer Area (block 2) CodeIso15693AsTag(aia_data, sizeof(aia_data)); memcpy(resp_aia, ts->buf, ts->max); resp_aia_len = ts->max; @@ -1008,29 +1009,29 @@ int do_iclass_simulation_nonsec(void) { } goto send; - } else if (cmd == ICLASS_CMD_SELECT && len == 9) { - // Reader selects anticollision CSN. - // Tag sends the corresponding real CSN - if (chip_state == ACTIVATED || chip_state == SELECTED) { - if (!memcmp(receivedCmd + 1, anticoll_data, 8)) { - modulated_response = resp_csn; - modulated_response_size = resp_csn_len; - trace_data = csn_data; - trace_data_size = sizeof(csn_data); - chip_state = SELECTED; - } else { - chip_state = IDLE; - } - } else if (chip_state == HALTED) { - // RESELECT with CSN - if (!memcmp(receivedCmd + 1, csn_data, 8)) { - modulated_response = resp_csn; - modulated_response_size = resp_csn_len; - trace_data = csn_data; - trace_data_size = sizeof(csn_data); - chip_state = SELECTED; - } - } + } else if (cmd == ICLASS_CMD_SELECT && len == 9) { + // Reader selects anticollision CSN. + // Tag sends the corresponding real CSN + if (chip_state == ACTIVATED || chip_state == SELECTED) { + if (!memcmp(receivedCmd + 1, anticoll_data, 8)) { + modulated_response = resp_csn; + modulated_response_size = resp_csn_len; + trace_data = csn_data; + trace_data_size = sizeof(csn_data); + chip_state = SELECTED; + } else { + chip_state = IDLE; + } + } else if (chip_state == HALTED) { + // RESELECT with CSN + if (!memcmp(receivedCmd + 1, csn_data, 8)) { + modulated_response = resp_csn; + modulated_response_size = resp_csn_len; + trace_data = csn_data; + trace_data_size = sizeof(csn_data); + chip_state = SELECTED; + } + } goto send; @@ -1206,8 +1207,6 @@ static bool iclass_send_cmd_with_retries(uint8_t* cmd, size_t cmdsize, uint8_t* if (expected_size == GetIso15693AnswerFromTag(resp, max_resp_size, timeout, eof_time)) { return true; } - - *start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; } return false; } @@ -1281,8 +1280,8 @@ static bool select_iclass_tag_ex(uint8_t *card_data, bool use_credit_key, uint32 *status |= (FLAG_ICLASS_CSN | FLAG_ICLASS_CONF); picopass_hdr *hdr = (picopass_hdr *)card_data; - uint8_t pagemap = (hdr->conf.fuses & (FUSE_CRYPT0 | FUSE_CRYPT1)) >> 3; // 0x18 + uint8_t pagemap = get_pagemap(hdr); if (pagemap != PICOPASS_NON_SECURE_PAGEMODE) { //Read App Issuer Area block 5 @@ -1414,7 +1413,7 @@ void ReaderIClass(uint8_t flags) { } // turn off afterwards -void ReaderIClass_Replay(uint8_t arg0, uint8_t *mac) { +void ReaderIClass_Replay(uint8_t reader, uint8_t *mac) { uint8_t cardsize = 0; uint8_t mem = 0; @@ -1540,6 +1539,8 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *mac) { 0 ); switch_off(); + + reply_ng(CMD_HF_ICLASS_REPLAY, PM3_SUCCESS, (uint8_t *)&res, sizeof(uint8_t)); } // used with function select_and_auth (cmdhficlass.c) @@ -1653,7 +1654,7 @@ void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain) { check[8] = keys[i].mac[3]; // expect 4bytes, 3 retries times.. - isOK = iclass_send_cmd_with_retries(check, sizeof(check), resp, sizeof(resp), 4, 3, &start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time); + isOK = iclass_send_cmd_with_retries(check, sizeof(check), resp, sizeof(resp), 4, 2, &start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time); if (isOK) goto out; @@ -1672,14 +1673,14 @@ out: } // Tries to read block. -// retries 10times. +// retries 3times. // reply 8 bytes block bool iclass_read_block(uint8_t blockno, uint8_t *data) { uint8_t resp[10]; uint8_t c[] = {ICLASS_CMD_READ_OR_IDENTIFY, blockno, 0x00, 0x00}; AddCrc(c + 1, 1); uint32_t eof_time = 0, start_time = 0; - bool isOK = iclass_send_cmd_with_retries(c, sizeof(c), resp, sizeof(resp), 10, 10, &start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time); + bool isOK = iclass_send_cmd_with_retries(c, sizeof(c), resp, sizeof(resp), 10, 3, &start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time); if (isOK) memcpy(data, resp, 8); return isOK; @@ -1697,7 +1698,7 @@ void iClass_ReadBlock(uint8_t *msg) { uint8_t cmd_read[] = {ICLASS_CMD_READ_OR_IDENTIFY, payload->blockno, 0x00, 0x00}; AddCrc(cmd_read + 1, 1); - + Iso15693InitReader(); // select tag. @@ -1731,7 +1732,7 @@ void iClass_ReadBlock(uint8_t *msg) { // read data uint8_t resp[10]; - res = iclass_send_cmd_with_retries(cmd_read, sizeof(cmd_read), resp, sizeof(resp), 10, 10, &start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time); + res = iclass_send_cmd_with_retries(cmd_read, sizeof(cmd_read), resp, sizeof(resp), 10, 3, &start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time); if (res) { memcpy(response.data, resp, sizeof(response.data)); if (payload->send_reply) { @@ -1757,18 +1758,20 @@ void iClass_Dump(uint8_t *msg) { BigBuf_free(); + iclass_dump_req_t *cmd = (iclass_dump_req_t *)msg; + iclass_auth_req_t *req = &cmd->req; + uint8_t *dataout = BigBuf_malloc(0xFF * 8); if (dataout == NULL) { DbpString("fail to allocate memory"); - reply_ng(CMD_HF_ICLASS_DUMP, PM3_EMALLOC, NULL, 0); + if (req->send_reply) { + reply_ng(CMD_HF_ICLASS_DUMP, PM3_EMALLOC, NULL, 0); + } switch_off(); return; } memset(dataout, 0xFF, 0xFF * 8); - iclass_dump_req_t *cmd = (iclass_dump_req_t *)msg; - iclass_auth_req_t *req = &cmd->req; - Iso15693InitReader(); // select tag. @@ -1782,12 +1785,11 @@ void iClass_Dump(uint8_t *msg) { switch_off(); return; } - + uint32_t start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; // authenticate if (req->do_auth) { - res = authenticate_iclass_tag(req, &hdr, &start_time, &eof_time, NULL); if (res == false) { if (req->send_reply) { @@ -1800,32 +1802,23 @@ void iClass_Dump(uint8_t *msg) { start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + bool dumpsuccess = true; + // main read loop - uint8_t i = cmd->start_block; - for (; i <= cmd->end_block; i++) { - res = iclass_read_block(i, dataout + (8 * i)); - if (res == false) { - Dbprintf("failed to read block %02X", req->blockno + i); - break; + uint8_t i; + for (i = cmd->start_block; i <= cmd->end_block; i++) { + + uint8_t resp[10]; + uint8_t c[] = {ICLASS_CMD_READ_OR_IDENTIFY, i, 0x00, 0x00}; + AddCrc(c + 1, 1); + + res = iclass_send_cmd_with_retries(c, sizeof(c), resp, sizeof(resp), 10, 3, &start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time); + if (res) { + memcpy(dataout + (8 * i), resp, 8); + } else { + Dbprintf("failed to read block %u ( 0x%02x)", i, i); + dumpsuccess = false; } - /* - else { - Dbprintf("blk: %u (0x%02x) | %02x %02x %02x %02x %02x %02x %02x %02x ", - i, - i, - dataout[8 * i], - dataout[(8 * i) + 1], - dataout[(8 * i) + 2], - dataout[(8 * i) + 3], - dataout[(8 * i) + 4], - dataout[(8 * i) + 5], - dataout[(8 * i) + 6], - dataout[(8 * i) + 7] - ); - - - } - */ } switch_off(); @@ -1845,11 +1838,12 @@ void iClass_Dump(uint8_t *msg) { uint32_t bb_offset; } PACKED response; - response.isOK = res; + response.isOK = dumpsuccess; response.block_cnt = i; response.bb_offset = dataout - BigBuf_get_addr(); reply_ng(CMD_HF_ICLASS_DUMP, PM3_SUCCESS, (uint8_t *)&response, sizeof(response)); } + BigBuf_free(); } diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index 379d094af..1b25b946b 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -190,9 +190,13 @@ static void CodeIso15693AsReader256(uint8_t *cmd, int n) { } static const uint8_t encode_4bits[16] = { +// 0 1 2 3 0xaa, 0x6a, 0x9a, 0x5a, +// 4 5 6 7 0xa6, 0x66, 0x96, 0x56, +// 8 9 A B 0xa9, 0x69, 0x99, 0x59, +// C D E F 0xa5, 0x65, 0x95, 0x55 }; @@ -230,9 +234,11 @@ void CodeIso15693AsTag(uint8_t *cmd, size_t len) { ts->buf[++ts->max] = 0x1D; // 00011101 // data - for (int i = 0; i < len; i++) { + for (int i = 0; i < len; i += 2) { ts->buf[++ts->max] = encode_4bits[cmd[i] & 0xF]; ts->buf[++ts->max] = encode_4bits[cmd[i] >> 4]; + ts->buf[++ts->max] = encode_4bits[cmd[i + 1] & 0xF]; + ts->buf[++ts->max] = encode_4bits[cmd[i + 1] >> 4]; } // EOF @@ -304,8 +310,8 @@ void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t *start_time, LED_C_ON(); uint8_t bits_to_shift = 0x00; - uint8_t bits_to_send = 0x00; - + uint8_t bits_to_send = 0x00; + for (size_t c = 0; c < len; c++) { for (int i = (c == 0 ? 4 : 7); i >= 0; i--) { @@ -322,12 +328,15 @@ void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t *start_time, } WDT_HIT(); } + // send the remaining bits, padded with 0: bits_to_send = bits_to_shift << (8 - shift_delay); - for ( ; ; ) { - if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { - AT91C_BASE_SSC->SSC_THR = bits_to_send; - break; + if (bits_to_send) { + for ( ; ; ) { + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { + AT91C_BASE_SSC->SSC_THR = bits_to_send; + break; + } } } LED_C_OFF(); @@ -614,8 +623,12 @@ int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, uint16_t timeo int samples = 0, ret = 0; // the Decoder data structure - DecodeTag_t DecodeTag = { 0 }; - DecodeTagInit(&DecodeTag, response, max_len); + DecodeTag_t dtm = { 0 }; + DecodeTag_t *dt = &dtm; + DecodeTagInit(dt, response, max_len); + + //DecodeTag_t *dt = (DecodeTag_t *)BigBuf_malloc(sizeof(DecodeTag_t)); + //DecodeTagInit(dt, response, max_len); // wait for last transfer to complete while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)); @@ -665,18 +678,18 @@ int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, uint16_t timeo AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE; // DMA Next Counter registers } - if (Handle15693SamplesFromTag(tagdata, &DecodeTag)) { + if (Handle15693SamplesFromTag(tagdata, dt)) { *eof_time = dma_start_time + (samples * 16) - DELAY_TAG_TO_ARM; // end of EOF - if (DecodeTag.lastBit == SOF_PART2) { + if (dt->lastBit == SOF_PART2) { *eof_time -= (8 * 16); // needed 8 additional samples to confirm single SOF (iCLASS) } - if (DecodeTag.len > DecodeTag.max_len) { + if (dt->len > dt->max_len) { ret = -2; // buffer overflow } break; } - if (samples > timeout && DecodeTag.state < STATE_TAG_RECEIVING_DATA) { + if (samples > timeout && dt->state < STATE_TAG_RECEIVING_DATA) { ret = -3; // timeout break; } @@ -686,20 +699,20 @@ int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, uint16_t timeo FpgaDisableSscDma(); uint32_t sof_time = *eof_time - - (DecodeTag.len * 8 * 8 * 16) // time for byte transfers + - (dt->len * 8 * 8 * 16) // time for byte transfers - (32 * 16) // time for SOF transfer - - (DecodeTag.lastBit != SOF_PART2 ? (32 * 16) : 0); // time for EOF transfer + - (dt->lastBit != SOF_PART2 ? (32 * 16) : 0); // time for EOF transfer if (DBGLEVEL >= DBG_EXTENDED) { Dbprintf("samples = %d, ret = %d, Decoder: state = %d, lastBit = %d, len = %d, bitCount = %d, posCount = %d, maxlen = %u", samples, ret, - DecodeTag.state, - DecodeTag.lastBit, - DecodeTag.len, - DecodeTag.bitCount, - DecodeTag.posCount, - DecodeTag.max_len + dt->state, + dt->lastBit, + dt->len, + dt->bitCount, + dt->posCount, + dt->max_len ); Dbprintf("timing: sof_time = %d, eof_time = %d", (sof_time * 4), (*eof_time * 4)); } @@ -708,8 +721,8 @@ int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, uint16_t timeo return ret; } - LogTrace_ISO15693(DecodeTag.output, DecodeTag.len, (sof_time * 4), (*eof_time * 4), NULL, false); - return DecodeTag.len; + LogTrace_ISO15693(dt->output, dt->len, (sof_time * 4), (*eof_time * 4), NULL, false); + return dt->len; } @@ -1049,8 +1062,8 @@ int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eo bool gotFrame = false; // the decoder data structure - DecodeReader_t DecodeReader = {0}; - DecodeReaderInit(&DecodeReader, received, max_len, 0, NULL); + DecodeReader_t *dr = (DecodeReader_t *)BigBuf_malloc(sizeof(DecodeReader_t)); + DecodeReaderInit(dr, received, max_len, 0, NULL); // wait for last transfer to complete while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)); @@ -1097,7 +1110,7 @@ int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eo } for (int i = 7; i >= 0; i--) { - if (Handle15693SampleFromReader((b >> i) & 0x01, &DecodeReader)) { + if (Handle15693SampleFromReader((b >> i) & 0x01, dr)) { *eof_time = dma_start_time + samples - DELAY_READER_TO_ARM; // end of EOF gotFrame = true; break; @@ -1110,7 +1123,7 @@ int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eo } if (BUTTON_PRESS()) { - DecodeReader.byteCount = -1; + dr->byteCount = -1; break; } @@ -1121,19 +1134,19 @@ int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eo if (DBGLEVEL >= DBG_EXTENDED) { Dbprintf("samples = %d, gotFrame = %d, Decoder: state = %d, len = %d, bitCount = %d, posCount = %d", - samples, gotFrame, DecodeReader.state, DecodeReader.byteCount, - DecodeReader.bitCount, DecodeReader.posCount); + samples, gotFrame, dr->state, dr->byteCount, + dr->bitCount, dr->posCount); } - if (DecodeReader.byteCount >= 0) { + if (dr->byteCount >= 0) { uint32_t sof_time = *eof_time - - DecodeReader.byteCount * (DecodeReader.Coding == CODING_1_OUT_OF_4 ? 128 : 2048) // time for byte transfers + - dr->byteCount * (dr->Coding == CODING_1_OUT_OF_4 ? 128 : 2048) // time for byte transfers - 32 // time for SOF transfer - 16; // time for EOF transfer - LogTrace_ISO15693(DecodeReader.output, DecodeReader.byteCount, (sof_time * 32), (*eof_time * 32), NULL, true); + LogTrace_ISO15693(dr->output, dr->byteCount, (sof_time * 32), (*eof_time * 32), NULL, true); } - return DecodeReader.byteCount; + return dr->byteCount; } //----------------------------------------------------------------------------- @@ -1193,19 +1206,19 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string) { // Count of samples received so far, so that we can include timing int samples = 0; -// DecodeTag_t dtag = {0}; -// uint8_t response[ISO15693_MAX_RESPONSE_LENGTH] = {0}; -// DecodeTagInit(&dtag, response, sizeof(response)); - DecodeTag_t *dtag = (DecodeTag_t *)BigBuf_malloc(sizeof(DecodeTag_t)); - uint8_t *response = BigBuf_malloc(ISO15693_MAX_RESPONSE_LENGTH); - DecodeTagInit(dtag, response, ISO15693_MAX_RESPONSE_LENGTH); + DecodeTag_t dtag = {0}; + uint8_t response[ISO15693_MAX_RESPONSE_LENGTH] = {0}; + DecodeTagInit(&dtag, response, sizeof(response)); +// DecodeTag_t *dtag = (DecodeTag_t *)BigBuf_malloc(sizeof(DecodeTag_t)); +// uint8_t *response = BigBuf_malloc(ISO15693_MAX_RESPONSE_LENGTH); +// DecodeTagInit(dtag, response, ISO15693_MAX_RESPONSE_LENGTH); -// DecodeReader_t dreader = {0}; -// uint8_t cmd[ISO15693_MAX_COMMAND_LENGTH] = {0}; -// DecodeReaderInit(&dreader, cmd, sizeof(cmd), jam_search_len, jam_search_string); - DecodeReader_t *dreader = (DecodeReader_t *)BigBuf_malloc(sizeof(DecodeReader_t)); - uint8_t *cmd = BigBuf_malloc(ISO15693_MAX_COMMAND_LENGTH); - DecodeReaderInit(dreader, cmd, ISO15693_MAX_COMMAND_LENGTH, jam_search_len, jam_search_string); + DecodeReader_t dreader = {0}; + uint8_t cmd[ISO15693_MAX_COMMAND_LENGTH] = {0}; + DecodeReaderInit(&dreader, cmd, sizeof(cmd), jam_search_len, jam_search_string); +// DecodeReader_t *dreader = (DecodeReader_t *)BigBuf_malloc(sizeof(DecodeReader_t)); +// uint8_t *cmd = BigBuf_malloc(ISO15693_MAX_COMMAND_LENGTH); +// DecodeReaderInit(dreader, cmd, ISO15693_MAX_COMMAND_LENGTH, jam_search_len, jam_search_string); // Print some debug information about the buffer sizes if (DBGLEVEL >= DBG_EXTENDED) { @@ -1214,8 +1227,19 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string) { Dbprintf(" Reader -> tag: %i bytes", ISO15693_MAX_COMMAND_LENGTH); Dbprintf(" Tag -> Reader: %i bytes", ISO15693_MAX_RESPONSE_LENGTH); Dbprintf(" DMA: %i bytes", DMA_BUFFER_SIZE * sizeof(uint16_t)); + + Dbprintf(" Decoder Reader : %u bytes", (uint32_t)&dreader ); + Dbprintf(" Decode Tag : %u bytes", (uint32_t)&dtag); } + // The DMA buffer, used to stream samples from the FPGA + dmabuf16_t *dma = get_dma16(); + + Dbprintf("dmabuf %u", (uint32_t)dma->buf ); + Dbprintf("dmabuf +1 %u", (uint32_t)dma->buf + 1); + Dbprintf("dmabuf +256 %u", (uint32_t)dma->buf + DMA_BUFFER_SIZE); + Dbprintf("dmabuf +512 %u", (uint32_t)dma->buf + (DMA_BUFFER_SIZE * 2)); + Dbprintf("Starting to sniff. Press PM3 Button to stop."); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SNIFF_AMPLITUDE); @@ -1226,11 +1250,11 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string) { StartCountSspClk(); // The DMA buffer, used to stream samples from the FPGA - dmabuf16_t *dma = get_dma16(); + //dmabuf16_t *dma = get_dma16(); uint16_t *upTo = dma->buf; // Setup and start DMA. - if (FpgaSetupSscDma((uint8_t *) dma->buf, DMA_BUFFER_SIZE) == false) { + if (FpgaSetupSscDma((uint8_t *) dma->buf, DMA_BUFFER_SIZE * 2) == false) { if (DBGLEVEL > DBG_ERROR) Dbprintf("FpgaSetupSscDma failed. Exiting"); switch_off(); return; @@ -1291,6 +1315,7 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string) { uint16_t behindBy = ((uint16_t*)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (DMA_BUFFER_SIZE - 1); if (behindBy == 0) continue; + Dbprintf("behindBy %d", behindBy); if (upTo >= dma->buf + DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. @@ -1321,69 +1346,69 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string) { // no need to try decoding reader data if the tag is sending if (tag_is_active == false) { - if (Handle15693SampleFromReader(sniffdata & 0x02, dreader)) { + if (Handle15693SampleFromReader(sniffdata & 0x02, &dreader)) { uint32_t eof_time = dma_start_time + (samples * 16) + 8 - DELAY_READER_TO_ARM_SNIFF; // end of EOF - if (dreader->byteCount > 0) { + if (dreader.byteCount > 0) { uint32_t sof_time = eof_time - - dreader->byteCount * (dreader->Coding == CODING_1_OUT_OF_4 ? 128 * 16 : 2048 * 16) // time for byte transfers + - dreader.byteCount * (dreader.Coding == CODING_1_OUT_OF_4 ? 128 * 16 : 2048 * 16) // time for byte transfers - 32 * 16 // time for SOF transfer - 16 * 16; // time for EOF transfer - LogTrace_ISO15693(dreader->output, dreader->byteCount, (sof_time * 4), (eof_time * 4), NULL, true); + LogTrace_ISO15693(dreader.output, dreader.byteCount, (sof_time * 4), (eof_time * 4), NULL, true); } // And ready to receive another command. - DecodeReaderReset(dreader); + DecodeReaderReset(&dreader); // And also reset the demod code, which might have been // false-triggered by the commands from the reader. - DecodeTagReset(dtag); + DecodeTagReset(&dtag); reader_is_active = false; expect_tag_answer = true; - } else if (Handle15693SampleFromReader(sniffdata & 0x01, dreader)) { + } else if (Handle15693SampleFromReader(sniffdata & 0x01, &dreader)) { uint32_t eof_time = dma_start_time + (samples * 16) + 16 - DELAY_READER_TO_ARM_SNIFF; // end of EOF - if (dreader->byteCount > 0) { + if (dreader.byteCount > 0) { uint32_t sof_time = eof_time - - dreader->byteCount * (dreader->Coding == CODING_1_OUT_OF_4 ? 128 * 16 : 2048 * 16) // time for byte transfers + - dreader.byteCount * (dreader.Coding == CODING_1_OUT_OF_4 ? 128 * 16 : 2048 * 16) // time for byte transfers - 32 * 16 // time for SOF transfer - 16 * 16; // time for EOF transfer - LogTrace_ISO15693(dreader->output, dreader->byteCount, (sof_time * 4), (eof_time * 4), NULL, true); + LogTrace_ISO15693(dreader.output, dreader.byteCount, (sof_time * 4), (eof_time * 4), NULL, true); } // And ready to receive another command - DecodeReaderReset(dreader); + DecodeReaderReset(&dreader); // And also reset the demod code, which might have been // false-triggered by the commands from the reader. - DecodeTagReset(dtag); + DecodeTagReset(&dtag); reader_is_active = false; expect_tag_answer = true; } else { - reader_is_active = (dreader->state >= STATE_READER_RECEIVE_DATA_1_OUT_OF_4); + reader_is_active = (dreader.state >= STATE_READER_RECEIVE_DATA_1_OUT_OF_4); } } if (reader_is_active == false && expect_tag_answer) { // no need to try decoding tag data if the reader is currently sending or no answer expected yet - if (Handle15693SamplesFromTag(sniffdata >> 2, dtag)) { + if (Handle15693SamplesFromTag(sniffdata >> 2, &dtag)) { uint32_t eof_time = dma_start_time + (samples * 16) - DELAY_TAG_TO_ARM_SNIFF; // end of EOF - if (dtag->lastBit == SOF_PART2) { + if (dtag.lastBit == SOF_PART2) { eof_time -= (8 * 16); // needed 8 additional samples to confirm single SOF (iCLASS) } uint32_t sof_time = eof_time - - dtag->len * 8 * 8 * 16 // time for byte transfers + - dtag.len * 8 * 8 * 16 // time for byte transfers - (32 * 16) // time for SOF transfer - - (dtag->lastBit != SOF_PART2 ? (32 * 16) : 0); // time for EOF transfer + - (dtag.lastBit != SOF_PART2 ? (32 * 16) : 0); // time for EOF transfer - LogTrace_ISO15693(dtag->output, dtag->len, (sof_time * 4), (eof_time * 4), NULL, false); + LogTrace_ISO15693(dtag.output, dtag.len, (sof_time * 4), (eof_time * 4), NULL, false); // And ready to receive another response. - DecodeTagReset(dtag); - DecodeReaderReset(dreader); + DecodeTagReset(&dtag); + DecodeReaderReset(&dreader); expect_tag_answer = false; tag_is_active = false; } else { - tag_is_active = (dtag->state >= STATE_TAG_RECEIVING_DATA); + tag_is_active = (dtag.state >= STATE_TAG_RECEIVING_DATA); } } @@ -1394,12 +1419,12 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string) { DbpString("Sniff statistics:"); Dbprintf(" ExpectTagAnswer: %d, TagIsActive: %d, ReaderIsActive: %d", expect_tag_answer, tag_is_active, reader_is_active); - Dbprintf(" DecodeTag State: %d", dtag->state); - Dbprintf(" DecodeTag byteCnt: %d", dtag->len); - Dbprintf(" DecodeTag posCount: %d", dtag->posCount); - Dbprintf(" DecodeReader State: %d", dreader->state); - Dbprintf(" DecodeReader byteCnt: %d", dreader->byteCount); - Dbprintf(" DecodeReader posCount: %d", dreader->posCount); + Dbprintf(" DecodeTag State: %d", dtag.state); + Dbprintf(" DecodeTag byteCnt: %d", dtag.len); + Dbprintf(" DecodeTag posCount: %d", dtag.posCount); + Dbprintf(" DecodeReader State: %d", dreader.state); + Dbprintf(" DecodeReader byteCnt: %d", dreader.byteCount); + Dbprintf(" DecodeReader posCount: %d", dreader.posCount); Dbprintf(" Trace length: %d", BigBuf_get_traceLen()); // Dbprintf(" Max behindBy: %d", max_behindBy); } diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index fc79a7689..3158665c9 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -860,16 +860,22 @@ static int CmdHFiClassReader_Replay(const char *Cmd) { char cmdp = tolower(param_getchar(Cmd, 0)); if (strlen(Cmd) < 1 || cmdp == 'h') return usage_hf_iclass_replay(); - uint8_t readerType = 0; - uint8_t MAC[4] = {0x00, 0x00, 0x00, 0x00}; + struct { + uint8_t reader; + uint8_t mac[4]; + } PACKED payload; - if (param_gethex(Cmd, 0, MAC, 8)) { + if (param_gethex(Cmd, 0, payload.mac, 8)) { PrintAndLogEx(FAILED, "MAC must include 8 HEX symbols"); return PM3_EINVARG; } clearCommandBuffer(); - SendCommandMIX(CMD_HF_ICLASS_REPLAY, readerType, 0, 0, MAC, 4); + SendCommandNG(CMD_HF_ICLASS_REPLAY, (uint8_t *)&payload, sizeof(payload)); + PacketResponseNG resp; + if (!WaitForResponseTimeout(CMD_HF_ICLASS_REPLAY, &resp, 2000) == 0) { + } + return PM3_SUCCESS; } @@ -1516,28 +1522,12 @@ static int CmdHFiClassDump(const char *Cmd) { } if (errors) return usage_hf_iclass_dump(); - // if no debit key given try credit key on AA1 (not for iclass but for some picopass this will work) - -// vi behöver: -// block 0-5 (6st) om AA1/AA2 -// - block 3 får vi vid KD normalt 0xFF -// - block 4 får vi vid KC normalt 0xFF - -// block 0-2 (3st) om non-secure.. -// -// -// vi har 0,1,2 redan. -// -// från bigbuffer så behöver vi... -// -// block 18 /0x12 saknas i dump data. - - uint32_t flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE); //get CSN and config PacketResponseNG resp; uint8_t tag_data[255 * 8]; + memset(tag_data, 0xFF, sizeof(tag_data)); clearCommandBuffer(); SendCommandMIX(CMD_HF_ICLASS_READER, flags, 0, 0, NULL, 0); @@ -1651,17 +1641,7 @@ static int CmdHFiClassDump(const char *Cmd) { uint32_t startindex = packet->bb_offset; uint32_t blocks_read = packet->block_cnt; - if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) { - if (blocks_read != app_limit1 - 2) { - PrintAndLogEx(WARNING, "failed to get all memory (non secure page mode)"); - } - } else { - if (blocks_read != app_limit1 - 5) { - PrintAndLogEx(WARNING, "failed to get all AA1 memory"); - } - } - - uint8_t tempbuf[0xFF * 8] = {0}; + uint8_t tempbuf[0xFF * 8]; // response ok - now get bigbuf content of the dump if (!GetFromDevice(BIG_BUF, tempbuf, sizeof(tempbuf), startindex, NULL, 0, NULL, 2500, false)) { @@ -1675,6 +1655,8 @@ static int CmdHFiClassDump(const char *Cmd) { } else { // div key KD memcpy(tag_data + (8 * 3), tempbuf + (8 * 3), 8); + // AIA data + memcpy(tag_data + (8 * 5), tempbuf + (8 * 5), 8); // AA1 data memcpy(tag_data + (8 * 6), tempbuf + (8 * 6), (blocks_read * 8) ); } @@ -1930,7 +1912,12 @@ static int CmdHFiClass_WriteBlock(const char *Cmd) { return isok; } -static int CmdHFiClassCloneTag(const char *Cmd) { +/* +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}; uint8_t KEY[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; @@ -2127,9 +2114,9 @@ static int CmdHFiClassCloneTag(const char *Cmd) { if (resp.status == PM3_SUCCESS) { if (resp.data.asBytes[0] == 1) - PrintAndLogEx(SUCCESS, "Clone successful"); + PrintAndLogEx(SUCCESS, "Restore successful"); else - PrintAndLogEx(WARNING, "Clone failed"); + PrintAndLogEx(WARNING, "Restore failed"); } return resp.status; } @@ -2260,6 +2247,7 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) { if (auth == false && verbose) { PrintAndLogEx(WARNING, "warning: no authentication used with read. Typical for cards configured toin `non-secure page`"); + } uint8_t data[8] = {0}; @@ -2735,6 +2723,30 @@ static int CmdHFiClassManageKeys(const char *Cmd) { return PM3_SUCCESS; } +static void add_key(uint8_t *key) { + + uint8_t i; + for (i = 0; i < ICLASS_KEYS_MAX; i++) { + + if (memcmp(iClass_Key_Table[i], key, 8) == 0) { + PrintAndLogEx(SUCCESS, "Key already at keyslot " _GREEN_("%d"), i); + break; + } + + if (memcmp(iClass_Key_Table[i], "\x00\x00\x00\x00\x00\x00\x00\x00", 8) == 0) { + memcpy(iClass_Key_Table[i], key, 8); + PrintAndLogEx(SUCCESS, "Added key to keyslot " _GREEN_("%d"), i); + break; + } + } + + if (i == ICLASS_KEYS_MAX) { + PrintAndLogEx(INFO, "Couldn't find an empty keyslot"); + } else { + PrintAndLogEx(HINT, "Try " _YELLOW_("`hf iclass managekeys p`") " to view keys"); + } +} + static int CmdHFiClassCheckKeys(const char *Cmd) { // empty string @@ -2747,7 +2759,7 @@ static int CmdHFiClassCheckKeys(const char *Cmd) { bool use_elite = false; bool use_raw = false; bool use_credit_key = false; - bool found_debit = false; + bool found_key = false; //bool found_credit = false; bool got_csn = false; bool errors = false; @@ -2792,20 +2804,6 @@ static int CmdHFiClassCheckKeys(const char *Cmd) { } if (errors) return usage_hf_iclass_chk(); - // Get CSN / UID and CCNR - PrintAndLogEx(SUCCESS, "Reading tag CSN"); - for (uint8_t i = 0; i < ICLASS_AUTH_RETRY && !got_csn; i++) { - got_csn = select_only(CSN, CCNR, false); - if (got_csn == false) - PrintAndLogEx(WARNING, "one more try"); - } - - if (got_csn == false) { - PrintAndLogEx(WARNING, "Tried 10 times. Can't select card, aborting..."); - DropField(); - return PM3_ESOFT; - } - uint8_t *keyBlock = NULL; uint32_t keycount = 0; @@ -2818,25 +2816,37 @@ static int CmdHFiClassCheckKeys(const char *Cmd) { pre = calloc(keycount, sizeof(iclass_premac_t)); if (!pre) { - DropField(); free(keyBlock); return PM3_EMALLOC; } - PrintAndLogEx(SUCCESS, "Generating diversified keys"); + // Get CSN / UID and CCNR + PrintAndLogEx(SUCCESS, "Reading tag CSN / CCNR..."); + for (uint8_t i = 0; i < ICLASS_AUTH_RETRY && !got_csn; i++) { + got_csn = select_only(CSN, CCNR, false); + if (got_csn == false) + PrintAndLogEx(WARNING, "one more try"); + } + + if (got_csn == false) { + PrintAndLogEx(WARNING, "Tried 10 times. Can't select card, aborting..."); + free(keyBlock); + DropField(); + return PM3_ESOFT; + } + + PrintAndLogEx(SUCCESS, " CSN: " _GREEN_("%s"), sprint_hex(CSN, sizeof(CSN))); + PrintAndLogEx(SUCCESS, " CCNR: " _GREEN_("%s"), sprint_hex(CCNR, sizeof(CCNR))); + + PrintAndLogEx(SUCCESS, "Generating diversified keys..."); if (use_elite) PrintAndLogEx(SUCCESS, "Using " _YELLOW_("elite algo")); if (use_raw) - PrintAndLogEx(SUCCESS, "Using " _YELLOW_(" raw mode")); - - PrintAndLogEx(SUCCESS, "Searching for " _YELLOW_("%s") " key", (use_credit_key) ? "CREDIT" : "DEBIT"); - PrintAndLogEx(SUCCESS, "Tag info"); - PrintAndLogEx(SUCCESS, "CSN | %s", sprint_hex(CSN, sizeof(CSN))); - PrintAndLogEx(SUCCESS, "CCNR | %s", sprint_hex(CCNR, sizeof(CCNR))); + PrintAndLogEx(SUCCESS, "Using " _YELLOW_("raw mode")); GenerateMacFrom(CSN, CCNR, use_raw, use_elite, keyBlock, keycount, pre); - //PrintPreCalcMac(keyBlock, keycnt, pre); + PrintAndLogEx(SUCCESS, "Searching for " _YELLOW_("%s") " key...", (use_credit_key) ? "CREDIT" : "DEBIT"); // max 42 keys inside USB_COMMAND. 512/4 = 103 mac uint32_t chunksize = keycount > (PM3_CMD_DATA_SIZE / 4) ? (PM3_CMD_DATA_SIZE / 4) : keycount; @@ -2876,7 +2886,8 @@ static int CmdHFiClassCheckKeys(const char *Cmd) { clearCommandBuffer(); SendCommandOLD(CMD_HF_ICLASS_CHKKEYS, flags, keys, 0, pre + key_offset, 4 * keys); PacketResponseNG resp; - + + bool looped = false; while (!WaitForResponseTimeout(CMD_HF_ICLASS_CHKKEYS, &resp, 2000)) { timeout++; printf("."); @@ -2886,8 +2897,11 @@ static int CmdHFiClassCheckKeys(const char *Cmd) { PrintAndLogEx(WARNING, "No response from Proxmark3. Aborting..."); goto out; } + looped = true; } - PrintAndLogEx(NORMAL, ""); + + if (looped) + PrintAndLogEx(NORMAL, ""); found_offset = resp.oldarg[1] & 0xFF; uint8_t isOK = resp.oldarg[0] & 0xFF; @@ -2895,23 +2909,17 @@ static int CmdHFiClassCheckKeys(const char *Cmd) { t2 = msclock() - t2; switch (isOK) { case 1: { - found_debit = true; - PrintAndLogEx(INFO, "Chunk [%d/%d]: %.1fs [%s] idx [%u] - found key "_YELLOW_("%s") - , key_offset - , keycount - , (float)(t2 / 1000.0) - , (use_credit_key) ? "credit" : "debit" - , found_offset + found_key = true; + PrintAndLogEx(SUCCESS, "Found valid key " _GREEN_("%s") , sprint_hex(keyBlock + (key_offset + found_offset) * 8, 8) ); break; } case 0: { - PrintAndLogEx(INFO, "Chunk [%d/%d] : %.1fs [%s]" + PrintAndLogEx(INFO, "Chunk [%d/%d] : %.1fs - no luck" , key_offset , keycount , (float)(t2 / 1000.0) - , (use_credit_key) ? "credit" : "debit" ); break; } @@ -2922,8 +2930,7 @@ static int CmdHFiClassCheckKeys(const char *Cmd) { } // both keys found. - if (found_debit) { - PrintAndLogEx(SUCCESS, "All keys found, exiting"); + if (found_key) { break; } @@ -2932,25 +2939,17 @@ static int CmdHFiClassCheckKeys(const char *Cmd) { out: t1 = msclock() - t1; - PrintAndLogEx(SUCCESS, "Time in iclass checkkeys: %.0f seconds\n", (float)t1 / 1000.0); + PrintAndLogEx(SUCCESS, "Time in iclass chk: " _YELLOW_("%.0f") " seconds\n", (float)t1 / 1000.0); DropField(); - // add to managekeys - if (found_debit) { - for (uint8_t i = 0; i < ICLASS_KEYS_MAX; i++) { - // simple check for preexistences - if (memcmp(iClass_Key_Table[i], keyBlock + (key_offset + found_offset) * 8, 8) == 0) break; - - if (memcmp(iClass_Key_Table[i], "\x00\x00\x00\x00\x00\x00\x00\x00", 8) == 0) { - memcpy(iClass_Key_Table[i], keyBlock + (key_offset + found_offset) * 8, 8); - PrintAndLogEx(SUCCESS, "Added key to keyslot [%d] - "_YELLOW_("`hf iclass managekeys p`")" to view", i); - break; - } - } + if (found_key) { + uint8_t *key = keyBlock + (key_offset + found_offset) * 8; + add_key(key); } free(pre); free(keyBlock); + PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } @@ -3051,11 +3050,11 @@ static int CmdHFiClassLookUp(const char *Cmd) { memcpy(CCNR, EPURSE, 8); memcpy(CCNR + 8, MACS, 4); - PrintAndLogEx(SUCCESS, "CSN | %s", sprint_hex(CSN, sizeof(CSN))); - PrintAndLogEx(SUCCESS, "Epurse | %s", sprint_hex(EPURSE, sizeof(EPURSE))); - PrintAndLogEx(SUCCESS, "MACS | %s", sprint_hex(MACS, sizeof(MACS))); - PrintAndLogEx(SUCCESS, "CCNR | %s", sprint_hex(CCNR, sizeof(CCNR))); - PrintAndLogEx(SUCCESS, "MAC_TAG | %s", sprint_hex(MAC_TAG, sizeof(MAC_TAG))); + PrintAndLogEx(SUCCESS, " CSN: " _GREEN_("%s"), sprint_hex(CSN, sizeof(CSN))); + PrintAndLogEx(SUCCESS, " Epurse: %s", sprint_hex(EPURSE, sizeof(EPURSE))); + PrintAndLogEx(SUCCESS, " MACS: %s", sprint_hex(MACS, sizeof(MACS))); + PrintAndLogEx(SUCCESS, " CCNR: " _GREEN_("%s"), sprint_hex(CCNR, sizeof(CCNR))); + PrintAndLogEx(SUCCESS, "TAG MAC: %s", sprint_hex(MAC_TAG, sizeof(MAC_TAG))); uint8_t *keyBlock = NULL; uint32_t keycount = 0; @@ -3074,41 +3073,34 @@ static int CmdHFiClassLookUp(const char *Cmd) { return PM3_EMALLOC; } - PrintAndLogEx(INFO, "Generating diversified keys"); + PrintAndLogEx(SUCCESS, "Generating diversified keys..."); GenerateMacKeyFrom(CSN, CCNR, use_raw, use_elite, keyBlock, keycount, prekey); - PrintAndLogEx(INFO, "Sorting"); + if (use_elite) + PrintAndLogEx(SUCCESS, "Using " _YELLOW_("elite algo")); + if (use_raw) + PrintAndLogEx(SUCCESS, "Using " _YELLOW_("raw mode")); + + PrintAndLogEx(SUCCESS, "Sorting..."); // sort mac list. qsort(prekey, keycount, sizeof(iclass_prekey_t), cmp_uint32); - //PrintPreCalc(prekey, keycnt); - - PrintAndLogEx(INFO, "Searching"); + PrintAndLogEx(SUCCESS, "Searching for " _YELLOW_("%s") " key...", "DEBIT"); iclass_prekey_t *item; iclass_prekey_t lookup; memcpy(lookup.mac, MAC_TAG, 4); // binsearch item = (iclass_prekey_t *) bsearch(&lookup, prekey, keycount, sizeof(iclass_prekey_t), cmp_uint32); + + if (item != NULL) { + PrintAndLogEx(SUCCESS, "Found valid key " _GREEN_("%s"), sprint_hex(item->key, 8)); + add_key(item->key); + } t1 = msclock() - t1; - PrintAndLogEx(NORMAL, "\nTime in iclass : %.0f seconds\n", (float)t1 / 1000.0); - - // foudn - if (item != NULL) { - PrintAndLogEx(SUCCESS, "[debit] found key " _YELLOW_("%s"), sprint_hex(item->key, 8)); - for (uint8_t i = 0; i < ICLASS_KEYS_MAX; i++) { - // simple check for preexistences - if (memcmp(item->key, iClass_Key_Table[i], 8) == 0) break; - - if (memcmp(iClass_Key_Table[i], "\x00\x00\x00\x00\x00\x00\x00\x00", 8) == 0) { - memcpy(iClass_Key_Table[i], item->key, 8); - PrintAndLogEx(SUCCESS, "Added key to keyslot [%d] - "_YELLOW_("`hf iclass managekeys p`")" to view", i); - break; - } - } - } + PrintAndLogEx(SUCCESS, "Time in iclass lookup: " _YELLOW_("%.0f") " seconds", (float)t1 / 1000.0); free(prekey); free(keyBlock); @@ -3287,28 +3279,37 @@ static int CmdHFiClassPermuteKey(const char *Cmd) { } static command_t CommandTable[] = { + {"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("operations") " ---------------------"}, {"help", CmdHelp, AlwaysAvailable, "This help"}, - {"calcnewkey", CmdHFiClassCalcNewKey, AlwaysAvailable, "[options..] Calc diversified keys (blocks 3 & 4) to write new keys"}, - {"chk", CmdHFiClassCheckKeys, AlwaysAvailable, "[options..] Check keys"}, - {"clone", CmdHFiClassCloneTag, IfPm3Iclass, "[options..] Restore a dump file onto a iCLASS tag"}, - {"decrypt", CmdHFiClassDecrypt, AlwaysAvailable, "[options..] Decrypt given block data or tag dump file" }, - {"dump", CmdHFiClassDump, IfPm3Iclass, "[options..] Dump iCLASS tag to file"}, - {"eload", CmdHFiClassELoad, IfPm3Iclass, "[f ] Load iCLASS dump file into emulator memory"}, - {"esave", CmdHFiClassESave, IfPm3Iclass, "[f ] Save emulator memory to file"}, - {"encrypt", CmdHFiClassEncryptBlk, AlwaysAvailable, "[options..] Encrypt given block data"}, +// {"clone", CmdHFiClassClone, IfPm3Iclass, "[options..] Create a HID credential to Picopass / iCLASS tag"}, + {"dump", CmdHFiClassDump, IfPm3Iclass, "[options..] Dump Picopass / iCLASS tag to file"}, {"info", CmdHFiClassInfo, AlwaysAvailable, " Tag information"}, - {"list", CmdHFiClassList, AlwaysAvailable, " List iCLASS history"}, + {"list", CmdHFiClassList, AlwaysAvailable, " List iclass history"}, + {"rdbl", CmdHFiClass_ReadBlock, IfPm3Iclass, "[options..] Read Picopass / iCLASS block"}, + {"reader", CmdHFiClassReader, IfPm3Iclass, " Act like an Picopass / iCLASS reader"}, + {"restore", CmdHFiClassRestore, IfPm3Iclass, "[options..] Restore a dump file onto a Picopass / iCLASS tag"}, + {"sniff", CmdHFiClassSniff, IfPm3Iclass, " Eavesdrop Picopass / iCLASS communication"}, + {"wrbl", CmdHFiClass_WriteBlock, IfPm3Iclass, "[options..] Write Picopass / iCLASS block"}, + + {"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("recovery") " ---------------------"}, + {"chk", CmdHFiClassCheckKeys, AlwaysAvailable, "[options..] Check keys"}, {"loclass", CmdHFiClass_loclass, AlwaysAvailable, "[options..] Use loclass to perform bruteforce reader attack"}, - {"lookup", CmdHFiClassLookUp, AlwaysAvailable, "[options..] Uses authentication trace to check for key in dictionary file"}, - {"managekeys", CmdHFiClassManageKeys, AlwaysAvailable, "[options..] Manage keys to use with iCLASS"}, - {"permutekey", CmdHFiClassPermuteKey, IfPm3Iclass, " Permute function from 'heart of darkness' paper"}, - {"rdbl", CmdHFiClass_ReadBlock, IfPm3Iclass, "[options..] Read iCLASS block"}, - {"reader", CmdHFiClassReader, IfPm3Iclass, " Act like an iCLASS reader"}, - {"view", CmdHFiClassView, AlwaysAvailable, "[options..] Display content from tag dump file"}, - {"replay", CmdHFiClassReader_Replay, IfPm3Iclass, " Read iCLASS tag via replay attack"}, + {"lookup", CmdHFiClassLookUp, AlwaysAvailable, "[options..] Uses authentication trace to check for key in dictionary file"}, + {"replay", CmdHFiClassReader_Replay, IfPm3Iclass, " Read Picopass / iCLASS tag via replay attack"}, + + {"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("simulation") " ---------------------"}, {"sim", CmdHFiClassSim, IfPm3Iclass, "[options..] Simulate iCLASS tag"}, - {"sniff", CmdHFiClassSniff, IfPm3Iclass, " Eavesdrop iCLASS communication"}, - {"wrbl", CmdHFiClass_WriteBlock, IfPm3Iclass, "[options..] Write iCLASS block"}, + {"eload", CmdHFiClassELoad, IfPm3Iclass, "[f ] Load Picopass / iCLASS dump file into emulator memory"}, + {"esave", CmdHFiClassESave, IfPm3Iclass, "[f ] Save emulator memory to file"}, + + {"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("utils") " ---------------------"}, + {"calcnewkey", CmdHFiClassCalcNewKey, AlwaysAvailable, "[options..] Calc diversified keys (blocks 3 & 4) to write new keys"}, + {"encrypt", CmdHFiClassEncryptBlk, AlwaysAvailable, "[options..] Encrypt given block data"}, + {"decrypt", CmdHFiClassDecrypt, AlwaysAvailable, "[options..] Decrypt given block data or tag dump file" }, + {"managekeys", CmdHFiClassManageKeys, AlwaysAvailable, "[options..] Manage keys to use with iclass commands"}, + {"permutekey", CmdHFiClassPermuteKey, IfPm3Iclass, " Permute function from 'heart of darkness' paper"}, + {"view", CmdHFiClassView, AlwaysAvailable, "[options..] Display content from tag dump file"}, + {NULL, NULL, NULL, NULL} };