add: support for all Hitag S response protocol mode

This commit is contained in:
douniwan5788 2024-10-23 21:43:02 +08:00
commit 911766b212
4 changed files with 217 additions and 221 deletions

View file

@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file.
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
## [unreleased][unreleased] ## [unreleased][unreleased]
- Added support for all Hitag S response protocol mode (@douniwan5788)
- Changed `hf mf sim` - add option to allow key b to be used even if readable (@doegox) - Changed `hf mf sim` - add option to allow key b to be used even if readable (@doegox)
- Changed `data num` - outputed binary strings are now properly zero padded (@iceman1001) - Changed `data num` - outputed binary strings are now properly zero padded (@iceman1001)
- Changed `hf iclass info` - now tries default keys and decode if legacy (@iceman1001) - Changed `hf iclass info` - now tries default keys and decode if legacy (@iceman1001)

View file

@ -65,6 +65,7 @@ typedef enum modulation {
MC8K MC8K
} MOD; } MOD;
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;
static int rotate_uid = 0; static int rotate_uid = 0;
@ -383,18 +384,17 @@ static void hts_init_clock(void) {
// Disable timer during configuration // Disable timer during configuration
hts_stop_clock(); hts_stop_clock();
// TC0: Capture mode, clock source = MCK/32 (TIMER_CLOCK3), no triggers // TC0: Capture mode, default timer source = MCK/32 (TIMER_CLOCK3), no triggers
AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK; AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK;
// TC1: Capture mode, clock source = MCK/32 (TIMER_CLOCK3), TIOA is external trigger, // TC1: Capture mode, default timer source = MCK/32 (TIMER_CLOCK3), TIOA is external trigger,
// external trigger falling edge, set RA on falling edge of TIOA. AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK // use MCK/32 (TIMER_CLOCK3)
AT91C_BASE_TC1->TC_CMR = | AT91C_TC_ABETRG // TIOA is used as an external trigger
AT91C_TC_CLKS_TIMER_DIV3_CLOCK | // MCK/32 (TIMER_CLOCK3) | AT91C_TC_ETRGEDG_FALLING // external trigger on falling edge
AT91C_TC_ETRGEDG_FALLING | // external trigger on falling edge | AT91C_TC_LDRA_RISING // load RA on on rising edge of TIOA
AT91C_TC_ABETRG | // TIOA is used as an external trigger | AT91C_TC_LDRB_FALLING; // load RB on on falling edge of TIOA
AT91C_TC_LDRA_FALLING; // load RA on on falling edge
// TC2: Capture mode, clock source = MCK/32 (TIMER_CLOCK3), no triggers // TC2: Capture mode, default timer source = MCK/32 (TIMER_CLOCK3), no triggers
AT91C_BASE_TC2->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK; AT91C_BASE_TC2->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK;
// Enable and reset counters // Enable and reset counters
@ -429,24 +429,35 @@ static int check_select(const uint8_t *rx, uint32_t uid) {
return 0; return 0;
} }
static void hts_set_frame_modulation(void) { static void hts_set_frame_modulation(uint8_t mode, bool ac_seq) {
switch (tag.mode) { switch (mode) {
case HT_STANDARD: { case HITAGS_UID_REQ_STD: {
sof_bits = 1; sof_bits = 1;
if (ac_seq)
m = AC2K;
else
m = MC4K; m = MC4K;
break; break;
} }
case HT_ADVANCED: { case HITAGS_UID_REQ_ADV1:
case HITAGS_UID_REQ_ADV2: {
if (ac_seq) {
sof_bits = 3;
m = AC2K;
} else {
sof_bits = 6; sof_bits = 6;
m = MC4K; m = MC4K;
}
break; break;
} }
case HT_FAST_ADVANCED: { case HITAGS_UID_REQ_FADV: {
if (ac_seq) {
sof_bits = 3;
m = AC4K;
} else {
sof_bits = 6; sof_bits = 6;
m = MC8K; m = MC8K;
break;
} }
default: {
break; break;
} }
} }
@ -463,7 +474,7 @@ static void hts_handle_reader_command(uint8_t *rx, const size_t rxlen,
// Reset the transmission frame length // Reset the transmission frame length
*txlen = 0; *txlen = 0;
// Reset the frame modulation // Reset the frame modulation
hts_set_frame_modulation(); hts_set_frame_modulation(protocol_mode, false);
// Try to find out which command was send by selecting on length (in bits) // Try to find out which command was send by selecting on length (in bits)
switch (rxlen) { switch (rxlen) {
@ -475,24 +486,15 @@ static void hts_handle_reader_command(uint8_t *rx, const size_t rxlen,
if (rx[0] == HITAGS_UID_REQ_STD) { if (rx[0] == HITAGS_UID_REQ_STD) {
DBG Dbprintf("HT_STANDARD"); DBG Dbprintf("HT_STANDARD");
tag.mode = HT_STANDARD; } else if (rx[0] == HITAGS_UID_REQ_ADV1 || rx[0] == HITAGS_UID_REQ_ADV2) {
sof_bits = 1;
m = AC2K;
}
if (rx[0] == HITAGS_UID_REQ_ADV1 || rx[0] == HITAGS_UID_REQ_ADV2) {
DBG Dbprintf("HT_ADVANCED"); DBG Dbprintf("HT_ADVANCED");
tag.mode = HT_ADVANCED; } else if (rx[0] == HITAGS_UID_REQ_FADV) {
sof_bits = 3; DBG Dbprintf("HT_FAST_ADVANCED");
m = AC2K;
} }
if (rx[0] == HITAGS_UID_REQ_FADV) { protocol_mode = rx[0];
DBG Dbprintf("HT_FAST_ADVANCED"); hts_set_frame_modulation(protocol_mode, true);
tag.mode = HT_FAST_ADVANCED;
sof_bits = 3;
m = AC4K;
}
//send uid as a response //send uid as a response
*txlen = 32; *txlen = 32;
memcpy(tx, tag.data.pages[HITAGS_UID_PADR], HITAGS_PAGE_SIZE); memcpy(tx, tag.data.pages[HITAGS_UID_PADR], HITAGS_PAGE_SIZE);
@ -515,7 +517,7 @@ static void hts_handle_reader_command(uint8_t *rx, const size_t rxlen,
tx[3] = 0xff; tx[3] = 0xff;
if (tag.mode != HT_STANDARD) { if (protocol_mode != HITAGS_UID_REQ_STD) {
//add crc8 //add crc8
*txlen += 8; *txlen += 8;
crc = CRC_PRESET; crc = CRC_PRESET;
@ -549,7 +551,7 @@ static void hts_handle_reader_command(uint8_t *rx, const size_t rxlen,
tx[2] = ht2_hitag2_byte(&state) ^ tag.data.s.pwdl0; tx[2] = ht2_hitag2_byte(&state) ^ tag.data.s.pwdl0;
tx[3] = ht2_hitag2_byte(&state) ^ tag.data.s.pwdl1; tx[3] = ht2_hitag2_byte(&state) ^ tag.data.s.pwdl1;
if (tag.mode != HT_STANDARD) { if (protocol_mode != HITAGS_UID_REQ_STD) {
//add crc8 //add crc8
*txlen += 8; *txlen += 8;
crc = CRC_PRESET; crc = CRC_PRESET;
@ -616,7 +618,7 @@ static void hts_handle_reader_command(uint8_t *rx, const size_t rxlen,
tx[3] = 0xFF; tx[3] = 0xFF;
} }
if (tag.mode != HT_STANDARD) { if (protocol_mode != HITAGS_UID_REQ_STD) {
//add crc8 //add crc8
*txlen += 8; *txlen += 8;
crc = CRC_PRESET; crc = CRC_PRESET;
@ -638,7 +640,7 @@ static void hts_handle_reader_command(uint8_t *rx, const size_t rxlen,
//send page,...,page+3 data //send page,...,page+3 data
memcpy(tx, tag.data.pages[page], *txlen / 8); memcpy(tx, tag.data.pages[page], *txlen / 8);
if (tag.mode != HT_STANDARD) { if (protocol_mode != HITAGS_UID_REQ_STD) {
//add crc8 //add crc8
crc = CRC_PRESET; crc = CRC_PRESET;
for (int i = 0; i < *txlen / 8; i++) { for (int i = 0; i < *txlen / 8; i++) {
@ -751,40 +753,7 @@ void hts_simulate(bool tag_mem_supplied, const uint8_t *data, bool ledcontrol) {
// Disable modulation at default, which means release resistance // Disable modulation at default, which means release resistance
LOW(GPIO_SSC_DOUT); LOW(GPIO_SSC_DOUT);
// Enable Peripheral Clock for hts_init_clock();
// 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,
// external trigger rising edge, load RA on rising edge of TIOA.
AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK
| AT91C_TC_ETRGEDG_RISING | AT91C_TC_ABETRG | AT91C_TC_LDRA_RISING;
// 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 counter
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
while (AT91C_BASE_TC0->TC_CV != 0); // wait until TC0 returned to zero
// reset timestamp
timestamp_high = 0;
if (ledcontrol) LED_D_ON(); if (ledcontrol) LED_D_ON();
@ -890,21 +859,29 @@ static void hts_receive_frame(uint8_t *rx, size_t sizeofrx, size_t *rxlen, uint3
bool bSkip = true; bool bSkip = true;
uint32_t errorCount = 0; uint32_t errorCount = 0;
bool bStarted = false; bool bStarted = false;
uint16_t next_edge_event = AT91C_TC_LDRBS;
int double_speed = (m == AC4K || m == MC8K) ? 2 : 1;
uint32_t ra_i = 0, h2 = 0, h3 = 0, h4 = 0; uint32_t rb_i = 0, h2 = 0, h3 = 0, h4 = 0;
uint8_t edges[160] = {0}; uint8_t edges[160] = {0};
// Dbprintf("TC0_CV:%i TC1_CV:%i TC1_RA:%i", AT91C_BASE_TC0->TC_CV, AT91C_BASE_TC1->TC_CV ,AT91C_BASE_TC1->TC_RA); // Dbprintf("TC0_CV:%i TC1_CV:%i TC1_RB:%i TIMESTAMP:%u", AT91C_BASE_TC0->TC_CV, AT91C_BASE_TC1->TC_CV,
// AT91C_BASE_TC1->TC_RB, TIMESTAMP);
// Receive tag frame, watch for at most T0*HITAG_T_PROG_MAX periods // Receive tag frame, watch for at most T0*HITAG_T_PROG_MAX periods
while (AT91C_BASE_TC0->TC_CV < (T0 * HITAG_T_PROG_MAX)) { while (AT91C_BASE_TC0->TC_CV < (T0 * HITAG_T_PROG_MAX)) {
// Check if falling edge in tag modulation is detected // Check if edge in tag modulation is detected
if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { 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 // Retrieve the new timing values
uint32_t ra = AT91C_BASE_TC1->TC_RA / T0; uint32_t rb = AT91C_BASE_TC1->TC_RB / T0;
edges[ra_i++] = ra; edges[rb_i++] = rb;
// Reset timer every frame, we have to capture the last edge for timing // Reset timer every frame, we have to capture the last edge for timing
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
@ -916,7 +893,7 @@ static void hts_receive_frame(uint8_t *rx, size_t sizeofrx, size_t *rxlen, uint3
// Capture tag frame (manchester decoding using only falling edges) // Capture tag frame (manchester decoding using only falling edges)
if (bStarted == false) { if (bStarted == false) {
if (ra >= HITAG_T_WAIT_RESP) { if (rb >= HITAG_T_WAIT_RESP) {
bStarted = true; bStarted = true;
// We always receive a 'one' first, which has the falling edge after a half period |-_| // We always receive a 'one' first, which has the falling edge after a half period |-_|
@ -926,8 +903,37 @@ static void hts_receive_frame(uint8_t *rx, size_t sizeofrx, size_t *rxlen, uint3
errorCount++; errorCount++;
} }
} else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) { } 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) // Manchester coding example |-_|_-|-_| (101)
rx[(*rxlen) / 8] |= 0 << (7 - ((*rxlen) % 8)); rx[(*rxlen) / 8] |= 0 << (7 - ((*rxlen) % 8));
(*rxlen)++; (*rxlen)++;
@ -935,8 +941,7 @@ static void hts_receive_frame(uint8_t *rx, size_t sizeofrx, size_t *rxlen, uint3
rx[(*rxlen) / 8] |= 1 << (7 - ((*rxlen) % 8)); rx[(*rxlen) / 8] |= 1 << (7 - ((*rxlen) % 8));
(*rxlen)++; (*rxlen)++;
h4++; h4++;
} else if (ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) { } else if (rb >= HITAG_T_TAG_CAPTURE_THREE_HALF / double_speed) {
// Manchester coding example |_-|...|_-|-_| (0...01) // Manchester coding example |_-|...|_-|-_| (0...01)
rx[(*rxlen) / 8] |= 0 << (7 - ((*rxlen) % 8)); rx[(*rxlen) / 8] |= 0 << (7 - ((*rxlen) % 8));
(*rxlen)++; (*rxlen)++;
@ -950,7 +955,7 @@ static void hts_receive_frame(uint8_t *rx, size_t sizeofrx, size_t *rxlen, uint3
lastbit = !lastbit; lastbit = !lastbit;
bSkip = !bSkip; bSkip = !bSkip;
h3++; h3++;
} else if (ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) { } else if (rb >= HITAG_T_TAG_CAPTURE_TWO_HALF / double_speed) {
// Manchester coding example |_-|_-| (00) or |-_|-_| (11) // Manchester coding example |_-|_-| (00) or |-_|-_| (11)
// bit is same as last bit // bit is same as last bit
rx[(*rxlen) / 8] |= lastbit << (7 - ((*rxlen) % 8)); rx[(*rxlen) / 8] |= lastbit << (7 - ((*rxlen) % 8));
@ -961,6 +966,8 @@ static void hts_receive_frame(uint8_t *rx, size_t sizeofrx, size_t *rxlen, uint3
errorCount++; errorCount++;
} }
} }
}
}
// if we saw over 100 weird values break it probably isn't hitag... // if we saw over 100 weird values break it probably isn't hitag...
if (errorCount > 100 || (*rxlen) / 8 >= sizeofrx) { if (errorCount > 100 || (*rxlen) / 8 >= sizeofrx) {
@ -979,10 +986,10 @@ static void hts_receive_frame(uint8_t *rx, size_t sizeofrx, size_t *rxlen, uint3
} }
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 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(ra_i, edges, false); 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 *prxbits, 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;
// Send and store the reader command // Send and store the reader command
@ -1010,74 +1017,42 @@ static int hts_send_receive(const uint8_t *tx, size_t txlen, uint8_t *rx, size_t
// Enable and reset external trigger in timer for capturing future frames // Enable and reset external trigger in timer for capturing future frames
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
size_t rxlen = 0; hts_set_frame_modulation(protocol_mode, ac_seq);
hts_receive_frame(rx, sizeofrx, &rxlen, &start_time, ledcontrol);
int k = 0; 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) {
DBG {
uint8_t response_bit[sizeofrx * 8]; uint8_t response_bit[sizeofrx * 8];
for (size_t i = 0; i < rxlen; i++) { for (size_t i = 0; i < *rxlen; i++) {
response_bit[i] = (rx[i / 8] >> (7 - (i % 8))) & 1; response_bit[i] = (rx[i / 8] >> (7 - (i % 8))) & 1;
} }
DBG Dbprintf("htS: rxlen...... %zu", rxlen); Dbprintf("htS: rxlen...... %zu", *rxlen);
DBG Dbprintf("htS: sizeofrx... %zu", sizeofrx); Dbprintf("htS: sizeofrx... %zu", sizeofrx);
DBG DbpString("htS: response_bit:"); DbpString("htS: response_bit:");
DBG Dbhexdump(rxlen, response_bit, false); Dbhexdump(*rxlen, response_bit, false);
Dbprintf("htS: skipping %d bit SOF", sof_bits);
memset(rx, 0x00, sizeofrx); if ((rx[0] >> (8 - sof_bits)) != ((1 << sof_bits) - 1)) {
DbpString("htS: Warning, not all bits of SOF are 1");
if (ac_seq) {
// Tag Response is AC encoded
// We used UID Request Advanced, meaning AC SEQ SOF is 111.
for (int i = 7; i < rxlen; i += 2) {
rx[k / 8] |= response_bit[i] << (7 - (k % 8));
k++;
if (k > 8 * sizeofrx) {
break;
} }
} }
// TODO: It's very confusing to reinterpreter the MC to AC; we should implement a more straightforward approach. // remove first sof_bits bits SOF
// add the lost bit zero, when AC64 last bit is zero for (size_t i = 0; i < (*rxlen + 8) / 8; i++) {
if (k % 8 == 7) { rx[i] <<= sof_bits;
k++; if (i + 1 < (*rxlen + 8) / 8) {
rx[i] |= (rx[i + 1] >> (8 - sof_bits));
}
} }
if (g_dbglevel >= DBG_EXTENDED) { *rxlen -= sof_bits;
DbpString("htS: ac sequence compress");
Dbhexdump(k / 8, rx, false);
}
} else { LogTraceBits(rx, *rxlen, start_time, TIMESTAMP, false);
if (g_dbglevel >= DBG_EXTENDED) {
DbpString("htS: skipping 6 bit header");
} }
// ignore first 6 bits: SOF (actually 1 or 6 depending on response protocol)
// or rather a header.
for (size_t i = 6; i < rxlen; i++) {
rx[k / 8] |= response_bit[i] << (7 - (k % 8));
k++;
if (k > 8 * sizeofrx) {
break;
}
}
}
LogTraceBits(rx, k, start_time, TIMESTAMP, false);
}
*prxbits = k;
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -1112,7 +1087,9 @@ static int hts_select_tag(const lf_hitag_data_t *packet, uint8_t *tx, size_t siz
// UID request FAdvanced 11010 // UID request FAdvanced 11010
size_t txlen = 0; size_t txlen = 0;
size_t rxlen = 0; size_t rxlen = 0;
uint8_t cmd = HITAGS_UID_REQ_ADV1;
protocol_mode = packet->mode;
uint8_t cmd = protocol_mode;
txlen = concatbits(tx, txlen, &cmd, 0, 5); txlen = concatbits(tx, txlen, &cmd, 0, 5);
hts_send_receive(tx, txlen, rx, sizeofrx, &rxlen, t_wait, ledcontrol, true); hts_send_receive(tx, txlen, rx, sizeofrx, &rxlen, t_wait, ledcontrol, true);
@ -1135,7 +1112,7 @@ static int hts_select_tag(const lf_hitag_data_t *packet, uint8_t *tx, size_t siz
hts_send_receive(tx, txlen, rx, sizeofrx, &rxlen, HITAG_T_WAIT_SC, ledcontrol, false); hts_send_receive(tx, txlen, rx, sizeofrx, &rxlen, HITAG_T_WAIT_SC, ledcontrol, false);
if (rxlen != 40) { if (rxlen != 32 + (protocol_mode == HITAGS_UID_REQ_STD ? 0 : 8)) {
DBG Dbprintf("Select UID failed! %i", rxlen); DBG Dbprintf("Select UID failed! %i", rxlen);
return -3; return -3;
} }
@ -1234,7 +1211,7 @@ static int hts_select_tag(const lf_hitag_data_t *packet, uint8_t *tx, size_t siz
hts_send_receive(tx, txlen, rx, sizeofrx, &rxlen, HITAG_T_WAIT_SC, ledcontrol, false); hts_send_receive(tx, txlen, rx, sizeofrx, &rxlen, HITAG_T_WAIT_SC, ledcontrol, false);
if (rxlen != 40) { if (rxlen != 32 + (protocol_mode == HITAGS_UID_REQ_STD ? 0 : 8)) {
DBG Dbprintf("Authenticate failed! " _RED_("%i"), rxlen); DBG Dbprintf("Authenticate failed! " _RED_("%i"), rxlen);
return -8; return -8;
} }
@ -1310,7 +1287,7 @@ void hts_read(const lf_hitag_data_t *payload, bool ledcontrol) {
hts_send_receive(tx, txlen, rx, ARRAYLEN(rx), &rxlen, HITAG_T_WAIT_SC, ledcontrol, false); hts_send_receive(tx, txlen, rx, ARRAYLEN(rx), &rxlen, HITAG_T_WAIT_SC, ledcontrol, false);
if (rxlen != 40) { if (rxlen != 32 + (protocol_mode == HITAGS_UID_REQ_STD ? 0 : 8)) {
DBG Dbprintf("Read page failed!"); DBG Dbprintf("Read page failed!");
card.pages_reason[page_index] = -4; card.pages_reason[page_index] = -4;
// status = PM3_ERFTRANS; // status = PM3_ERFTRANS;
@ -1505,7 +1482,8 @@ int hts_read_uid(uint32_t *uid, bool ledcontrol, bool send_answer) {
// UID request standard 00110 // UID request standard 00110
// UID request Advanced 1100x // UID request Advanced 1100x
// UID request FAdvanced 11010 // UID request FAdvanced 11010
uint8_t cmd = HITAGS_UID_REQ_ADV1; protocol_mode = HITAGS_UID_REQ_ADV1;
uint8_t cmd = protocol_mode;
size_t rxlen = 0; size_t rxlen = 0;
uint8_t rx[HITAG_FRAME_LEN] = { 0x00 }; uint8_t rx[HITAG_FRAME_LEN] = { 0x00 };

View file

@ -147,6 +147,13 @@ static int process_hitags_common_args(CLIParserContext *ctx, lf_hitag_data_t *co
return PM3_EINVARG; return PM3_EINVARG;
} }
uint8_t mode = arg_get_int_def(ctx, 5, 3);
if (mode > 3) {
PrintAndLogEx(WARNING, "Wrong response protocol mode, expected 0, 1, 2 or 3, got %d", mode);
return PM3_EINVARG;
}
// complete options // complete options
switch (key_len) { switch (key_len) {
case HITAG_PASSWORD_SIZE: case HITAG_PASSWORD_SIZE:
@ -194,6 +201,21 @@ static int process_hitags_common_args(CLIParserContext *ctx, lf_hitag_data_t *co
PrintAndLogEx(INFO, "Authenticating to " _YELLOW_("Hitag S") " in Crypto mode"); PrintAndLogEx(INFO, "Authenticating to " _YELLOW_("Hitag S") " in Crypto mode");
} }
switch (mode) {
case 0:
packet->mode = HITAGS_UID_REQ_STD;
break;
case 1:
packet->mode = HITAGS_UID_REQ_ADV1;
break;
case 2:
packet->mode = HITAGS_UID_REQ_ADV2;
break;
default:
packet->mode = HITAGS_UID_REQ_FADV;
break;
}
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -254,8 +276,9 @@ static int CmdLFHitagSRead(const char *Cmd) {
arg_str0(NULL, "nrar", "<hex>", "nonce / answer writer, 8 hex bytes"), arg_str0(NULL, "nrar", "<hex>", "nonce / answer writer, 8 hex bytes"),
arg_lit0(NULL, "crypto", "crypto mode"), arg_lit0(NULL, "crypto", "crypto mode"),
arg_str0("k", "key", "<hex>", "pwd or key, 4 or 6 hex bytes"), arg_str0("k", "key", "<hex>", "pwd or key, 4 or 6 hex bytes"),
arg_int0("m", "mode", "<dec>", "response protocol mode. 0 (Standard 00110), 1 (Advanced 11000), 2 (Advanced 11001), 3 (Fast Advanced 11010) (def: 3)"),
arg_int0("p", "page", "<dec>", "page address to read from"), arg_int0("p", "page", "<dec>", "page address to read from"),
arg_int0("c", "count", "<dec>", "how many pages to read. '0' reads all pages up to the end page (default: 1)"), arg_int0("c", "count", "<dec>", "how many pages to read. '0' reads all pages up to the end page (def: 1)"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, true); CLIExecWithReturn(ctx, Cmd, argtable, true);
@ -264,14 +287,14 @@ static int CmdLFHitagSRead(const char *Cmd) {
if (process_hitags_common_args(ctx, &packet) < 0) return PM3_EINVARG; if (process_hitags_common_args(ctx, &packet) < 0) return PM3_EINVARG;
uint32_t page = arg_get_int_def(ctx, 5, 0); uint32_t page = arg_get_int_def(ctx, 6, 0);
if (page > 255) { if (page > 255) {
PrintAndLogEx(WARNING, "Page address Invalid."); PrintAndLogEx(WARNING, "Page address Invalid.");
return PM3_EINVARG; return PM3_EINVARG;
} }
uint32_t count = arg_get_int_def(ctx, 6, 1); uint32_t count = arg_get_int_def(ctx, 7, 1);
if (count > HITAGS_MAX_PAGES) { if (count > HITAGS_MAX_PAGES) {
PrintAndLogEx(WARNING, "No more than 64 pages can be read at once."); PrintAndLogEx(WARNING, "No more than 64 pages can be read at once.");
@ -438,6 +461,7 @@ static int CmdLFHitagSWrite(const char *Cmd) {
arg_str0(NULL, "nrar", "<hex>", "nonce / answer writer, 8 hex bytes"), arg_str0(NULL, "nrar", "<hex>", "nonce / answer writer, 8 hex bytes"),
arg_lit0(NULL, "crypto", "crypto mode"), arg_lit0(NULL, "crypto", "crypto mode"),
arg_str0("k", "key", "<hex>", "pwd or key, 4 or 6 hex bytes"), arg_str0("k", "key", "<hex>", "pwd or key, 4 or 6 hex bytes"),
arg_int0("m", "mode", "<dec>", "response protocol mode. 0 (Standard 00110), 1 (Advanced 11000), 2 (Advanced 11001), 3 (Fast Advanced 11010) (def: 3)"),
arg_int1("p", "page", "<dec>", "page address to write to"), arg_int1("p", "page", "<dec>", "page address to write to"),
arg_str1("d", "data", "<hex>", "data, 4 hex bytes"), arg_str1("d", "data", "<hex>", "data, 4 hex bytes"),
arg_param_end arg_param_end
@ -448,12 +472,12 @@ static int CmdLFHitagSWrite(const char *Cmd) {
if (process_hitags_common_args(ctx, &packet) < 0) return PM3_EINVARG; if (process_hitags_common_args(ctx, &packet) < 0) return PM3_EINVARG;
int page = arg_get_int_def(ctx, 5, 0); int page = arg_get_int_def(ctx, 6, 0);
uint8_t data[HITAGS_PAGE_SIZE]; uint8_t data[HITAGS_PAGE_SIZE];
int data_len = 0; int data_len = 0;
int res = CLIParamHexToBuf(arg_get_str(ctx, 6), data, HITAGS_PAGE_SIZE, &data_len); int res = CLIParamHexToBuf(arg_get_str(ctx, 7), data, HITAGS_PAGE_SIZE, &data_len);
if (res != 0) { if (res != 0) {
CLIParserFree(ctx); CLIParserFree(ctx);
return PM3_EINVARG; return PM3_EINVARG;
@ -538,7 +562,7 @@ static int CmdLFHitagSSim(const char *Cmd) {
CLIParserFree(ctx); CLIParserFree(ctx);
clearCommandBuffer(); clearCommandBuffer();
SendCommandNG(CMD_LF_HITAGS_SIMULATE, NULL, 0); SendCommandMIX(CMD_LF_HITAGS_SIMULATE, false, 0, 0, NULL, 0);
return PM3_SUCCESS; return PM3_SUCCESS;
} }

View file

@ -65,30 +65,6 @@ typedef enum {
HT2_LAST_CMD = HT2F_UID_ONLY, HT2_LAST_CMD = HT2F_UID_ONLY,
} PACKED hitag_function; } PACKED hitag_function;
typedef struct {
hitag_function cmd;
uint8_t page;
uint8_t page_count;
uint8_t data[HITAGS_PAGE_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?
uint8_t key[HITAG_CRYPTOKEY_SIZE] __attribute__((aligned(4)));
uint8_t pwd[HITAG_PASSWORD_SIZE];
// Hitag 1 section.
// will reuse pwd or key field.
uint8_t key_no;
uint8_t logdata_0[4];
uint8_t logdata_1[4];
uint8_t nonce[4];
} PACKED lf_hitag_data_t;
typedef struct {
int status;
uint8_t data[256];
} PACKED lf_hitag_crack_response_t;
//--------------------------------------------------------- //---------------------------------------------------------
// Hitag S // Hitag S
//--------------------------------------------------------- //---------------------------------------------------------
@ -111,15 +87,6 @@ typedef enum TAG_STATE {
HT_WRITING_BLOCK_DATA HT_WRITING_BLOCK_DATA
} TSATE; } TSATE;
//number of start-of-frame bits
typedef enum SOF_TYPE {
HT_STANDARD = 0,
HT_ADVANCED,
HT_FAST_ADVANCED,
HT_ONE,
HT_NO_BITS
} stype;
typedef struct { typedef struct {
// con0 // con0
uint8_t MEMT : 2; uint8_t MEMT : 2;
@ -156,7 +123,6 @@ struct hitagS_tag {
TSATE tstate; // tag-state TSATE tstate; // tag-state
int max_page; int max_page;
stype mode;
union { union {
uint8_t pages[64][4]; uint8_t pages[64][4];
@ -177,6 +143,33 @@ struct hitagS_tag {
} PACKED; } PACKED;
typedef struct {
hitag_function cmd;
uint8_t page;
uint8_t page_count;
uint8_t data[HITAGS_PAGE_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?
uint8_t key[HITAG_CRYPTOKEY_SIZE] __attribute__((aligned(4)));
uint8_t pwd[HITAG_PASSWORD_SIZE];
// Hitag 1 section.
// will reuse pwd or key field.
uint8_t key_no;
uint8_t logdata_0[4];
uint8_t logdata_1[4];
uint8_t nonce[4];
//Hitag s section
uint8_t mode;
} PACKED lf_hitag_data_t;
typedef struct {
int status;
uint8_t data[256];
} PACKED lf_hitag_crack_response_t;
typedef struct { typedef struct {
union { union {
uint8_t asBytes[HITAGS_PAGE_SIZE]; uint8_t asBytes[HITAGS_PAGE_SIZE];