X-Git-Url: http://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/c41dd5f9f690777eefd08eaeb43db52f599ce38c..ece38ef311b28eefb1d716937139aad9ee00985c:/armsrc/iclass.c diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 392271bd..1a729f3f 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -63,9 +63,9 @@ // 56,64us = 24 ssp_clk_cycles #define DELAY_ICLASS_VCD_TO_VICC_SIM (140 - 24) // times in ssp_clk_cycles @ 3,3625MHz when acting as reader -#define DELAY_ICLASS_VICC_TO_VCD_READER DELAY_ISO15693_VICC_TO_VCD_READER +#define DELAY_ICLASS_VICC_TO_VCD_READER DELAY_ISO15693_VICC_TO_VCD_READER // times in samples @ 212kHz when acting as reader -#define ICLASS_READER_TIMEOUT_ACTALL 330 // 1558us, nominal 330us + 7slots*160us = 1450us +#define ICLASS_READER_TIMEOUT_ACTALL 330 // 1558us, nominal 330us + 7slots*160us = 1450us #define ICLASS_READER_TIMEOUT_OTHERS 80 // 380us, nominal 330us @@ -695,7 +695,6 @@ void RAMFUNC SnoopIClass(void) { if (OutOfNDecoding((smpl & 0xF0) >> 4)) { rsamples = samples - Uart.samples; time_stop = (GetCountSspClk()-time_0) << 4; - LED_C_ON(); //if (!LogTrace(Uart.output, Uart.byteCnt, rsamples, Uart.parityBits,true)) break; //if (!LogTrace(NULL, 0, Uart.endTime*16 - DELAY_READER_AIR2ARM_AS_SNIFFER, 0, true)) break; @@ -708,7 +707,6 @@ void RAMFUNC SnoopIClass(void) { /* And also reset the demod code, which might have been */ /* false-triggered by the commands from the reader. */ Demod.state = DEMOD_UNSYNCD; - LED_B_OFF(); Uart.byteCnt = 0; } else { time_start = (GetCountSspClk()-time_0) << 4; @@ -722,7 +720,6 @@ void RAMFUNC SnoopIClass(void) { time_stop = (GetCountSspClk()-time_0) << 4; rsamples = samples - Demod.samples; - LED_B_ON(); uint8_t parity[MAX_PARITY_SIZE]; GetParity(Demod.output, Demod.len, parity); @@ -732,7 +729,6 @@ void RAMFUNC SnoopIClass(void) { memset(&Demod, 0, sizeof(Demod)); Demod.output = tagToReaderResponse; Demod.state = DEMOD_UNSYNCD; - LED_C_OFF(); } else { time_start = (GetCountSspClk()-time_0) << 4; } @@ -1341,7 +1337,7 @@ static void ReaderTransmitIClass(uint8_t *frame, int len, uint32_t *start_time) } -static bool sendCmdGetResponseWithRetries(uint8_t* command, size_t cmdsize, uint8_t* resp, size_t max_resp_size, +static bool sendCmdGetResponseWithRetries(uint8_t* command, size_t cmdsize, uint8_t* resp, size_t max_resp_size, uint8_t expected_size, uint8_t retries, uint32_t start_time, uint32_t *eof_time) { while (retries-- > 0) { ReaderTransmitIClass(command, cmdsize, &start_time); @@ -1353,39 +1349,31 @@ static bool sendCmdGetResponseWithRetries(uint8_t* command, size_t cmdsize, uint } /** - * @brief Talks to an iclass tag, sends the commands to get CSN and CC. - * @param card_data where the CSN and CC are stored for return - * @return 0 = fail - * 1 = Got CSN - * 2 = Got CSN and CC + * @brief Selects an iclass tag + * @param card_data where the CSN is stored for return + * @return false = fail + * true = success */ -static uint8_t handshakeIclassTag_ext(uint8_t *card_data, bool use_credit_key, uint32_t *eof_time) { +static bool selectIclassTag(uint8_t *card_data, uint32_t *eof_time) { uint8_t act_all[] = { 0x0a }; uint8_t identify[] = { 0x0c }; uint8_t select[] = { 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - uint8_t readcheck_cc[] = { 0x88, 0x02 }; - if (use_credit_key) - readcheck_cc[0] = 0x18; - else - readcheck_cc[0] = 0x88; uint8_t resp[ICLASS_BUFFER_SIZE]; - uint8_t read_status = 0; uint32_t start_time = GetCountSspClk(); // Send act_all ReaderTransmitIClass(act_all, 1, &start_time); // Card present? - if (GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_ACTALL, eof_time) < 0) return read_status;//Fail - + if (GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_ACTALL, eof_time) < 0) return false;//Fail + //Send Identify start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; ReaderTransmitIClass(identify, 1, &start_time); - // FpgaDisableTracing(); // DEBUGGING //We expect a 10-byte response here, 8 byte anticollision-CSN and 2 byte CRC uint8_t len = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time); - if (len != 10) return read_status;//Fail + if (len != 10) return false;//Fail //Copy the Anti-collision CSN to our select-packet memcpy(&select[1], resp, 8); @@ -1394,54 +1382,33 @@ static uint8_t handshakeIclassTag_ext(uint8_t *card_data, bool use_credit_key, u ReaderTransmitIClass(select, sizeof(select), &start_time); //We expect a 10-byte response here, 8 byte CSN and 2 byte CRC len = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time); - if (len != 10) return read_status;//Fail + if (len != 10) return false;//Fail - //Success - level 1, we got CSN + //Success - we got CSN //Save CSN in response data memcpy(card_data, resp, 8); - //Flag that we got to at least stage 1, read CSN - read_status = 1; - - // Card selected, now read e-purse (cc) (only 8 bytes no CRC) - start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc), &start_time); - if (GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time) == 8) { - //Save CC (e-purse) in response data - memcpy(card_data+8, resp, 8); - read_status++; - } - - return read_status; -} - -static uint8_t handshakeIclassTag(uint8_t *card_data, uint32_t *eof_time) { - return handshakeIclassTag_ext(card_data, false, eof_time); + return true; } -// Reader iClass Anticollission +// Select an iClass tag and read all blocks which are always readable without authentication void ReaderIClass(uint8_t arg0) { + LED_A_ON(); + uint8_t card_data[6 * 8] = {0}; memset(card_data, 0xFF, sizeof(card_data)); - uint8_t last_csn[8] = {0,0,0,0,0,0,0,0}; uint8_t resp[ICLASS_BUFFER_SIZE]; - memset(resp, 0xFF, sizeof(resp)); //Read conf block CRC(0x01) => 0xfa 0x22 - uint8_t readConf[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x01, 0xfa, 0x22}; + uint8_t readConf[] = {ICLASS_CMD_READ_OR_IDENTIFY, 0x01, 0xfa, 0x22}; + //Read e-purse block CRC(0x02) => 0x61 0x10 + uint8_t readEpurse[] = {ICLASS_CMD_READ_OR_IDENTIFY, 0x02, 0x61, 0x10}; //Read App Issuer Area block CRC(0x05) => 0xde 0x64 - uint8_t readAA[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x05, 0xde, 0x64}; + uint8_t readAA[] = {ICLASS_CMD_READ_OR_IDENTIFY, 0x05, 0xde, 0x64}; - int read_status= 0; uint8_t result_status = 0; - // flag to read until one tag is found successfully - bool abort_after_read = arg0 & FLAG_ICLASS_READER_ONLY_ONCE; - // flag to only try 5 times to find one tag then return - bool try_once = arg0 & FLAG_ICLASS_READER_ONE_TRY; - // if neither abort_after_read nor try_once then continue reading until button pressed. - bool use_credit_key = arg0 & FLAG_ICLASS_READER_CEDITKEY; // test flags for what blocks to be sure to read uint8_t flagReadConfig = arg0 & FLAG_ICLASS_READER_CONF; uint8_t flagReadCC = arg0 & FLAG_ICLASS_READER_CC; @@ -1454,93 +1421,57 @@ void ReaderIClass(uint8_t arg0) { StartCountSspClk(); uint32_t start_time = 0; uint32_t eof_time = 0; + + if (selectIclassTag(resp, &eof_time)) { + result_status = FLAG_ICLASS_READER_CSN; + memcpy(card_data, resp, 8); + } - uint16_t tryCnt = 0; - bool userCancelled = BUTTON_PRESS() || usb_poll_validate_length(); - while (!userCancelled) { - // if only looking for one card try 2 times if we missed it the first time - if (try_once && tryCnt > 2) { - break; - } - tryCnt++; - if (!get_tracing()) { - DbpString("Trace full"); - break; + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + + //Read block 1, config + if (flagReadConfig) { + if (sendCmdGetResponseWithRetries(readConf, sizeof(readConf), resp, sizeof(resp), 10, 10, start_time, &eof_time)) { + result_status |= FLAG_ICLASS_READER_CONF; + memcpy(card_data+8, resp, 8); + } else { + Dbprintf("Failed to read config block"); } - WDT_HIT(); - - read_status = handshakeIclassTag_ext(card_data, use_credit_key, &eof_time); - - if (read_status == 0) continue; - if (read_status == 1) result_status = FLAG_ICLASS_READER_CSN; - if (read_status == 2) result_status = FLAG_ICLASS_READER_CSN | FLAG_ICLASS_READER_CC; - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - // handshakeIclass returns CSN|CC, but the actual block - // layout is CSN|CONFIG|CC, so here we reorder the data, - // moving CC forward 8 bytes - memcpy(card_data+16, card_data+8, 8); - //Read block 1, config - if (flagReadConfig) { - if (sendCmdGetResponseWithRetries(readConf, sizeof(readConf), resp, sizeof(resp), 10, 10, start_time, &eof_time)) { - result_status |= FLAG_ICLASS_READER_CONF; - memcpy(card_data+8, resp, 8); - } else { - Dbprintf("Failed to dump config block"); - } - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - } + } - //Read block 5, AA - if (flagReadAA) { - if (sendCmdGetResponseWithRetries(readAA, sizeof(readAA), resp, sizeof(resp), 10, 10, start_time, &eof_time)) { - result_status |= FLAG_ICLASS_READER_AA; - memcpy(card_data + (8*5), resp, 8); - } else { - //Dbprintf("Failed to dump AA block"); - } + //Read block 2, e-purse + if (flagReadCC) { + if (sendCmdGetResponseWithRetries(readEpurse, sizeof(readEpurse), resp, sizeof(resp), 10, 10, start_time, &eof_time)) { + result_status |= FLAG_ICLASS_READER_CC; + memcpy(card_data + (8*2), resp, 8); + } else { + Dbprintf("Failed to read e-purse"); } + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + } - // 0 : CSN - // 1 : Configuration - // 2 : e-purse - // 3 : kd / debit / aa2 (write-only) - // 4 : kc / credit / aa1 (write-only) - // 5 : AIA, Application issuer area - //Then we can 'ship' back the 6 * 8 bytes of data, - // with 0xFF:s in block 3 and 4. - - LED_B_ON(); - //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) - if (memcmp(last_csn, card_data, 8) != 0) { - // If caller requires that we get Conf, CC, AA, continue until we got it - if ( (result_status ^ FLAG_ICLASS_READER_CSN ^ flagReadConfig ^ flagReadCC ^ flagReadAA) == 0) { - cmd_send(CMD_ACK, result_status, 0, 0, card_data, sizeof(card_data)); - if (abort_after_read) { - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_A_OFF(); - LED_B_OFF(); - return; - } - //Save that we already sent this.... - memcpy(last_csn, card_data, 8); - } - + //Read block 5, AA + if (flagReadAA) { + if (sendCmdGetResponseWithRetries(readAA, sizeof(readAA), resp, sizeof(resp), 10, 10, start_time, &eof_time)) { + result_status |= FLAG_ICLASS_READER_AA; + memcpy(card_data + (8*5), resp, 8); + } else { + Dbprintf("Failed to read AA block"); } - LED_B_OFF(); - userCancelled = BUTTON_PRESS() || usb_poll_validate_length(); - } - if (userCancelled) { - cmd_send(CMD_ACK, 0xFF, 0, 0, card_data, 0); - } else { - cmd_send(CMD_ACK, 0, 0, 0, card_data, 0); } + + cmd_send(CMD_ACK, result_status, 0, 0, card_data, sizeof(card_data)); + LED_A_OFF(); } + void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) { + LED_A_ON(); + + bool use_credit_key = false; uint8_t card_data[USB_CMD_DATA_SIZE]={0}; uint16_t block_crc_LUT[255] = {0}; @@ -1551,6 +1482,9 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) { } //Dbprintf("Lookup table: %02x %02x %02x" ,block_crc_LUT[0],block_crc_LUT[1],block_crc_LUT[2]); + uint8_t readcheck_cc[] = { ICLASS_CMD_READCHECK_KD, 0x02 }; + if (use_credit_key) + readcheck_cc[0] = ICLASS_CMD_READCHECK_KC; uint8_t check[] = { 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; uint8_t read[] = { 0x0c, 0x00, 0x00, 0x00 }; @@ -1575,7 +1509,7 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) { StartCountSspClk(); uint32_t start_time = 0; uint32_t eof_time = 0; - + while (!BUTTON_PRESS()) { WDT_HIT(); @@ -1585,34 +1519,33 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) { break; } - uint8_t read_status = handshakeIclassTag(card_data, &eof_time); - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + if (!selectIclassTag(card_data, &eof_time)) continue; - if (read_status < 2) continue; + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + if (!sendCmdGetResponseWithRetries(readcheck_cc, sizeof(readcheck_cc), resp, sizeof(resp), 8, 3, start_time, &eof_time)) continue; - //for now replay captured auth (as cc not updated) + // replay captured auth (cc must not have been updated) memcpy(check+5, MAC, 4); + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; if (!sendCmdGetResponseWithRetries(check, sizeof(check), resp, sizeof(resp), 4, 5, start_time, &eof_time)) { - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; Dbprintf("Error: Authentication Fail!"); continue; } - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; //first get configuration block (block 1) crc = block_crc_LUT[1]; read[1] = 1; read[2] = crc >> 8; read[3] = crc & 0xff; + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; if (!sendCmdGetResponseWithRetries(read, sizeof(read), resp, sizeof(resp), 10, 10, start_time, &eof_time)) { start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; Dbprintf("Dump config (block 1) failed"); continue; } - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; mem = resp[5]; memory.k16 = (mem & 0x80); memory.book = (mem & 0x20); @@ -1633,8 +1566,8 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) { read[2] = crc >> 8; read[3] = crc & 0xff; + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; if (sendCmdGetResponseWithRetries(read, sizeof(read), resp, sizeof(resp), 10, 10, start_time, &eof_time)) { - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; Dbprintf(" %02x: %02x %02x %02x %02x %02x %02x %02x %02x", block, resp[0], resp[1], resp[2], resp[3], resp[4], resp[5], @@ -1683,19 +1616,33 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) { 0); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_D_OFF(); LED_A_OFF(); } -void iClass_Authentication(uint8_t *MAC) { - uint8_t check[] = { ICLASS_CMD_CHECK_KD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - uint8_t resp[ICLASS_BUFFER_SIZE]; + +void iClass_Check(uint8_t *MAC) { + uint8_t check[9] = {ICLASS_CMD_CHECK_KD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t resp[4]; memcpy(check+5, MAC, 4); - bool isOK; uint32_t eof_time; - isOK = sendCmdGetResponseWithRetries(check, sizeof(check), resp, sizeof(resp), 4, 6, 0, &eof_time); - cmd_send(CMD_ACK,isOK, 0, 0, 0, 0); + bool isOK = sendCmdGetResponseWithRetries(check, sizeof(check), resp, sizeof(resp), 4, 6, 0, &eof_time); + cmd_send(CMD_ACK, isOK, 0, 0, resp, sizeof(resp)); +} + + +void iClass_Readcheck(uint8_t block, bool use_credit_key) { + uint8_t readcheck[2] = {ICLASS_CMD_READCHECK_KD, block}; + if (use_credit_key) { + readcheck[0] = ICLASS_CMD_READCHECK_KC; + } + uint8_t resp[8]; + uint32_t eof_time; + bool isOK = sendCmdGetResponseWithRetries(readcheck, sizeof(readcheck), resp, sizeof(resp), 8, 6, 0, &eof_time); + cmd_send(CMD_ACK, isOK, 0, 0, resp, sizeof(resp)); } + static bool iClass_ReadBlock(uint8_t blockNo, uint8_t *readdata) { uint8_t readcmd[] = {ICLASS_CMD_READ_OR_IDENTIFY, blockNo, 0x00, 0x00}; //0x88, 0x00 // can i use 0C? char bl = blockNo; @@ -1705,23 +1652,32 @@ static bool iClass_ReadBlock(uint8_t blockNo, uint8_t *readdata) { uint8_t resp[10]; bool isOK = false; uint32_t eof_time; - - //readcmd[1] = blockNo; + isOK = sendCmdGetResponseWithRetries(readcmd, sizeof(readcmd), resp, sizeof(resp), 10, 10, 0, &eof_time); memcpy(readdata, resp, sizeof(resp)); return isOK; } + void iClass_ReadBlk(uint8_t blockno) { + + LED_A_ON(); + uint8_t readblockdata[] = {0,0,0,0,0,0,0,0,0,0}; bool isOK = false; isOK = iClass_ReadBlock(blockno, readblockdata); cmd_send(CMD_ACK, isOK, 0, 0, readblockdata, 8); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_D_OFF(); + + LED_A_OFF(); } void iClass_Dump(uint8_t blockno, uint8_t numblks) { + + LED_A_ON(); + uint8_t readblockdata[] = {0,0,0,0,0,0,0,0,0,0}; bool isOK = false; uint8_t blkCnt = 0; @@ -1751,12 +1707,19 @@ void iClass_Dump(uint8_t blockno, uint8_t numblks) { } //return pointer to dump memory in arg3 cmd_send(CMD_ACK, isOK, blkCnt, BigBuf_max_traceLen(), 0, 0); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); + LED_D_OFF(); BigBuf_free(); + + LED_A_OFF(); } + static bool iClass_WriteBlock_ext(uint8_t blockNo, uint8_t *data) { + + LED_A_ON(); + uint8_t write[] = { ICLASS_CMD_UPDATE, blockNo, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; //uint8_t readblockdata[10]; //write[1] = blockNo; @@ -1768,7 +1731,7 @@ static bool iClass_WriteBlock_ext(uint8_t blockNo, uint8_t *data) { uint8_t resp[10]; bool isOK = false; uint32_t eof_time = 0; - + isOK = sendCmdGetResponseWithRetries(write, sizeof(write), resp, sizeof(resp), 10, 10, 0, &eof_time); uint32_t start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; if (isOK) { //if reader responded correctly @@ -1780,10 +1743,17 @@ static bool iClass_WriteBlock_ext(uint8_t blockNo, uint8_t *data) { } } } + + LED_A_OFF(); + return isOK; } + void iClass_WriteBlock(uint8_t blockNo, uint8_t *data) { + + LED_A_ON(); + bool isOK = iClass_WriteBlock_ext(blockNo, data); if (isOK){ Dbprintf("Write block [%02x] successful", blockNo); @@ -1791,7 +1761,11 @@ void iClass_WriteBlock(uint8_t blockNo, uint8_t *data) { Dbprintf("Write block [%02x] failed", blockNo); } cmd_send(CMD_ACK, isOK, 0, 0, 0, 0); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_D_OFF(); + + LED_A_OFF(); } void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t *data) { @@ -1819,5 +1793,6 @@ void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t *data) { cmd_send(CMD_ACK, 1, 0, 0, 0, 0); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); + LED_D_OFF(); + LED_A_OFF(); }