diff --git a/armsrc/Makefile b/armsrc/Makefile index b71614c83..6ff1455de 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -72,7 +72,7 @@ else endif ifneq (,$(findstring WITH_HITAG,$(APP_CFLAGS))) - SRC_HITAG = hitag2_crypto.c hitag2.c hitagS.c hitag2_crack.c + SRC_HITAG = hitag2_crypto.c hitag_common.c hitag2.c hitagS.c hitag2_crack.c APP_CFLAGS += -I../common/hitag2 else SRC_HITAG = diff --git a/armsrc/appmain.c b/armsrc/appmain.c index a32024223..e4e903a45 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1200,7 +1200,7 @@ static void PacketReceived(PacketCommandNG *packet) { break; } case CMD_LF_HITAGS_SIMULATE: { // Simulate Hitag s tag, args = memory content - hts_simulate((bool)packet->oldarg[0], packet->data.asBytes, true); + hts_simulate((bool)packet->oldarg[0], packet->oldarg[1], packet->data.asBytes, true); break; } case CMD_LF_HITAGS_TEST_TRACES: { // Tests every challenge within the given file @@ -1218,7 +1218,7 @@ static void PacketReceived(PacketCommandNG *packet) { break; } case CMD_LF_HITAGS_UID: { - hts_read_uid(NULL, false, true); + hts_read_uid(NULL, true, true); break; } case CMD_LF_HITAG2_WRITE: { diff --git a/armsrc/hitagS.c b/armsrc/hitagS.c index 7a42fcd81..6a9f71969 100644 --- a/armsrc/hitagS.c +++ b/armsrc/hitagS.c @@ -19,6 +19,7 @@ //----------------------------------------------------------------------------- #include "hitagS.h" +#include "hitag_common.h" #include "proxmark3_arm.h" #include "cmd.h" @@ -33,12 +34,8 @@ #include "lfadc.h" #include "crc.h" #include "protocols.h" -#include "hitag.h" #include "appmain.h" // tearoff_hook() -#define CRC_PRESET 0xFF -#define CRC_POLYNOM 0x1D - static struct hitagS_tag tag = { .data.pages = { // Plain mode: | Authentication mode: @@ -58,13 +55,6 @@ static uint8_t page_to_be_written = 0; static int block_data_left = 0; static bool enable_page_tearoff = false; -typedef enum modulation { - AC2K = 0, - AC4K, - MC4K, - MC8K -} MOD; - static uint8_t protocol_mode = HITAGS_UID_REQ_ADV1; static MOD m = AC2K; // used modulation static uint32_t reader_selected_uid; @@ -72,9 +62,6 @@ static int rotate_uid = 0; static int sof_bits; // number of start-of-frame bits static uint8_t pwdh0, pwdl0, pwdl1; // password bytes static uint8_t rnd[] = {0x85, 0x44, 0x12, 0x74}; // random number -static uint16_t timestamp_high = 0; // Timer Counter 2 overflow count, ~47min - -#define TIMESTAMP ( (AT91C_BASE_TC2->TC_SR & AT91C_TC_COVFS) ? timestamp_high += 1 : 0, ((timestamp_high << 16) + AT91C_BASE_TC2->TC_CV) / T0) //#define SENDBIT_TEST @@ -98,60 +85,6 @@ datasheet HitagS_V11.pdf bytes in tables printed 3 2 1 0 #define ht2bs_4b(a,b,c,d) (~(((d|c)&(a^b))^(d|a|b))) #define ht2bs_5c(a,b,c,d,e) (~((((((c^e)|d)&a)^b)&(c^b))^(((d^e)|a)&((d^b)|c)))) -// Sam7s has several timers, we will use the source TIMER_CLOCK3 (aka AT91C_TC_CLKS_TIMER_DIV3_CLOCK) -// TIMER_CLOCK3 = MCK/32, MCK is running at 48 MHz, Timer is running at 48MHz/32 = 1500 KHz -// Hitag units (T0) have duration of 8 microseconds (us), which is 1/125000 per second (carrier) -// T0 = TIMER_CLOCK3 / 125000 = 12 - -#define T0 12 - -#define HITAG_FRAME_LEN 20 - -// TC0 and TC1 are 16-bit counters and will overflow after 5461 * T0 -// Ensure not to set these timings above 5461 (~43ms) when comparing without considering overflow, as they will never reach that value. - -#define HITAG_T_STOP 36 /* T_EOF should be > 36 */ -#define HITAG_T_LOW 8 /* T_LOW should be 4..10 */ -#define HITAG_T_0_MIN 15 /* T[0] should be 18..22 */ -#define HITAG_T_1_MIN 25 /* T[1] should be 26..30 */ -#define HITAG_T_0 20 /* T[0] should be 18..22 */ -#define HITAG_T_1 28 /* T[1] should be 26..30 */ -// #define HITAG_T_EOF 40 /* T_EOF should be > 36 */ -#define HITAG_T_EOF 80 /* T_EOF should be > 36 */ -#define HITAG_T_WAIT_RESP 200 /* T_wresp should be 204..212 */ -#define HITAG_T_WAIT_SC 200 /* T_wsc should be 90..5000 */ -#define HITAG_T_WAIT_FIRST 300 /* T_wfc should be 280..565 (T_ttf) */ -#define HITAG_T_PROG_MAX 750 /* T_prog should be 716..726 */ - -#define HITAG_T_TAG_ONE_HALF_PERIOD 10 -#define HITAG_T_TAG_TWO_HALF_PERIOD 25 -#define HITAG_T_TAG_THREE_HALF_PERIOD 41 -#define HITAG_T_TAG_FOUR_HALF_PERIOD 57 - -#define HITAG_T_TAG_HALF_PERIOD 16 -#define HITAG_T_TAG_FULL_PERIOD 32 - -#define HITAG_T_TAG_CAPTURE_ONE_HALF 13 -#define HITAG_T_TAG_CAPTURE_TWO_HALF 25 -#define HITAG_T_TAG_CAPTURE_THREE_HALF 41 -#define HITAG_T_TAG_CAPTURE_FOUR_HALF 57 - -/* - * Implementation of the crc8 calculation from Hitag S - * from http://www.proxmark.org/files/Documents/125%20kHz%20-%20Hitag/HitagS.V11.pdf - */ -static void calc_crc(unsigned char *crc, unsigned char data, unsigned char Bitcount) { - *crc ^= data; // crc = crc (exor) data - do { - if (*crc & 0x80) { // if (MSB-CRC == 1) - *crc <<= 1; // CRC = CRC Bit-shift left - *crc ^= CRC_POLYNOM; // CRC = CRC (exor) CRC_POLYNOM - } else { - *crc <<= 1; // CRC = CRC Bit-shift left - } - } while (--Bitcount); -} - static void update_tag_max_page(void) { //check which memorysize this tag has if (tag.data.s.config.MEMT == 0x00) { @@ -165,254 +98,6 @@ static void update_tag_max_page(void) { } } -static void hitag_send_bit(int bit, bool ledcontrol) { - - if (ledcontrol) LED_A_ON(); - // Reset clock for the next bit - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - - switch (m) { - case AC2K: { - if (bit == 0) { - // AC Coding --__ - HIGH(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 32) {}; - - LOW(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 64) {}; - - } else { - // AC coding -_-_ - HIGH(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 16) {}; - - LOW(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 32) {}; - - HIGH(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 48) {}; - - LOW(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 64) {}; - - } - if (ledcontrol) LED_A_OFF(); - break; - } - case AC4K: { - if (bit == 0) { - // AC Coding --__ - HIGH(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * HITAG_T_TAG_HALF_PERIOD) {}; - - LOW(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * HITAG_T_TAG_FULL_PERIOD) {}; - - } else { - // AC coding -_-_ - HIGH(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 8) {}; - - LOW(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 16) {}; - - HIGH(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 24) {}; - - LOW(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 32) {}; - } - if (ledcontrol) LED_A_OFF(); - break; - } - case MC4K: { - if (bit == 0) { - // Manchester: Unloaded, then loaded |__--| - LOW(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 16) {}; - - HIGH(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 32) {}; - - } else { - // Manchester: Loaded, then unloaded |--__| - HIGH(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 16) {}; - - LOW(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 32) {}; - - } - if (ledcontrol) LED_A_OFF(); - break; - } - case MC8K: { - if (bit == 0) { - // Manchester: Unloaded, then loaded |__--| - LOW(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 8) {}; - - HIGH(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 16) {}; - - } else { - // Manchester: Loaded, then unloaded |--__| - HIGH(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 8) {}; - - LOW(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 16) {}; - - } - if (ledcontrol) LED_A_OFF(); - break; - } - default: { - break; - } - } -} - -static void hitag_send_frame(const uint8_t *frame, size_t frame_len, bool ledcontrol) { - - DBG Dbprintf("hitag_send_frame: (%i) %02X %02X %02X %02X", frame_len, frame[0], frame[1], frame[2], frame[3]); - - // The beginning of the frame is hidden in some high level; pause until our bits will have an effect - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - HIGH(GPIO_SSC_DOUT); - switch (m) { - case AC4K: - case MC8K: { - while (AT91C_BASE_TC0->TC_CV < T0 * 40) {}; //FADV - break; - } - case AC2K: - case MC4K: { - while (AT91C_BASE_TC0->TC_CV < T0 * 20) {}; //STD + ADV - break; - } - } - - // SOF - send start of frame - for (size_t i = 0; i < sof_bits; i++) { - hitag_send_bit(1, ledcontrol); - } - - // Send the content of the frame - for (size_t i = 0; i < frame_len; i++) { - hitag_send_bit((frame[i / 8] >> (7 - (i % 8))) & 1, ledcontrol); - } - - LOW(GPIO_SSC_DOUT); -} - -static void hitag_reader_send_bit(int bit, bool ledcontrol) { - - if (ledcontrol) LED_A_ON(); - // Reset clock for the next bit - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - while (AT91C_BASE_TC0->TC_CV != 0) {}; - - // Binary puls length modulation (BPLM) is used to encode the data stream - // This means that a transmission of a one takes longer than that of a zero - - HIGH(GPIO_SSC_DOUT); - -#ifdef SENDBIT_TEST - // Wait for 4-10 times the carrier period - while (AT91C_BASE_TC0->TC_CV < T0 * 6) {}; - - LOW(GPIO_SSC_DOUT); - - if (bit == 0) { - // Zero bit: |_-| - while (AT91C_BASE_TC0->TC_CV < T0 * 11) {}; - } else { - // One bit: |_--| - while (AT91C_BASE_TC0->TC_CV < T0 * 14) {}; - } -#else - // Wait for 4-10 times the carrier period - while (AT91C_BASE_TC0->TC_CV < T0 * HITAG_T_LOW) {}; - - LOW(GPIO_SSC_DOUT); - - if (bit == 0) { - // Zero bit: |_-| - while (AT91C_BASE_TC0->TC_CV < T0 * HITAG_T_0) {}; - } else { - // One bit: |_--| - while (AT91C_BASE_TC0->TC_CV < T0 * HITAG_T_1) {}; - } -#endif - - if (ledcontrol) LED_A_OFF(); -} - -static void hitag_reader_send_frame(const uint8_t *frame, size_t frame_len, bool ledcontrol) { - // Send the content of the frame - for (size_t i = 0; i < frame_len; i++) { - hitag_reader_send_bit((frame[i / 8] >> (7 - (i % 8))) & 1, ledcontrol); - } - // send EOF - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - while (AT91C_BASE_TC0->TC_CV != 0) {}; - - HIGH(GPIO_SSC_DOUT); - - // Wait for 4-10 times the carrier period - while (AT91C_BASE_TC0->TC_CV < T0 * HITAG_T_LOW) {}; - - LOW(GPIO_SSC_DOUT); -} - -static void hts_stop_clock(void) { - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKDIS; -} - -static void hts_init_clock(void) { - // Enable Peripheral Clock for - // Timer Counter 0, used to measure exact timing before answering - // Timer Counter 1, used to capture edges of the tag frames - // Timer Counter 2, used to log trace time - AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1) | (1 << AT91C_ID_TC2); - - AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; - - // Disable timer during configuration - hts_stop_clock(); - - // TC0: Capture mode, default timer source = MCK/32 (TIMER_CLOCK3), no triggers - AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK; - - // TC1: Capture mode, default timer source = MCK/32 (TIMER_CLOCK3), TIOA is external trigger, - AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK // use MCK/32 (TIMER_CLOCK3) - | AT91C_TC_ABETRG // TIOA is used as an external trigger - | AT91C_TC_ETRGEDG_FALLING // external trigger on falling edge - | AT91C_TC_LDRA_RISING // load RA on on rising edge of TIOA - | AT91C_TC_LDRB_FALLING; // load RB on on falling edge of TIOA - - // TC2: Capture mode, default timer source = MCK/32 (TIMER_CLOCK3), no triggers - AT91C_BASE_TC2->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK; - - // Enable and reset counters - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - - // Assert a sync signal. This sets all timers to 0 on next active clock edge - AT91C_BASE_TCB->TCB_BCR = 1; - - // synchronized startup procedure - // In theory, with MCK/32, we shouldn't be waiting longer than 32 instruction statements, right? - while (AT91C_BASE_TC0->TC_CV != 0) {}; // wait until TC0 returned to zero - - // reset timestamp - timestamp_high = 0; -} - /* * to check if the right uid was selected */ @@ -506,7 +191,6 @@ static void hts_handle_reader_command(uint8_t *rx, const size_t rxlen, DBG DbpString("SELECT"); if ((rx[0] & 0xf8) == HITAGS_SELECT && check_select(rx, BSWAP_32(tag.data.s.uid_le)) == 1) { - DBG DbpString("SELECT match"); //if the right tag was selected @@ -519,13 +203,8 @@ static void hts_handle_reader_command(uint8_t *rx, const size_t rxlen, if (protocol_mode != HITAGS_UID_REQ_STD) { //add crc8 + crc = CRC8Hitag1Bits(tx, 32); *txlen += 8; - crc = CRC_PRESET; - - for (int i = 0; i < 4; i++) { - calc_crc(&crc, tx[i], 8); - } - tx[4] = crc; } } @@ -546,26 +225,31 @@ static void hts_handle_reader_command(uint8_t *rx, const size_t rxlen, ht2_hitag2_byte(&state); } - //send con2, pwdh0, pwdl0, pwdl1 encrypted as a response - tx[0] = ht2_hitag2_byte(&state) ^ tag.data.pages[HITAGS_CONFIG_PADR][2]; - tx[1] = ht2_hitag2_byte(&state) ^ tag.data.s.config.pwdh0; - tx[2] = ht2_hitag2_byte(&state) ^ tag.data.s.pwdl0; - tx[3] = ht2_hitag2_byte(&state) ^ tag.data.s.pwdl1; + // store plaintext first + tx[0] = tag.data.pages[HITAGS_CONFIG_PADR][2]; + tx[1] = tag.data.s.config.pwdh0; + tx[2] = tag.data.s.pwdl0; + tx[3] = tag.data.s.pwdl1; if (protocol_mode != HITAGS_UID_REQ_STD) { - //add crc8 + // add crc8 *txlen += 8; - crc = CRC_PRESET; - calc_crc(&crc, tag.data.pages[HITAGS_CONFIG_PADR][2], 8); - calc_crc(&crc, tag.data.s.config.pwdh0, 8); - calc_crc(&crc, tag.data.s.pwdl0, 8); - calc_crc(&crc, tag.data.s.pwdl1, 8); - tx[4] = (crc ^ ht2_hitag2_byte(&state)); + crc = CRC8Hitag1Bits(tx, 32); + tx[4] = crc; } + + // then xor with keystream + tx[0] ^= ht2_hitag2_byte(&state); + tx[1] ^= ht2_hitag2_byte(&state); + tx[2] ^= ht2_hitag2_byte(&state); + tx[3] ^= ht2_hitag2_byte(&state); + if (protocol_mode != HITAGS_UID_REQ_STD) { + tx[4] ^= ht2_hitag2_byte(&state); + } + /* * some readers do not allow to authenticate multiple times in a row with the same tag. * use this to change the uid between authentications. - if (rotate_uid % 2 == 0) { tag.data.s.uid_le = 0x44332211; } else { @@ -621,11 +305,8 @@ static void hts_handle_reader_command(uint8_t *rx, const size_t rxlen, if (protocol_mode != HITAGS_UID_REQ_STD) { //add crc8 + crc = CRC8Hitag1Bits(tx, 32); *txlen += 8; - crc = CRC_PRESET; - for (int i = 0; i < 4; i++) { - calc_crc(&crc, tx[i], 8); - } tx[4] = crc; } @@ -643,10 +324,7 @@ static void hts_handle_reader_command(uint8_t *rx, const size_t rxlen, if (protocol_mode != HITAGS_UID_REQ_STD) { //add crc8 - crc = CRC_PRESET; - for (int i = 0; i < *txlen / 8; i++) { - calc_crc(&crc, tx[i], 8); - } + crc = CRC8Hitag1Bits(tx, *txlen); *txlen += 8; tx[16] = crc; } @@ -692,26 +370,17 @@ static void hts_handle_reader_command(uint8_t *rx, const size_t rxlen, /* * Emulates a Hitag S Tag with the given data from the .hts file */ -void hts_simulate(bool tag_mem_supplied, const uint8_t *data, bool ledcontrol) { - - StopTicks(); - +void hts_simulate(bool tag_mem_supplied, int8_t threshold, const uint8_t *data, bool ledcontrol) { int overflow = 0; - uint8_t rx[HITAG_FRAME_LEN]; + uint8_t rx[HITAG_FRAME_LEN] = {0}; size_t rxlen = 0; uint8_t tx[HITAG_FRAME_LEN]; size_t txlen = 0; - // Reset the received frame, frame count and timing info - memset(rx, 0x00, sizeof(rx)); - // free eventually allocated BigBuf memory BigBuf_free(); BigBuf_Clear_ext(false); - // Enable tracing - set_tracing(true); - DbpString("Starting Hitag S simulation"); tag.pstate = HT_READY; @@ -738,67 +407,16 @@ void hts_simulate(bool tag_mem_supplied, const uint8_t *data, bool ledcontrol) { ); } - - // Set up simulator mode, frequency divisor which will drive the FPGA - // and analog mux selection. - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + hitag_setup_fpga(0, threshold, ledcontrol); FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_125); //125kHz - SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - - // Configure output pin that is connected to the FPGA (for modulating) - AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; - AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; - - // Disable modulation at default, which means release resistance - LOW(GPIO_SSC_DOUT); - - hts_init_clock(); - - if (ledcontrol) LED_D_ON(); while ((BUTTON_PRESS() == false) && (data_available() == false)) { uint32_t start_time = 0; WDT_HIT(); - // Receive frame, watch for at most T0*EOF periods - while (AT91C_BASE_TC1->TC_CV < T0 * HITAG_T_EOF) { - - // Check if rising edge in modulation is detected - if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { - - // Retrieve the new timing values - int rb = (AT91C_BASE_TC1->TC_RB / T0) + overflow; - overflow = 0; - - // Reset timer every frame, we have to capture the last edge for timing - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - - if (ledcontrol) LED_B_ON(); - // Capture reader cmd start timestamp - if (start_time == 0) { - start_time = TIMESTAMP - HITAG_T_LOW; - } - - // Capture reader frame - if (rb >= HITAG_T_STOP) { - if (rxlen != 0) { - //DbpString("weird0?"); - } - } else if (rb >= HITAG_T_1_MIN) { - // '1' bit - rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); - rxlen++; - } else if (rb >= HITAG_T_0_MIN) { - // '0' bit - rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); - rxlen++; - } else { - // Ignore weird value, is to small to mean anything - } - } - } + // Receive commands from the reader + hitag_tag_receive_frame(rx, sizeof(rx), &rxlen, &start_time, ledcontrol, &overflow); // Check if frame was captured if (rxlen > 0) { @@ -821,7 +439,7 @@ void hts_simulate(bool tag_mem_supplied, const uint8_t *data, bool ledcontrol) { if (txlen > 0) { // Transmit the tag frame start_time = TIMESTAMP; - hitag_send_frame(tx, txlen, ledcontrol); + hitag_tag_send_frame(tx, txlen, sof_bits, m, ledcontrol); LogTraceBits(tx, txlen, start_time, TIMESTAMP, false); } @@ -842,152 +460,13 @@ void hts_simulate(bool tag_mem_supplied, const uint8_t *data, bool ledcontrol) { } - hts_stop_clock(); - set_tracing(false); - lf_finalize(ledcontrol); + hitag_cleanup(ledcontrol); // release allocated memory from BigBuff. BigBuf_free(); DbpString("Sim stopped"); } -static void hts_receive_frame(uint8_t *rx, size_t sizeofrx, size_t *rxlen, uint32_t *resptime, bool ledcontrol) { - - // Reset values for receiving frames - memset(rx, 0x00, sizeofrx); - *rxlen = 0; - - int lastbit = 1; - bool bSkip = true; - uint32_t errorCount = 0; - bool bStarted = false; - uint16_t next_edge_event = AT91C_TC_LDRBS; - int double_speed = (m == AC4K || m == MC8K) ? 2 : 1; - - uint32_t rb_i = 0, h2 = 0, h3 = 0, h4 = 0; - uint8_t edges[160] = {0}; - - // Receive tag frame, watch for at most T0*HITAG_T_PROG_MAX periods - while (AT91C_BASE_TC0->TC_CV < (T0 * HITAG_T_PROG_MAX)) { - - // Check if edge in tag modulation is detected - if (AT91C_BASE_TC1->TC_SR & next_edge_event) { - - next_edge_event = next_edge_event ^ (AT91C_TC_LDRAS | AT91C_TC_LDRBS); - - // only use AT91C_TC_LDRBS falling edge for now - if (next_edge_event == AT91C_TC_LDRBS) continue; - - // Retrieve the new timing values - uint32_t rb = AT91C_BASE_TC1->TC_RB / T0; - edges[rb_i++] = rb; - // Reset timer every frame, we have to capture the last edge for timing - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - - if (ledcontrol) LED_B_ON(); - - // Capture tag response timestamp - if (*rxlen == 0) *resptime = TIMESTAMP; - - // Capture tag frame (manchester decoding using only falling edges) - if (bStarted == false) { - - if (rb >= HITAG_T_WAIT_RESP) { - bStarted = true; - - // We always receive a 'one' first, which has the falling edge after a half period |-_| - rx[0] = 0x80; - (*rxlen)++; - } else { - errorCount++; - } - - } else { - // Anticollision Coding - if (m == AC2K || m == AC4K) { - if (rb >= HITAG_T_TAG_CAPTURE_FOUR_HALF / double_speed) { - // Anticollision Coding example |--__|--__| (00) - lastbit = 0; - rx[(*rxlen) / 8] |= lastbit << (7 - ((*rxlen) % 8)); - (*rxlen)++; - } else if (rb >= HITAG_T_TAG_CAPTURE_THREE_HALF / double_speed) { - // Anticollision Coding example |-_-_|--__| (10) or |--__|-_-_| (01) - lastbit = !lastbit; - rx[(*rxlen) / 8] |= lastbit << (7 - ((*rxlen) % 8)); - (*rxlen)++; - - bSkip = !!lastbit; - } else if (rb >= HITAG_T_TAG_CAPTURE_TWO_HALF / double_speed) { - // Anticollision Coding example |-_-_| (1) - if (bSkip == false) { - lastbit = 1; - rx[(*rxlen) / 8] |= lastbit << (7 - ((*rxlen) % 8)); - (*rxlen)++; - } - - bSkip = !bSkip; - } else { - // Ignore weird value, is to small to mean anything - errorCount++; - } - } else { - // Manchester coding - if (rb >= HITAG_T_TAG_CAPTURE_FOUR_HALF / double_speed) { - // Manchester coding example |-_|_-|-_| (101) - rx[(*rxlen) / 8] |= 0 << (7 - ((*rxlen) % 8)); - (*rxlen)++; - - rx[(*rxlen) / 8] |= 1 << (7 - ((*rxlen) % 8)); - (*rxlen)++; - h4++; - } else if (rb >= HITAG_T_TAG_CAPTURE_THREE_HALF / double_speed) { - // Manchester coding example |_-|...|_-|-_| (0...01) - rx[(*rxlen) / 8] |= 0 << (7 - ((*rxlen) % 8)); - (*rxlen)++; - - // We have to skip this half period at start and add the 'one' the second time - if (bSkip == false) { - rx[(*rxlen) / 8] |= 1 << (7 - ((*rxlen) % 8)); - (*rxlen)++; - } - - lastbit = !lastbit; - bSkip = !bSkip; - h3++; - } else if (rb >= HITAG_T_TAG_CAPTURE_TWO_HALF / double_speed) { - // Manchester coding example |_-|_-| (00) or |-_|-_| (11) - // bit is same as last bit - rx[(*rxlen) / 8] |= lastbit << (7 - ((*rxlen) % 8)); - (*rxlen)++; - h2++; - } else { - // Ignore weird value, is to small to mean anything - errorCount++; - } - } - } - } - - // if we saw over 100 weird values break it probably isn't hitag... - if (errorCount > 100 || (*rxlen) / 8 >= sizeofrx) { - break; - } - - // We can break this loop if we received the last bit from a frame - // max periods between 2 falling edge - // RTF AC64 |--__|--__| (00) 64 * T0 - // RTF MC32 |_-|-_|_-| (010) 48 * T0 - if (AT91C_BASE_TC1->TC_CV > (T0 * 80)) { - if ((*rxlen)) { - break; - } - } - } - - DBG Dbprintf("RX0 %i:%02X.. err:%i resptime:%i h2:%i h3:%i h4:%i edges:", *rxlen, rx[0], errorCount, *resptime, h2, h3, h4); - DBG Dbhexdump(rb_i, edges, false); -} - static int hts_send_receive(const uint8_t *tx, size_t txlen, uint8_t *rx, size_t sizeofrx, size_t *rxlen, int t_wait, bool ledcontrol, bool ac_seq) { uint32_t start_time; @@ -1005,7 +484,7 @@ static int hts_send_receive(const uint8_t *tx, size_t txlen, uint8_t *rx, size_t start_time = TIMESTAMP; // Transmit the reader frame - hitag_reader_send_frame(tx, txlen, ledcontrol); + hitag_reader_send_frame(tx, txlen, ledcontrol, false); if (enable_page_tearoff && tearoff_hook() == PM3_ETEAROFF) { return PM3_ETEAROFF; @@ -1018,7 +497,8 @@ static int hts_send_receive(const uint8_t *tx, size_t txlen, uint8_t *rx, size_t hts_set_frame_modulation(protocol_mode, ac_seq); - hts_receive_frame(rx, sizeofrx, rxlen, &start_time, ledcontrol); + hitag_reader_receive_frame(rx, sizeofrx, rxlen, &start_time, ledcontrol, m, sof_bits); + // hts_receive_frame(rx, sizeofrx, rxlen, &start_time, ledcontrol); // Check if frame was captured and store it if (*rxlen > 0) { @@ -1033,23 +513,8 @@ static int hts_send_receive(const uint8_t *tx, size_t txlen, uint8_t *rx, size_t Dbprintf("htS: sizeofrx... %zu", sizeofrx); DbpString("htS: response_bit:"); Dbhexdump(*rxlen, response_bit, false); - Dbprintf("htS: skipping %d bit SOF", sof_bits); - - if ((rx[0] >> (8 - sof_bits)) != ((1 << sof_bits) - 1)) { - DBG DbpString("htS: Warning, not all bits of SOF are 1"); - } } - // remove first sof_bits bits SOF - for (size_t i = 0; i < (*rxlen + 8) / 8; i++) { - rx[i] <<= sof_bits; - if (i + 1 < (*rxlen + 8) / 8) { - rx[i] |= (rx[i + 1] >> (8 - sof_bits)); - } - } - - *rxlen -= sof_bits; - LogTraceBits(rx, *rxlen, start_time, TIMESTAMP, false); } @@ -1057,37 +522,15 @@ static int hts_send_receive(const uint8_t *tx, size_t txlen, uint8_t *rx, size_t } static int hts_select_tag(const lf_hitag_data_t *packet, uint8_t *tx, size_t sizeoftx, uint8_t *rx, size_t sizeofrx, int t_wait, bool ledcontrol) { + size_t txlen = 0; + size_t rxlen = 0; - StopTicks(); - - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - - // Clean up trace and prepare it for storing frames - set_tracing(true); - clear_trace(); - - if (ledcontrol) LED_D_ON(); - - hts_init_clock(); - - // Set fpga in edge detect with reader field, we can modulate as reader now - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_READER_FIELD); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_125); //125kHz - SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - - // Configure output and enable pin that is connected to the FPGA (for modulating) - AT91C_BASE_PIOA->PIO_OER |= GPIO_SSC_DOUT; - AT91C_BASE_PIOA->PIO_PER |= GPIO_SSC_DOUT; - - // Disable modulation at default, which means enable the field - LOW(GPIO_SSC_DOUT); + // Setup FPGA and initialize + hitag_setup_fpga(FPGA_LF_EDGE_DETECT_READER_FIELD, 127, ledcontrol); // UID request standard 00110 // UID request Advanced 1100x // UID request FAdvanced 11010 - size_t txlen = 0; - size_t rxlen = 0; - protocol_mode = packet->mode; uint8_t cmd = protocol_mode; txlen = concatbits(tx, txlen, &cmd, 0, 5, false); @@ -1356,9 +799,7 @@ void hts_read(const lf_hitag_data_t *payload, bool ledcontrol) { } read_end: - hts_stop_clock(); - set_tracing(false); - lf_finalize(ledcontrol); + hitag_cleanup(ledcontrol); reply_reason(CMD_LF_HITAGS_READ, status, reason, (uint8_t *)&card, sizeof(card)); } @@ -1449,41 +890,14 @@ void hts_write_page(const lf_hitag_data_t *payload, bool ledcontrol) { } write_end: - hts_stop_clock(); - set_tracing(false); - lf_finalize(ledcontrol); + hitag_cleanup(ledcontrol); reply_reason(CMD_LF_HITAGS_WRITE, status, reason, NULL, 0); } int hts_read_uid(uint32_t *uid, bool ledcontrol, bool send_answer) { + // Setup FPGA and initialize + hitag_setup_fpga(FPGA_LF_EDGE_DETECT_READER_FIELD, 127, ledcontrol); - StopTicks(); - - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - - // Clean up trace and prepare it for storing frames - set_tracing(true); - clear_trace(); - - if (ledcontrol) LED_D_ON(); - - hts_init_clock(); - - // Set fpga in edge detect with reader field, we can modulate as reader now - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_READER_FIELD); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_125); //125kHz - SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - - // Configure output and enable pin that is connected to the FPGA (for modulating) - AT91C_BASE_PIOA->PIO_OER |= GPIO_SSC_DOUT; - AT91C_BASE_PIOA->PIO_PER |= GPIO_SSC_DOUT; - - // Disable modulation at default, which means enable the field - LOW(GPIO_SSC_DOUT); - - // UID request standard 00110 - // UID request Advanced 1100x - // UID request FAdvanced 11010 protocol_mode = HITAGS_UID_REQ_ADV1; uint8_t cmd = protocol_mode; @@ -1511,10 +925,10 @@ int hts_read_uid(uint32_t *uid, bool ledcontrol, bool send_answer) { status = PM3_ERFTRANS; } - hts_stop_clock(); - set_tracing(false); - lf_finalize(ledcontrol); - reply_ng(CMD_LF_HITAGS_UID, status, (uint8_t *)tag.data.pages, sizeof(tag.data.pages)); + hitag_cleanup(ledcontrol); + if (send_answer) { + reply_ng(CMD_LF_HITAGS_UID, status, (uint8_t *)tag.data.pages, sizeof(tag.data.pages)); + } return status; } @@ -1576,9 +990,7 @@ void hts_check_challenges(const uint8_t *data, uint32_t datalen, bool ledcontrol SpinDelay(2); } - hts_stop_clock(); - set_tracing(false); - lf_finalize(ledcontrol); + hitag_cleanup(ledcontrol); reply_ng(CMD_LF_HITAGS_TEST_TRACES, PM3_SUCCESS, NULL, 0); return; } diff --git a/armsrc/hitagS.h b/armsrc/hitagS.h index 8c49439dc..5c2008b31 100644 --- a/armsrc/hitagS.h +++ b/armsrc/hitagS.h @@ -24,7 +24,7 @@ #include "common.h" #include "hitag.h" -void hts_simulate(bool tag_mem_supplied, const uint8_t *data, bool ledcontrol); +void hts_simulate(bool tag_mem_supplied, int8_t threshold, const uint8_t *data, bool ledcontrol); void hts_read(const lf_hitag_data_t *payload, bool ledcontrol); void hts_write_page(const lf_hitag_data_t *payload, bool ledcontrol); void hts_check_challenges(const uint8_t *data, uint32_t datalen, bool ledcontrol); diff --git a/armsrc/hitag_common.c b/armsrc/hitag_common.c new file mode 100644 index 000000000..43837486f --- /dev/null +++ b/armsrc/hitag_common.c @@ -0,0 +1,539 @@ +//----------------------------------------------------------------------------- +// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// See LICENSE.txt for the text of the license. +//----------------------------------------------------------------------------- +// Hitag shared functionality +//----------------------------------------------------------------------------- + +#include "hitag_common.h" + +#include "proxmark3_arm.h" +#include "cmd.h" +#include "BigBuf.h" +#include "fpgaloader.h" +#include "ticks.h" +#include "dbprint.h" +#include "util.h" +#include "string.h" +#include "commonutil.h" +#include "hitag2/hitag2_crypto.h" +#include "lfadc.h" +#include "crc.h" +#include "protocols.h" +#include "appmain.h" // tearoff_hook() + +uint16_t timestamp_high = 0; // Timer Counter 2 overflow count, combined with TC2 counter for ~47min timing + +static void hitag_stop_clock(void) { + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; + AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKDIS; +} + +static void hitag_init_clock(void) { + // Enable Peripheral Clock for + // Timer Counter 0, used to measure exact timing before answering + // Timer Counter 1, used to capture edges of the tag frames + // Timer Counter 2, used to log trace time + AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1) | (1 << AT91C_ID_TC2); + + AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; + + // Disable timer during configuration + hitag_stop_clock(); + + // TC0: Capture mode, default timer source = MCK/32 (TIMER_CLOCK3), no triggers + AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK; + + // TC1: Capture mode, default timer source = MCK/32 (TIMER_CLOCK3), TIOA is external trigger, + AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK // use MCK/32 (TIMER_CLOCK3) + | AT91C_TC_ABETRG // TIOA is used as an external trigger + | AT91C_TC_ETRGEDG_FALLING // external trigger on falling edge + | AT91C_TC_LDRA_RISING // load RA on on rising edge of TIOA + | AT91C_TC_LDRB_FALLING; // load RB on on falling edge of TIOA + + // TC2: Capture mode, default timer source = MCK/32 (TIMER_CLOCK3), no triggers + AT91C_BASE_TC2->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK; + + // Enable and reset counters + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + + // Assert a sync signal. This sets all timers to 0 on next active clock edge + AT91C_BASE_TCB->TCB_BCR = 1; + + // synchronized startup procedure + // In theory, with MCK/32, we shouldn't be waiting longer than 32 instruction statements, right? + while (AT91C_BASE_TC0->TC_CV != 0) { + }; // wait until TC0 returned to zero + + // reset timestamp + timestamp_high = 0; +} + +// Initialize FPGA and timer for Hitag operations +void hitag_setup_fpga(uint16_t conf, uint8_t threshold, bool ledcontrol) { + StopTicks(); + + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + + // Clean up trace and prepare it for storing frames + set_tracing(true); + clear_trace(); + + if (ledcontrol) LED_D_ON(); + + hitag_init_clock(); + + // Set fpga in edge detect with/without reader field, we can modulate as reader/tag now + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | conf); + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_125); //125kHz + if (threshold != 127) FpgaSendCommand(FPGA_CMD_SET_EDGE_DETECT_THRESHOLD, threshold); + SetAdcMuxFor(GPIO_MUXSEL_LOPKD); + + // Configure output and enable pin that is connected to the FPGA (for modulating) + AT91C_BASE_PIOA->PIO_OER |= GPIO_SSC_DOUT; + AT91C_BASE_PIOA->PIO_PER |= GPIO_SSC_DOUT; + + // Disable modulation at default, which means enable the field + LOW(GPIO_SSC_DOUT); +} + +// Clean up and finalize Hitag operations +void hitag_cleanup(bool ledcontrol) { + hitag_stop_clock(); + set_tracing(false); + lf_finalize(ledcontrol); +} + +// Reader functions +static void hitag_reader_send_bit(int bit, bool ledcontrol) { + // Reset clock for the next bit + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + while (AT91C_BASE_TC0->TC_CV != 0) {}; + + if (ledcontrol) LED_A_ON(); + + // Binary puls length modulation (BPLM) is used to encode the data stream + // This means that a transmission of a one takes longer than that of a zero + HIGH(GPIO_SSC_DOUT); + + // Wait for 4-10 times the carrier period + while (AT91C_BASE_TC0->TC_CV < T0 * HITAG_T_LOW) {}; + + LOW(GPIO_SSC_DOUT); + + if (bit == 0) { + // Zero bit: |_-| + while (AT91C_BASE_TC0->TC_CV < T0 * HITAG_T_0) {}; + } else { + // One bit: |_--| + while (AT91C_BASE_TC0->TC_CV < T0 * HITAG_T_1) {}; + } + + if (ledcontrol) LED_A_OFF(); +} + +void hitag_reader_send_frame(const uint8_t *frame, size_t frame_len, bool ledcontrol, bool send_sof) { + // Send SOF (Start of Frame) for Hitag µ if requested + if (send_sof) { + hitag_reader_send_bit(0, ledcontrol); + + // Reset clock for the code violation + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + while (AT91C_BASE_TC0->TC_CV != 0) {}; + + if (ledcontrol) LED_A_ON(); + + // SOF is HIGH for HITAG_T_LOW + HIGH(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * HITAG_T_LOW) {}; + + // Then LOW for HITAG_T_CODE_VIOLATION + LOW(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * HITAG_T_CODE_VIOLATION) {}; + + if (ledcontrol) LED_A_OFF(); + } + + // Send the content of the frame + for (size_t i = 0; i < frame_len; i++) { + hitag_reader_send_bit(TEST_BIT_MSB(frame, i), ledcontrol); + } + + // Send EOF + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + while (AT91C_BASE_TC0->TC_CV != 0) {}; + + HIGH(GPIO_SSC_DOUT); + + // Wait for 4-10 times the carrier period + while (AT91C_BASE_TC0->TC_CV < T0 * HITAG_T_LOW) {}; + + LOW(GPIO_SSC_DOUT); +} + +void hitag_reader_receive_frame(uint8_t *rx, size_t sizeofrx, size_t *rxlen, uint32_t *resptime, bool ledcontrol, + MOD modulation, int sof_bits) { + // Reset values for receiving frames + memset(rx, 0x00, sizeofrx); + *rxlen = 0; + + int lastbit = 1; + bool bSkip = true; + uint32_t errorCount = 0; + bool bStarted = false; + uint16_t next_edge_event = AT91C_TC_LDRBS; + int double_speed = (modulation == AC4K || modulation == MC8K) ? 2 : 1; + + uint32_t rb_i = 0; + uint8_t edges[160] = {0}; + + // Skip SOF bits + bool sof_received = false; + + // Receive tag frame, watch for at most T0*HITAG_T_PROG_MAX periods + while (AT91C_BASE_TC0->TC_CV < (T0 * HITAG_T_PROG_MAX)) { + // Check if edge in tag modulation is detected + if (AT91C_BASE_TC1->TC_SR & next_edge_event) { + next_edge_event = next_edge_event ^ (AT91C_TC_LDRAS | AT91C_TC_LDRBS); + + // only use AT91C_TC_LDRBS falling edge for now + if (next_edge_event == AT91C_TC_LDRBS) continue; + + // Retrieve the new timing values + uint32_t rb = AT91C_BASE_TC1->TC_RB / T0; + edges[rb_i++] = rb; + + // Reset timer every frame, we have to capture the last edge for timing + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + + if (ledcontrol) LED_B_INV(); + + // Capture tag frame (manchester decoding using only falling edges) + if (bStarted == false) { + if (rb >= HITAG_T_WAIT_RESP) { + bStarted = true; + + // Capture tag response timestamp + *resptime = TIMESTAMP; + + // We always receive a 'one' first, which has the falling edge after a half period |-_| + rx[0] = 0x80; + *rxlen = 1; + } else { + errorCount++; + } + } else { + // Handle different modulation types + if (modulation == AC2K || modulation == AC4K) { + // Anticollision Coding + if (rb >= HITAG_T_TAG_CAPTURE_FOUR_HALF / double_speed) { + // Anticollision Coding example |--__|--__| (00) + lastbit = 0; + // CLEAR_BIT_MSB(rx, *rxlen); + (*rxlen)++; + } else if (rb >= HITAG_T_TAG_CAPTURE_THREE_HALF / double_speed) { + // Anticollision Coding example |-_-_|--__| (10) or |--__|-_-_| (01) + lastbit = !lastbit; + if (lastbit) SET_BIT_MSB(rx, *rxlen); + (*rxlen)++; + + bSkip = !!lastbit; + } else if (rb >= HITAG_T_TAG_CAPTURE_TWO_HALF / double_speed) { + // Anticollision Coding example |-_-_| (1) + if (bSkip == false) { + lastbit = 1; + SET_BIT_MSB(rx, *rxlen); + (*rxlen)++; + } + + bSkip = !bSkip; + } else { + // Ignore weird value, is to small to mean anything + errorCount++; + } + } else { + // Manchester coding (MC4K, MC8K) + if (rb >= HITAG_T_TAG_CAPTURE_FOUR_HALF / double_speed) { + // Manchester coding example |-_|_-|-_| (101) + // CLEAR_BIT_MSB(rx, *rxlen); + (*rxlen)++; + + SET_BIT_MSB(rx, *rxlen); + (*rxlen)++; + } else if (rb >= HITAG_T_TAG_CAPTURE_THREE_HALF / double_speed) { + // Manchester coding example |_-|...|_-|-_| (0...01) + // CLEAR_BIT_MSB(rx, *rxlen); + (*rxlen)++; + + // We have to skip this half period at start and add the 'one' the second time + if (bSkip == false) { + SET_BIT_MSB(rx, *rxlen); + (*rxlen)++; + } + + lastbit = !lastbit; + bSkip = !bSkip; + } else if (rb >= HITAG_T_TAG_CAPTURE_TWO_HALF / double_speed) { + // Manchester coding example |_-|_-| (00) or |-_|-_| (11) + // bit is same as last bit + if (lastbit) SET_BIT_MSB(rx, *rxlen); + (*rxlen)++; + } else { + // Ignore weird value, is to small to mean anything + errorCount++; + } + } + + // Handle SOF bits + if (sof_received == false && *rxlen >= sof_bits) { + // Check if SOF is valid (all bits should be 1) + if ((rx[0] >> (8 - sof_bits)) != ((1 << sof_bits) - 1)) { + if (sof_bits == 4) { + sof_bits = 3; + // Hitag µ is LSB first 0b110 + if ((rx[0] & 0xE0) != 0xC0) { + DBG Dbprintf("Warning, SOF is invalid rx[0]: 0x%02X", rx[0]); + } + } else { + DBG DbpString("Warning, not all bits of SOF are 1"); + } + } + + *rxlen -= sof_bits; + uint8_t tmp = rx[0]; + rx[0] = 0x00; + for (size_t i = 0; i < *rxlen; i++) { + if (TEST_BIT_MSB(&tmp, sof_bits + i)) SET_BIT_MSB(rx, i); + } + // DBG Dbprintf("after sof_bits rxlen: %d rx[0]: 0x%02X", *rxlen, rx[0]); + sof_received = true; + } + } + } + + // if we saw over 100 weird values break it probably isn't hitag... + if (errorCount > 100 || (*rxlen) / 8 >= sizeofrx) { + break; + } + + // We can break this loop if we received the last bit from a frame + // max periods between 2 falling edge + // RTF AC64 |--__|--__| (00) 64 * T0 + // RTF MC32 |_-|-_|_-| (010) 48 * T0 + if (AT91C_BASE_TC1->TC_CV > (T0 * 80)) { + if (bStarted) { + break; + } + } + } + + DBG { + Dbprintf("RX %i:%02X.. resptime:%i edges:", *rxlen, rx[0], *resptime); + Dbhexdump(rb_i, edges, false); + } +} + +// Tag functions - depends on modulation type +static void hitag_tag_send_bit(int bit, MOD modulation, bool ledcontrol) { + // Reset clock for the next bit + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + + if (ledcontrol) LED_A_ON(); + + switch (modulation) { + case AC2K: { + if (bit == 0) { + // AC Coding --__ + HIGH(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 32) {}; + + LOW(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 64) {}; + } else { + // AC coding -_-_ + HIGH(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 16) {}; + + LOW(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 32) {}; + + HIGH(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 48) {}; + + LOW(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 64) {}; + } + break; + } + case AC4K: { + if (bit == 0) { + // AC Coding --__ + HIGH(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * HITAG_T_TAG_HALF_PERIOD) {}; + + LOW(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * HITAG_T_TAG_FULL_PERIOD) {}; + } else { + // AC coding -_-_ + HIGH(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 8) {}; + + LOW(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 16) {}; + + HIGH(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 24) {}; + + LOW(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 32) {}; + } + break; + } + case MC4K: { + if (bit == 0) { + // Manchester: Unloaded, then loaded |__--| + LOW(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 16) {}; + + HIGH(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 32) {}; + } else { + // Manchester: Loaded, then unloaded |--__| + HIGH(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 16) {}; + + LOW(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 32) {}; + } + break; + } + case MC8K: { + if (bit == 0) { + // Manchester: Unloaded, then loaded |__--| + LOW(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 8) {}; + + HIGH(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 16) {}; + } else { + // Manchester: Loaded, then unloaded |--__| + HIGH(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 8) {}; + + LOW(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 16) {}; + } + break; + } + } + + if (ledcontrol) LED_A_OFF(); +} + +void hitag_tag_receive_frame(uint8_t *rx, size_t sizeofrx, size_t *rxlen, uint32_t *start_time, bool ledcontrol, int *overflow) { + uint16_t next_edge_event = AT91C_TC_LDRBS; + uint8_t edges[160] = {0}; + uint32_t rb_i = 0; + + // Receive frame, watch for at most T0*EOF periods + while (AT91C_BASE_TC1->TC_CV < T0 * HITAG_T_EOF) { + + // Check if edge in modulation is detected + if (AT91C_BASE_TC1->TC_SR & next_edge_event) { + next_edge_event = next_edge_event ^ (AT91C_TC_LDRAS | AT91C_TC_LDRBS); + + // only use AT91C_TC_LDRBS falling edge for now + if (next_edge_event == AT91C_TC_LDRBS) continue; + + // Retrieve the new timing values + uint32_t rb = AT91C_BASE_TC1->TC_RB / T0 + *overflow; + *overflow = 0; + + edges[rb_i++] = rb; + + if (ledcontrol) LED_B_INV(); + + // Capture reader cmd start timestamp + if (*start_time == 0) { + *start_time = TIMESTAMP - HITAG_T_LOW; + } + + // Capture reader frame + if (rb >= HITAG_T_STOP) { + // Hitag µ SOF + if (*rxlen != 0 && *rxlen != 1) { + // DBG DbpString("weird0?"); + break; + } + *rxlen = 0; + } else if (rb >= HITAG_T_1_MIN) { + // '1' bit + SET_BIT_MSB(rx, *rxlen); + (*rxlen)++; + } else if (rb >= HITAG_T_0_MIN) { + // '0' bit + // CLEAR_BIT_MSB(rx, *rxlen); + (*rxlen)++; + } else { + // Ignore weird value, is too small to mean anything + } + } + } + + if (ledcontrol) LED_B_OFF(); + + DBG if (rb_i) { + Dbprintf("RX %i bits.. start_time:%i edges:", *rxlen, *start_time); + Dbhexdump(rb_i, edges, false); + } +} + +void hitag_tag_send_frame(const uint8_t *frame, size_t frame_len, int sof_bits, MOD modulation, bool ledcontrol) { + // The beginning of the frame is hidden in some high level; pause until our bits will have an effect + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + HIGH(GPIO_SSC_DOUT); + + switch (modulation) { + case AC4K: + case MC8K: { + while (AT91C_BASE_TC0->TC_CV < T0 * 40) {}; // FADV + break; + } + case AC2K: + case MC4K: { + while (AT91C_BASE_TC0->TC_CV < T0 * 20) {}; // STD + ADV + break; + } + } + + // SOF - send start of frame + for (size_t i = 0; i < sof_bits; i++) { + if (sof_bits == 4 && i == 3) { + // Hitag µ SOF is 110 + hitag_tag_send_bit(0, modulation, ledcontrol); + break; + } else + hitag_tag_send_bit(1, modulation, ledcontrol); + } + + // Send the content of the frame + for (size_t i = 0; i < frame_len; i++) { + hitag_tag_send_bit(TEST_BIT_MSB(frame, i), modulation, ledcontrol); + } + + LOW(GPIO_SSC_DOUT); +} diff --git a/armsrc/hitag_common.h b/armsrc/hitag_common.h new file mode 100644 index 000000000..16a966240 --- /dev/null +++ b/armsrc/hitag_common.h @@ -0,0 +1,57 @@ +#ifndef HITAG_COMMON_H +#define HITAG_COMMON_H + +#include "hitag.h" + +// Sam7s has several timers, we will use the source TIMER_CLOCK3 (aka AT91C_TC_CLKS_TIMER_DIV3_CLOCK) +// TIMER_CLOCK3 = MCK/32, MCK is running at 48 MHz, Timer is running at 48MHz/32 = 1500 KHz +// Hitag units (T0) have duration of 8 microseconds (us), which is 1/125000 per second (carrier) +// T0 = TIMER_CLOCK3 / 125000 = 12 + +#define T0 12 + +#define HITAG_FRAME_LEN 20 + +// TC0 and TC1 are 16-bit counters and will overflow after 5461 * T0 +// Ensure not to set these timings above 5461 (~43ms) when comparing without considering overflow, as they will never reach that value. + +#define HITAG_T_LOW 8 /* T_LOW should be 4..10 */ +#define HITAG_T_0 20 /* T[0] should be 18..22 */ +#define HITAG_T_1 28 /* T[1] should be 26..32 */ +#define HITAG_T_0_MIN 15 /* T[0] should be 18..22 */ +#define HITAG_T_1_MIN 25 /* T[1] should be 26..32 */ +#define HITAG_T_STOP 36 /* T_EOF should be > 36 */ +#define HITAG_T_CODE_VIOLATION 36 /* Hitag µ TFcv should be 34..38 */ +#define HITAG_T_EOF 80 /* T_EOF should be > 36 */ + +#define HITAG_T_WAIT_RESP 200 /* T_wresp should be 204..212 */ +#define HITAG_T_WAIT_SC 200 /* T_wsc should be 90..5000 */ +#define HITAG_T_WAIT_FIRST 300 /* T_wfc should be 280..565 (T_ttf) */ +#define HITAG_T_PROG_MAX 750 /* T_prog should be 716..726 */ + +#define HITAG_T_TAG_ONE_HALF_PERIOD 10 +#define HITAG_T_TAG_TWO_HALF_PERIOD 25 +#define HITAG_T_TAG_THREE_HALF_PERIOD 41 +#define HITAG_T_TAG_FOUR_HALF_PERIOD 57 + +#define HITAG_T_TAG_HALF_PERIOD 16 +#define HITAG_T_TAG_FULL_PERIOD 32 + +#define HITAG_T_TAG_CAPTURE_ONE_HALF 13 +#define HITAG_T_TAG_CAPTURE_TWO_HALF 25 +#define HITAG_T_TAG_CAPTURE_THREE_HALF 41 +#define HITAG_T_TAG_CAPTURE_FOUR_HALF 57 + +extern uint16_t timestamp_high; +#define TIMESTAMP ( (AT91C_BASE_TC2->TC_SR & AT91C_TC_COVFS) ? timestamp_high += 1 : 0, ((timestamp_high << 16) + AT91C_BASE_TC2->TC_CV) / T0) + +// Common hitag functions +void hitag_setup_fpga(uint16_t conf, uint8_t threshold, bool ledcontrol); +void hitag_cleanup(bool ledcontrol); +void hitag_reader_send_frame(const uint8_t *frame, size_t frame_len, bool ledcontrol, bool send_sof); +void hitag_reader_receive_frame(uint8_t *rx, size_t sizeofrx, size_t *rxlen, uint32_t *resptime, bool ledcontrol, MOD modulation, + int sof_bits); +void hitag_tag_receive_frame(uint8_t *rx, size_t sizeofrx, size_t *rxlen, uint32_t *start_time, bool ledcontrol, int *overflow); +void hitag_tag_send_frame(const uint8_t *frame, size_t frame_len, int sof_bits, MOD modulation, bool ledcontrol); + +#endif diff --git a/client/src/cmdlfhitag.c b/client/src/cmdlfhitag.c index ec9e7361a..2cafdb161 100644 --- a/client/src/cmdlfhitag.c +++ b/client/src/cmdlfhitag.c @@ -793,9 +793,6 @@ void annotateHitag2(char *exp, size_t size, const uint8_t *cmd, uint8_t cmdsize, free(binstr); } -void annotateHitagS(char *exp, size_t size, const uint8_t *cmd, uint8_t cmdsize, bool is_response) { -} - static const char *identify_transponder_hitag2(uint32_t uid) { switch (uid) { diff --git a/client/src/cmdlfhitag.h b/client/src/cmdlfhitag.h index 81bc26a7e..5c82613cf 100644 --- a/client/src/cmdlfhitag.h +++ b/client/src/cmdlfhitag.h @@ -31,7 +31,6 @@ int ht2_read_uid(void); int ht2_read_paxton(void); void annotateHitag1(char *exp, size_t size, const uint8_t *cmd, uint8_t cmdsize, bool is_response); void annotateHitag2(char *exp, size_t size, const uint8_t *cmd, uint8_t cmdsize, uint8_t bits, bool is_response, const uint64_t *keys, uint32_t keycount, bool isdecrypted); -void annotateHitagS(char *exp, size_t size, const uint8_t *cmd, uint8_t cmdsize, bool is_response); void annotateHitag2_init(void); bool hitag2_get_plain(uint8_t *plain, uint8_t *plen); diff --git a/client/src/cmdlfhitaghts.c b/client/src/cmdlfhitaghts.c index e14c870ad..fdf8fbe28 100644 --- a/client/src/cmdlfhitaghts.c +++ b/client/src/cmdlfhitaghts.c @@ -36,6 +36,8 @@ static int CmdHelp(const char *Cmd); +void annotateHitagS(char *exp, size_t size, const uint8_t *cmd, uint8_t cmdsize, bool is_response) {} + static const char *hts_get_type_str(uint32_t uid) { // source 1: https://www.scorpio-lk.com/downloads/Tango/HITAG_Classification.pdf // IDE Mark @@ -88,7 +90,7 @@ static bool hts_get_uid(uint32_t *uid) { } if (resp.status != PM3_SUCCESS) { - PrintAndLogEx(DEBUG, "DEBUG: Error - failed getting UID"); + PrintAndLogEx(DEBUG, "DEBUG: Error - failed getting Hitag S UID"); return false; } @@ -253,10 +255,38 @@ static void print_error(int8_t reason) { break; default: // PM3_REASON_UNKNOWN - PrintAndLogEx(DEBUG, "DEBUG: Error - Hitag S failed"); + PrintAndLogEx(FAILED, "Error - Hitag S failed"); } } +static void hitags_config_print(hitags_config_t config) { + PrintAndLogEx(INFO, " Memory type...... " _GREEN_("%s"), + (const char *[]) {"Hitag S 32", "Hitag S 256", "Hitag S 2048", "Unknown Hitag S/8211"}[config.MEMT]); + + PrintAndLogEx(INFO, " Authenticaion.... %s", config.auth ? _YELLOW_("Yes") : "No"); + + PrintAndLogEx(INFO, " TTF coding....... %s", + config.RES3 ? "FSK 0=RF/10 1=RF/8" : (const char *[]) {"Manchester", "Biphase"}[config.TTFC]); + + PrintAndLogEx(INFO, " TTF data rate.... %s", + (const char *[]) {"4 kBit", "8 kBit", "2 kBit", "2 kBit and Pigeon Race Standard"}[config.TTFDR]); + + PrintAndLogEx(INFO, " TTF mode......... %s", + (const char *[]) { + "TTF Mode disabled (= RTF Mode)", + "Page 4, Page 5", + "Page 4, Page 5, Page 6, Page 7", + "Page 4", + "TTF Mode disabled (= RTF Mode)", + "Page 4, Page 5, Page 6", + "Page 4, Page 5, Page 6, Page 7, Page 8", + "Page 4, Page 5, Page 6, Page 7, Page 8, Page 9, Page 10, Page 11", + }[config.RES0 << 2 | config.TTFM]); + + PrintAndLogEx(INFO, " Config locked.... %s", config.LCON ? _RED_("Yes") : _GREEN_("No")); + PrintAndLogEx(INFO, " Key/PWD locked... %s", config.LKP ? _RED_("Yes") : _GREEN_("No")); +} + static int CmdLFHitagSRead(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "lf hitag hts rdbl", @@ -868,20 +898,23 @@ static int CmdLFHitagSSim(const char *Cmd) { "Simulate Hitag S transponder\n" "You need to `lf hitag hts eload` first", "lf hitag hts sim\n" - "lf hitag hts sim --82xx"); + "lf hitag hts sim --82xx\n" + "lf hitag hts sim -t 30 -> set threshold to 30"); void *argtable[] = { arg_param_begin, arg_lit0("8", "82xx", "simulate 8268/8310"), + arg_int0("t", "threshold", "", "set edge detect threshold (def: 127)"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); // bool use_82xx = arg_get_lit(ctx, 1); // not implemented yet + int threshold = arg_get_int_def(ctx, 2, 127); CLIParserFree(ctx); clearCommandBuffer(); - SendCommandMIX(CMD_LF_HITAGS_SIMULATE, false, 0, 0, NULL, 0); + SendCommandMIX(CMD_LF_HITAGS_SIMULATE, false, threshold, 0, NULL, 0); return PM3_SUCCESS; } @@ -889,40 +922,6 @@ static int CmdLFHitagSList(const char *Cmd) { return CmdTraceListAlias(Cmd, "lf hitag hts", "hitags"); } -void hitags_config_print(hitags_config_t config) { - PrintAndLogEx(INFO, " Memory type...... " _GREEN_("%s"), - (const char *[]) { - "Hitag S 32", "Hitag S 256", "Hitag S 2048", - "Unknown Hitag S/8211" - }[config.MEMT]); - - PrintAndLogEx(INFO, " Authenticaion.... %s", config.auth ? _YELLOW_("Yes") : "No"); - - PrintAndLogEx(INFO, " TTF coding....... %s", - config.RES3 ? "FSK 0=RF/10 1=RF/8" : (const char *[]) {"Manchester", "Biphase"}[config.TTFC]); - - PrintAndLogEx(INFO, " TTF data rate.... %s", - (const char *[]) { - "4 kBit", "8 kBit", "2 kBit", - "2 kBit and Pigeon Race Standard" - }[config.TTFDR]); - - PrintAndLogEx(INFO, " TTF mode......... %s", - (const char *[]) { - "TTF Mode disabled (= RTF Mode)", - "Page 4, Page 5", - "Page 4, Page 5, Page 6, Page 7", - "Page 4", - "TTF Mode disabled (= RTF Mode)", - "Page 4, Page 5, Page 6", - "Page 4, Page 5, Page 6, Page 7, Page 8", - "Page 4, Page 5, Page 6, Page 7, Page 8, Page 9, Page 10, Page 11", - }[config.RES0 << 2 | config.TTFM]); - - PrintAndLogEx(INFO, " Config locked.... %s", config.LCON ? _RED_("Yes") : _GREEN_("No")); - PrintAndLogEx(INFO, " Key/PWD locked... %s", config.LKP ? _RED_("Yes") : _GREEN_("No")); -} - static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, {"list", CmdLFHitagSList, AlwaysAvailable, "List Hitag S trace history"}, diff --git a/client/src/cmdlfhitaghts.h b/client/src/cmdlfhitaghts.h index 171510d7c..d22fa4518 100644 --- a/client/src/cmdlfhitaghts.h +++ b/client/src/cmdlfhitaghts.h @@ -22,9 +22,10 @@ #include "common.h" #include "hitag.h" +void annotateHitagS(char *exp, size_t size, const uint8_t *cmd, uint8_t cmdsize, bool is_response); + int CmdLFHitagS(const char *Cmd); int read_hts_uid(void); -void hitags_config_print(hitags_config_t config); #endif //CMDLFHITAGS_H__ diff --git a/client/src/cmdtrace.c b/client/src/cmdtrace.c index 07ffc3377..4ae143b1c 100644 --- a/client/src/cmdtrace.c +++ b/client/src/cmdtrace.c @@ -28,6 +28,7 @@ #include "comms.h" // for sending cmds to device. GetFromBigBuf #include "fileutils.h" // for saveFile #include "cmdlfhitag.h" // annotate hitag +#include "cmdlfhitaghts.h" // annotate hitags #include "pm3_cmd.h" // tracelog_hdr_t #include "cliparser.h" // args.. diff --git a/include/hitag.h b/include/hitag.h index e63b8c448..330ce8ddf 100644 --- a/include/hitag.h +++ b/include/hitag.h @@ -41,11 +41,18 @@ // need to see which limits these cards has #define HITAG1_MAX_BYTE_SIZE 64 -#define HITAGU_MAX_BYTE_SIZE 64 -#define HITAG_MAX_BYTE_SIZE (64 * HITAG_BLOCK_SIZE) +#define HITAG_MAX_BYTE_SIZE (64 * HITAG_BLOCK_SIZE) #define HITAG2_CONFIG_BLOCK 3 +// Modulation types - used by shared code +typedef enum modulation { + AC2K = 0, // Amplitude modulation 2000 bits/s + AC4K, // Amplitude modulation 4000 bits/s + MC4K, // Manchester modulation 4000 bits/s + MC8K // Manchester modulation 8000 bits/s +} MOD; + typedef enum { HTSF_PLAIN, HTSF_82xx, @@ -125,7 +132,7 @@ struct hitagS_tag { int max_page; union { - uint8_t pages[64][4]; + uint8_t pages[HITAGS_MAX_PAGES][HITAGS_PAGE_SIZE]; struct { // page 0 uint32_t uid_le; @@ -147,7 +154,7 @@ typedef struct { hitag_function cmd; uint8_t page; uint8_t page_count; - uint8_t data[HITAGS_PAGE_SIZE]; + uint8_t data[HITAG_BLOCK_SIZE]; uint8_t NrAr[HITAG_NRAR_SIZE]; // unaligned access to key as uint64_t will abort. // todo: Why does the compiler without -munaligned-access generate unaligned-access code in the first place?