mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-03-20 12:07:05 +08:00
hf iclass chk - now uses NG
This commit is contained in:
parent
305903c513
commit
cd9090b6c8
8 changed files with 96 additions and 68 deletions
|
@ -1695,14 +1695,14 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
break;
|
||||
}
|
||||
case CMD_HF_ICLASS_CHKKEYS: {
|
||||
iClass_Authentication_fast(packet->oldarg[0], packet->oldarg[1], packet->data.asBytes);
|
||||
iClass_Authentication_fast((iclass_chk_t*)packet->data.asBytes);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_ICLASS_DUMP: {
|
||||
iClass_Dump(packet->data.asBytes);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_ICLASS_RESTORE: {
|
||||
case CMD_HF_ICLASS_RESTORE: {
|
||||
iClass_Restore((iclass_restore_req_t *)packet->data.asBytes);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -1512,9 +1512,6 @@ bool authenticate_iclass_tag(iclass_auth_req_t *payload, picopass_hdr_t *hdr, ui
|
|||
return iclass_send_cmd_with_retries(cmd_check, sizeof(cmd_check), resp_auth, sizeof(resp_auth), 4, 2, start_time, ICLASS_READER_TIMEOUT_OTHERS, eof_time);
|
||||
}
|
||||
|
||||
typedef struct iclass_premac {
|
||||
uint8_t mac[4];
|
||||
} iclass_premac_t;
|
||||
|
||||
/* this function works on the following assumptions.
|
||||
* - one select first, to get CSN / CC (e-purse)
|
||||
|
@ -1523,36 +1520,35 @@ typedef struct iclass_premac {
|
|||
* - key loop only test one type of authtication key. Ie two calls needed
|
||||
* to cover debit and credit key. (AA1/AA2)
|
||||
*/
|
||||
void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain) {
|
||||
|
||||
// uint8_t lastChunk = ((arg0 >> 8) & 0xFF);
|
||||
bool use_credit_key = ((arg0 >> 16) & 0xFF);
|
||||
uint8_t keyCount = arg1 & 0xFF;
|
||||
void iClass_Authentication_fast(iclass_chk_t *p) {
|
||||
// sanitation
|
||||
if (p == NULL) {
|
||||
reply_ng(CMD_HF_ICLASS_CHKKEYS, PM3_ESOFT, NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t check[9] = { ICLASS_CMD_CHECK };
|
||||
uint8_t resp[ICLASS_BUFFER_SIZE] = {0};
|
||||
uint8_t readcheck_cc[] = { 0x80 | ICLASS_CMD_READCHECK, 0x02 };
|
||||
|
||||
if (use_credit_key)
|
||||
if (p->use_credit_key)
|
||||
readcheck_cc[0] = 0x10 | ICLASS_CMD_READCHECK;
|
||||
|
||||
// select card / e-purse
|
||||
picopass_hdr_t hdr = {0};
|
||||
|
||||
iclass_premac_t *keys = (iclass_premac_t *)datain;
|
||||
iclass_premac_t *keys = p->items;
|
||||
|
||||
LED_A_ON();
|
||||
|
||||
// fresh start
|
||||
switch_off();
|
||||
SpinDelay(20);
|
||||
|
||||
Iso15693InitReader();
|
||||
|
||||
bool isOK = false;
|
||||
|
||||
uint32_t start_time = 0, eof_time = 0;
|
||||
if (select_iclass_tag(&hdr, use_credit_key, &eof_time) == false)
|
||||
if (select_iclass_tag(&hdr, p->use_credit_key, &eof_time) == false)
|
||||
goto out;
|
||||
|
||||
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
||||
|
@ -1562,7 +1558,7 @@ void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain) {
|
|||
|
||||
// Keychunk loop
|
||||
uint8_t i = 0;
|
||||
for (i = 0; i < keyCount; i++) {
|
||||
for (i = 0; i < p->count; i++) {
|
||||
|
||||
// Allow button press / usb cmd to interrupt device
|
||||
if (checked == 1000) {
|
||||
|
|
|
@ -28,7 +28,7 @@ int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf);
|
|||
void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
|
||||
void iclass_simulate(uint8_t sim_type, uint8_t num_csns, bool send_reply, uint8_t *datain, uint8_t *dataout, uint16_t *dataoutlen);
|
||||
|
||||
void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain);
|
||||
void iClass_Authentication_fast(iclass_chk_t *p);
|
||||
bool iclass_auth(iclass_auth_req_t *payload, uint8_t *out);
|
||||
|
||||
void iClass_ReadBlock(uint8_t *msg);
|
||||
|
|
|
@ -449,19 +449,10 @@ static bool MifareSimInit(uint16_t flags, uint8_t *datain, uint16_t atqa, uint8_
|
|||
void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint16_t atqa, uint8_t sak) {
|
||||
tag_response_info_t *responses;
|
||||
uint8_t cardSTATE = MFEMUL_NOFIELD;
|
||||
uint8_t uid_len = 0; // 4,7, 10
|
||||
uint32_t cuid = 0;
|
||||
|
||||
// int vHf = 0; // in mV
|
||||
|
||||
uint32_t selTimer = 0;
|
||||
uint32_t authTimer = 0;
|
||||
|
||||
uint8_t uid_len = 0; // 4, 7, 10
|
||||
uint32_t cuid = 0, selTimer = 0, authTimer = 0;
|
||||
uint32_t nr, ar;
|
||||
uint8_t blockNo;
|
||||
|
||||
uint32_t nr;
|
||||
uint32_t ar;
|
||||
|
||||
bool encrypted_data;
|
||||
|
||||
uint8_t cardWRBL = 0;
|
||||
|
@ -469,9 +460,9 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1
|
|||
uint8_t cardAUTHKEY = AUTHKEYNONE; // no authentication
|
||||
uint32_t cardRr = 0;
|
||||
uint32_t ans = 0;
|
||||
|
||||
uint32_t cardINTREG = 0;
|
||||
uint8_t cardINTBLOCK = 0;
|
||||
|
||||
struct Crypto1State mpcs = {0, 0};
|
||||
struct Crypto1State *pcs;
|
||||
pcs = &mpcs;
|
||||
|
@ -849,7 +840,8 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1
|
|||
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
|
||||
FpgaDisableTracing();
|
||||
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("[MFEMUL_WORK] Reader tried to operate (0x%02x) on block (0x%02x) not authenticated for (0x%02x), nacking", receivedCmd_dec[0], receivedCmd_dec[1], cardAUTHSC);
|
||||
if (DBGLEVEL >= DBG_ERROR)
|
||||
Dbprintf("[MFEMUL_WORK] Reader tried to operate (0x%02x) on block (0x%02x) not authenticated for (0x%02x), nacking", receivedCmd_dec[0], receivedCmd_dec[1], cardAUTHSC);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -883,20 +875,20 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1
|
|||
// Check if selected Block is a Sector Trailer
|
||||
if (IsSectorTrailer(blockNo)) {
|
||||
|
||||
if (!IsAccessAllowed(blockNo, cardAUTHKEY, AC_KEYA_READ)) {
|
||||
if (IsAccessAllowed(blockNo, cardAUTHKEY, AC_KEYA_READ) == false) {
|
||||
memset(response, 0x00, 6); // keyA can never be read
|
||||
if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK - IsSectorTrailer] keyA can never be read - block %d (0x%02x)", blockNo, blockNo);
|
||||
}
|
||||
if (!IsAccessAllowed(blockNo, cardAUTHKEY, AC_KEYB_READ)) {
|
||||
if (IsAccessAllowed(blockNo, cardAUTHKEY, AC_KEYB_READ) == false) {
|
||||
memset(response + 10, 0x00, 6); // keyB cannot be read
|
||||
if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK - IsSectorTrailer] keyB cannot be read - block %d (0x%02x)", blockNo, blockNo);
|
||||
}
|
||||
if (!IsAccessAllowed(blockNo, cardAUTHKEY, AC_AC_READ)) {
|
||||
if (IsAccessAllowed(blockNo, cardAUTHKEY, AC_AC_READ) == false) {
|
||||
memset(response + 6, 0x00, 4); // AC bits cannot be read
|
||||
if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK - IsAccessAllowed] AC bits cannot be read - block %d (0x%02x)", blockNo, blockNo);
|
||||
}
|
||||
} else {
|
||||
if (!IsAccessAllowed(blockNo, cardAUTHKEY, AC_DATA_READ)) {
|
||||
if (IsAccessAllowed(blockNo, cardAUTHKEY, AC_DATA_READ) == false) {
|
||||
memset(response, 0x00, 16); // datablock cannot be read
|
||||
if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK - IsAccessAllowed] Data block %d (0x%02x) cannot be read", blockNo, blockNo);
|
||||
}
|
||||
|
|
|
@ -2970,39 +2970,47 @@ static int CmdHFiClassCheckKeys(const char *Cmd) {
|
|||
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};
|
||||
|
||||
bool found_key = false;
|
||||
//bool found_credit = false;
|
||||
bool got_csn = false;
|
||||
|
||||
uint64_t t1 = msclock();
|
||||
|
||||
// load keys
|
||||
uint8_t *keyBlock = NULL;
|
||||
uint32_t keycount = 0;
|
||||
|
||||
// load keys
|
||||
int res = loadFileDICTIONARY_safe(filename, (void **)&keyBlock, 8, &keycount);
|
||||
if (res != PM3_SUCCESS || keycount == 0) {
|
||||
free(keyBlock);
|
||||
return res;
|
||||
}
|
||||
|
||||
// limit size of keys that can be held in memory
|
||||
if (keycount > 100000) {
|
||||
PrintAndLogEx(FAILED, "File contains more than 100 000 keys, aborting...");
|
||||
free(keyBlock);
|
||||
return PM3_EFILE;
|
||||
}
|
||||
|
||||
// Get CSN / UID and CCNR
|
||||
PrintAndLogEx(SUCCESS, "Reading tag CSN / CCNR...");
|
||||
for (uint8_t i = 0; i < ICLASS_AUTH_RETRY && !got_csn; i++) {
|
||||
|
||||
bool got_csn = false;
|
||||
for (uint8_t i = 0; i < ICLASS_AUTH_RETRY; i++) {
|
||||
got_csn = select_only(CSN, CCNR, false);
|
||||
if (got_csn == false)
|
||||
PrintAndLogEx(WARNING, "one more try");
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (got_csn == false) {
|
||||
PrintAndLogEx(WARNING, "Tried 10 times. Can't select card, aborting...");
|
||||
PrintAndLogEx(WARNING, "Tried %d times. Can't select card, aborting...", ICLASS_AUTH_RETRY);
|
||||
free(keyBlock);
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
// allocate memory for the pre calculated macs
|
||||
iclass_premac_t *pre = calloc(keycount, sizeof(iclass_premac_t));
|
||||
if (pre == NULL) {
|
||||
PrintAndLogEx(WARNING, "failed to allocate memory");
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
|
@ -3019,19 +3027,28 @@ static int CmdHFiClassCheckKeys(const char *Cmd) {
|
|||
|
||||
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;
|
||||
bool lastChunk = false;
|
||||
// USB_COMMAND. 512/4 = 103 mac
|
||||
uint32_t max_chunk_size = 0;
|
||||
if (keycount > ((PM3_CMD_DATA_SIZE - sizeof(iclass_chk_t)) / 4))
|
||||
max_chunk_size = (PM3_CMD_DATA_SIZE - sizeof(iclass_chk_t)) / 4;
|
||||
else
|
||||
max_chunk_size = keycount;
|
||||
|
||||
// fast push mode
|
||||
conn.block_after_ACK = true;
|
||||
|
||||
// keep track of position of found key
|
||||
uint32_t chunk_offset = 0;
|
||||
uint8_t found_offset = 0;
|
||||
uint32_t key_offset = 0;
|
||||
bool found_key = false;
|
||||
|
||||
// We have
|
||||
// - a list of keys.
|
||||
// - a list of precalculated macs that corresponds to the key list
|
||||
// We send a chunk of macs to the device each time
|
||||
|
||||
// main keychunk loop
|
||||
for (key_offset = 0; key_offset < keycount && (found_key == false); key_offset += chunksize) {
|
||||
for (chunk_offset = 0; chunk_offset < keycount; chunk_offset += max_chunk_size) {
|
||||
|
||||
if (kbd_enter_pressed()) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
|
@ -3039,31 +3056,40 @@ static int CmdHFiClassCheckKeys(const char *Cmd) {
|
|||
goto out;
|
||||
}
|
||||
|
||||
uint32_t keys = ((keycount - key_offset) > chunksize) ? chunksize : keycount - key_offset;
|
||||
uint32_t curr_chunk_cnt = keycount - chunk_offset;
|
||||
if ((keycount - chunk_offset) > max_chunk_size) {
|
||||
curr_chunk_cnt = max_chunk_size;
|
||||
}
|
||||
|
||||
// last chunk?
|
||||
if (keys == keycount - key_offset) {
|
||||
lastChunk = true;
|
||||
if (curr_chunk_cnt == keycount - chunk_offset) {
|
||||
// Disable fast mode on last command
|
||||
conn.block_after_ACK = false;
|
||||
}
|
||||
uint32_t flags = lastChunk << 8;
|
||||
// bit 16
|
||||
// - 1 indicates credit key
|
||||
// - 0 indicates debit key (default)
|
||||
flags |= (use_credit_key << 16);
|
||||
|
||||
uint32_t tmp_plen = sizeof(iclass_chk_t) + (4 * curr_chunk_cnt);
|
||||
iclass_chk_t *packet = calloc(tmp_plen, sizeof(uint8_t) );
|
||||
if (packet == NULL) {
|
||||
|
||||
}
|
||||
packet->use_credit_key = use_credit_key;
|
||||
packet->count = curr_chunk_cnt;
|
||||
// copy chunk of pre calculated macs to packet
|
||||
memcpy(packet->items, (pre + chunk_offset), (4 * curr_chunk_cnt));
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandOLD(CMD_HF_ICLASS_CHKKEYS, flags, keys, 0, pre + key_offset, 4 * keys);
|
||||
PacketResponseNG resp;
|
||||
SendCommandNG(CMD_HF_ICLASS_CHKKEYS, (uint8_t*)packet, tmp_plen);
|
||||
free(packet);
|
||||
|
||||
bool looped = false;
|
||||
uint8_t timeout = 0;
|
||||
|
||||
PacketResponseNG resp;
|
||||
while (WaitForResponseTimeout(CMD_HF_ICLASS_CHKKEYS, &resp, 2000) == false) {
|
||||
timeout++;
|
||||
PrintAndLogEx(NORMAL, "." NOLF);
|
||||
if (timeout > 10) {
|
||||
PrintAndLogEx(WARNING, "\nno response from device, aborting...");
|
||||
PrintAndLogEx(WARNING, "\ncommand execute timeout, aborting...");
|
||||
goto out;
|
||||
}
|
||||
looped = true;
|
||||
|
@ -3078,10 +3104,11 @@ static int CmdHFiClassCheckKeys(const char *Cmd) {
|
|||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(SUCCESS,
|
||||
"Found valid key " _GREEN_("%s")
|
||||
, sprint_hex(keyBlock + (key_offset + found_offset) * 8, 8)
|
||||
, sprint_hex(keyBlock + (chunk_offset + found_offset) * 8, 8)
|
||||
);
|
||||
break;
|
||||
} else {
|
||||
PrintAndLogEx(INPLACE, "Chunk [%d/%d]", key_offset, keycount);
|
||||
PrintAndLogEx(INPLACE, "Chunk [%d/%d]", chunk_offset, keycount);
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
|
@ -3090,11 +3117,11 @@ out:
|
|||
t1 = msclock() - t1;
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(SUCCESS, "time in iclass chk " _YELLOW_("%.3f") " seconds", (float)t1 / 1000.0);
|
||||
PrintAndLogEx(SUCCESS, "time in iclass chk " _YELLOW_("%.1f") " seconds", (float)t1 / 1000.0);
|
||||
DropField();
|
||||
|
||||
if (found_key) {
|
||||
uint8_t *key = keyBlock + (key_offset + found_offset) * 8;
|
||||
uint8_t *key = keyBlock + (chunk_offset + found_offset) * 8;
|
||||
add_key(key);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,10 +19,6 @@ typedef struct iclass_block {
|
|||
uint8_t d[8];
|
||||
} iclass_block_t;
|
||||
|
||||
typedef struct iclass_premac {
|
||||
uint8_t mac[4];
|
||||
} iclass_premac_t;
|
||||
|
||||
typedef struct iclass_prekey {
|
||||
uint8_t mac[4];
|
||||
uint8_t key[8];
|
||||
|
|
|
@ -3288,6 +3288,7 @@ static int CmdHF14AMfSim(const char *Cmd) {
|
|||
arg_lit0("x", NULL, "Performs the 'reader attack', nr/ar attack against a reader"),
|
||||
arg_lit0("e", "emukeys", "Fill simulator keys from found keys"),
|
||||
arg_lit0("v", "verbose", "verbose output"),
|
||||
arg_lit0(NULL, "cve", "trigger CVE 2021_0430"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
@ -3345,6 +3346,9 @@ static int CmdHF14AMfSim(const char *Cmd) {
|
|||
bool setEmulatorMem = arg_get_lit(ctx, 11);
|
||||
bool verbose = arg_get_lit(ctx, 12);
|
||||
|
||||
if (arg_get_lit(ctx, 13)) {
|
||||
flags |= FLAG_CVE21_0430;
|
||||
}
|
||||
CLIParserFree(ctx);
|
||||
|
||||
nonces_t data[1];
|
||||
|
|
|
@ -348,6 +348,16 @@ typedef struct {
|
|||
iclass_restore_item_t blocks[];
|
||||
} PACKED iclass_restore_req_t;
|
||||
|
||||
typedef struct iclass_premac {
|
||||
uint8_t mac[4];
|
||||
} iclass_premac_t;
|
||||
|
||||
typedef struct {
|
||||
bool use_credit_key;
|
||||
uint8_t count;
|
||||
iclass_premac_t items[];
|
||||
} PACKED iclass_chk_t;
|
||||
|
||||
|
||||
// iclass / picopass chip config structures and shared routines
|
||||
typedef struct {
|
||||
|
@ -593,6 +603,7 @@ typedef struct {
|
|||
#define CMD_HF_ISO15693_COMMAND 0x0313
|
||||
#define CMD_HF_ISO15693_FINDAFI 0x0315
|
||||
#define CMD_HF_ISO15693_CSETUID 0x0316
|
||||
#define CMD_HF_ISO15693_SLIX_L_DISABLE_PRIVACY 0x0317
|
||||
|
||||
#define CMD_LF_SNIFF_RAW_ADC 0x0360
|
||||
|
||||
|
@ -756,6 +767,8 @@ typedef struct {
|
|||
#define FLAG_MF_4K 0x400
|
||||
#define FLAG_FORCED_ATQA 0x800
|
||||
#define FLAG_FORCED_SAK 0x1000
|
||||
#define FLAG_CVE21_0430 0x2000
|
||||
|
||||
|
||||
// iCLASS reader flags
|
||||
#define FLAG_ICLASS_READER_INIT 0x01
|
||||
|
|
Loading…
Add table
Reference in a new issue