diff --git a/armsrc/Makefile b/armsrc/Makefile index beb19c243..12819c3d0 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -23,7 +23,7 @@ APP_CFLAGS = $(PLATFORM_DEFS) \ -DON_DEVICE \ -fno-strict-aliasing -ffunction-sections -fdata-sections -SRC_LF = lfops.c lfsampling.c pcf7931.c lfdemod.c +SRC_LF = lfops.c lfsampling.c pcf7931.c lfdemod.c lfadc.c SRC_ISO15693 = iso15693.c iso15693tools.c SRC_ISO14443a = iso14443a.c mifareutil.c mifarecmd.c epa.c mifaresim.c #UNUSED: mifaresniff.c desfire_crypto.c diff --git a/armsrc/hitag2.c b/armsrc/hitag2.c index 3531ac9ea..60cd76416 100644 --- a/armsrc/hitag2.c +++ b/armsrc/hitag2.c @@ -16,7 +16,8 @@ // (c) 2012 Roel Verdult //----------------------------------------------------------------------------- // Piwi, 2019 -// Iceman, 2019 +// Iceman, 2019 +// Anon, 2019 #include "hitag2.h" #include "hitag2_crypto.h" @@ -28,12 +29,18 @@ #include "ticks.h" #include "dbprint.h" #include "util.h" +#include "lfadc.h" +#include "lfsampling.h" +#include "lfdemod.h" +#include "commonutil.h" // Successful crypto auth static bool bCrypto; // Is in auth stage static bool bAuthenticating; // Successful password auth +bool bSelecting; +bool bCollision; static bool bPwd; static bool bSuccessful; @@ -52,6 +59,7 @@ static struct hitag2_tag tag = { [9] = { 0x00, 0x00, 0x00, 0x00}, // RSK High [10] = { 0x00, 0x00, 0x00, 0x00}, // RCF [11] = { 0x00, 0x00, 0x00, 0x00}, // SYNC + // up to index 15 reserved for HITAG1/HITAGS public data }, }; @@ -73,6 +81,9 @@ static uint8_t password[4]; static uint8_t NrAr[8]; static uint8_t key[8]; static uint8_t writedata[4]; +uint8_t logdata_0[4], logdata_1[4]; +uint8_t nonce[4]; +bool key_no; static uint64_t cipher_state; static int hitag2_reset(void) { @@ -288,29 +299,26 @@ static void hitag2_handle_reader_command(uint8_t *rx, const size_t rxlen, uint8_ // sim static void hitag_reader_send_bit(int bit) { LED_A_ON(); - // Reset clock for the next bit - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - - // Binary puls length modulation (BPLM) is used to encode the data stream + // Binary pulse 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 - // Enable modulation, which means, drop the field - HIGH(GPIO_SSC_DOUT); + // Enable modulation, which means, drop the field + lf_modulation(true); // Wait for 4-10 times the carrier period - while (AT91C_BASE_TC0->TC_CV < T0 * 6) {}; + lf_wait_periods(8); // wait for 4-10 times the carrier period // Disable modulation, just activates the field again - LOW(GPIO_SSC_DOUT); + lf_modulation(false); if (bit == 0) { // Zero bit: |_-| - while (AT91C_BASE_TC0->TC_CV < T0 * 22) {}; - + lf_wait_periods(12); // wait for 18-22 times the carrier period } else { // One bit: |_--| - while (AT91C_BASE_TC0->TC_CV < T0 * 28) {}; + lf_wait_periods(22); // wait for 26-32 times the carrier period } + /*lf_wait_periods(10);*/ LED_A_OFF(); } @@ -320,18 +328,243 @@ static void hitag_reader_send_frame(const uint8_t *frame, size_t frame_len) { for (size_t i = 0; i < frame_len; i++) { hitag_reader_send_bit((frame[i / 8] >> (7 - (i % 8))) & 1); } - // Send EOF - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - // Enable modulation, which means, drop the field - HIGH(GPIO_SSC_DOUT); + // Enable modulation, which means, drop the field + lf_modulation(true); // Wait for 4-10 times the carrier period - while (AT91C_BASE_TC0->TC_CV < T0 * 6) {}; + lf_wait_periods(8); // Disable modulation, just activates the field again - LOW(GPIO_SSC_DOUT); + lf_modulation(false); + + // t_stop, high field for stop condition (> 36) + lf_wait_periods(28); } size_t blocknr; +uint8_t hitag_crc(uint8_t *data, size_t length){ + uint8_t crc = 0xff; + unsigned int byte, bit; + for(byte=0; byte<((length+7)/8); byte++){ + crc ^= *(data + byte); + bit = length < (8*(byte+1)) ? (length % 8) : 8; + while(bit--){ + if(crc & 0x80){ + crc<<=1; + crc ^= 0x1d; + } else { + crc<<=1; + } + } + } + return crc; +} + +#define test_bit(data, i) (*(data+(i/8)) >> (7-(i%8))) & 1 +#define set_bit(data, i) *(data+(i/8)) |= (1 << (7-(i%8))) +#define clear_bit(data, i) *(data+(i/8)) &= ~(1 << (7-(i%8))) +#define flip_bit(data, i) *(data+(i/8)) ^= (1 << (7-(i%8))) +void fix_ac_decoding(uint8_t *input, size_t len){ + // Reader routine tries to decode AC data after Manchester decoding + // AC has double the bitrate, extract data from bit-pairs + uint8_t temp[len / 16]; + memset(temp, 0, sizeof(temp)); + + for (size_t i = 1; i < len; i += 2) { + if (test_bit(input, i) && test_bit(input, (i + 1))){ + set_bit(temp, (i / 2)); + } + } + memcpy(input, temp, sizeof(temp)); +} + +bool hitag_plain(uint8_t* rx, const size_t rxlen, uint8_t* tx, size_t* txlen, bool hitag_s) { + uint8_t crc; + *txlen = 0; + switch (rxlen) { + case 0: { + // retry waking up card + /*tx[0] = 0xb0; // Rev 3.0*/ + tx[0] = 0x30; // Rev 2.0 + *txlen = 5; + if(!bCollision) blocknr--; + if(blocknr < 0) { + blocknr = 0; + } + if(!hitag_s){ + if (blocknr > 1 && blocknr < 31) { + blocknr=31; + } + } + bCollision = true; + return true; + } + case 32: { + if(bCollision){ + // Select card by serial from response + tx[0] = 0x00 | rx[0] >> 5; + tx[1] = rx[0] << 3 | rx[1] >> 5; + tx[2] = rx[1] << 3 | rx[2] >> 5; + tx[3] = rx[2] << 3 | rx[3] >> 5; + tx[4] = rx[3] << 3; + crc = hitag_crc(tx,37); + tx[4] |= crc >> 5; + tx[5] = crc << 3; + *txlen = 45; + bCollision = false; + } else { + memcpy(tag.sectors[blocknr], rx, 4); + blocknr++; + if(!hitag_s){ + if (blocknr > 1 && blocknr < 31) { + blocknr=31; + } + } + if (blocknr > 63) { + DbpString("Read succesful!"); + *txlen = 0; + bSuccessful = true; + return false; + } + // read next page of card until done + Dbprintf("Reading page %02u", blocknr); + tx[0] = 0xc0 | blocknr >> 4; // RDPPAGE + tx[1] = blocknr << 4; + crc = hitag_crc(tx,12); + tx[1] |= crc >> 4; + tx[2] = crc << 4; + *txlen = 20; + } + } break; + default: { + Dbprintf("Uknown frame length: %d",rxlen); + return false; + } break; + } + return true; +} + +size_t flipped_bit = 0; + +uint32_t byte_value = 0; +bool hitag1_authenticate(uint8_t* rx, const size_t rxlen, uint8_t* tx, size_t* txlen) { + uint8_t crc; + *txlen = 0; + switch (rxlen) { + case 0: { + // retry waking up card + /*tx[0] = 0xb0; // Rev 3.0*/ + tx[0] = 0x30; // Rev 2.0 + *txlen = 5; + if (bCrypto && byte_value <= 0xff){ + // to retry + bCrypto = false; + } + if(!bCollision) blocknr--; + if(blocknr < 0) { + blocknr = 0; + } + bCollision = true; + // will receive 32-bit UID + } break; + case 2: { + if (bAuthenticating) { + // received Auth init ACK, send nonce + // TODO Roel, bit-manipulation goes here + /*nonce[0] = 0x2d;*/ + /*nonce[1] = 0x74;*/ + /*nonce[2] = 0x80;*/ + /*nonce[3] = 0xa5;*/ + nonce[0]=byte_value; + byte_value++; + /*set_bit(nonce,flipped_bit);*/ + memcpy(tx,nonce,4); + *txlen = 32; + // will receive 32 bit encrypted Logdata + } else if (bCrypto) { + // authed, start reading + tx[0] = 0xe0 | blocknr >> 4; // RDCPAGE + tx[1] = blocknr << 4; + crc = hitag_crc(tx,12); + tx[1] |= crc >> 4; + tx[2] = crc << 4; + *txlen = 20; + // will receive 32-bit encrypted page + } + } break; + case 32: { + if (bCollision){ + // Select card by serial from response + tx[0] = 0x00 | rx[0] >> 5; + tx[1] = rx[0] << 3 | rx[1] >> 5; + tx[2] = rx[1] << 3 | rx[2] >> 5; + tx[3] = rx[2] << 3 | rx[3] >> 5; + tx[4] = rx[3] << 3; + crc = hitag_crc(tx,37); + tx[4] |= crc >> 5; + tx[5] = crc << 3; + *txlen = 45; + bCollision = false; + bSelecting = true; + // will receive 32-bit configuration page + } else if (bSelecting){ + // Initiate auth + tx[0] = 0xa0 | key_no >> 4; // WRCPAGE + tx[1] = blocknr << 4; + crc = hitag_crc(tx,12); + tx[1] |= crc >> 4; + tx[2] = crc << 4; + *txlen = 20; + bSelecting = false; + bAuthenticating = true; + // will receive 2-bit ACK + } else if (bAuthenticating) { + // received 32-bit logdata 0 + // TODO decrypt logdata 0, verify against logdata_0 + memcpy(tag.sectors[0], rx, 4); + memcpy(tag.sectors[1], tx, 4); + Dbprintf("%02x%02x%02x%02x %02x%02x%02x%02x", rx[0], rx[1], rx[2], rx[3], tx[0], tx[1], tx[2], tx[3]); + // TODO replace with secret data stream + // TODO encrypt logdata_1 + memcpy(tx,logdata_1,4); + *txlen = 32; + bAuthenticating = false; + bCrypto = true; + // will receive 2-bit ACK + } else if (bCrypto) { + // received 32-bit encrypted page + // TODO decrypt rx + memcpy(tag.sectors[blocknr],rx,4); + blocknr++; + if (blocknr > 63) { + DbpString("Read succesful!"); + bSuccessful = true; + return false; + } + + // TEST + Dbprintf("Succesfully authenticated with logdata:"); + Dbhexdump(4,logdata_1,false); + bSuccessful = true; + return false; + + // read next page of card until done + tx[0] = 0xe0 | blocknr >> 4; // RDCPAGE + tx[1] = blocknr << 4; + crc = hitag_crc(tx,12); + tx[1] |= crc >> 4; + tx[2] = crc << 4; + *txlen = 20; + } + } break; + default: { + Dbprintf("Uknown frame length: %d",rxlen); + return false; + } break; + } + + return true; +} + //----------------------------------------------------------------------------- // Hitag2 operations //----------------------------------------------------------------------------- @@ -686,9 +919,11 @@ static bool hitag2_read_uid(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t // Store the received block memcpy(tag.sectors[blocknr], rx, 4); blocknr++; + + Dbhexdump(4, rx, false); } if (blocknr > 0) { - // DbpString("Read successful!"); + DbpString("Read successful!"); bSuccessful = true; return false; } @@ -705,21 +940,11 @@ static bool hitag2_read_uid(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t } // Hitag2 Sniffing -void SniffHitag(void) { +void SniffHitag(uint32_t type) { + LEDsoff(); StopTicks(); - - // int frame_count; - int response; - int overflow; - bool rising_edge; - bool reader_frame; - int lastbit; - bool bSkip; - int tag_sof; - uint8_t rx[HITAG_FRAME_LEN]; - size_t rxlen = 0; - + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); BigBuf_free(); BigBuf_Clear_ext(false); @@ -735,143 +960,41 @@ void SniffHitag(void) { DbpString("Starting Hitag2 sniffing"); LED_D_ON(); - // Set up eavesdropping mode, frequency divisor which will drive the FPGA - // and analog mux selection. - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_TOGGLE_MODE); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_125); - SetAdcMuxFor(GPIO_MUXSEL_LOPKD); + lf_init(false); + logging = false; - // Configure output pin that is connected to the FPGA (for modulating) - AT91C_BASE_PIOA->PIO_OER |= GPIO_SSC_DOUT; - AT91C_BASE_PIOA->PIO_PER |= GPIO_SSC_DOUT; - - // Disable modulation, we are going to eavesdrop, not modulate ;) - LOW(GPIO_SSC_DOUT); - - // Enable Peripheral Clock for TIMER_CLOCK1, used to capture edges of the reader frames - AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1); - AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; - - // Disable timer during configuration - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - - // TC1: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), 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_TC_ETRGEDG_BOTH | AT91C_TC_ABETRG | AT91C_TC_LDRA_BOTH; - - // Enable and reset counter - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - - // synchronized startup procedure - while (AT91C_BASE_TC1->TC_CV > 0) {}; // wait until TC1 returned to zero - - // Reset the received frame, frame count and timing info - memset(rx, 0x00, sizeof(rx)); - // frame_count = 0; - response = 0; - overflow = 0; - reader_frame = false; - lastbit = 1; - bSkip = true; - tag_sof = 4; + size_t periods = 0; + uint8_t periods_bytes[4]; + /*bool waiting_for_first_edge = true;*/ + LED_C_ON(); + while (!BUTTON_PRESS() && !data_available()) { - // Watchdog hit + WDT_HIT(); - // Receive frame, watch for at most T0*EOF periods - while (AT91C_BASE_TC1->TC_CV < T0 * HITAG_T_EOF) { - // Check if rising edge in modulation is detected - if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { - // Retrieve the new timing values - int ra = (AT91C_BASE_TC1->TC_RA / T0); - - // Find out if we are dealing with a rising or falling edge - rising_edge = (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME) > 0; - - // Shorter periods will only happen with reader frames - if (!reader_frame && rising_edge && ra < HITAG_T_TAG_CAPTURE_ONE_HALF) { - // Switch from tag to reader capture - LED_C_OFF(); - reader_frame = true; - memset(rx, 0x00, sizeof(rx)); - rxlen = 0; - } - - // Only handle if reader frame and rising edge, or tag frame and falling edge - if (reader_frame != rising_edge) { - overflow += ra; - continue; - } - - // Add the buffered timing values of earlier captured edges which were skipped - ra += overflow; - overflow = 0; - - if (reader_frame) { - LED_B_ON(); - // Capture reader frame - if (ra >= HITAG_T_STOP) { - if (rxlen != 0) { - //DbpString("wierd0?"); - } - // Capture the T0 periods that have passed since last communication or field drop (reset) - response = (ra - HITAG_T_LOW); - } else if (ra >= HITAG_T_1_MIN) { - // '1' bit - rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); - rxlen++; - } else if (ra >= HITAG_T_0_MIN) { - // '0' bit - rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); - rxlen++; - } else { - // Ignore wierd value, is to small to mean anything - } - } else { - LED_C_ON(); - // Capture tag frame (manchester decoding using only falling edges) - if (ra >= HITAG_T_EOF) { - if (rxlen != 0) { - //DbpString("wierd1?"); - } - // Capture the T0 periods that have passed since last communication or field drop (reset) - // We always recieve a 'one' first, which has the falling edge after a half period |-_| - response = ra - HITAG_T_TAG_HALF_PERIOD; - } 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++; - } 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) { - rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); - rxlen++; - } - lastbit = !lastbit; - bSkip = !bSkip; - } else if (ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) { - // Manchester coding example |_-|_-| (00) or |-_|-_| (11) - if (tag_sof) { - // Ignore bits that are transmitted during SOF - tag_sof--; - } else { - // bit is same as last bit - rx[rxlen / 8] |= lastbit << (7 - (rxlen % 8)); - rxlen++; - } - } else { - // Ignore wierd value, is to small to mean anything - } - } + // Receive frame, watch for at most T0*EOF periods + lf_reset_counter(); + + // Wait "infinite" for reader modulation + periods = lf_detect_gap(20000); + + // Test if we detected the first reader modulation edge + if (periods != 0) { + if (logging == false) { + logging = true; + LED_D_ON(); } } + + /*lf_count_edge_periods(10000);*/ + while ((periods = lf_detect_gap(64)) != 0){ + num_to_bytes(periods, 4, periods_bytes); + LogTrace(periods_bytes, 4, 0, 0, NULL, true); + } + +/* // Check if frame was captured if (rxlen > 0) { // frame_count++; @@ -885,38 +1008,14 @@ void SniffHitag(void) { auth_table_len += 8; } } - - // Reset the received frame and response timing info - memset(rx, 0x00, sizeof(rx)); - response = 0; - reader_frame = false; - lastbit = 1; - bSkip = true; - tag_sof = 4; - overflow = 0; - - LED_B_OFF(); - LED_C_OFF(); - } else { - // Save the timer overflow, will be 0 when frame was received - overflow += (AT91C_BASE_TC1->TC_CV / T0); - } - // Reset the frame length - rxlen = 0; - // Reset the timer to restart while-loop that receives frames - AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; +*/ } - LEDsoff(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - set_tracing(false); - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; + lf_finalize(); - // release allocated memory from BigBuff. - BigBuf_free(); StartTicks(); - DbpString("Hitag2 sniffing end, use `lf hitag list` for annotations"); + DbpString("Hitag2 sniffing finish. Use `lf hitag list` for annotations"); } // Hitag2 simulation @@ -1098,24 +1197,61 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) { StopTicks(); - // int frame_count = 0; - int response = 0; + int frame_count = 0; + int response; uint8_t rx[HITAG_FRAME_LEN]; size_t rxlen = 0; uint8_t txbuf[HITAG_FRAME_LEN]; uint8_t *tx = txbuf; size_t txlen = 0; - int lastbit = 1; - bool bSkip; - int reset_sof; - int tag_sof; - int t_wait = HITAG_T_WAIT_MAX; - bool bStop = false; - + int t_wait_1; + int t_wait_2; + size_t tag_size; + bool bStop = false; + + // Raw demodulation/decoding by sampling edge periods + size_t periods = 0; + + // Reset the return status bSuccessful = false; + bCrypto = false; + + // Clean up trace and prepare it for storing frames + set_tracing(true); + clear_trace(); + + DbpString("Starting Hitag reader family"); // Check configuration switch (htf) { + case RHT1F_PLAIN: { + Dbprintf("Read public blocks in plain mode"); + // this part will be unreadable + memset(tag.sectors+2, 0x0, 30); + blocknr = 0; + } break; + + case RHT1F_AUTHENTICATE: { + Dbprintf("Read all blocks in authed mode"); + memcpy(nonce, htd->ht1auth.nonce, 4); + memcpy(key, htd->ht1auth.key, 4); + memcpy(logdata_0, htd->ht1auth.logdata_0, 4); + memcpy(logdata_1, htd->ht1auth.logdata_1, 4); + // TEST + memset(nonce, 0x0, 4); + memset(logdata_1, 0x00, 4); + byte_value = 0; + key_no = htd->ht1auth.key_no; + Dbprintf("Authenticating using key #%d:", key_no); + Dbhexdump(4, key, false); + DbpString("Nonce:"); + Dbhexdump(4, nonce, false); + DbpString("Logdata_0:"); + Dbhexdump(4, logdata_0, false); + DbpString("Logdata_1:"); + Dbhexdump(4, logdata_1, false); + blocknr = 0; + } break; case RHT2F_PASSWORD: { Dbprintf("List identifier in password mode"); memcpy(password, htd->pwd.password, 4); @@ -1136,6 +1272,9 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) { DbpString("Authenticating using key:"); memcpy(key, htd->crypto.key, 6); //HACK; 4 or 6?? I read both in the code. Dbhexdump(6, key, false); + DbpString("Nonce:"); + Dbhexdump(4,nonce,false); + memcpy(nonce,htd->crypto.data,4); blocknr = 0; bCrypto = false; bAuthenticating = false; @@ -1162,71 +1301,45 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) { } } - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - BigBuf_free(); - clear_trace(); - set_tracing(true); - LED_D_ON(); hitag2_init(); + // init as reader + lf_init(true); - // Set fpga in edge detect with reader field, we can modulate as reader now - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_READER_FIELD); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_125); //125kHz - SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - - // Configure output and enable pin that is connected to the FPGA (for modulating) - AT91C_BASE_PIOA->PIO_OER |= GPIO_SSC_DOUT; - AT91C_BASE_PIOA->PIO_PER |= GPIO_SSC_DOUT; - - // Disable modulation at default, which means enable the field - 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 - AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1); - - // PIO_A - BSR - AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; - - // Disable timer during configuration - 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; - - // 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. - AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_ETRGEDG_FALLING | AT91C_TC_ABETRG | AT91C_TC_LDRA_FALLING; - - // Enable and reset counters - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - - // synchronized startup procedure - while (AT91C_BASE_TC0->TC_CV > 0) {}; // wait until TC0 returned to zero - + uint8_t attempt_count = 0; + // Tag specific configuration settings (sof, timings, etc.) - if (htf < 10) { + if (htf < 10){ // hitagS settings - reset_sof = 1; - t_wait = 200; + t_wait_1 = 204; + t_wait_2 = 128; + /*tag_size = 256;*/ + flipped_bit = 0; + tag_size = 8; + DbpString("Configured for hitagS reader"); } else if (htf < 20) { // hitag1 settings - reset_sof = 1; - t_wait = 200; + t_wait_1 = 204; + t_wait_2 = 128; + tag_size = 256; + flipped_bit = 0; + DbpString("Configured for hitag1 reader"); } else if (htf < 30) { // hitag2 settings - reset_sof = 4; - t_wait = HITAG_T_WAIT_2; + t_wait_1 = 206; + t_wait_2 = 90; + tag_size = 48; + DbpString("Configured for hitag2 reader"); } else { Dbprintf("Error, unknown hitag reader type: %d", htf); - goto out; + return; } - uint8_t attempt_count = 0; + + uint8_t tag_modulation; + size_t max_nrzs = 8 * HITAG_FRAME_LEN + 5; + uint8_t nrz_samples[max_nrzs]; + size_t nrzs = 0; while (!bStop && !BUTTON_PRESS() && !data_available()) { @@ -1234,13 +1347,23 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) { // Check if frame was captured and store it if (rxlen > 0) { - // frame_count++; + frame_count++; + response++; LogTrace(rx, nbytes(rxlen), response, response, NULL, false); + //Dbhexdump(nbytes(rxlen), rx, false); } // By default reset the transmission buffer tx = txbuf; switch (htf) { + case RHT1F_PLAIN: { + bStop = !hitag_plain(rx, rxlen, tx, &txlen, false); + } break; + + case RHT1F_AUTHENTICATE: { + bStop = !hitag1_authenticate(rx, rxlen, tx, &txlen); + } break; + case RHT2F_PASSWORD: { bStop = !hitag2_password(rx, rxlen, tx, &txlen, false); break; @@ -1271,113 +1394,153 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) { } } - // Send and store the reader command - // Disable timer 1 with external trigger to avoid triggers during our own modulation - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - - // Wait for HITAG_T_WAIT_2 carrier periods after the last tag bit before transmitting, - // Since the clock counts since the last falling edge, a 'one' means that the - // falling edge occurred halfway the period. with respect to this falling edge, - // we need to wait (T_Wait2 + half_tag_period) when the last was a 'one'. - // All timer values are in terms of T0 units - while (AT91C_BASE_TC0->TC_CV < T0 * (t_wait + (HITAG_T_TAG_HALF_PERIOD * lastbit))); - + // Wait for t_wait_2 carrier periods after the last tag bit before transmitting, + lf_wait_periods(t_wait_2); + // Transmit the reader frame hitag_reader_send_frame(tx, txlen); - // Enable and reset external trigger in timer for capturing future frames - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + // Let the antenna and ADC values settle + // And find the position where edge sampling should start + lf_wait_periods(t_wait_1 - 64); - // Add transmitted frame to total count + // Reset the response time (in number of periods) + response = 0; + + // Keep administration of the first edge detection + bool waiting_for_first_edge = true; + + // Did we detected any modulaiton at all + bool detected_tag_modulation = false; + + // Use the current modulation state as starting point + tag_modulation = lf_get_tag_modulation(); + + // Reset the number of NRZ samples and use edge detection to detect them + nrzs = 0; + while (nrzs < max_nrzs) { + // Get the timing of the next edge in number of wave periods + periods = lf_count_edge_periods(128); + + // Are we dealing with the first incoming edge + if (waiting_for_first_edge) { + // Just break out of loop after an initial time-out (tag is probably not available) + if (periods == 0) break; + // Register the number of periods that have passed + response = t_wait_1-64 + periods; + // Indicate that we have dealt with the first edge + waiting_for_first_edge = false; + // The first edge is always a single NRZ bit, force periods on 16 + periods = 16; + // We have received more than 0 periods, so we have detected a tag response + detected_tag_modulation = true; + } else { + // The function lf_count_edge_periods() returns 0 when a time-out occurs + if (periods == 0) { + Dbprintf("Detected timeout after [%d] nrz samples",nrzs); + break; + } + } + + // Evaluate the number of periods before the next edge + if (periods > 24 && periods <= 64){ + // Detected two sequential equal bits and a modulation switch + // NRZ modulation: (11 => --|) or (11 __|) + nrz_samples[nrzs++] = tag_modulation; + nrz_samples[nrzs++] = tag_modulation; + // Invert tag modulation state + tag_modulation ^= 1; + } else if (periods > 0 && periods <= 24){ + // Detected one bit and a modulation switch + // NRZ modulation: (1 => -|) or (0 _|) + nrz_samples[nrzs++] = tag_modulation; + tag_modulation ^= 1; + } else { + tag_modulation ^= 1; + // The function lf_count_edge_periods() returns > 64 periods, this is not a valid number periods + Dbprintf("Detected unexpected period count: %d", periods); + break; + } + } + + // Store the TX frame, we do this now at this point, to avoid delay in processing + // and to be able to overwrite the first samples with the trace (since they currently + // still use the same memory space) if (txlen > 0) { - // frame_count++; + frame_count++; LogTrace(tx, nbytes(txlen), HITAG_T_WAIT_2, HITAG_T_WAIT_2, NULL, true); } // Reset values for receiving frames memset(rx, 0x00, sizeof(rx)); rxlen = 0; - lastbit = 1; - bSkip = true; - tag_sof = reset_sof; - response = 0; - uint32_t errorCount = 0; - // Receive frame, watch for at most T0*EOF periods - while (AT91C_BASE_TC1->TC_CV < T0 * HITAG_T_WAIT_MAX) { + // If there is no response, just repeat the loop + if (!detected_tag_modulation) continue; - // Check if falling edge in tag modulation is detected - if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { - // Retrieve the new timing values - int ra = (AT91C_BASE_TC1->TC_RA / T0); + // Make sure we always have an even number of samples. This fixes the problem + // of ending the manchester decoding with a zero. See the example below where + // the '|' character is end of modulation + // One at the end: ..._-|_____... + // Zero at the end: ...-_|_____... + // The last modulation change of a zero is not detected, but we should take + // the half period in account, otherwise the demodulator will fail. + if ((nrzs % 2) != 0) { + nrz_samples[nrzs++] = tag_modulation; + } - // Reset timer every frame, we have to capture the last edge for timing - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + LED_B_ON(); - LED_B_ON(); + // decode bitstream + manrawdecode((uint8_t*)nrz_samples, &nrzs, true, 0); - // Capture tag frame (manchester decoding using only falling edges) - if (ra >= HITAG_T_EOF) { - // Capture the T0 periods that have passed since last communication or field drop (reset) - // We always recieve a 'one' first, which has the falling edge after a half period |-_| - response = ra - HITAG_T_TAG_HALF_PERIOD; - } 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++; - } 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) { - rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); - rxlen++; - } - lastbit = !lastbit; - bSkip = !bSkip; - } else if (ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) { - // Manchester coding example |_-|_-| (00) or |-_|-_| (11) - if (tag_sof) { - // Ignore bits that are transmitted during SOF - tag_sof--; - } else { - // bit is same as last bit - rx[rxlen / 8] |= lastbit << (7 - (rxlen % 8)); - rxlen++; - } - } else { - errorCount++; - // Ignore wierd value, is to small to mean anything + // decode frame + + // Verify if the header consists of five consecutive ones + if (nrzs < 5) { + Dbprintf("Detected unexpected number of manchester decoded samples [%d]",nrzs); + break; + } else { + for (size_t i = 0; i < 5; i++){ + if (nrz_samples[i] != 1) { + Dbprintf("Detected incorrect header, the bit [%d] is zero instead of one",i); } } - //if we saw over 100 wierd values break it probably isn't hitag... - if (errorCount > 100) break; - // We can break this loop if we received the last bit from a frame - if (AT91C_BASE_TC1->TC_CV > T0 * HITAG_T_EOF) { - if (rxlen > 0) break; - } } - } + + // Pack the response into a byte array + for (size_t i = 5; i < 37; i++){ + uint8_t bit = nrz_samples[i]; + rx[rxlen / 8] |= bit << (7 - (rxlen % 8)); + rxlen++; + } + + // Check if frame was captured and store it + if (rxlen > 0) { + frame_count++; + if (bCollision){ + // AC decoding hack + fix_ac_decoding(rx, 64); + rxlen = 32; + } + + LogTrace(rx, rxlen, response, 0, NULL, false); + //Dbhexdump(rxlen, rx, false); + } + } out: - LEDsoff(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - set_tracing(false); - - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; + lf_finalize(); + Dbprintf("frame received: %u", frame_count); // release allocated memory from BigBuff. BigBuf_free(); StartTicks(); if (bSuccessful) - reply_old(CMD_ACK, bSuccessful, 0, 0, (uint8_t *)tag.sectors, 48); + reply_old(CMD_ACK, bSuccessful, 0, 0, (uint8_t *)tag.sectors, tag_size); else - reply_old(CMD_ACK, bSuccessful, 0, 0, 0, 0); + reply_mix(CMD_ACK, bSuccessful, 0, 0, 0, 0); } void WriterHitag(hitag_function htf, hitag_data *htd, int page) { diff --git a/armsrc/hitag2.h b/armsrc/hitag2.h index 9e0fb84e6..79ada4ddf 100644 --- a/armsrc/hitag2.h +++ b/armsrc/hitag2.h @@ -14,7 +14,7 @@ #include "common.h" #include "hitag.h" -void SniffHitag(void); +void SniffHitag(uint32_t type); void SimulateHitagTag(bool tag_mem_supplied, uint8_t *data); void ReaderHitag(hitag_function htf, hitag_data *htd); void WriterHitag(hitag_function htf, hitag_data *htd, int page); diff --git a/armsrc/lfadc.c b/armsrc/lfadc.c index d59fae07d..09ee5a2a6 100644 --- a/armsrc/lfadc.c +++ b/armsrc/lfadc.c @@ -168,7 +168,9 @@ void lf_init(bool reader) { AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // Prepare data trace - if (logging) initSampleBuffer(NULL); + uint32_t bufsize = 20000; + + if (logging) initSampleBuffer(&bufsize); } diff --git a/armsrc/lfsampling.c b/armsrc/lfsampling.c index 3378a9f94..8b0c14d94 100644 --- a/armsrc/lfsampling.c +++ b/armsrc/lfsampling.c @@ -106,17 +106,23 @@ sampling_t samples = {0, 0, 0, 0}; void initSampleBuffer(uint32_t *sample_size) { + BigBuf_free(); + BigBuf_Clear_ext(false); + if (sample_size == NULL || *sample_size == 0) { *sample_size = BigBuf_max_traceLen(); + + data.buffer = BigBuf_get_addr(); + + memset(data.buffer, 0, *sample_size); } else { *sample_size = MIN(*sample_size, BigBuf_max_traceLen()); + + data.buffer = BigBuf_malloc(*sample_size); + + memset(data.buffer, 0, *sample_size); } - // use a bitstream to handle the output - data.buffer = BigBuf_get_addr(); - - memset(data.buffer, 0, *sample_size); - // samples.dec_counter = 0; samples.sum = 0; diff --git a/client/cmdlfhitag.c b/client/cmdlfhitag.c index 40e909024..625b0bef0 100644 --- a/client/cmdlfhitag.c +++ b/client/cmdlfhitag.c @@ -485,8 +485,9 @@ static int CmdLFHitagInfo(const char *Cmd) { if (getHitagUid(&uid) == false) return 1; - PrintAndLogEx(SUCCESS, "UID: %08X", uid); + PrintAndLogEx(SUCCESS, "UID: " _YELLOW_("%08X"), uid); + return PM3_SUCCESS; // how to detemine Hitag types? // read block3, get configuration byte. PrintAndLogEx(FAILED, _RED_("TODO: This is a hardcoded example!")); @@ -497,7 +498,7 @@ static int CmdLFHitagInfo(const char *Cmd) { //printHitagConfiguration( 0x02 ); //printHitagConfiguration( 0x00 ); //printHitagConfiguration( 0x04 ); - return 0; + return PM3_SUCCESS; } // TODO: iceman @@ -564,7 +565,7 @@ static int CmdLFHitagReader(const char *Cmd) { uint32_t id = bytes_to_num(resp.data.asBytes, 4); - PrintAndLogEx(SUCCESS, "Valid Hitag2 tag found - UID: %08x", id); + PrintAndLogEx(SUCCESS, "Valid Hitag2 tag found - UID: " _YELLOW_("%08x"), id); if (htf != RHT2F_UID_ONLY) { PrintAndLogEx(SUCCESS, "Dumping tag memory..."); diff --git a/include/hitag.h b/include/hitag.h index 9df93fcf7..b8555600b 100644 --- a/include/hitag.h +++ b/include/hitag.h @@ -21,6 +21,8 @@ typedef enum { RHTSF_KEY = 02, WHTSF_CHALLENGE = 03, WHTSF_KEY = 04, + RHT1F_PLAIN = 11, + RHT1F_AUTHENTICATE = 12, RHT2F_PASSWORD = 21, RHT2F_AUTHENTICATE = 22, RHT2F_CRYPTO = 23, @@ -44,8 +46,17 @@ typedef struct { uint8_t data[4]; } PACKED rht2d_crypto; +typedef struct { + bool key_no; + uint8_t logdata_0[4]; + uint8_t logdata_1[4]; + uint8_t nonce[4]; + uint8_t key[4]; +} PACKED rht1d_authenticate; + typedef union { rht2d_password pwd; + rht1d_authenticate ht1auth; rht2d_authenticate auth; rht2d_crypto crypto; } hitag_data;