Refactor Hitag low-level functions into hitag_common

This commit is contained in:
douniwan5788 2025-03-15 04:09:21 +08:00
commit 3d0c8cab5c
12 changed files with 696 additions and 684 deletions

View file

@ -72,7 +72,7 @@ else
endif endif
ifneq (,$(findstring WITH_HITAG,$(APP_CFLAGS))) 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 APP_CFLAGS += -I../common/hitag2
else else
SRC_HITAG = SRC_HITAG =

View file

@ -1200,7 +1200,7 @@ static void PacketReceived(PacketCommandNG *packet) {
break; break;
} }
case CMD_LF_HITAGS_SIMULATE: { // Simulate Hitag s tag, args = memory content 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; break;
} }
case CMD_LF_HITAGS_TEST_TRACES: { // Tests every challenge within the given file case CMD_LF_HITAGS_TEST_TRACES: { // Tests every challenge within the given file
@ -1218,7 +1218,7 @@ static void PacketReceived(PacketCommandNG *packet) {
break; break;
} }
case CMD_LF_HITAGS_UID: { case CMD_LF_HITAGS_UID: {
hts_read_uid(NULL, false, true); hts_read_uid(NULL, true, true);
break; break;
} }
case CMD_LF_HITAG2_WRITE: { case CMD_LF_HITAG2_WRITE: {

View file

@ -19,6 +19,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include "hitagS.h" #include "hitagS.h"
#include "hitag_common.h"
#include "proxmark3_arm.h" #include "proxmark3_arm.h"
#include "cmd.h" #include "cmd.h"
@ -33,12 +34,8 @@
#include "lfadc.h" #include "lfadc.h"
#include "crc.h" #include "crc.h"
#include "protocols.h" #include "protocols.h"
#include "hitag.h"
#include "appmain.h" // tearoff_hook() #include "appmain.h" // tearoff_hook()
#define CRC_PRESET 0xFF
#define CRC_POLYNOM 0x1D
static struct hitagS_tag tag = { static struct hitagS_tag tag = {
.data.pages = { .data.pages = {
// Plain mode: | Authentication mode: // Plain mode: | Authentication mode:
@ -58,13 +55,6 @@ static uint8_t page_to_be_written = 0;
static int block_data_left = 0; static int block_data_left = 0;
static bool enable_page_tearoff = false; 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 uint8_t protocol_mode = HITAGS_UID_REQ_ADV1;
static MOD m = AC2K; // used modulation static MOD m = AC2K; // used modulation
static uint32_t reader_selected_uid; 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 int sof_bits; // number of start-of-frame bits
static uint8_t pwdh0, pwdl0, pwdl1; // password bytes static uint8_t pwdh0, pwdl0, pwdl1; // password bytes
static uint8_t rnd[] = {0x85, 0x44, 0x12, 0x74}; // random number 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 //#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_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)))) #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) { static void update_tag_max_page(void) {
//check which memorysize this tag has //check which memorysize this tag has
if (tag.data.s.config.MEMT == 0x00) { 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 * 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"); DBG DbpString("SELECT");
if ((rx[0] & 0xf8) == HITAGS_SELECT && check_select(rx, BSWAP_32(tag.data.s.uid_le)) == 1) { if ((rx[0] & 0xf8) == HITAGS_SELECT && check_select(rx, BSWAP_32(tag.data.s.uid_le)) == 1) {
DBG DbpString("SELECT match"); DBG DbpString("SELECT match");
//if the right tag was selected //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) { if (protocol_mode != HITAGS_UID_REQ_STD) {
//add crc8 //add crc8
crc = CRC8Hitag1Bits(tx, 32);
*txlen += 8; *txlen += 8;
crc = CRC_PRESET;
for (int i = 0; i < 4; i++) {
calc_crc(&crc, tx[i], 8);
}
tx[4] = crc; tx[4] = crc;
} }
} }
@ -546,26 +225,31 @@ static void hts_handle_reader_command(uint8_t *rx, const size_t rxlen,
ht2_hitag2_byte(&state); ht2_hitag2_byte(&state);
} }
//send con2, pwdh0, pwdl0, pwdl1 encrypted as a response // store plaintext first
tx[0] = ht2_hitag2_byte(&state) ^ tag.data.pages[HITAGS_CONFIG_PADR][2]; tx[0] = tag.data.pages[HITAGS_CONFIG_PADR][2];
tx[1] = ht2_hitag2_byte(&state) ^ tag.data.s.config.pwdh0; tx[1] = tag.data.s.config.pwdh0;
tx[2] = ht2_hitag2_byte(&state) ^ tag.data.s.pwdl0; tx[2] = tag.data.s.pwdl0;
tx[3] = ht2_hitag2_byte(&state) ^ tag.data.s.pwdl1; tx[3] = tag.data.s.pwdl1;
if (protocol_mode != HITAGS_UID_REQ_STD) { if (protocol_mode != HITAGS_UID_REQ_STD) {
// add crc8 // add crc8
*txlen += 8; *txlen += 8;
crc = CRC_PRESET; crc = CRC8Hitag1Bits(tx, 32);
calc_crc(&crc, tag.data.pages[HITAGS_CONFIG_PADR][2], 8); tx[4] = crc;
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));
} }
// 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. * some readers do not allow to authenticate multiple times in a row with the same tag.
* use this to change the uid between authentications. * use this to change the uid between authentications.
if (rotate_uid % 2 == 0) { if (rotate_uid % 2 == 0) {
tag.data.s.uid_le = 0x44332211; tag.data.s.uid_le = 0x44332211;
} else { } 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) { if (protocol_mode != HITAGS_UID_REQ_STD) {
//add crc8 //add crc8
crc = CRC8Hitag1Bits(tx, 32);
*txlen += 8; *txlen += 8;
crc = CRC_PRESET;
for (int i = 0; i < 4; i++) {
calc_crc(&crc, tx[i], 8);
}
tx[4] = crc; 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) { if (protocol_mode != HITAGS_UID_REQ_STD) {
//add crc8 //add crc8
crc = CRC_PRESET; crc = CRC8Hitag1Bits(tx, *txlen);
for (int i = 0; i < *txlen / 8; i++) {
calc_crc(&crc, tx[i], 8);
}
*txlen += 8; *txlen += 8;
tx[16] = crc; 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 * 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) { void hts_simulate(bool tag_mem_supplied, int8_t threshold, const uint8_t *data, bool ledcontrol) {
StopTicks();
int overflow = 0; int overflow = 0;
uint8_t rx[HITAG_FRAME_LEN]; uint8_t rx[HITAG_FRAME_LEN] = {0};
size_t rxlen = 0; size_t rxlen = 0;
uint8_t tx[HITAG_FRAME_LEN]; uint8_t tx[HITAG_FRAME_LEN];
size_t txlen = 0; size_t txlen = 0;
// Reset the received frame, frame count and timing info
memset(rx, 0x00, sizeof(rx));
// free eventually allocated BigBuf memory // free eventually allocated BigBuf memory
BigBuf_free(); BigBuf_free();
BigBuf_Clear_ext(false); BigBuf_Clear_ext(false);
// Enable tracing
set_tracing(true);
DbpString("Starting Hitag S simulation"); DbpString("Starting Hitag S simulation");
tag.pstate = HT_READY; tag.pstate = HT_READY;
@ -738,67 +407,16 @@ void hts_simulate(bool tag_mem_supplied, const uint8_t *data, bool ledcontrol) {
); );
} }
hitag_setup_fpga(0, threshold, ledcontrol);
// Set up simulator mode, frequency divisor which will drive the FPGA
// and analog mux selection.
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); 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)) { while ((BUTTON_PRESS() == false) && (data_available() == false)) {
uint32_t start_time = 0; uint32_t start_time = 0;
WDT_HIT(); WDT_HIT();
// Receive frame, watch for at most T0*EOF periods // Receive commands from the reader
while (AT91C_BASE_TC1->TC_CV < T0 * HITAG_T_EOF) { hitag_tag_receive_frame(rx, sizeof(rx), &rxlen, &start_time, ledcontrol, &overflow);
// 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
}
}
}
// Check if frame was captured // Check if frame was captured
if (rxlen > 0) { if (rxlen > 0) {
@ -821,7 +439,7 @@ void hts_simulate(bool tag_mem_supplied, const uint8_t *data, bool ledcontrol) {
if (txlen > 0) { if (txlen > 0) {
// Transmit the tag frame // Transmit the tag frame
start_time = TIMESTAMP; 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); 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(); hitag_cleanup(ledcontrol);
set_tracing(false);
lf_finalize(ledcontrol);
// release allocated memory from BigBuff. // release allocated memory from BigBuff.
BigBuf_free(); BigBuf_free();
DbpString("Sim stopped"); 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) { 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; 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; start_time = TIMESTAMP;
// Transmit the reader frame // 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) { if (enable_page_tearoff && tearoff_hook() == PM3_ETEAROFF) {
return 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_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 // Check if frame was captured and store it
if (*rxlen > 0) { if (*rxlen > 0) {
@ -1033,22 +513,7 @@ static int hts_send_receive(const uint8_t *tx, size_t txlen, uint8_t *rx, size_t
Dbprintf("htS: sizeofrx... %zu", sizeofrx); Dbprintf("htS: sizeofrx... %zu", sizeofrx);
DbpString("htS: response_bit:"); DbpString("htS: response_bit:");
Dbhexdump(*rxlen, response_bit, false); 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); 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) { 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(); // Setup FPGA and initialize
hitag_setup_fpga(FPGA_LF_EDGE_DETECT_READER_FIELD, 127, ledcontrol);
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 standard 00110
// UID request Advanced 1100x // UID request Advanced 1100x
// UID request FAdvanced 11010 // UID request FAdvanced 11010
size_t txlen = 0;
size_t rxlen = 0;
protocol_mode = packet->mode; protocol_mode = packet->mode;
uint8_t cmd = protocol_mode; uint8_t cmd = protocol_mode;
txlen = concatbits(tx, txlen, &cmd, 0, 5, false); 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: read_end:
hts_stop_clock(); hitag_cleanup(ledcontrol);
set_tracing(false);
lf_finalize(ledcontrol);
reply_reason(CMD_LF_HITAGS_READ, status, reason, (uint8_t *)&card, sizeof(card)); 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: write_end:
hts_stop_clock(); hitag_cleanup(ledcontrol);
set_tracing(false);
lf_finalize(ledcontrol);
reply_reason(CMD_LF_HITAGS_WRITE, status, reason, NULL, 0); reply_reason(CMD_LF_HITAGS_WRITE, status, reason, NULL, 0);
} }
int hts_read_uid(uint32_t *uid, bool ledcontrol, bool send_answer) { 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; protocol_mode = HITAGS_UID_REQ_ADV1;
uint8_t cmd = protocol_mode; uint8_t cmd = protocol_mode;
@ -1511,10 +925,10 @@ int hts_read_uid(uint32_t *uid, bool ledcontrol, bool send_answer) {
status = PM3_ERFTRANS; status = PM3_ERFTRANS;
} }
hts_stop_clock(); hitag_cleanup(ledcontrol);
set_tracing(false); if (send_answer) {
lf_finalize(ledcontrol);
reply_ng(CMD_LF_HITAGS_UID, status, (uint8_t *)tag.data.pages, sizeof(tag.data.pages)); reply_ng(CMD_LF_HITAGS_UID, status, (uint8_t *)tag.data.pages, sizeof(tag.data.pages));
}
return status; return status;
} }
@ -1576,9 +990,7 @@ void hts_check_challenges(const uint8_t *data, uint32_t datalen, bool ledcontrol
SpinDelay(2); SpinDelay(2);
} }
hts_stop_clock(); hitag_cleanup(ledcontrol);
set_tracing(false);
lf_finalize(ledcontrol);
reply_ng(CMD_LF_HITAGS_TEST_TRACES, PM3_SUCCESS, NULL, 0); reply_ng(CMD_LF_HITAGS_TEST_TRACES, PM3_SUCCESS, NULL, 0);
return; return;
} }

