mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-20 13:23:51 -07:00
Merge branch 'master' into master
Signed-off-by: Iceman <iceman@iuse.se>
This commit is contained in:
commit
49ac2339b5
10 changed files with 344 additions and 248 deletions
|
@ -6,6 +6,8 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
|
|||
- Changed `hf iclass info` - now checks for cards silicon version (@antiklesys)
|
||||
- Changed `hf iclass legrec` - updated script implementation to ensure functionality (@antiklesys)
|
||||
- Added recovered iclass custom key to dictionary (@antiklesys)
|
||||
- Added support for all Hitag S response protocol mode (@douniwan5788)
|
||||
- Fixed 'hf_young.c' - flags declaration was missing a semicolon (@jakkpotts)
|
||||
- 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 `hf iclass info` - now tries default keys and decode if legacy (@iceman1001)
|
||||
|
|
|
@ -236,7 +236,7 @@ void RunMod(void) {
|
|||
int button_pressed = BUTTON_HELD(1000);
|
||||
if (button_pressed == BUTTON_NO_CLICK) { // No button action, proceed with sim
|
||||
|
||||
uint16_t flags = 0
|
||||
uint16_t flags = 0;
|
||||
FLAG_SET_UID_IN_DATA(flags, 4);
|
||||
uint8_t data[PM3_CMD_DATA_SIZE] = {0}; // in case there is a read command received we shouldn't break
|
||||
|
||||
|
|
358
armsrc/hitagS.c
358
armsrc/hitagS.c
|
@ -65,6 +65,7 @@ typedef enum modulation {
|
|||
MC8K
|
||||
} MOD;
|
||||
|
||||
static uint8_t protocol_mode = HITAGS_UID_REQ_ADV1;
|
||||
static MOD m = AC2K; // used modulation
|
||||
static uint32_t reader_selected_uid;
|
||||
static int rotate_uid = 0;
|
||||
|
@ -383,18 +384,17 @@ static void hts_init_clock(void) {
|
|||
// Disable timer during configuration
|
||||
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;
|
||||
|
||||
// TC1: Capture mode, clock 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 | // MCK/32 (TIMER_CLOCK3)
|
||||
AT91C_TC_ETRGEDG_FALLING | // external trigger on falling edge
|
||||
AT91C_TC_ABETRG | // TIOA is used as an external trigger
|
||||
AT91C_TC_LDRA_FALLING; // load RA on on falling edge
|
||||
// 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, 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;
|
||||
|
||||
// Enable and reset counters
|
||||
|
@ -429,24 +429,35 @@ static int check_select(const uint8_t *rx, uint32_t uid) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void hts_set_frame_modulation(void) {
|
||||
switch (tag.mode) {
|
||||
case HT_STANDARD: {
|
||||
static void hts_set_frame_modulation(uint8_t mode, bool ac_seq) {
|
||||
switch (mode) {
|
||||
case HITAGS_UID_REQ_STD: {
|
||||
sof_bits = 1;
|
||||
m = MC4K;
|
||||
if (ac_seq)
|
||||
m = AC2K;
|
||||
else
|
||||
m = MC4K;
|
||||
break;
|
||||
}
|
||||
case HT_ADVANCED: {
|
||||
sof_bits = 6;
|
||||
m = MC4K;
|
||||
case HITAGS_UID_REQ_ADV1:
|
||||
case HITAGS_UID_REQ_ADV2: {
|
||||
if (ac_seq) {
|
||||
sof_bits = 3;
|
||||
m = AC2K;
|
||||
} else {
|
||||
sof_bits = 6;
|
||||
m = MC4K;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case HT_FAST_ADVANCED: {
|
||||
sof_bits = 6;
|
||||
m = MC8K;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
case HITAGS_UID_REQ_FADV: {
|
||||
if (ac_seq) {
|
||||
sof_bits = 3;
|
||||
m = AC4K;
|
||||
} else {
|
||||
sof_bits = 6;
|
||||
m = MC8K;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -463,7 +474,7 @@ static void hts_handle_reader_command(uint8_t *rx, const size_t rxlen,
|
|||
// Reset the transmission frame length
|
||||
*txlen = 0;
|
||||
// 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)
|
||||
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) {
|
||||
DBG Dbprintf("HT_STANDARD");
|
||||
tag.mode = HT_STANDARD;
|
||||
sof_bits = 1;
|
||||
m = AC2K;
|
||||
}
|
||||
|
||||
if (rx[0] == HITAGS_UID_REQ_ADV1 || rx[0] == HITAGS_UID_REQ_ADV2) {
|
||||
} else if (rx[0] == HITAGS_UID_REQ_ADV1 || rx[0] == HITAGS_UID_REQ_ADV2) {
|
||||
DBG Dbprintf("HT_ADVANCED");
|
||||
tag.mode = HT_ADVANCED;
|
||||
sof_bits = 3;
|
||||
m = AC2K;
|
||||
} else if (rx[0] == HITAGS_UID_REQ_FADV) {
|
||||
DBG Dbprintf("HT_FAST_ADVANCED");
|
||||
}
|
||||
|
||||
if (rx[0] == HITAGS_UID_REQ_FADV) {
|
||||
DBG Dbprintf("HT_FAST_ADVANCED");
|
||||
tag.mode = HT_FAST_ADVANCED;
|
||||
sof_bits = 3;
|
||||
m = AC4K;
|
||||
}
|
||||
protocol_mode = rx[0];
|
||||
hts_set_frame_modulation(protocol_mode, true);
|
||||
|
||||
//send uid as a response
|
||||
*txlen = 32;
|
||||
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;
|
||||
|
||||
if (tag.mode != HT_STANDARD) {
|
||||
if (protocol_mode != HITAGS_UID_REQ_STD) {
|
||||
//add crc8
|
||||
*txlen += 8;
|
||||
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[3] = ht2_hitag2_byte(&state) ^ tag.data.s.pwdl1;
|
||||
|
||||
if (tag.mode != HT_STANDARD) {
|
||||
if (protocol_mode != HITAGS_UID_REQ_STD) {
|
||||
//add crc8
|
||||
*txlen += 8;
|
||||
crc = CRC_PRESET;
|
||||
|
@ -616,7 +618,7 @@ static void hts_handle_reader_command(uint8_t *rx, const size_t rxlen,
|
|||
tx[3] = 0xFF;
|
||||
}
|
||||
|
||||
if (tag.mode != HT_STANDARD) {
|
||||
if (protocol_mode != HITAGS_UID_REQ_STD) {
|
||||
//add crc8
|
||||
*txlen += 8;
|
||||
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
|
||||
memcpy(tx, tag.data.pages[page], *txlen / 8);
|
||||
|
||||
if (tag.mode != HT_STANDARD) {
|
||||
if (protocol_mode != HITAGS_UID_REQ_STD) {
|
||||
//add crc8
|
||||
crc = CRC_PRESET;
|
||||
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
|
||||
LOW(GPIO_SSC_DOUT);
|
||||
|
||||
// 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,
|
||||
// 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;
|
||||
hts_init_clock();
|
||||
|
||||
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;
|
||||
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 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};
|
||||
|
||||
// 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
|
||||
while (AT91C_BASE_TC0->TC_CV < (T0 * HITAG_T_PROG_MAX)) {
|
||||
|
||||
// Check if falling edge in tag modulation is detected
|
||||
if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) {
|
||||
// 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 ra = AT91C_BASE_TC1->TC_RA / T0;
|
||||
edges[ra_i++] = ra;
|
||||
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;
|
||||
|
||||
|
@ -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)
|
||||
if (bStarted == false) {
|
||||
|
||||
if (ra >= HITAG_T_WAIT_RESP) {
|
||||
if (rb >= HITAG_T_WAIT_RESP) {
|
||||
bStarted = true;
|
||||
|
||||
// We always receive a 'one' first, which has the falling edge after a half period |-_|
|
||||
|
@ -926,39 +903,69 @@ static void hts_receive_frame(uint8_t *rx, size_t sizeofrx, size_t *rxlen, uint3
|
|||
errorCount++;
|
||||
}
|
||||
|
||||
} else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) {
|
||||
|
||||
// Manchester coding example |-_|_-|-_| (101)
|
||||
rx[(*rxlen) / 8] |= 0 << (7 - ((*rxlen) % 8));
|
||||
(*rxlen)++;
|
||||
|
||||
rx[(*rxlen) / 8] |= 1 << (7 - ((*rxlen) % 8));
|
||||
(*rxlen)++;
|
||||
h4++;
|
||||
} else if (ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) {
|
||||
|
||||
// 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 (ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) {
|
||||
// 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++;
|
||||
// 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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 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;
|
||||
|
||||
// Send and store the reader command
|
||||
|
@ -1010,73 +1017,41 @@ 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
|
||||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
|
||||
|
||||
size_t rxlen = 0;
|
||||
hts_receive_frame(rx, sizeofrx, &rxlen, &start_time, ledcontrol);
|
||||
int k = 0;
|
||||
hts_set_frame_modulation(protocol_mode, ac_seq);
|
||||
|
||||
hts_receive_frame(rx, sizeofrx, rxlen, &start_time, ledcontrol);
|
||||
|
||||
// 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++) {
|
||||
response_bit[i] = (rx[i / 8] >> (7 - (i % 8))) & 1;
|
||||
}
|
||||
|
||||
DBG Dbprintf("htS: rxlen...... %zu", rxlen);
|
||||
DBG Dbprintf("htS: sizeofrx... %zu", sizeofrx);
|
||||
DBG DbpString("htS: response_bit:");
|
||||
DBG Dbhexdump(rxlen, response_bit, false);
|
||||
|
||||
memset(rx, 0x00, sizeofrx);
|
||||
|
||||
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;
|
||||
}
|
||||
for (size_t i = 0; i < *rxlen; i++) {
|
||||
response_bit[i] = (rx[i / 8] >> (7 - (i % 8))) & 1;
|
||||
}
|
||||
|
||||
// TODO: It's very confusing to reinterpreter the MC to AC; we should implement a more straightforward approach.
|
||||
// add the lost bit zero, when AC64 last bit is zero
|
||||
if (k % 8 == 7) {
|
||||
k++;
|
||||
}
|
||||
|
||||
if (g_dbglevel >= DBG_EXTENDED) {
|
||||
DbpString("htS: ac sequence compress");
|
||||
Dbhexdump(k / 8, rx, false);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
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;
|
||||
}
|
||||
Dbprintf("htS: rxlen...... %zu", *rxlen);
|
||||
Dbprintf("htS: sizeofrx... %zu", sizeofrx);
|
||||
DbpString("htS: response_bit:");
|
||||
Dbhexdump(*rxlen, response_bit, false);
|
||||
Dbprintf("htS: skipping %d bit SOF", sof_bits);
|
||||
if ((rx[0] >> (8 - sof_bits)) != ((1 << sof_bits) - 1)) {
|
||||
DbpString("htS: Warning, not all bits of SOF are 1");
|
||||
}
|
||||
}
|
||||
LogTraceBits(rx, k, start_time, TIMESTAMP, false);
|
||||
|
||||
// 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);
|
||||
}
|
||||
*prxbits = k;
|
||||
|
||||
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
|
||||
size_t txlen = 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);
|
||||
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);
|
||||
|
||||
if (rxlen != 40) {
|
||||
if (rxlen != 32 + (protocol_mode == HITAGS_UID_REQ_STD ? 0 : 8)) {
|
||||
DBG Dbprintf("Select UID failed! %i", rxlen);
|
||||
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);
|
||||
|
||||
if (rxlen != 40) {
|
||||
if (rxlen != 32 + (protocol_mode == HITAGS_UID_REQ_STD ? 0 : 8)) {
|
||||
DBG Dbprintf("Authenticate failed! " _RED_("%i"), rxlen);
|
||||
return -8;
|
||||
}
|
||||
|
@ -1295,6 +1272,12 @@ void hts_read(const lf_hitag_data_t *payload, bool ledcontrol) {
|
|||
|
||||
while ((BUTTON_PRESS() == false) && (data_available() == false)) {
|
||||
|
||||
if (payload->page_count == 0) {
|
||||
if (page_addr > tag.max_page) break;
|
||||
} else if (page_addr > 255 || page_addr >= payload->page + payload->page_count) {
|
||||
break;
|
||||
}
|
||||
|
||||
WDT_HIT();
|
||||
|
||||
size_t rxlen = 0;
|
||||
|
@ -1310,9 +1293,9 @@ 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);
|
||||
|
||||
if (rxlen != 40) {
|
||||
if (rxlen != 32 + (protocol_mode == HITAGS_UID_REQ_STD ? 0 : 8)) {
|
||||
DBG Dbprintf("Read page failed!");
|
||||
card.pages_reason[page_index] = -4;
|
||||
card.pages_reason[page_index] = -11;
|
||||
// status = PM3_ERFTRANS;
|
||||
// goto read_end;
|
||||
page_addr++;
|
||||
|
@ -1362,18 +1345,12 @@ void hts_read(const lf_hitag_data_t *payload, bool ledcontrol) {
|
|||
//if the authentication is done with a challenge the key and password are unknown
|
||||
DBG Dbprintf("Page[ 2]: __ __ __ __");
|
||||
DBG Dbprintf("Page[ 3]: __ __ __ __");
|
||||
card.pages_reason[page_index++] = -4;
|
||||
card.pages_reason[page_index++] = -4;
|
||||
card.pages_reason[page_index++] = -11;
|
||||
card.pages_reason[page_index++] = -11;
|
||||
}
|
||||
// since page 2+3 are not accessible when LKP == 1 and AUT == 1 fastforward to next readable page
|
||||
page_addr = 4;
|
||||
}
|
||||
|
||||
if (payload->page_count == 0) {
|
||||
if (page_addr > tag.max_page) break;
|
||||
} else if (page_addr > 255 || page_addr >= payload->page + payload->page_count) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
read_end:
|
||||
|
@ -1505,7 +1482,8 @@ int hts_read_uid(uint32_t *uid, bool ledcontrol, bool send_answer) {
|
|||
// UID request standard 00110
|
||||
// UID request Advanced 1100x
|
||||
// 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;
|
||||
uint8_t rx[HITAG_FRAME_LEN] = { 0x00 };
|
||||
|
|
|
@ -1534,7 +1534,7 @@ void MifareStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo,
|
|||
continue;
|
||||
};
|
||||
|
||||
if (mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_NESTED, NULL, NULL)) {
|
||||
if (mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_NESTED, &nt2, NULL)) {
|
||||
continue;
|
||||
};
|
||||
|
||||
|
@ -1544,6 +1544,12 @@ void MifareStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo,
|
|||
};
|
||||
|
||||
nt3 = bytes_to_num(receivedAnswer, 4);
|
||||
// fix for cards with distance 0
|
||||
if (nt1 == nt2) {
|
||||
target_nt[0] = nt1;
|
||||
target_nt[1] = nt1;
|
||||
target_ks[0] = nt3 ^ target_nt[0];
|
||||
}
|
||||
target_ks[1] = nt3 ^ target_nt[1];
|
||||
|
||||
isOK = PM3_SUCCESS;
|
||||
|
|
|
@ -191,7 +191,7 @@ local function read_config()
|
|||
if magicconfig == nil then lib14a.disconnect(); return nil, "can't read configuration, "..err_lock end
|
||||
if #magicconfig ~= 64 and #magicconfig ~= 68 then lib14a.disconnect(); return nil, "partial read of configuration, "..err_lock end
|
||||
if gtumode == '00' then gtustr = 'Pre-write/Shadow Mode'
|
||||
elseif gtumode == '01' then gtustr = 'Restore Mode'
|
||||
elseif gtumode == '01' or gtumode == '04' then gtustr = 'Restore Mode'
|
||||
elseif gtumode == '02' then gtustr = 'Disabled'
|
||||
elseif gtumode == '03' then gtustr = 'Disabled, high speed R/W mode for Ultralight'
|
||||
end
|
||||
|
@ -553,7 +553,7 @@ local function write_gtu(gtu)
|
|||
if gtu == '00' then
|
||||
print('Enabling GTU Pre-Write')
|
||||
send('CF'.._key..'32'..gtu)
|
||||
elseif gtu == '01' then
|
||||
elseif gtu == '01' or gtu == '04' then
|
||||
print('Enabling GTU Restore Mode')
|
||||
send('CF'.._key..'32'..gtu)
|
||||
elseif gtu == '02' then
|
||||
|
|
|
@ -76,6 +76,10 @@ parser.add_argument('-x', '--init-check', action='store_true', help='Run an init
|
|||
parser.add_argument('-y', '--final-check', action='store_true', help='Run a final fchk with the found keys')
|
||||
parser.add_argument('-k', '--keep', action='store_true', help='Keep generated dictionaries after processing')
|
||||
parser.add_argument('-d', '--debug', action='store_true', help='Enable debug mode')
|
||||
parser.add_argument('-s', '--supply-chain', action='store_true', help='Enable supply-chain mode. Look for hf-mf-XXXXXXXX-default_nonces.json')
|
||||
# Such json can be produced from the json saved by
|
||||
# "hf mf isen --collect_fm11rf08s --key A396EFA4E24F" on a wiped card, then processed with
|
||||
# jq '{Created: .Created, FileType: "fm11rf08s_default_nonces", nt: .nt | del(.["32"]) | map_values(.a)}'
|
||||
args = parser.parse_args()
|
||||
|
||||
start_time = time.time()
|
||||
|
@ -191,6 +195,22 @@ if os.path.isfile(DICT_DEF_PATH):
|
|||
else:
|
||||
print(f"Warning, {DICT_DEF} not found.")
|
||||
|
||||
dict_dnwd = None
|
||||
def_nt = ["" for _ in range(NUM_SECTORS)]
|
||||
if args.supply_chain:
|
||||
try:
|
||||
default_nonces = f'{save_path}hf-mf-{uid:04X}-default_nonces.json'
|
||||
with open(default_nonces, 'r') as file:
|
||||
# Load and parse the JSON data
|
||||
dict_dnwd = json.load(file)
|
||||
for sec in range(NUM_SECTORS):
|
||||
def_nt[sec] = dict_dnwd["nt"][f"{sec}"].lower()
|
||||
print(f"Loaded default nonces from {default_nonces}.")
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
except json.decoder.JSONDecodeError:
|
||||
print(f"Error parsing {default_nonces}, skipping.")
|
||||
|
||||
print("Running staticnested_1nt & 2x1nt when doable...")
|
||||
keys = [[set(), set()] for _ in range(NUM_SECTORS + NUM_EXTRA_SECTORS)]
|
||||
all_keys = set()
|
||||
|
@ -225,9 +245,21 @@ for sec in range(NUM_SECTORS + NUM_EXTRA_SECTORS):
|
|||
keys[sec][key_type] = keys_set.copy()
|
||||
duplicates.update(all_keys.intersection(keys_set))
|
||||
all_keys.update(keys_set)
|
||||
# Prioritize default keys
|
||||
keys_def_set = DEFAULT_KEYS.intersection(keys_set)
|
||||
keys_set.difference_update(DEFAULT_KEYS)
|
||||
if dict_dnwd is not None and sec < NUM_SECTORS:
|
||||
# Prioritize keys from supply-chain attack
|
||||
cmd = [tools["staticnested_2x1nt1key"], def_nt[sec], "FFFFFFFFFFFF", f"keys_{uid:08x}_{real_sec:02}_{nt[sec][key_type]}_filtered.dic"]
|
||||
if args.debug:
|
||||
print(' '.join(cmd))
|
||||
result = subprocess.run(cmd, capture_output=True, text=True).stdout
|
||||
keys_def_set = set()
|
||||
for line in result.split('\n'):
|
||||
if "MATCH:" in line:
|
||||
keys_def_set.add(line[12:])
|
||||
keys_set.difference_update(keys_def_set)
|
||||
else:
|
||||
# Prioritize default keys
|
||||
keys_def_set = DEFAULT_KEYS.intersection(keys_set)
|
||||
keys_set.difference_update(keys_def_set)
|
||||
# Prioritize sector 32 keyB starting with 0000
|
||||
if real_sec == 32:
|
||||
keyb32cands = set(x for x in keys_set if x.startswith("0000"))
|
||||
|
@ -257,9 +289,21 @@ for sec in range(NUM_SECTORS + NUM_EXTRA_SECTORS):
|
|||
keys[sec][key_type] = keys_set.copy()
|
||||
duplicates.update(all_keys.intersection(keys_set))
|
||||
all_keys.update(keys_set)
|
||||
# Prioritize default keys
|
||||
keys_def_set = DEFAULT_KEYS.intersection(keys_set)
|
||||
keys_set.difference_update(DEFAULT_KEYS)
|
||||
if dict_dnwd is not None and sec < NUM_SECTORS:
|
||||
# Prioritize keys from supply-chain attack
|
||||
cmd = [tools["staticnested_2x1nt1key"], def_nt[sec], "FFFFFFFFFFFF", f"keys_{uid:08x}_{real_sec:02}_{nt[sec][key_type]}.dic"]
|
||||
if args.debug:
|
||||
print(' '.join(cmd))
|
||||
result = subprocess.run(cmd, capture_output=True, text=True).stdout
|
||||
keys_def_set = set()
|
||||
for line in result.split('\n'):
|
||||
if "MATCH:" in line:
|
||||
keys_def_set.add(line[12:])
|
||||
keys_set.difference_update(keys_def_set)
|
||||
else:
|
||||
# Prioritize default keys
|
||||
keys_def_set = DEFAULT_KEYS.intersection(keys_set)
|
||||
keys_set.difference_update(keys_def_set)
|
||||
if len(keys_def_set) > 0:
|
||||
found_default[sec][key_type] = True
|
||||
with (open(f"keys_{uid:08x}_{real_sec:02}_{nt[sec][key_type]}.dic", "w")) as f:
|
||||
|
@ -484,6 +528,7 @@ if abort:
|
|||
print("Brute-forcing phase aborted via keyboard!")
|
||||
args.final_check = False
|
||||
|
||||
plus = "[" + color("+", fg="green") + "] "
|
||||
if args.final_check:
|
||||
print("Letting fchk do a final dump, just for confirmation and display...")
|
||||
keys_set = set([i for sl in found_keys for i in sl if i != ""])
|
||||
|
@ -495,7 +540,6 @@ if args.final_check:
|
|||
print(cmd)
|
||||
p.console(cmd, passthru=True)
|
||||
else:
|
||||
plus = "[" + color("+", fg="green") + "] "
|
||||
print()
|
||||
print(plus + color("found keys:", fg="green"))
|
||||
print()
|
||||
|
|
|
@ -1311,6 +1311,52 @@ static int CmdGallagherDecode(const char *cmd) {
|
|||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int CmdGallagherEncode (const char *cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf gallagher encode",
|
||||
"Encode a Gallagher credential block\n"
|
||||
"Credential block can be specified with or without the bitwise inverse.",
|
||||
"hf gallagher encode --rc 1 --fc 22153 --cn 1253518 --il 1"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_u64_1("r", "rc", "<dec>", "Region code. 4 bits max"),
|
||||
arg_u64_1("f", "fc", "<dec>", "Facility code. 2 bytes max"),
|
||||
arg_u64_1("c", "cn", "<dec>", "Card number. 3 bytes max"),
|
||||
arg_u64_1("i", "il", "<dec>", "Issue level. 4 bits max"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, cmd, argtable, false);
|
||||
|
||||
uint64_t region_code = arg_get_u64(ctx, 1); // uint4, input will be validated later
|
||||
uint64_t facility_code = arg_get_u64(ctx, 2); // uint16
|
||||
uint64_t card_number = arg_get_u64(ctx, 3); // uint24
|
||||
uint64_t issue_level = arg_get_u64(ctx, 4); // uint4
|
||||
|
||||
CLIParserFree(ctx);
|
||||
|
||||
GallagherCredentials_t creds = {
|
||||
.region_code = region_code,
|
||||
.facility_code = facility_code,
|
||||
.card_number = card_number,
|
||||
.issue_level = issue_level,
|
||||
};
|
||||
|
||||
|
||||
uint8_t contents[16] = {0};
|
||||
|
||||
gallagher_encode_creds(contents, &creds);
|
||||
for (int i = 0; i < 8; i++) {
|
||||
contents[i + 8] = contents[i] ^ 0xFF;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Raw: " _YELLOW_("%s"), sprint_hex_inrow(contents, ARRAYLEN(contents)/2));
|
||||
PrintAndLogEx(SUCCESS, "Bitwise: " _YELLOW_("%s"), sprint_hex_inrow(contents, ARRAYLEN(contents)));
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
|
@ -1319,6 +1365,7 @@ static command_t CommandTable[] = {
|
|||
{"delete", CmdGallagherDelete, IfPm3Iso14443, "Delete Gallagher credentials from a DESFire card"},
|
||||
{"diversifykey", CmdGallagherDiversify, AlwaysAvailable, "Diversify Gallagher key"},
|
||||
{"decode", CmdGallagherDecode, AlwaysAvailable, "Decode Gallagher credential block"},
|
||||
{"encode", CmdGallagherEncode, AlwaysAvailable, "Encode Gallagher credential block"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
|
|
@ -4131,15 +4131,12 @@ static int CmdHF14AMfSim(const char *Cmd) {
|
|||
uint8_t uid[10] = {0};
|
||||
CLIGetHexWithReturn(ctx, 1, uid, &uidlen);
|
||||
|
||||
char uidsize[9] = {0};
|
||||
if (uidlen > 0) {
|
||||
FLAG_SET_UID_IN_DATA(flags, uidlen);
|
||||
if (IS_FLAG_UID_IN_EMUL(flags)) {
|
||||
PrintAndLogEx(WARNING, "Invalid parameter for UID");
|
||||
CLIParserFree(ctx);
|
||||
return PM3_EINVARG;
|
||||
} else {
|
||||
snprintf(uidsize, sizeof(uidsize), "%i bytes", uidlen);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4247,9 +4244,9 @@ static int CmdHF14AMfSim(const char *Cmd) {
|
|||
}
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, _YELLOW_("MIFARE %s") " | %s UID " _YELLOW_("%s") ""
|
||||
PrintAndLogEx(INFO, _YELLOW_("MIFARE %s") " | %i bytes UID " _YELLOW_("%s") ""
|
||||
, csize
|
||||
, uidsize
|
||||
, uidlen
|
||||
, (uidlen == 0) ? "n/a" : sprint_hex(uid, uidlen)
|
||||
);
|
||||
|
||||
|
|
|
@ -147,6 +147,13 @@ static int process_hitags_common_args(CLIParserContext *ctx, lf_hitag_data_t *co
|
|||
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
|
||||
switch (key_len) {
|
||||
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");
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -226,6 +248,9 @@ static void print_error(int8_t reason) {
|
|||
case -10:
|
||||
PrintAndLogEx(FAILED, "Write to page failed!");
|
||||
break;
|
||||
case -11:
|
||||
PrintAndLogEx(FAILED, "Read page failed!");
|
||||
break;
|
||||
default:
|
||||
// PM3_REASON_UNKNOWN
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - Hitag S failed");
|
||||
|
@ -254,8 +279,9 @@ static int CmdLFHitagSRead(const char *Cmd) {
|
|||
arg_str0(NULL, "nrar", "<hex>", "nonce / answer writer, 8 hex bytes"),
|
||||
arg_lit0(NULL, "crypto", "crypto mode"),
|
||||
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("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
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
@ -264,14 +290,14 @@ static int CmdLFHitagSRead(const char *Cmd) {
|
|||
|
||||
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) {
|
||||
PrintAndLogEx(WARNING, "Page address Invalid.");
|
||||
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) {
|
||||
PrintAndLogEx(WARNING, "No more than 64 pages can be read at once.");
|
||||
|
@ -404,8 +430,10 @@ static int CmdLFHitagSRead(const char *Cmd) {
|
|||
PrintAndLogEx(NORMAL, "Key");
|
||||
} else
|
||||
PrintAndLogEx(NORMAL, "Data");
|
||||
} else
|
||||
PrintAndLogEx(INFO, "%02u | -- -- -- -- | read failed reason: " _YELLOW_("%d"), page_addr, card->pages_reason[i]);
|
||||
} else {
|
||||
PrintAndLogEx(INFO, "% 3u | -- -- -- -- | .... | N/A | " NOLF, page_addr);
|
||||
print_error(card->pages_reason[i]);
|
||||
}
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "----+-------------+-------+------+------");
|
||||
|
@ -438,6 +466,7 @@ static int CmdLFHitagSWrite(const char *Cmd) {
|
|||
arg_str0(NULL, "nrar", "<hex>", "nonce / answer writer, 8 hex bytes"),
|
||||
arg_lit0(NULL, "crypto", "crypto mode"),
|
||||
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_str1("d", "data", "<hex>", "data, 4 hex bytes"),
|
||||
arg_param_end
|
||||
|
@ -448,12 +477,12 @@ static int CmdLFHitagSWrite(const char *Cmd) {
|
|||
|
||||
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];
|
||||
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) {
|
||||
CLIParserFree(ctx);
|
||||
return PM3_EINVARG;
|
||||
|
@ -538,7 +567,7 @@ static int CmdLFHitagSSim(const char *Cmd) {
|
|||
CLIParserFree(ctx);
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_LF_HITAGS_SIMULATE, NULL, 0);
|
||||
SendCommandMIX(CMD_LF_HITAGS_SIMULATE, false, 0, 0, NULL, 0);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -65,30 +65,6 @@ typedef enum {
|
|||
HT2_LAST_CMD = HT2F_UID_ONLY,
|
||||
} 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
|
||||
//---------------------------------------------------------
|
||||
|
@ -111,15 +87,6 @@ typedef enum TAG_STATE {
|
|||
HT_WRITING_BLOCK_DATA
|
||||
} 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 {
|
||||
// con0
|
||||
uint8_t MEMT : 2;
|
||||
|
@ -156,7 +123,6 @@ struct hitagS_tag {
|
|||
TSATE tstate; // tag-state
|
||||
|
||||
int max_page;
|
||||
stype mode;
|
||||
|
||||
union {
|
||||
uint8_t pages[64][4];
|
||||
|
@ -177,6 +143,33 @@ struct hitagS_tag {
|
|||
|
||||
} 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 {
|
||||
union {
|
||||
uint8_t asBytes[HITAGS_PAGE_SIZE];
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue