mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-20 21:33:47 -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 info` - now checks for cards silicon version (@antiklesys)
|
||||||
- Changed `hf iclass legrec` - updated script implementation to ensure functionality (@antiklesys)
|
- Changed `hf iclass legrec` - updated script implementation to ensure functionality (@antiklesys)
|
||||||
- Added recovered iclass custom key to dictionary (@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 `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)
|
||||||
|
|
|
@ -236,7 +236,7 @@ void RunMod(void) {
|
||||||
int button_pressed = BUTTON_HELD(1000);
|
int button_pressed = BUTTON_HELD(1000);
|
||||||
if (button_pressed == BUTTON_NO_CLICK) { // No button action, proceed with sim
|
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);
|
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
|
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
|
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;
|
||||||
m = MC4K;
|
if (ac_seq)
|
||||||
|
m = AC2K;
|
||||||
|
else
|
||||||
|
m = MC4K;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case HT_ADVANCED: {
|
case HITAGS_UID_REQ_ADV1:
|
||||||
sof_bits = 6;
|
case HITAGS_UID_REQ_ADV2: {
|
||||||
m = MC4K;
|
if (ac_seq) {
|
||||||
|
sof_bits = 3;
|
||||||
|
m = AC2K;
|
||||||
|
} else {
|
||||||
|
sof_bits = 6;
|
||||||
|
m = MC4K;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case HT_FAST_ADVANCED: {
|
case HITAGS_UID_REQ_FADV: {
|
||||||
sof_bits = 6;
|
if (ac_seq) {
|
||||||
m = MC8K;
|
sof_bits = 3;
|
||||||
break;
|
m = AC4K;
|
||||||
}
|
} else {
|
||||||
default: {
|
sof_bits = 6;
|
||||||
|
m = MC8K;
|
||||||
|
}
|
||||||
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,39 +903,69 @@ 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) {
|
|
||||||
|
|
||||||
// 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 {
|
} else {
|
||||||
// Ignore weird value, is to small to mean anything
|
// Anticollision Coding
|
||||||
errorCount++;
|
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 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,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
|
// 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++) {
|
||||||
|
response_bit[i] = (rx[i / 8] >> (7 - (i % 8))) & 1;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: It's very confusing to reinterpreter the MC to AC; we should implement a more straightforward approach.
|
Dbprintf("htS: rxlen...... %zu", *rxlen);
|
||||||
// add the lost bit zero, when AC64 last bit is zero
|
Dbprintf("htS: sizeofrx... %zu", sizeofrx);
|
||||||
if (k % 8 == 7) {
|
DbpString("htS: response_bit:");
|
||||||
k++;
|
Dbhexdump(*rxlen, response_bit, false);
|
||||||
}
|
Dbprintf("htS: skipping %d bit SOF", sof_bits);
|
||||||
|
if ((rx[0] >> (8 - sof_bits)) != ((1 << sof_bits) - 1)) {
|
||||||
if (g_dbglevel >= DBG_EXTENDED) {
|
DbpString("htS: Warning, not all bits of SOF are 1");
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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;
|
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;
|
||||||
}
|
}
|
||||||
|
@ -1295,6 +1272,12 @@ void hts_read(const lf_hitag_data_t *payload, bool ledcontrol) {
|
||||||
|
|
||||||
while ((BUTTON_PRESS() == false) && (data_available() == false)) {
|
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();
|
WDT_HIT();
|
||||||
|
|
||||||
size_t rxlen = 0;
|
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);
|
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] = -11;
|
||||||
// status = PM3_ERFTRANS;
|
// status = PM3_ERFTRANS;
|
||||||
// goto read_end;
|
// goto read_end;
|
||||||
page_addr++;
|
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
|
//if the authentication is done with a challenge the key and password are unknown
|
||||||
DBG Dbprintf("Page[ 2]: __ __ __ __");
|
DBG Dbprintf("Page[ 2]: __ __ __ __");
|
||||||
DBG Dbprintf("Page[ 3]: __ __ __ __");
|
DBG Dbprintf("Page[ 3]: __ __ __ __");
|
||||||
card.pages_reason[page_index++] = -4;
|
card.pages_reason[page_index++] = -11;
|
||||||
card.pages_reason[page_index++] = -4;
|
card.pages_reason[page_index++] = -11;
|
||||||
}
|
}
|
||||||
// since page 2+3 are not accessible when LKP == 1 and AUT == 1 fastforward to next readable page
|
// since page 2+3 are not accessible when LKP == 1 and AUT == 1 fastforward to next readable page
|
||||||
page_addr = 4;
|
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:
|
read_end:
|
||||||
|
@ -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 };
|
||||||
|
|
|
@ -1534,7 +1534,7 @@ void MifareStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo,
|
||||||
continue;
|
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;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1544,6 +1544,12 @@ void MifareStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo,
|
||||||
};
|
};
|
||||||
|
|
||||||
nt3 = bytes_to_num(receivedAnswer, 4);
|
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];
|
target_ks[1] = nt3 ^ target_nt[1];
|
||||||
|
|
||||||
isOK = PM3_SUCCESS;
|
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 == 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 #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'
|
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 == '02' then gtustr = 'Disabled'
|
||||||
elseif gtumode == '03' then gtustr = 'Disabled, high speed R/W mode for Ultralight'
|
elseif gtumode == '03' then gtustr = 'Disabled, high speed R/W mode for Ultralight'
|
||||||
end
|
end
|
||||||
|
@ -553,7 +553,7 @@ local function write_gtu(gtu)
|
||||||
if gtu == '00' then
|
if gtu == '00' then
|
||||||
print('Enabling GTU Pre-Write')
|
print('Enabling GTU Pre-Write')
|
||||||
send('CF'.._key..'32'..gtu)
|
send('CF'.._key..'32'..gtu)
|
||||||
elseif gtu == '01' then
|
elseif gtu == '01' or gtu == '04' then
|
||||||
print('Enabling GTU Restore Mode')
|
print('Enabling GTU Restore Mode')
|
||||||
send('CF'.._key..'32'..gtu)
|
send('CF'.._key..'32'..gtu)
|
||||||
elseif gtu == '02' then
|
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('-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('-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('-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()
|
args = parser.parse_args()
|
||||||
|
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
|
@ -191,6 +195,22 @@ if os.path.isfile(DICT_DEF_PATH):
|
||||||
else:
|
else:
|
||||||
print(f"Warning, {DICT_DEF} not found.")
|
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...")
|
print("Running staticnested_1nt & 2x1nt when doable...")
|
||||||
keys = [[set(), set()] for _ in range(NUM_SECTORS + NUM_EXTRA_SECTORS)]
|
keys = [[set(), set()] for _ in range(NUM_SECTORS + NUM_EXTRA_SECTORS)]
|
||||||
all_keys = set()
|
all_keys = set()
|
||||||
|
@ -225,9 +245,21 @@ for sec in range(NUM_SECTORS + NUM_EXTRA_SECTORS):
|
||||||
keys[sec][key_type] = keys_set.copy()
|
keys[sec][key_type] = keys_set.copy()
|
||||||
duplicates.update(all_keys.intersection(keys_set))
|
duplicates.update(all_keys.intersection(keys_set))
|
||||||
all_keys.update(keys_set)
|
all_keys.update(keys_set)
|
||||||
# Prioritize default keys
|
if dict_dnwd is not None and sec < NUM_SECTORS:
|
||||||
keys_def_set = DEFAULT_KEYS.intersection(keys_set)
|
# Prioritize keys from supply-chain attack
|
||||||
keys_set.difference_update(DEFAULT_KEYS)
|
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
|
# Prioritize sector 32 keyB starting with 0000
|
||||||
if real_sec == 32:
|
if real_sec == 32:
|
||||||
keyb32cands = set(x for x in keys_set if x.startswith("0000"))
|
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()
|
keys[sec][key_type] = keys_set.copy()
|
||||||
duplicates.update(all_keys.intersection(keys_set))
|
duplicates.update(all_keys.intersection(keys_set))
|
||||||
all_keys.update(keys_set)
|
all_keys.update(keys_set)
|
||||||
# Prioritize default keys
|
if dict_dnwd is not None and sec < NUM_SECTORS:
|
||||||
keys_def_set = DEFAULT_KEYS.intersection(keys_set)
|
# Prioritize keys from supply-chain attack
|
||||||
keys_set.difference_update(DEFAULT_KEYS)
|
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:
|
if len(keys_def_set) > 0:
|
||||||
found_default[sec][key_type] = True
|
found_default[sec][key_type] = True
|
||||||
with (open(f"keys_{uid:08x}_{real_sec:02}_{nt[sec][key_type]}.dic", "w")) as f:
|
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!")
|
print("Brute-forcing phase aborted via keyboard!")
|
||||||
args.final_check = False
|
args.final_check = False
|
||||||
|
|
||||||
|
plus = "[" + color("+", fg="green") + "] "
|
||||||
if args.final_check:
|
if args.final_check:
|
||||||
print("Letting fchk do a final dump, just for confirmation and display...")
|
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 != ""])
|
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)
|
print(cmd)
|
||||||
p.console(cmd, passthru=True)
|
p.console(cmd, passthru=True)
|
||||||
else:
|
else:
|
||||||
plus = "[" + color("+", fg="green") + "] "
|
|
||||||
print()
|
print()
|
||||||
print(plus + color("found keys:", fg="green"))
|
print(plus + color("found keys:", fg="green"))
|
||||||
print()
|
print()
|
||||||
|
|
|
@ -1311,6 +1311,52 @@ static int CmdGallagherDecode(const char *cmd) {
|
||||||
|
|
||||||
return PM3_SUCCESS;
|
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[] = {
|
static command_t CommandTable[] = {
|
||||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||||
|
@ -1319,6 +1365,7 @@ static command_t CommandTable[] = {
|
||||||
{"delete", CmdGallagherDelete, IfPm3Iso14443, "Delete Gallagher credentials from a DESFire card"},
|
{"delete", CmdGallagherDelete, IfPm3Iso14443, "Delete Gallagher credentials from a DESFire card"},
|
||||||
{"diversifykey", CmdGallagherDiversify, AlwaysAvailable, "Diversify Gallagher key"},
|
{"diversifykey", CmdGallagherDiversify, AlwaysAvailable, "Diversify Gallagher key"},
|
||||||
{"decode", CmdGallagherDecode, AlwaysAvailable, "Decode Gallagher credential block"},
|
{"decode", CmdGallagherDecode, AlwaysAvailable, "Decode Gallagher credential block"},
|
||||||
|
{"encode", CmdGallagherEncode, AlwaysAvailable, "Encode Gallagher credential block"},
|
||||||
{NULL, NULL, NULL, NULL}
|
{NULL, NULL, NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -4131,15 +4131,12 @@ static int CmdHF14AMfSim(const char *Cmd) {
|
||||||
uint8_t uid[10] = {0};
|
uint8_t uid[10] = {0};
|
||||||
CLIGetHexWithReturn(ctx, 1, uid, &uidlen);
|
CLIGetHexWithReturn(ctx, 1, uid, &uidlen);
|
||||||
|
|
||||||
char uidsize[9] = {0};
|
|
||||||
if (uidlen > 0) {
|
if (uidlen > 0) {
|
||||||
FLAG_SET_UID_IN_DATA(flags, uidlen);
|
FLAG_SET_UID_IN_DATA(flags, uidlen);
|
||||||
if (IS_FLAG_UID_IN_EMUL(flags)) {
|
if (IS_FLAG_UID_IN_EMUL(flags)) {
|
||||||
PrintAndLogEx(WARNING, "Invalid parameter for UID");
|
PrintAndLogEx(WARNING, "Invalid parameter for UID");
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
return PM3_EINVARG;
|
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
|
, csize
|
||||||
, uidsize
|
, uidlen
|
||||||
, (uidlen == 0) ? "n/a" : sprint_hex(uid, 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;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,6 +248,9 @@ static void print_error(int8_t reason) {
|
||||||
case -10:
|
case -10:
|
||||||
PrintAndLogEx(FAILED, "Write to page failed!");
|
PrintAndLogEx(FAILED, "Write to page failed!");
|
||||||
break;
|
break;
|
||||||
|
case -11:
|
||||||
|
PrintAndLogEx(FAILED, "Read page failed!");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
// PM3_REASON_UNKNOWN
|
// PM3_REASON_UNKNOWN
|
||||||
PrintAndLogEx(DEBUG, "DEBUG: Error - Hitag S failed");
|
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_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 +290,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.");
|
||||||
|
@ -404,8 +430,10 @@ static int CmdLFHitagSRead(const char *Cmd) {
|
||||||
PrintAndLogEx(NORMAL, "Key");
|
PrintAndLogEx(NORMAL, "Key");
|
||||||
} else
|
} else
|
||||||
PrintAndLogEx(NORMAL, "Data");
|
PrintAndLogEx(NORMAL, "Data");
|
||||||
} else
|
} else {
|
||||||
PrintAndLogEx(INFO, "%02u | -- -- -- -- | read failed reason: " _YELLOW_("%d"), page_addr, card->pages_reason[i]);
|
PrintAndLogEx(INFO, "% 3u | -- -- -- -- | .... | N/A | " NOLF, page_addr);
|
||||||
|
print_error(card->pages_reason[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "----+-------------+-------+------+------");
|
PrintAndLogEx(INFO, "----+-------------+-------+------+------");
|
||||||
|
@ -438,6 +466,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 +477,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 +567,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