View file

@ -24,7 +24,7 @@
#include "common.h" #include "common.h"
#include "hitag.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_read(const lf_hitag_data_t *payload, bool ledcontrol);
void hts_write_page(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); void hts_check_challenges(const uint8_t *data, uint32_t datalen, bool ledcontrol);

539
armsrc/hitag_common.c Normal file
View file

@ -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);
}

57
armsrc/hitag_common.h Normal file
View file

@ -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

View file

@ -793,9 +793,6 @@ void annotateHitag2(char *exp, size_t size, const uint8_t *cmd, uint8_t cmdsize,
free(binstr); 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) { static const char *identify_transponder_hitag2(uint32_t uid) {
switch (uid) { switch (uid) {

View file

@ -31,7 +31,6 @@ int ht2_read_uid(void);
int ht2_read_paxton(void); int ht2_read_paxton(void);
void annotateHitag1(char *exp, size_t size, const uint8_t *cmd, uint8_t cmdsize, bool is_response); 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 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); void annotateHitag2_init(void);
bool hitag2_get_plain(uint8_t *plain, uint8_t *plen); bool hitag2_get_plain(uint8_t *plain, uint8_t *plen);

View file

@ -36,6 +36,8 @@
static int CmdHelp(const char *Cmd); 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) { static const char *hts_get_type_str(uint32_t uid) {
// source 1: https://www.scorpio-lk.com/downloads/Tango/HITAG_Classification.pdf // source 1: https://www.scorpio-lk.com/downloads/Tango/HITAG_Classification.pdf
// IDE Mark // IDE Mark
@ -88,7 +90,7 @@ static bool hts_get_uid(uint32_t *uid) {
} }
if (resp.status != PM3_SUCCESS) { if (resp.status != PM3_SUCCESS) {
PrintAndLogEx(DEBUG, "DEBUG: Error - failed getting UID"); PrintAndLogEx(DEBUG, "DEBUG: Error - failed getting Hitag S UID");
return false; return false;
} }
@ -253,10 +255,38 @@ static void print_error(int8_t reason) {
break; break;
default: default:
// PM3_REASON_UNKNOWN // 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) { static int CmdLFHitagSRead(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "lf hitag hts rdbl", CLIParserInit(&ctx, "lf hitag hts rdbl",
@ -868,20 +898,23 @@ static int CmdLFHitagSSim(const char *Cmd) {
"Simulate Hitag S transponder\n" "Simulate Hitag S transponder\n"
"You need to `lf hitag hts eload` first", "You need to `lf hitag hts eload` first",
"lf hitag hts sim\n" "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[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_lit0("8", "82xx", "simulate 8268/8310"), arg_lit0("8", "82xx", "simulate 8268/8310"),
arg_int0("t", "threshold", "<dec>", "set edge detect threshold (def: 127)"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, true); CLIExecWithReturn(ctx, Cmd, argtable, true);
// bool use_82xx = arg_get_lit(ctx, 1); // not implemented yet // bool use_82xx = arg_get_lit(ctx, 1); // not implemented yet
int threshold = arg_get_int_def(ctx, 2, 127);
CLIParserFree(ctx); CLIParserFree(ctx);
clearCommandBuffer(); clearCommandBuffer();
SendCommandMIX(CMD_LF_HITAGS_SIMULATE, false, 0, 0, NULL, 0); SendCommandMIX(CMD_LF_HITAGS_SIMULATE, false, threshold, 0, NULL, 0);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -889,40 +922,6 @@ static int CmdLFHitagSList(const char *Cmd) {
return CmdTraceListAlias(Cmd, "lf hitag hts", "hitags"); 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[] = { static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"}, {"help", CmdHelp, AlwaysAvailable, "This help"},
{"list", CmdLFHitagSList, AlwaysAvailable, "List Hitag S trace history"}, {"list", CmdLFHitagSList, AlwaysAvailable, "List Hitag S trace history"},

View file

@ -22,9 +22,10 @@
#include "common.h" #include "common.h"
#include "hitag.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 CmdLFHitagS(const char *Cmd);
int read_hts_uid(void); int read_hts_uid(void);
void hitags_config_print(hitags_config_t config);
#endif //CMDLFHITAGS_H__ #endif //CMDLFHITAGS_H__

View file

@ -28,6 +28,7 @@
#include "comms.h" // for sending cmds to device. GetFromBigBuf #include "comms.h" // for sending cmds to device. GetFromBigBuf
#include "fileutils.h" // for saveFile #include "fileutils.h" // for saveFile
#include "cmdlfhitag.h" // annotate hitag #include "cmdlfhitag.h" // annotate hitag
#include "cmdlfhitaghts.h" // annotate hitags
#include "pm3_cmd.h" // tracelog_hdr_t #include "pm3_cmd.h" // tracelog_hdr_t
#include "cliparser.h" // args.. #include "cliparser.h" // args..

View file

@ -41,11 +41,18 @@
// need to see which limits these cards has // need to see which limits these cards has
#define HITAG1_MAX_BYTE_SIZE 64 #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 #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 { typedef enum {
HTSF_PLAIN, HTSF_PLAIN,
HTSF_82xx, HTSF_82xx,
@ -125,7 +132,7 @@ struct hitagS_tag {
int max_page; int max_page;
union { union {
uint8_t pages[64][4]; uint8_t pages[HITAGS_MAX_PAGES][HITAGS_PAGE_SIZE];
struct { struct {
// page 0 // page 0
uint32_t uid_le; uint32_t uid_le;
@ -147,7 +154,7 @@ typedef struct {
hitag_function cmd; hitag_function cmd;
uint8_t page; uint8_t page;
uint8_t page_count; uint8_t page_count;
uint8_t data[HITAGS_PAGE_SIZE]; uint8_t data[HITAG_BLOCK_SIZE];
uint8_t NrAr[HITAG_NRAR_SIZE]; uint8_t NrAr[HITAG_NRAR_SIZE];
// unaligned access to key as uint64_t will abort. // 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? // todo: Why does the compiler without -munaligned-access generate unaligned-access code in the first place?