From 1efa52d70415ee2bed5bc6591b1521b167f1ec8b Mon Sep 17 00:00:00 2001 From: douniwan5788 Date: Thu, 22 Aug 2024 02:16:10 +0800 Subject: [PATCH 1/3] add: Hitag S plain write --- armsrc/hitagS.c | 48 +++++++++++++++++++---------------------- client/src/cmdlfhitag.c | 9 +++++++- include/hitag.h | 26 ++++++++++++---------- 3 files changed, 45 insertions(+), 38 deletions(-) diff --git a/armsrc/hitagS.c b/armsrc/hitagS.c index d48ed55f1..b950deee7 100644 --- a/armsrc/hitagS.c +++ b/armsrc/hitagS.c @@ -1271,7 +1271,7 @@ static int selectHitagS(const lf_hitag_data_t *packet, uint8_t *tx, size_t sizeo //select uid txlen = 0; - cmd = 0x00; + cmd = 0x00; // 00000 SELECT UID txlen = concatbits(tx, txlen, &cmd, 8 - 5, 5); txlen = concatbits(tx, txlen, rx, 0, 32); uint8_t crc = CRC8Hitag1Bits(tx, txlen); @@ -1450,7 +1450,7 @@ void ReadHitagS(const lf_hitag_data_t *payload, bool ledcontrol) { //send read request size_t txlen = 0; - uint8_t cmd = 0x0c; + uint8_t cmd = 0x0c; // 1100 READ PAGE txlen = concatbits(tx, txlen, &cmd, 8 - 4, 4); uint8_t addr = pageNum; txlen = concatbits(tx, txlen, &addr, 0, 8); @@ -1555,7 +1555,7 @@ void WritePageHitagS(const lf_hitag_data_t *payload, bool ledcontrol) { //send write page request txlen = 0; - uint8_t cmd = 0x08; + uint8_t cmd = 0x08; // 1000 WRITE PAGE txlen = concatbits(tx, txlen, &cmd, 8 - 4, 4); uint8_t addr = payload->page; @@ -1566,41 +1566,37 @@ void WritePageHitagS(const lf_hitag_data_t *payload, bool ledcontrol) { sendReceiveHitagS(tx, txlen, rx, ARRAYLEN(rx), &rxlen, HITAG_T_WAIT_SC, ledcontrol, false); - if ((rxlen != 2) || (rx[0] >> (8 - 2) != 0x1)) { + if ((rxlen != 2) || (rx[0] >> (8 - 2) != 0x01)) { Dbprintf("no write access on page " _YELLOW_("%d"), payload->page); res = PM3_ESOFT; goto write_end; } - //ACK received to write the page. send data - uint8_t data[4] = {0, 0, 0, 0}; - switch (payload->cmd) { - case WHTSF_CHALLENGE: - data[0] = payload->data[3]; - data[1] = payload->data[2]; - data[2] = payload->data[1]; - data[3] = payload->data[0]; - break; - case WHTSF_KEY: - data[0] = payload->data[3]; - data[1] = payload->data[2]; - data[2] = payload->data[1]; - data[3] = payload->data[0]; - break; - default: { - res = PM3_EINVARG; - goto write_end; - } - } + // //ACK received to write the page. send data + // uint8_t data[4] = {0, 0, 0, 0}; + // switch (payload->cmd) { + // case WHTSF_PLAIN: + // case WHTSF_CHALLENGE: + // case WHTSF_KEY: + // data[0] = payload->data[3]; + // data[1] = payload->data[2]; + // data[2] = payload->data[1]; + // data[3] = payload->data[0]; + // break; + // default: { + // res = PM3_EINVARG; + // goto write_end; + // } + // } txlen = 0; - txlen = concatbits(tx, txlen, data, 0, 32); + txlen = concatbits(tx, txlen, payload->data, 0, 32); crc = CRC8Hitag1Bits(tx, txlen); txlen = concatbits(tx, txlen, &crc, 0, 8); sendReceiveHitagS(tx, txlen, rx, ARRAYLEN(rx), &rxlen, HITAG_T_WAIT_SC, ledcontrol, false); - if ((rxlen != 2) || (rx[0] >> (8 - 2) != 0x1)) { + if ((rxlen != 2) || (rx[0] >> (8 - 2) != 0x01)) { res = PM3_ESOFT; // write failed } else { res = PM3_SUCCESS; diff --git a/client/src/cmdlfhitag.c b/client/src/cmdlfhitag.c index 8d27d1362..0b670dea4 100644 --- a/client/src/cmdlfhitag.c +++ b/client/src/cmdlfhitag.c @@ -1293,7 +1293,14 @@ static int CmdLFHitagWriter(const char *Cmd) { lf_hitag_data_t packet; memset(&packet, 0, sizeof(packet)); - if (use_hts && use_nrar) { + if (use_hts && use_plain) { + packet.cmd = WHTSF_PLAIN; + packet.page = page; + memcpy(packet.data, data, sizeof(data)); + + PrintAndLogEx(INFO, "Write to " _YELLOW_("Hitag S") " in Plain mode"); + + } else if (use_hts && use_nrar) { packet.cmd = WHTSF_CHALLENGE; memcpy(packet.NrAr, nrar, sizeof(packet.NrAr)); memcpy(packet.data, data, sizeof(data)); diff --git a/include/hitag.h b/include/hitag.h index 0f70d43fa..331b12178 100644 --- a/include/hitag.h +++ b/include/hitag.h @@ -23,21 +23,25 @@ #include "common.h" typedef enum { - RHTSF_CHALLENGE = 01, - RHTSF_KEY = 02, - WHTSF_CHALLENGE = 03, - WHTSF_KEY = 04, + RHTSF_PLAIN = 01, + WHTSF_PLAIN, + RHTSF_CHALLENGE, + WHTSF_CHALLENGE, + RHTSF_KEY, + WHTSF_KEY, HTS_LAST_CMD = WHTSF_KEY, + RHT1F_PLAIN = 11, - RHT1F_AUTHENTICATE = 12, + RHT1F_AUTHENTICATE, HT1_LAST_CMD = RHT1F_AUTHENTICATE, + RHT2F_PASSWORD = 21, - RHT2F_AUTHENTICATE = 22, - RHT2F_CRYPTO = 23, - WHT2F_CRYPTO = 24, - RHT2F_TEST_AUTH_ATTEMPTS = 25, - RHT2F_UID_ONLY = 26, - WHT2F_PASSWORD = 27, + RHT2F_AUTHENTICATE, + RHT2F_CRYPTO, + WHT2F_CRYPTO, + RHT2F_TEST_AUTH_ATTEMPTS, + RHT2F_UID_ONLY, + WHT2F_PASSWORD, HT2_LAST_CMD = WHT2F_PASSWORD, } PACKED hitag_function; From b76ebd91247bc43179d47adadb489401a0243852 Mon Sep 17 00:00:00 2001 From: douniwan5788 Date: Thu, 22 Aug 2024 02:20:26 +0800 Subject: [PATCH 2/3] fix: Hitag S read/write in plain mode Switch the counter clock to MCK/32 to allow a longer overflow time --- CHANGELOG.md | 1 + armsrc/hitagS.c | 94 ++++++++++++++++++++----------------------------- 2 files changed, 39 insertions(+), 56 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 162f85729..56a33353f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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... ## [unreleased][unreleased] +- Fixed Hitag S read/write in plain mode (@douniwan5788) - Fixed fm11rf08s script for non-4B UID (FM11RF08S-7B) (@Foxushka) - Fixed missing require of ansicolors in `lf_hid_bulkclone_v2.lua` script (@whiteneon) - Added `lf_t55xx_reset.lua` - a script to aid in quickly resetting t55xx chips (@whiteneon) diff --git a/armsrc/hitagS.c b/armsrc/hitagS.c index b950deee7..14e28b36b 100644 --- a/armsrc/hitagS.c +++ b/armsrc/hitagS.c @@ -75,17 +75,17 @@ static uint32_t rnd = 0x74124485; // random number #define ht2bs_4b(a,b,c,d) (~(((d|c)&(a^b))^(d|a|b))) #define ht2bs_5c(a,b,c,d,e) (~((((((c^e)|d)&a)^b)&(c^b))^(((d^e)|a)&((d^b)|c)))) -// Sam7s has several timers, we will use the source TIMER_CLOCK1 (aka AT91C_TC_CLKS_TIMER_DIV1_CLOCK) -// TIMER_CLOCK1 = MCK/2, MCK is running at 48 MHz, Timer is running at 48/2 = 24 MHz +// Sam7s has several timers, we will use the source TIMER_CLOCK3 (aka AT91C_TC_CLKS_TIMER_DIV3_CLOCK) +// TIMER_CLOCK3 = MCK/32, MCK is running at 48 MHz, Timer is running at 48MHz/32 = 1500 KHz // Hitag units (T0) have duration of 8 microseconds (us), which is 1/125000 per second (carrier) -// T0 = TIMER_CLOCK1 / 125000 = 192 +// T0 = TIMER_CLOCK3 / 125000 = 12 -#define T0 192 +#define T0 12 #define HITAG_FRAME_LEN 20 -// TC0 and TC1 will overflow at 341 * T0, so avoid setting these timings above 341 when comparing without considering overflow, -// as they will never reach that value. +// TC0 and TC1 are 16-bit counters and will overflow after 5461 * T0 +// Ensure not to set these timings above 5461 (~43ms) when comparing without considering overflow, as they will never reach that value. #define HITAG_T_STOP 36 /* T_EOF should be > 36 */ #define HITAG_T_LOW 8 /* T_LOW should be 4..10 */ @@ -96,7 +96,7 @@ static uint32_t rnd = 0x74124485; // random number // #define HITAG_T_EOF 40 /* T_EOF should be > 36 */ #define HITAG_T_EOF 80 /* T_EOF should be > 36 */ #define HITAG_T_WAIT_RESP 200 /* T_wresp should be 204..212 */ -#define HITAG_T_WAIT_SC 90 /* T_wsc should be 90..5000 */ +#define HITAG_T_WAIT_SC 200 /* T_wsc should be 90..5000 */ #define HITAG_T_WAIT_FIRST 300 /* T_wfc should be 280..565 (T_ttf) */ #define HITAG_T_PROG_MAX 750 /* T_prog should be 716..726 */ @@ -277,6 +277,7 @@ static void hitag_reader_send_bit(int bit, bool ledcontrol) { if (ledcontrol) LED_A_ON(); // Reset clock for the next bit AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + while (AT91C_BASE_TC0->TC_CV > 0); // Binary puls length modulation (BPLM) is used to encode the data stream // This means that a transmission of a one takes longer than that of a zero @@ -324,7 +325,7 @@ static void hitag_reader_send_frame(const uint8_t *frame, size_t frame_len, bool } // send EOF AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - + while (AT91C_BASE_TC0->TC_CV > 0); HIGH(GPIO_SSC_DOUT); // Wait for 4-10 times the carrier period @@ -336,8 +337,8 @@ static void hitag_reader_send_frame(const uint8_t *frame, size_t frame_len, bool static void hitagS_init_clock(void) { // Enable Peripheral Clock for - // TIMER_CLOCK0, used to measure exact timing before answering - // TIMER_CLOCK1, used to capture edges of the tag frames + // Timer Counter 0, used to measure exact timing before answering + // Timer Counter 1, used to capture edges of the tag frames AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1); AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; @@ -346,39 +347,34 @@ static void hitagS_init_clock(void) { AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - // TC0: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), no triggers - AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; + // TC0: Capture mode, clock 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/2 (TIMER_CLOCK1), TIOA is external trigger, - // external trigger rising edge, load RA on falling edge of TIOA. + // 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_DIV1_CLOCK | - AT91C_TC_ETRGEDG_FALLING | - AT91C_TC_ABETRG | - AT91C_TC_LDRA_FALLING | - AT91C_TC_ACPA_CLEAR | // RA comperator clears TIOA (carry bit) - AT91C_TC_ASWTRG_SET; // SWTriger sets TIOA (carry bit) + AT91C_TC_CLKS_TIMER_DIV3_CLOCK | + 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 + AT91C_TC_ACPA_CLEAR | // RA comperator clears TIOA (carry bit) + AT91C_TC_ASWTRG_SET; // SWTriger sets TIOA (carry bit) - AT91C_BASE_TC0->TC_RC = 0; // set TIOA (carry bit) on overflow, return to zero - AT91C_BASE_TC0->TC_RA = 1; // clear carry bit on next clock cycle AT91C_BASE_TC1->TC_RA = 1; // clear carry bit on next clock cycle // Enable and reset counters AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - // Typically 2 or 3, indicating that our execution is slow enough to wait for TC0 reset. - // If I am calculating correctly, theoretically, for AT91C_TC_CLKS_TIMER_DIV1_CLOCK, 2 instruction statements are sufficient? - // Dbprintf("TC_CV:%i", AT91C_BASE_TC0->TC_CV); AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + // for (size_t i = 0; i < 10; i++) __asm(""); // uint16_t cv0 = AT91C_BASE_TC0->TC_CV; // synchronized startup procedure - // Waiting for TC0 to return to 0 takes a considerable amount of time (around 2730us), - // and we should be able to tolerate 1 * T0. Or is this even necessary? - while (AT91C_BASE_TC0->TC_CV > T0) {}; // wait until TC0 returned to zero + // In theory, with MCK/32, we shouldn't be waiting longer than 32 instruction statements, right? + while (AT91C_BASE_TC0->TC_CV > 0) {}; // wait until TC0 returned to zero // while (AT91C_BASE_TC0->TC_CV < 2) {}; // and has started (TC_CV > TC_RA, now TC1 is cleared) - // Dbprintf("TC_CV0:%i TC_CV:%i", cv0, AT91C_BASE_TC0->TC_CV); + // Dbprintf("TC0_CV0:%i TC0_CV:%i TC1_CV:%i", cv0, AT91C_BASE_TC0->TC_CV, AT91C_BASE_TC1->TC_CV); } static void hitagS_stop_clock(void) { @@ -879,8 +875,8 @@ void SimulateHitagSTag(bool tag_mem_supplied, const uint8_t *data, bool ledcontr LOW(GPIO_SSC_DOUT); // Enable Peripheral Clock for - // TIMER_CLOCK0, used to measure exact timing before answering - // TIMER_CLOCK1, used to capture edges of the tag frames + // Timer Counter 0, used to measure exact timing before answering + // Timer Counter 1, used to capture edges of the tag frames AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1); AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; @@ -889,12 +885,12 @@ void SimulateHitagSTag(bool tag_mem_supplied, const uint8_t *data, bool ledcontr AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - // TC0: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), no triggers - AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_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/2 (TIMER_CLOCK1), TIOA is external trigger, + // 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_DIV1_CLOCK + AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK | AT91C_TC_ETRGEDG_RISING | AT91C_TC_ABETRG | AT91C_TC_LDRA_RISING; // Enable and reset counter @@ -1004,11 +1000,6 @@ static void hitagS_receive_frame(uint8_t *rx, size_t sizeofrx, size_t *rxlen, ui bool bSkip = true; *resptime = 0; uint32_t errorCount = 0; - // clk overflow but I failed moving TC0 & TC1 to - // slower clock AT91C_TC_CLKS_TIMER_DIV3_CLOCK - // so tracking overflow manually... - uint32_t overcount = 0; - uint32_t prevcv = 0; bool bStarted = false; uint32_t ra_i=0, h2 = 0, h3 = 0, h4 = 0; @@ -1017,14 +1008,7 @@ static void hitagS_receive_frame(uint8_t *rx, size_t sizeofrx, size_t *rxlen, ui // 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); // Receive frame, watch for at most T0*HITAG_T_PROG_MAX periods - while (AT91C_BASE_TC0->TC_CV + (overcount << 16) < (T0 * HITAG_T_PROG_MAX)) { - - // detect and track counter overflows - uint32_t tmpcv = AT91C_BASE_TC0->TC_CV; - if (tmpcv < prevcv) { - overcount++; - } - prevcv = tmpcv; + 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) { @@ -1035,21 +1019,19 @@ static void hitagS_receive_frame(uint8_t *rx, size_t sizeofrx, size_t *rxlen, ui // Reset timer every frame, we have to capture the last edge for timing AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - prevcv = 0; - overcount = 0; - if (ledcontrol) LED_B_ON(); // Capture tag frame (manchester decoding using only falling edges) if (bStarted == false) { + // Capture the T0 periods that have passed since last communication or field drop (reset) + *resptime = ra - HITAG_T_TAG_HALF_PERIOD; + if (ra >= HITAG_T_WAIT_RESP) { bStarted = true; - // Capture the T0 periods that have passed since last communication or field drop (reset) - // We always receive a 'one' first, which has the falling edge after a half period |-_| - *resptime = ra - HITAG_T_TAG_HALF_PERIOD; + // We always receive a 'one' first, which has the falling edge after a half period |-_| rx[0] = 0x80; (*rxlen)++; } else { @@ -1093,7 +1075,7 @@ static void hitagS_receive_frame(uint8_t *rx, size_t sizeofrx, size_t *rxlen, ui } // if we saw over 100 weird values break it probably isn't hitag... - if (errorCount > 100) { + if (errorCount > 100 || (*rxlen) / 8 >= sizeofrx) { break; } @@ -1108,7 +1090,7 @@ static void hitagS_receive_frame(uint8_t *rx, size_t sizeofrx, size_t *rxlen, ui } } if (g_dbglevel >= DBG_EXTENDED) { - Dbprintf("RX0 %i:%02X.. err:%i resptime:%i h2:%i h3:%i h4:%i edges", *rxlen, rx[0], errorCount, *resptime, h2, h3, h4); + Dbprintf("RX0 %i:%02X.. err:%i resptime:%i h2:%i h3:%i h4:%i edges:", *rxlen, rx[0], errorCount, *resptime, h2, h3, h4); Dbhexdump(ra_i, edges, false); } } From fb6626d89f454d11ac29929e69d6439278af4de8 Mon Sep 17 00:00:00 2001 From: douniwan5788 Date: Thu, 22 Aug 2024 17:00:14 +0800 Subject: [PATCH 3/3] refactor: remove hitag_function enum value --- include/hitag.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/hitag.h b/include/hitag.h index 331b12178..75ae7a1eb 100644 --- a/include/hitag.h +++ b/include/hitag.h @@ -23,7 +23,7 @@ #include "common.h" typedef enum { - RHTSF_PLAIN = 01, + RHTSF_PLAIN, WHTSF_PLAIN, RHTSF_CHALLENGE, WHTSF_CHALLENGE, @@ -31,11 +31,11 @@ typedef enum { WHTSF_KEY, HTS_LAST_CMD = WHTSF_KEY, - RHT1F_PLAIN = 11, + RHT1F_PLAIN, RHT1F_AUTHENTICATE, HT1_LAST_CMD = RHT1F_AUTHENTICATE, - RHT2F_PASSWORD = 21, + RHT2F_PASSWORD, RHT2F_AUTHENTICATE, RHT2F_CRYPTO, WHT2F_CRYPTO,