mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-20 21:33:47 -07:00
add: support for all Hitag S response protocol mode
This commit is contained in:
parent
3f5266b19a
commit
911766b212
4 changed files with 217 additions and 221 deletions
|
@ -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)
|
||||||
|
|
260
armsrc/hitagS.c
260
armsrc/hitagS.c
|
@ -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 };
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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];
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue