From ace5d63ff98ce768ba788da5058c2114268a1864 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 4 Sep 2026 13:20:29 +0200 Subject: [PATCH] hitag2: fix simulation against genuine readers, add restore, fix info Simulation now completes the full exchange with a genuine Paxton reader in password mode, and crypto mode read/write passes Proxmark-to-Proxmark. Firmware: - SOF was one bit period short. The lead-in that compensated for the lost head half bit was removed and nothing replaced it, so readers rejected every answer with a second START_AUTH. Default is now 6. - The edge-detect threshold was latched before being measured, so the value chosen depended on whether the Proxmark was in a field when sim started. It is now measured on field entry and re-armed when the reader leaves. - The percentile walk latched on run-scoped variables, so one attempt made outside a field poisoned every later one. - Field loss was detected from TIMESTAMP, which is free-running MCU time and never stalls. Detect it from receive silence instead. - Frames of a length the protocol does not have no longer reach the state machine; our own modulation tail was resetting the session and breaking every write. - A dropped edge merges two or three reader bit periods into one gap. Those bits were discarded; they are now recovered by decomposition, which is what made crypto mode work (AUTH decode 15% -> 100%). - Threshold selection is limited to 20 and 32 and settles in under 25 ms. Client: - lf hitag info printed a hardcoded 0x06 and reported 'Password mode' for every tag. It now reads page 3, takes -k (4 bytes password, 6 bytes crypto), and says so when the config cannot be read. - lf hitag restore: writes a dump back in dependency order - user pages, then key material, then config last - validates the config byte, and prints the credential the tag will require afterwards. - lf hitag crack2 now reports why it failed instead of a bare 'fail'. - trace list: bit count moved to its own column, relative mode shows a Frame Delay Time row rather than renaming Start/End, --frame and -r rejected together. --- CHANGELOG.md | 1 + armsrc/appmain.c | 30 +- armsrc/hitag2.c | 3137 ++++++++++++++++++++++++------ armsrc/hitag2.h | 4 +- armsrc/hitag2_crack.c | 19 + armsrc/hitagS.c | 33 +- armsrc/hitagS.h | 2 +- armsrc/hitag_common.c | 693 ++++++- armsrc/hitag_common.h | 46 + armsrc/hitagu.c | 37 +- armsrc/hitagu.h | 2 +- armsrc/lfadc.c | 41 +- client/src/cmdlfhitag.c | 477 ++++- client/src/cmdtrace.c | 30 +- common/lfdemod.c | 9 +- common_arm/fpga/fpga_apis.h | 16 + common_arm/ticks/ticks_apis.h | 20 +- common_arm/ticks/ticks_hw_at32.c | 13 +- common_arm/ticks/ticks_hw_at91.c | 78 +- fpga/fpga_pm3_lf.bit | Bin 42172 -> 42172 bytes fpga/fpga_pm3_top.v | 5 + fpga/lf_edge_detect.v | 159 +- fpga/lo_adc.v | 7 +- fpga/lo_edge_detect.v | 82 +- fpga/min_max_tracker.v | 8 + include/pm3_cmd.h | 5 +- tools/pm3_online_tests.sh | 78 +- 27 files changed, 4309 insertions(+), 723 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b01d8358..a2fe44681 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] +- Changed `lf hitag` - refactoring hitag2 operations and now they work much better (@iceman1001) - Fixed `lf hitag list` - now prints in same style like the rest (@iceman1001) - Changed pathing - client now supports `~/` tilde sign in paths (@iceman1001) - Added `hf_legic_rdv4` - Standalone mode for managing 7 persistent legic dumps (@digitalhoax) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index ab94d1607..c25fe4b81 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1606,13 +1606,30 @@ static void PacketReceived(PacketCommandNG *packet) { #ifdef WITH_HITAG case CMD_LF_HITAG_SNIFF: { // Eavesdrop Hitag tag, args = type - SniffHitag2(true); + // threshold comes from `lf hitag sniff -t`, 0 = the slope default + uint8_t sniff_thr = (packet->length >= 1) ? packet->data.asBytes[0] : 0; + SniffHitag2(true, sniff_thr); //hitag_sniff(); reply_ng(CMD_LF_HITAG_SNIFF, PM3_SUCCESS, NULL, 0); break; } - case CMD_LF_HITAG_SIMULATE: { // Simulate Hitag tag, args = memory content - SimulateHitag2(true); + case CMD_LF_HITAG_SIMULATE: { + // The tag content comes from emulator memory, so the payload only + // carries the edge detect threshold. Older clients send nothing. + uint8_t threshold = 127; + uint16_t twait = 0; + uint8_t flags = 0; + uint8_t sof = 0; + uint8_t duty = 0; + if (packet->length >= sizeof(hitag_sim_t)) { + hitag_sim_t *payload = (hitag_sim_t *)packet->data.asBytes; + threshold = (uint8_t)payload->threshold; + twait = payload->twait; + flags = payload->flags; + sof = payload->sof; + duty = payload->duty; + } + SimulateHitag2(threshold, twait, flags, sof, duty, true); break; } case CMD_LF_HITAG2_CRACK: { @@ -1646,7 +1663,7 @@ static void PacketReceived(PacketCommandNG *packet) { break; } hitag_sim_t *payload = (hitag_sim_t *)packet->data.asBytes; - hts_simulate((bool)payload->tag_mem_supplied, payload->threshold, payload->data, true); + hts_simulate((int8_t)payload->threshold, true); break; } case CMD_LF_HITAGS_TEST_TRACES: { // Tests every challenge within the given file @@ -1695,7 +1712,7 @@ static void PacketReceived(PacketCommandNG *packet) { break; } hitag_sim_t *payload = (hitag_sim_t *)packet->data.asBytes; - htu_simulate((bool)payload->tag_mem_supplied, payload->threshold, payload->data, true); + htu_simulate((int8_t)payload->threshold, true); break; } case CMD_LF_HITAGU_UID: { @@ -2176,8 +2193,7 @@ static void PacketReceived(PacketCommandNG *packet) { break; } case CMD_HF_ISO14443A_SNIFF: { - SniffIso14443a(packet->data.asBytes[0]); - reply_ng(CMD_HF_ISO14443A_SNIFF, PM3_SUCCESS, NULL, 0); + reply_ng(CMD_HF_ISO14443A_SNIFF, SniffIso14443a(packet->data.asBytes[0]), NULL, 0); break; } case CMD_HF_HIDCONFIG_SNIFF: { diff --git a/armsrc/hitag2.c b/armsrc/hitag2.c index 038cb3a4d..8114e1742 100644 --- a/armsrc/hitag2.c +++ b/armsrc/hitag2.c @@ -26,6 +26,7 @@ #include "dbprint.h" #include "util.h" #include "lfadc.h" +#include "hitag_common.h" #include "lfsampling.h" #include "lfdemod.h" #include "commonutil.h" @@ -41,6 +42,26 @@ static bool bCrypto; // Is in auth stage static bool bAuthenticating; + +// How many times the reader re-sends the password when the tag's answer to it is +// not heard. See the case 0 handler in hitag2_password(). +// Public Mode C inserts a Program Mode Check phase between each 128 bit block. +// HT2 datasheet rev 2.1 section 4.2.4 gives t_PMC as 384 T0 typical, out of a +// 9120 T0 total against 8192 for the data. +#define HITAG2_T_PMC 384 + +#define HITAG2_PWD_RETRIES 3 + +// How many times a single block read is retried in crypto mode before the block +// is given up on and zero filled. Password mode has had this since the reader +// fixes went in; crypto mode skipped straight to the fill, so one marginal block +// - the receive still loses an edge now and then - put 00000000 in the dump and +// moved on. Measured against the simulator: crypto reads came back with all of +// blocks 0..7 correct except a single zeroed one, and which block it was moved +// between runs, so nothing about the block itself was wrong. +#define HITAG2_CRYPTO_RETRIES 3 +static uint8_t pwd_retries; +static uint8_t crypto_retries; // Successful password auth static bool bSelecting; static bool bCollision; @@ -55,25 +76,112 @@ Public Mode B : 0x00 - 0000 0000 Public Mode C : 0x04 - 0000 0100 */ +// Content presented by a bare `lf hitag sim` when nothing has been loaded with +// `lf hitag eload`. Kept separate from `tag` because `tag` is mutated while a +// simulation runs - reader writes land in tag.sectors - so it cannot serve as +// its own pristine default on a second run. +static const uint8_t hitag2_demo_sectors[12][4] = { + [0] = { 0x02, 0x4e, 0x02, 0x20}, // UID | UID + [1] = { 0x4d, 0x49, 0x4b, 0x52}, // Password RWD | 32 bit LSB key + [2] = { 0x20, 0xf0, 0x4f, 0x4e}, // Reserved | 16 bit MSB key, 16 bit reserved + [3] = { 0x06, 0xaa, 0x48, 0x54}, // Configuration, password TAG | Configuration, password TAG + [4] = { 0x46, 0x5f, 0x4f, 0x4b}, // Data: F_OK + [5] = { 0x55, 0x55, 0x55, 0x55}, // Data: UUUU + [6] = { 0xaa, 0xaa, 0xaa, 0xaa}, // Data: .... + [7] = { 0x55, 0x55, 0x55, 0x55}, // Data: UUUU + [8] = { 0x00, 0x00, 0x00, 0x00}, // RSK Low + [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 HITAG 1/HITAG S public data +}; + static hitag2_t tag = { .state = TAG_STATE_RESET, - .sectors = { // Password mode: | Crypto mode: - [0] = { 0x02, 0x4e, 0x02, 0x20}, // UID | UID - [1] = { 0x4d, 0x49, 0x4b, 0x52}, // Password RWD | 32 bit LSB key - [2] = { 0x20, 0xf0, 0x4f, 0x4e}, // Reserved | 16 bit MSB key, 16 bit reserved - [3] = { 0x06, 0xaa, 0x48, 0x54}, // Configuration, password TAG | Configuration, password TAG - [4] = { 0x46, 0x5f, 0x4f, 0x4b}, // Data: F_OK - [5] = { 0x55, 0x55, 0x55, 0x55}, // Data: UUUU - [6] = { 0xaa, 0xaa, 0xaa, 0xaa}, // Data: .... - [7] = { 0x55, 0x55, 0x55, 0x55}, // Data: UUUU - [8] = { 0x00, 0x00, 0x00, 0x00}, // RSK Low - [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 HITAG 1/HITAG S public data - }, }; +// see the START_AUTH case in hitag2_handle_reader_command(): a real transponder +// answers every second START_AUTH and treats the one in between as a reset. +// +// Which of the two we answer matters. A Paxton reader was captured sending +// START_AUTH in pairs 1750 T0 apart, with ~17000..19000 T0 between pairs, and +// the datasheet is explicit that it is the SECOND that resets the state machine +// - so the tag answers the first of a pair and the reader listens after it. +// Carrying the alternation across the gap between pairs locks onto the wrong +// element of every pair: we answered the reset instead of the request. +// +// This threshold therefore has to sit above the intra-pair gap and below the +// inter-pair gap. An earlier value of 100000 covered both and was wrong. +#define HITAG2_T_SESSION_IDLE 5000 + +// Step for the FPGA's slope edge detector, in ADC counts over its 32 us +// baseline. See lf_edge_detect.v for the sweep behind this value and for why it +// is not scaled to the tracked span. -t overrides it. +// Opening value for the auto-tune sweep, and what an explicit -t 0 settles on. +// The sensitive end of the measured working band - see thr_cand[]. +#define HITAG2_SLOPE_THRESHOLD 20 + +// What the simulator opens on, and the first candidate its sweep scores. +// +// The sniffer keeps 20 above; only a listener, it is not judged on whether a +// reader accepted an answer, and 20 is what its capture was verified at. The +// simulator is judged exactly that way, and 20 loses on both rigs measured: 0 of +// 8 pages against a Proxmark reader, and 59% legal framing against a Paxton. It +// stays in thr_cand[] as the fallback for a rig neither represents. +// +// Keep this equal to thr_cand[0]. Set independently once, and the simulator +// opened on 20 while the sweep believed it was scoring 32 - it read 0 of 8 pages +// on a rig that had just read 8 of 8. +#define HITAG2_SIM_THRESHOLD 32 + +// Frames scored per candidate by the threshold sweep. Large enough that one +// stray frame does not decide a candidate, small enough that walking the whole +// list is quick - eleven candidates at this window is a couple of seconds of +// ordinary reader traffic. +// Commands scored per candidate. Too small and a marginal threshold passes on a +// lucky run - at four, a value that managed 0 reads of 3 produced a flawless +// window and locked. Too large and the sweep outlives a reader that gives up +// after a handful of attempts. +// Modulation depth at or above which the rig is the strongly coupled kind and +// wants 32; below it, 20. Fitted on 44 runs across both rigs - see the decision +// site for the distribution and the two samples that cross it. +#define HITAG2_SPAN_STRONG 210 + +// Silence, in T0, after which the reader counts as gone and the threshold +// measurement re-arms. 125000 T0 is one second at 125 kHz - about six and a half +// Paxton poll cycles, so it cannot trip on a gap inside a live exchange. +#define HITAG2_FIELD_GONE_T0 125000 + +// Blanking window after our own answer, in T0, before the edge detector is +// re-armed. Covers our coil release; t_WAIT2 (HT2 datasheet 3.5) puts the +// reader's earliest real command at 90 T0, so this must stay under that. +// +// 32 was enough while the release transient landed within a few T0, but it is +// not a fixed property of the firmware - it moves with the coupling. After the +// rig was re-seated the echo arrived ~80 T0 after transmission instead, escaped +// the guard, opened a frame, and the 80 T0 EOF timeout that closed it ran past +// the reader's next command at +190 T0. The exchange died there: Paxton sent +// its AUTH, we were not listening, and it fell back to re-polling. +// +// 84 covers the observed echo with the whole t_WAIT2 window still ahead of it. +#define HITAG2_TX_TAIL_GUARD 32 + +#define HITAG2_THR_WINDOW 8 + + + +// flags bit1: answer every START_AUTH instead of every second one +static bool s_no_alternation = false; + +// flags bit5: which one of a START_AUTH pair to answer. A reader that polls in +// pairs gets an answer to the first by default; setting this answers the second. +// HT2 datasheet rev 2.1 section 4.2.2 says a repeated START_AUTH resets the state +// machine and the transponder responds to every second one, so which element of +// the pair the reader is actually listening after is worth being able to flip. +static bool s_alt_phase = false; +static bool start_auth_answered = false; +static uint32_t last_start_auth = 0; + static enum { WRITE_STATE_START = 0x0, WRITE_STATE_PAGENUM_WRITTEN, @@ -118,11 +226,66 @@ static void hitag2_init(void) { #define HITAG_FRAME_LEN 20 #define HITAG_FRAME_BIT_COUNT (8 * HITAG_FRAME_LEN) #define HITAG_T_STOP 36 /* T_EOF should be > 36 */ +// hitag_common.h defines these for Hitag S/u; this file keeps its own values, +// the working reader and writer paths below are timed against them +#undef HITAG_T_LOW #define HITAG_T_LOW 6 /* T_LOW should be 4..10 */ +#undef HITAG_T_0_MIN #define HITAG_T_0_MIN 15 /* T[0] should be 18..22 */ #define HITAG_T_0 20 /* T[0] should be 18..22 */ +#undef HITAG_T_1_MIN #define HITAG_T_1_MIN 25 /* T[1] should be 26..30 */ +#undef HITAG_T_1 #define HITAG_T_1 30 /* T[1] should be 26..30 */ +/* HT2 datasheet rev 2.1, sections 3.5 and 4.2.2: t_WAIT1, the transponder's + receive-to-transmit turnaround, is 199..206 T0 measured from the reader's + LAST BIT. Our reference is different: hitag_tag_receive_frame_ex() returns + HITAG_T_EOF after the last FALLING edge, and in BPLM that edge sits at the + start of the final bit, one t_low + T[0/1] (roughly 26..40 T0) before the bit + actually ends. Answering 202 from the falling edge therefore lands about a + bit-period early; a genuine fob sniffed on this rig answers noticeably later. + Add a bit period so the answer lands inside the real window. */ +/* t_WAIT1, HT2 datasheet 3.5, is 199..206 T0 measured from the END of the + reader's command. Our reference is the reader's last FALLING edge, which in + BPLM sits at the start of the final bit: the rest of that bit (T_LOW 6 plus + T[0]-T_LOW = 14) and the T_STOP 36 that closes the frame still have to run, + about 56 T0 in total. Counting the datasheet window from the falling edge + therefore answers a bit period and a half too early. + + That matters because the reader is not merely indifferent to an early reply, + it is not listening yet: ReaderHitag() waits t_wait_1 - t_wait_1_guard + (199 - 8 = 191 T0) after its command before sampling, then gives + lf_count_edge_periods(128) to see a first edge. The usable window is + 191..319 T0 after the command ends, so aim for the middle of it. */ +#define HITAG2_T_CMD_TAIL 56 + +/* Measured, against a genuine Paxton fob talking to a genuine Paxton reader on + this rig, with the Proxmark sandwiched between them listening. The fob's first + answer edge lands 227 T0 after the reader's last edge, three independent times + in the same capture and stable across cycles: + + frame last edge fob answers delta + START_AUTH 8767 8994 227 + password 11116 11343 227 + READ PAGE(4) 12972 13201 229 + + (Each logged frame end is last_edge + HITAG_T_EOF, so the 80 is subtracted.) + + The reasoning below arrived at 202 + 56 = 258, which is 31 T0 late. It is not + wrong about the tail - the datasheet's 199..206 is measured from the end of the + frame, and the frame does not end until t_stop has run - it just aimed at the + middle of OUR reader's window (191..319) rather than at what a real tag does. + 227 sits comfortably inside that window too, so this does not cost us the + Proxmark to Proxmark path. */ +#define HITAG2_T_WAIT_RESP 227 + +// runtime override for HITAG2_T_WAIT_RESP, so the turnaround can be swept +// against a real reader without reflashing. 0 keeps the default. +static uint16_t s_t_wait_resp = HITAG2_T_WAIT_RESP; +/* hitag_tag_send_frame() holds the line high for this many periods before the + SOF (the "STD + ADV" pause), so the wait below has to be shortened by it */ +#define HITAG2_T_SEND_LEADIN 20 +#undef HITAG_T_EOF #define HITAG_T_EOF 80 /* T_EOF should be > 36 and must be larger than HITAG_T_TAG_CAPTURE_FOUR_HALF */ #define HITAG_T_WAIT_1_MIN 199 /* T_wresp should be 199..206 */ #define HITAG_T_WAIT_2_MIN 90 /* T_wait2 should be at least 90 */ @@ -161,6 +324,57 @@ static void hitag2_handle_reader_command(uint8_t *rx, const size_t rxlen, uint8_ // Reset the transmission frame length *txlen = 0; + // Any other command ends the START_AUTH session. + // + // The datasheet's rule is that "the instruction START_AUTH cannot be + // repeated. A second START_AUTH resets the statemachine", so the transponder + // answers every second one - but that is about a START_AUTH immediately + // following another, not one arriving after the reader has said something + // else in between. Once a real command has gone by, the next START_AUTH + // opens a fresh session and has to be answered. + // + // Measured against a genuine Paxton reader, sniffed with a third Proxmark: + // + // Rdr 5: 18 START AUTH + // Tag 32: CE 12 99 11 UID + // Rdr 64: ... AUTH Nr/Ar crypto probe + // Rdr 5: 18 START AUTH <- fob ANSWERS this one + // Tag 32: CE 12 99 11 UID + // Rdr 32: BD F5 E8 46 PWD <- and now the password + // + // That second START_AUTH lands about 3500 T0 after the first, inside + // HITAG2_T_SESSION_IDLE, so without this reset it counts as the repeat and we + // stay silent. The reader then never reaches the password step at all, which + // is exactly what it did with this simulator all day: START_AUTH, our UID, + // crypto probe, and round again, dozens of times, never once a password. + // A frame of a length the protocol does not have is not a command at all. + // + // A Hitag 2 reader frame is 5, 10, 32 or 64 bits. Anything else fell through + // the switch below and did nothing - except that it still passed through the + // session reset that follows, and that is what broke writing. + // + // Measured on two Proxmarks, tracing the simulator through `lf hitag wrbl`: + // the exchange runs correctly as far as the password, and then + // + // Rdr 5: 18 START AUTH + // Tag 32: CE 12 99 11 UID + // Rdr 32: BD F5 E8 46 PWD + // Tag 32: 06 F9 07 C2 configuration page + // Rdr 1: 00 one T0 after our answer ends + // + // That one bit frame is our own modulation tail coming back through the edge + // detector, not the reader - it starts a single T0 after our transmission + // ends, where a real command cannot. Dispatched here it rewound the state + // machine, so the WRITE PAGE that genuinely followed found the session reset + // and every write failed. Discard it before it can do that. + if ((rxlen != 5) && (rxlen != 10) && (rxlen != 32) && (rxlen != 64)) { + return; + } + + if (rxlen != 5) { + start_auth_answered = false; + } + // Try to find out which command was send by selecting on length (in bits) switch (rxlen) { // Received 11000 from the reader, request for UID, send UID @@ -170,6 +384,55 @@ static void hitag2_handle_reader_command(uint8_t *rx, const size_t rxlen, uint8_ // Unknown frame ? return; } + + // HT2 datasheet rev 2.1 section 4.2.2: "The instruction START_AUTH + // cannot be repeated. A second START_AUTH resets the statemachine. + // Therefore the transponder only responds to every second + // START_AUTH." Answering every one presents a reader with a reply + // where a real tag stays silent. + // + // This gate was once removed on the strength of a sniffer capture + // that appeared to show a genuine fob answering every START_AUTH. + // That capture was bogus: the tag side decoder fabricates rows, and + // a control sniff with no card and no simulator present produced the + // same 1231 "Tag" rows. With no real counter-evidence the datasheet + // stands. + // + // TIMESTAMP is free running wall time scaled to carrier periods - it + // does NOT stall when the field goes, whatever this comment used to + // claim - so a gap larger than the idle threshold means a fresh + // session rather than the repeat that resets the state machine. + // That is all this needs; only the elapsed time matters here. + uint32_t now = TIMESTAMP; + if ((now - last_start_auth) > HITAG2_T_SESSION_IDLE) { + // A fresh session. Starting it as "already answered" skips the + // first START_AUTH of the pair and answers the second instead. + start_auth_answered = s_alt_phase; + } + last_start_auth = now; + + if (s_no_alternation) { + start_auth_answered = false; + } + + if (start_auth_answered) { + start_auth_answered = false; + tag.crypto_active = 0; + tag.state = TAG_STATE_RESET; + return; + } + start_auth_answered = true; + + // START_AUTH resets the state machine (HT2 datasheet 4.2.2), and that + // has to include a pending write. A garbled reader frame decoding as + // WRITE PAGE leaves tag.state at TAG_STATE_WRITING, and the next 32 bit + // frame - the reader's password - is then swallowed as write data and + // stored over emulator memory instead of being checked. Seen on this + // rig: the reader's follow up commands arrived as 8, 9 and 11 bit + // fragments, one of them annotated WRITE PAGE (255), and every + // exchange after it failed to authenticate. + tag.state = TAG_STATE_RESET; + *txlen = 32; memcpy(tx, tag.sectors[0], 4); tag.crypto_active = 0; @@ -224,10 +487,37 @@ static void hitag2_handle_reader_command(uint8_t *rx, const size_t rxlen, uint8_ if (tag.state == TAG_STATE_WRITING) { // These are the sector contents to be written. We don't have to do anything else. memcpy(tag.sectors[tag.active_sector], rx, nbytes(rxlen)); + + // Mirror the write into emulator memory. + // + // Simulation serves `tag.sectors`, which is loaded from emulator + // memory once at start up and never written back, so a reader + // could write a page, read it back correctly over the air, and + // `lf hitag eview` would still show the old content - measured on + // this rig, page 4 read back as 11223344 while eview reported the + // loaded B6447420. `lf hitag esave` would then have written the + // pre-write dump. Only the tag's own pages: sectors 8..11 hold + // crypto state, not tag content. + if (tag.active_sector < HITAG2_MAX_BLOCKS) { + uint8_t *emw = BigBuf_get_EM_addr(); + if (emw != NULL) { + memcpy(emw + (tag.active_sector * HITAG_BLOCK_SIZE), rx, HITAG_BLOCK_SIZE); + } + } + tag.state = TAG_STATE_RESET; return; } else { - // Received RWD password, respond with configuration and our password + // Received RWD password, respond with configuration and our password. + // + // Password mode only. In crypto mode a 32 bit frame at this point + // is an enciphered command, not a plaintext password, and checking + // it against page 1 would both fail and answer the wrong thing. + if ((tag.sectors[3][0] & 0x08) != 0) { + DBG DbpString("plaintext password to a crypto mode tag, ignoring"); + return; + } + if (memcmp(rx, tag.sectors[1], 4) != 0) { DBG DbpString("Reader password is wrong"); return; @@ -240,6 +530,22 @@ static void hitag2_handle_reader_command(uint8_t *rx, const size_t rxlen, uint8_ // Received RWD authentication challenge and response case 64: { + // Only a crypto mode tag answers this. + // + // Bit 3 of the configuration byte in page 3 selects the mode - 0x06 is + // password, 0x0E is crypto - and this used to run the cipher regardless + // of what the loaded tag actually says it is. A password mode tag has + // no business authenticating a crypto challenge, and a real one does + // not: measured against a genuine Paxton reader, it opens with a 64 bit + // Nr/Ar, the password mode fob stays completely silent, and only then + // does the reader fall back and send the 32 bit password. Simulating + // the tag means following the config block that was loaded, not + // answering whatever arrives. + if ((tag.sectors[3][0] & 0x08) == 0) { + DBG DbpString("crypto auth to a password mode tag, ignoring"); + return; + } + // Store the authentication attempt if (auth_table_len + 8 <= AUTH_TABLE_LENGTH) { memcpy(auth_table + auth_table_len, rx, 8); @@ -661,6 +967,41 @@ static bool hitag2_password(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t if (bPwd && (bAuthenticating == false) && write) { + // A frame we did not hear is not a failed write. + // + // Every call landed straight in hitag2_write_page(), rxlen == 0 included, + // and that reads a missing answer as a protocol error: state + // WRITE_STATE_PAGENUM_WRITTEN wants exactly 10 bits back, so it declares + // "page number was not received correctly" and the whole write is + // abandoned. The read path has retried a missed answer for a while now - + // this one never did. + // + // Measured against a simulator whose own trace shows it answering + // correctly: three writes, two lost a single frame to one merged interval + // in the tag's answer - WRXSTAT undecodable=1, the frame arriving as 35 + // bits where 36 is the minimum - and both failed on that one frame. The + // third had a clean run and succeeded. Re-sending the outstanding command + // costs one exchange and gives up nothing, exactly as on the read side. + if ((rxlen == 0) && (pwd_retries < HITAG2_PWD_RETRIES)) { + + pwd_retries++; + + if (writestate == WRITE_STATE_PAGENUM_WRITTEN) { + // still waiting for the page number echo - ask again + *txlen = 10; + tx[0] = HITAG2_WRITE_PAGE | (blocknr << 3) | ((blocknr ^ 7) >> 2); + tx[1] = ((blocknr ^ 7) << 6); + return true; + } + + if (writestate == WRITE_STATE_PROG) { + // the data went out and the tag answers nothing when it programs, + // so silence here is success, not a lost frame + bSuccessful = true; + return false; + } + } + SpinDelay(2); if (hitag2_write_page(rx, rxlen, tx, txlen) == false) { return false; @@ -671,8 +1012,41 @@ static bool hitag2_password(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t switch (rxlen) { // No answer, try to resurrect case 0: { - // Stop if there is no answer (after sending password) if (bPwd) { + + // Missing the tag's answer to the password is not proof that + // the password was wrong - it is usually just a frame we did + // not hear. The reader has to listen 174 T0 after its own + // 890 T0 transmission, and its front end is still recovering + // from that; measured against a simulator whose trace shows it + // answering correctly, this is the frame the reader misses + // while the shorter exchanges around it decode fine. + // + // The contents of that answer are discarded at this stage + // anyway - see the bAuthenticating branch below - so retrying + // the password costs one exchange and gives up nothing. Only + // give up once the retries are spent. + if (bAuthenticating && (pwd_retries < HITAG2_PWD_RETRIES)) { + pwd_retries++; + memcpy(tx, password, 4); + *txlen = 32; + break; + } + + // Past authentication the same applies to a page read: one + // answer we did not hear is not a reason to abandon the whole + // dump. Re-send the READ PAGE for the block we are on. + // Measured against a simulator that answers every command + // correctly, a single undecodable frame in eight page reads + // ended the read with one block returned. + if ((bAuthenticating == false) && (pwd_retries < HITAG2_PWD_RETRIES)) { + pwd_retries++; + *txlen = 10; + tx[0] = HITAG2_READ_PAGE | (blocknr << 3) | ((blocknr ^ 7) >> 2); + tx[1] = ((blocknr ^ 7) << 6); + break; + } + DBG DbpString("Password failed!"); return false; } @@ -706,6 +1080,7 @@ static bool hitag2_password(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t else { memcpy(tag.sectors[blocknr], rx, 4); blocknr++; + pwd_retries = 0; } if (blocknr > 7) { @@ -757,8 +1132,22 @@ static bool hitag2_crypto(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t * if (bAuthenticating) { DBG DbpString("Authentication failed!"); return false; + } else if (crypto_retries < HITAG2_CRYPTO_RETRIES) { + + // Try this block again rather than giving up on it. + // + // Re-authenticating is what makes the retry safe: the + // cipher stream has advanced by our unanswered command, + // so simply re-sending it would decrypt against the wrong + // keystream. Dropping bCrypto restarts from START_AUTH, + // which resynchronises both sides, and blocknr is left + // where it is so the same page is asked for again. + crypto_retries++; + bCrypto = false; + } else { // Failed reading a block, could be (read/write) locked, skip block and re-authenticate + crypto_retries = 0; if (blocknr == 1) { // Write the low part of the key in memory memcpy(tag.sectors[1], key + 2, 4); @@ -832,6 +1221,7 @@ static bool hitag2_crypto(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t * // Store the received block memcpy(tag.sectors[blocknr], rx, 4); blocknr++; + crypto_retries = 0; } if (blocknr > 7) { @@ -1016,14 +1406,128 @@ void hitag_sniff(void) { // T1 26-32 fc (total time ONE) // Tstop 36 > fc (high field stop limit) // Tlow 4-10 fc (reader field low time) -void SniffHitag2(bool ledcontrol) { +// One captured falling-edge interval, decoded into the frame in progress. +// +// Factored out of SniffHitag2()'s capture loop so the first edge of a frame - +// which has to be held until the following rising edge says whether this is the +// reader talking or the tag - can be dispatched through exactly the same code +// once it is classified, rather than through a second copy that would drift. +// Returns true when this edge closed the frame in progress. +static bool hitag2_sniff_bit(int rb, bool reader_frame, uint8_t *rx, size_t sizeofrx, + size_t *rxlen, int *lastbit, bool *bSkip, int *tag_sof) { + + if ((*rxlen / 8) >= sizeofrx) { + return false; + } + + if (reader_frame) { + + // Capture reader frame + if (rb >= HITAG_T_STOP) { + // Capture the T0 periods that have passed since last communication or field drop (reset) + // A gap this long is a frame boundary, but the frame is left + // to close on the EOF timeout instead of ending here. Ending + // it here does stop adjacent frames merging into one long + // "frame", however capture quality varies so much run to run + // that neither behaviour could be shown to be better on real + // hardware. Left as-is; revisit with a repeatable rig. + if (*rxlen != 0) { + DBG Dbprintf("stop gap mid-frame, rxlen %i", (int)*rxlen); + } + + } else if (rb >= HITAG_T_1_MIN) { + // '1' bit + rx[*rxlen / 8] |= 1 << (7 - (*rxlen % 8)); + (*rxlen)++; + + } else if (rb >= HITAG_T_0_MIN) { + // '0' bit + rx[*rxlen / 8] |= 0 << (7 - (*rxlen % 8)); + (*rxlen)++; + } + + } else { + + // Capture tag frame (manchester decoding using only falling edges) + if (rb >= HITAG_T_EOF) { + // 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 |-_| + + // A gap this long ends the tag's answer, and saying so here is what + // keeps the reader's next command in a frame of its own. + // + // The capture loop otherwise only ends a frame on HITAG_T_EOF of + // silence measured by the edge counter, and after a tag answer that + // silence never arrives: the tag's modulation decays rather than + // stopping, so the slope detector keeps firing across the ~230 T0 + // turnaround. After a READER frame the field is steady and the + // counter does time out, which is why tag frames come out perfect + // while reader frames do not. + // + // The consequence is that the reader's opening gap - and sometimes + // its first bit - is fed to the manchester decoder above before the + // rising edge has said whose frame this is, and resetting rxlen at + // that switch then throws the bit away. Measured against a genuine + // Paxton reader: 4 of every 6 reader frames came out one bit short + // with everything shifted left, the 32 bit password reading back as + // 7BEBD08C where BDF5E846 was sent. + // + // Ending the frame on the gap itself costs nothing - the gap carries + // no bit in either direction - and leaves the opening gap to start + // the next frame cleanly, which is where every other Hitag 2 receive + // path in this file already gets it right. + if (*rxlen > 0) { + return true; + } + + } else if (rb >= 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 (rb >= 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; + + } else if (rb >= 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)++; + } + } + } + + return false; +} + +void SniffHitag2(bool ledcontrol, uint8_t threshold) { if (ledcontrol) LED_D_ON(); + hitag_edges_reset(); + g_tx_samples = 0; g_tx_bails = 0; g_tx_frames = 0; FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - BigBuf_free(); - BigBuf_Clear_ext(false); + // a sniff needs the trace, not emulator memory - leave an eload intact + BigBuf_free_keep_EM(); + BigBuf_Clear_keep_EM(); + // BigBuf_Clear_ext() used to do this for us, BigBuf_Clear_keep_EM() does not + clear_trace(); set_tracing(true); /* @@ -1158,29 +1662,60 @@ void SniffHitag2(bool ledcontrol) { if (ledcontrol) LED_A_INV(); } - lf_finalize(ledcontrol); + StopTimestamp(); + lf_finalize(ledcontrol); Dbprintf("Collected %u bytes", total_count); switch_off(); BigBuf_free(); } */ + // Bring the front end up the same way the simulator does, in slope mode. + // + // This used to write the conf word by hand and nothing else, which left two + // things wrong. The LF ADC front end was never initialised, and this file's + // own note on that records the symptom exactly: "a detector free running at + // ~52 kHz - 633k edges in 12 s with nothing framed, and no value of the + // threshold making any measurable difference". And the conf word write + // resets lf_ed_threshold to 127 in fpga_pm3_top.v, so no threshold was ever + // in force. Measured on a live fob-to-Paxton exchange: `lf hitag sniff` + // returned zero rows and hung, where the simulator's listen only mode + // captured 1808 frames off the same exchange. + // + // hitag_setup_fpga() does the bring up in the right order and sets the + // threshold after its own conf word write. Slope mode is what made the + // simulator's receive work; the level slicing path this used before is the + // configuration that was measured not to. + hitag_setup_fpga(FPGA_LF_EDGE_DETECT_SLOPE, threshold, ledcontrol); + + uint8_t active_threshold = threshold; + if (threshold == 0) { + active_threshold = HITAG2_SLOPE_THRESHOLD; + FpgaSendCommand(FPGA_CMD_SET_EDGE_DETECT_THRESHOLD, active_threshold); + } + // Dont use the FPGA modulation output, we only want to capture the tag/reader comms gpio_fpga_mod_only_setup(); Gpio_SSC_DOUT_Low(); - // Set up eavesdropping mode, frequency divisor which will drive the FPGA - // and analog mux selection. - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_125); // 125Khz - SetAdcMuxFor(ADC_MUXSEL_LOPKD); - // Configure the input capture (TC1) via the HAL: it enables the TC1 clock, routes // SSC_FRAME to the timer input, resets on each falling edge and captures RB // (falling->falling) / RA (falling->rising). StartLoEdgeCapture(); - int frame_count = 0, response = 0, lastbit = 1, tag_sof = 4; + // the trace wants real timestamps, and nothing else in this function starts + // the counter - without it every logged frame gets a garbage start and end + StartTimestamp(); + + uint32_t frame_start = 0; + int frame_count = 0, lastbit = 1, tag_sof = 4; + + // Count both ways a reader can try to authenticate. + // + // Only the 64 bit crypto challenge was ever tallied, so a capture of a + // password mode exchange - which is most of them - reported "Auth + // attempts... 0" however many times the reader had presented its password. + uint32_t crypto_attempts = 0, pwd_attempts = 0; bool reader_frame = false, bSkip = true; // HACK -- add one byte to avoid rewriting manchester decoder for edge case @@ -1196,13 +1731,45 @@ void SniffHitag2(bool ledcontrol) { uint8_t edges[100]; uint8_t e_count = 0; - while (BUTTON_PRESS() == false) { + // TEMP DIAG: what the falling edge just before the reader/tag switch was + // carrying, for the first few reader frames. If it is a bit length interval + // (18..32 T0) rather than a long opening gap, the first bit was consumed by + // the tag path before the switch happened - which is the head bit loss. + + // Candidate first bit of a reader frame, see the switch below. + bool head_valid = false, head_bit = false; + uint16_t last_rb = 0; + + // TEMP DIAG: falling-edge intervals of frames that turn out to be TAG frames, + // so a genuine fob's answer and a simulated one can be diffed edge for edge. + uint8_t d_cur[24] = {0}, d_curn = 0; + uint8_t d_tag[2][24] = {{0}}, d_tagn[2] = {0}, d_tagf = 0; + + + while ((BUTTON_PRESS() == false) && (data_available() == false)) { WDT_HIT(); - // Receive frame, watch for at most HITAG_T0 * HITAG_T_EOF periods since the last edge + // Receive frame, watch for at most HITAG_T0 * HITAG_T_EOF periods since the last edge. + // + // Bounded, for the same reason hitag_tag_receive_frame_ex() is: when the + // edge detector has nothing clean to work with it fires continuously, the + // capture counter never reaches the EOF limit and this loop never returns + // - so the outer loop never gets back to its data_available() check and + // the device wedges with no way back short of a replug. Measured: this + // is why `lf hitag sniff` ignored `hw break` and hung the client. The + // shared receive already had this guard; this was a private copy that + // never got it. + uint32_t guard = HITAG_RX_IDLE_GUARD; while (GetLoEdgeCaptureCount() < (HITAG_T0 * HITAG_T_EOF)) { + if (--guard == 0) { + break; + } + if ((guard & 0x3FF) == 0) { + WDT_HIT(); + } + // Read (and clear) the input-capture edge-event flags. lo_edge_t lo_edge = GetLoEdgeCaptureStatus(); @@ -1210,6 +1777,7 @@ void SniffHitag2(bool ledcontrol) { if (lo_edge == LO_EDGE_RISING) { int ra = GetLoEdgeCaptureRising() / HITAG_T0; + // Shorter periods only happen with reader frames (reader tlow is 4..10 T0, // while the shortest tag Manchester half-period is 16 T0). if (reader_frame == false && ra < HITAG_T_TAG_CAPTURE_ONE_HALF) { @@ -1218,102 +1786,159 @@ void SniffHitag2(bool ledcontrol) { reader_frame = true; rxlen = 0; memset(rx, 0x00, sizeof(rx)); + + // Keep the first bit, if the switch came one edge too late. + // + // The reader/tag decision is taken on the RISING edge that + // closes a gap, but the falling edge that opened it has + // already been through the loop - and while reader_frame is + // still false that goes to the tag manchester path. When the + // gap being classified is the frame's first BIT rather than + // its opener, resetting rxlen here throws that bit away. + // + // Measured against a genuine Paxton reader: the falling edge + // immediately before the switch carried 48, 47, 31, 47, 47, + // 31 T0. The 31s are bit length intervals ('1' is 26..32), + // not opening gaps, and the frames they belong to came out + // exactly one bit short with everything shifted left - the + // 32 bit password read back as 31 bits, 7BEBD08C where + // BDF5E846 was sent, and 10 bit READ PAGEs as 9. + // + // An opening gap is longer than t_stop, so anything shorter + // than that is a bit. Remember it as a candidate head bit + // rather than committing to it here: the idle before a frame + // can carry noise edges, and seeding on those turned the 5 bit + // START_AUTH into 6. The frame's own length decides, below. + // + // Where the missing interval comes from. + // + // Measured, by logging every edge event unfiltered across one + // turnaround. A reader frame that follows a tag answer opens: + // + // 80fe RISING ra=254 no falling preceded this at all + // 800a RISING ra=10 two risings running: one lost + // 001a FALLING rb=26 ... and the frame decodes from here + // + // ra is the falling to rising sub period, so ra=254 says the + // capture counter had not been reset for 254 T0 - the FPGA + // produced no falling edge for that first gap. The interval + // that would have carried bit 0 was therefore never measured, + // which is why recovering it from TC_RB, holding the first + // falling edge for classification, and closing the tag frame + // on its own gap all changed nothing: there was nothing there + // to recover. + // + // Both risings sit one t_low after their own gap, so the + // difference between their timestamps IS the gap to gap + // interval, and that is bit 0's period. Fall back to the last + // decoded interval when the falling edge was present, which is + // the case this used to handle. + // Deriving it from the two rising timestamps was tried and is + // inert: those two risings straddle the whole turnaround, about + // 230 T0, not the missing bit, so the value is never in the bit + // range. Left out rather than left in doing nothing. + const uint16_t head_rb = last_rb; + + head_valid = ((head_rb >= HITAG_T_0_MIN) && (head_rb < HITAG_T_STOP)); + head_bit = (head_rb >= HITAG_T_1_MIN); } } // Falling edge: RB holds the falling->falling full period (the bit timing). if (lo_edge == LO_EDGE_FALLING) { int rb = GetLoEdgeCaptureFalling() / HITAG_T0; + g_hitag_edges++; + last_rb = (uint16_t)rb; + + if (d_curn < sizeof(d_cur)) { + d_cur[d_curn++] = (rb > 255) ? 255 : (uint8_t)rb; + } if (e_count < sizeof(edges)) { edges[e_count++] = rb; // Store the edge timing for debug purposes } - if (reader_frame) { + if (frame_start == 0) { + frame_start = TIMESTAMP; + } - if (ledcontrol) LED_B_ON(); - // Capture reader frame - if (rb >= HITAG_T_STOP) { - // Capture the T0 periods that have passed since last communication or field drop (reset) - response = (rb - HITAG_T_LOW); - if (rxlen != 0) { - DBG Dbprintf("rb - HITAG_T_LOW... %i", response); - } + if (ledcontrol) { + if (reader_frame) LED_B_ON(); + else LED_C_ON(); + } - } else if (rb >= HITAG_T_1_MIN) { - // '1' bit - rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); - rxlen++; - - } else if (rb >= HITAG_T_0_MIN) { - // '0' bit - rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); - rxlen++; - } - - } else { - if (ledcontrol) LED_C_ON(); - // Capture tag frame (manchester decoding using only falling edges) - if (rb >= HITAG_T_EOF) { - // 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 |-_| - response = rb - HITAG_T_TAG_HALF_PERIOD; - - } else if (rb >= 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 (rb >= 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; - - } else if (rb >= 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++; - } - } + if (hitag2_sniff_bit(rb, reader_frame, rx, sizeof(rx), &rxlen, + &lastbit, &bSkip, &tag_sof)) { + // Frame closed by this gap. Leave the capture loop so the + // frame is logged, and let the gap open the next one. + break; } } } // end while - // Check if frame was captured - if (rxlen) { + // Check if frame was captured. + // + // A tag frame has to be long enough to be one: a Hitag 2 answer is 10 or + // 32 bits behind its SOF, so anything shorter on the tag side is noise + // that the manchester path above happily turned into bits. That is what + // produced the fabricated "Tag" rows - a control sniff with no card and + // no simulator present still logged 1231 of them - which made every tag + // side number from this command untrustworthy. Reader frames keep their + // own minimum of 1, since START_AUTH is legitimately 5 bits. + if (rxlen && (reader_frame || (rxlen >= 8))) { + + // Put back the head bit, but only when the length says one is missing. + // + // A Hitag 2 reader frame is 5, 10, 32 or 64 bits - START_AUTH, a + // read/write command, a password or page, or an authentication pair. + // Landing exactly one short of one of those is the signature of the + // lost head bit, and nothing else produces it. Deciding here rather + // than at the switch means a noise edge in the idle cannot lengthen a + // frame that was already the right size. + if (reader_frame && head_valid && + ((rxlen == 4) || (rxlen == 9) || (rxlen == 31) || (rxlen == 63))) { + + const size_t nb = (rxlen + 8) / 8; + if (nb <= sizeof(rx)) { + uint8_t carry = head_bit ? 0x80 : 0x00; + for (size_t i = 0; i < nb; i++) { + const uint8_t next = (rx[i] & 1) ? 0x80 : 0x00; + rx[i] = (uint8_t)(rx[i] >> 1) | carry; + carry = next; + } + rxlen++; + } + } + head_valid = false; frame_count++; - LogTraceBits(rx, rxlen, response, 0, reader_frame); + LogTraceBits(rx, rxlen, frame_start, TIMESTAMP, reader_frame); - // Print only from tag response(No auth cmd from reader) + // Dump the raw edge timings of tag frames. A tag answer that decodes + // to only a bit or two still has all its edges here, which is the only + // way to see which half-period thresholds it is actually falling into. DBG { - if (rxlen >= 8) { - for (size_t i = 0; i < e_count; i++) { - Dbprintf("edges[%zu] = %u", i, edges[i]); - } + if ((reader_frame == false) && (e_count > 3)) { + DBG Dbprintf("TAGEDGES bits=%zu count=%u", rxlen, e_count); + Dbhexdump(e_count, edges, false); } } // Check if we recognize a valid authentication attempt - if (rxlen == 64) { - // Store the authentication attempt - if (auth_table_len + 8 <= AUTH_TABLE_LENGTH) { - memcpy(auth_table + auth_table_len, rx, 8); - auth_table_len += 8; + // + // 64 bits from the reader is a crypto challenge, 32 bits from the + // reader is a password. The same 32 bits from the TAG is page data, + // so the direction has to be part of the test. + if (reader_frame) { + if (rxlen == 64) { + crypto_attempts++; + // Store the authentication attempt + if (auth_table_len + 8 <= AUTH_TABLE_LENGTH) { + memcpy(auth_table + auth_table_len, rx, 8); + auth_table_len += 8; + } + } else if (rxlen == 32) { + pwd_attempts++; } } @@ -1322,42 +1947,164 @@ void SniffHitag2(bool ledcontrol) { LED_C_OFF(); } - response = 0; + // commit the interval trace if this was a real tag answer + if ((reader_frame == false) && (rxlen >= 8) && (d_tagf < 2)) { + d_tagn[d_tagf] = d_curn; + for (uint8_t k = 0; k < d_curn; k++) { + d_tag[d_tagf][k] = d_cur[k]; + } + d_tagf++; + } + reader_frame = false; lastbit = 1; bSkip = true; tag_sof = 4; e_count = 0; + frame_start = 0; } // Reset the frame length and clear the buffer so that '0' bits written // by the next frame don't inherit stale '1' bits from this one. rxlen = 0; + d_curn = 0; memset(rx, 0x00, sizeof(rx)); } if (ledcontrol) LEDsoff(); DBG Dbprintf("frames.......... %d", frame_count); - Dbprintf("Auth attempts... %d", (auth_table_len / 8)); + for (uint8_t i = 0; i < d_tagf; i++) { + DBG Dbprintf("TAGIV%u n=%u: %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u", i, d_tagn[i], + d_tag[i][0], d_tag[i][1], d_tag[i][2], d_tag[i][3], + d_tag[i][4], d_tag[i][5], d_tag[i][6], d_tag[i][7], + d_tag[i][8], d_tag[i][9], d_tag[i][10], d_tag[i][11], + d_tag[i][12], d_tag[i][13], d_tag[i][14], d_tag[i][15]); + } + Dbprintf("Auth attempts... crypto %u, password %u", + (unsigned)crypto_attempts, (unsigned)pwd_attempts); + + // Stop logging raw samples. + // + // g_logging is global and this was the only place that ever set it, with + // nothing to clear it - so one `lf hitag sniff` left sample logging on for + // the rest of the power cycle. Every LF command afterwards then calls + // logSampleSimple() for every ADC sample inside lf_count_edge_periods_ex(), + // which slows that loop, makes it miss samples, and stretches the bit timings + // of anything that transmits. It reads as the reader and writer becoming + // unreliable until the device is replugged. + g_logging = false; StopLoEdgeCapture(); + StopTimestamp(); switch_off(); - BigBuf_free(); + BigBuf_free_keep_EM(); } +// Measured, so it is not retried: validating each bit duration against the +// datasheet windows - T[0] 18..22, T[1] 26..32, nothing in between or beyond - +// as an extra condition for locking a threshold candidate makes things worse, +// not better. 6 of 10 authentications when applied to START_AUTH, 7 of 10 when +// applied to the password, against 9 of 10 with the frame length alone. So few +// candidates satisfy it on a recovering envelope that the search never settles. +// It does correctly identify the bad frames - a spurious early edge gives +// 19,20,40,30 where 19,30,30,30 was sent - but rejecting them costs more than the +// occasional wrong bit does. + // Hitag 2 simulation -void SimulateHitag2(bool ledcontrol) { +void SimulateHitag2(uint8_t threshold, uint16_t twait, uint8_t flags, uint8_t sof, uint8_t duty, bool ledcontrol) { - BigBuf_free(); - BigBuf_Clear_ext(false); - set_tracing(true); + hitag_tag_set_mod_polarity((flags & 1) != 0); + hitag_tag_set_mod_duty(duty); + s_no_alternation = ((flags & 2) != 0); + s_alt_phase = false; - // empties bigbuff etc - lf_init(LF_ADC_TAG_SIM, LF_ADC_WAV_REVERSED, ledcontrol); + // flags bit5: toggle mode. lo_edge_detect.v drives ssp_frame from + // edge_toggle instead of edge_state, which its own comment says is there "to + // enable detecting two consecutive peaks at the same level" - the run of BPLM + // zeroes we lose a bit in. edge_state needs the envelope back over a + // threshold before it will report another gap; toggle only needs the peak. + // Slope detection is the default, not an option. + // + // It used to be opt in behind diagnostic bit 5, which meant a plain + // `lf hitag sim -2` - the documented command - ran the level slicing path + // instead and did nothing at all: measured on two Proxmarks 1 cm apart, + // start_auth=0 answers=0 at the simulator and RXFAIL no_signal=122 at the + // reader, not one block read. Everything that works here was developed and + // verified with bit 5 set, so it is the working configuration and belongs on + // by default. Bit 5 stays accepted so existing command lines keep working; + // it simply no longer changes anything. + // + // The level slicing path needs the envelope back over a threshold before it + // will report another gap, and on a run of BPLM zeroes it never gets there, + // so two bits merge into one interval. Slope compares each sample against + // one 32 us earlier and calls the edge on the difference, which is what a + // gap looks like whatever the DC level is doing. + const uint16_t slope = FPGA_LF_EDGE_DETECT_SLOPE; + + // flags bit6: listen only. Receive and trace the reader exactly as the + // simulator does, but never answer, so a genuine tag can be watched talking + // to a real reader over the receive path that is known to work here. + // `lf hitag sniff` uses the ADC sniff path instead and captures nothing on + // this rig, so it is no use as a reference. + const bool listen_only = ((flags & 64) != 0); + + // flags bit4: modulate on the 10k leg alone. A genuine fob dips our antenna's + // envelope to ~105 of ~148; both legs together take it to 0. + const uint16_t weak = ((flags & 16) != 0) ? FPGA_LF_WEAK_LOAD : 0; + + // flags bit7: let the edge detector work on a small tracked span, so the + // reader's frame is still sliced while our envelope is recovering. Holding + // the envelope follower instead (FPGA_LF_EDGE_DETECT_HOLD_TRACKER) was tried + // and measured to change nothing: the trouble is not the follower's stored + // min and max, it is that the signal itself is ramping. + const uint16_t sensitive = ((flags & 128) != 0) ? FPGA_LF_EDGE_DETECT_SENSITIVE : 0; + + start_auth_answered = false; + last_start_auth = 0; + hitag_edges_reset(); + + s_t_wait_resp = (twait != 0) ? twait : HITAG2_T_WAIT_RESP; + + // Six SOF bits, though the datasheet (HT2 3.3.1) says five. + // + // The sixth replaces a compensation that no longer exists. This used to read + // "five SOF bits, per the datasheet; the lost head half bit is covered by the + // lead-in in hitag_tag_send_frame_mc4k_sync()" - but that lead-in was measured + // to break the frame for our own reader and was taken out, and nothing + // replaced it. The answer has been one bit period short ever since. + // + // A genuine Paxton reader rejects the short answer outright. It does not + // fail loudly: it replies to our UID with a SECOND START_AUTH about 1100 T0 + // later, which the datasheet says resets the state machine, then goes quiet + // for a whole poll cycle. In a trace that second START_AUTH decodes as a 3 or + // 4 bit frame - 06, 0C - and the giveaway is its length, ~190 T0, the same as + // a real five bit START_AUTH. Measured on , no card in field: + // + // sof answer(T0) rdr 32-bit pwd_ok read_ok + // 5 1186 0 0 0 + // 6 1218 154 187 747 + // 7 1250 0 0 0 + // 8 1282 20 20 25 + // + // Six costs nothing anywhere else. On , over eight runs each, + // reads went 6/8 at five and 5/8 at six, and writes 3/3 against 2/3 - the same + // rig's own run to run spread, not a regression. + // + // Not understood: a genuine fob's answer measures 1247 T0 sniffed, which is + // sof 7 (1250), yet sof 7 fails on the same reader that sof 6 satisfies. So + // the fob's extra length is not simply more SOF bits, and this constant is + // where the evidence points rather than where a derivation ends. + const int sof_bits = (sof != 0) ? (int)sof : 6; + + + // keep emulator memory, that is where eload put the tag content. + // hitag_setup_fpga() below loads the LF bitstream with the EM-preserving + // variant and clears the trace, so nothing here may wipe BigBuf wholesale. + BigBuf_free_keep_EM(); + BigBuf_Clear_keep_EM(); - int response = 0; uint8_t rx[HITAG_FRAME_LEN] = {0}; uint8_t tx[HITAG_FRAME_LEN] = {0}; @@ -1370,9 +2117,39 @@ void SimulateHitag2(bool ledcontrol) { // hitag2 state machine? hitag2_init(); + // Serve what `lf hitag eload` put in emulator memory. The static table this + // file initialises `tag` with is only a fallback: a bare `lf hitag sim` with + // nothing loaded keeps presenting the built-in demo tag rather than a tag of + // all zeroes. Only the 8 real pages come from emulator memory, sectors 8-11 + // hold crypto state (RSK, RCF, SYNC) that is not part of the tag content. + uint8_t *em = BigBuf_get_EM_addr(); + bool em_empty = true; + for (size_t i = 0; i < HITAG2_MAX_BYTE_SIZE; i++) { + if (em[i] != 0) { + em_empty = false; + break; + } + } + + // Always repopulate, never inherit - a previous run leaves its tag content, + // and any writes the reader made, behind in the static `tag`. + if (em_empty) { + DbpString("Emulator memory is empty, simulating the built-in demo tag"); + memcpy(tag.sectors, hitag2_demo_sectors, sizeof(hitag2_demo_sectors)); + } else { + memset(tag.sectors, 0, sizeof(tag.sectors)); + for (size_t i = 0; i < HITAG2_MAX_BLOCKS; i++) { + memcpy(tag.sectors[i], em + (i * HITAG_BLOCK_SIZE), HITAG_BLOCK_SIZE); + } + } + // printing uint32_t block = 0; - for (size_t i = 0; i < 12; i++) { + // Only the tag's own blocks. `tag.sectors` is sized for the largest Hitag + // variant, and sectors 8..11 hold crypto state (RSK, RCF, SYNC) rather than + // tag content, so printing all twelve showed four rows of 00000000 that are + // not part of a Hitag 2 at all. + for (size_t i = 0; i < HITAG2_MAX_BLOCKS; i++) { // num2bytes? for (size_t j = 0; j < 4; j++) { @@ -1382,193 +2159,1111 @@ void SimulateHitag2(bool ledcontrol) { Dbprintf("| %d | %08x |", i, block); } - size_t max_nrzs = 8 * HITAG_FRAME_LEN + 5; - uint8_t nrz_samples[max_nrzs]; - -// uint32_t command_start = 0, command_duration = 0; - // int16_t checked = 0; - // SIMULATE - uint32_t signal_size = 10000; - while (BUTTON_PRESS() == false) { + // + // Physical layer: the FPGA edge-detect path shared with the Hitag S and u + // simulators, not the older ADC sample-and-threshold path. The ADC path + // compares against a hardcoded avg +/- LIMIT_DEV (20) window, and a 100% ASK + // reader carrier sits at its own average, so the rising half of every + // transition can never cross avg+20 and the frame decoding collapses. The + // edge detector thresholds in hardware and the level is tunable. + // Do NOT write the conf word again here. fpga_pm3_top.v resets the edge + // detect threshold whenever FPGA_CMD_SET_CONFREG selects LF_EDGE_DETECT: + // `FPGA_CMD_SET_CONFREG: + // if (shift_reg[8:6] == `FPGA_MAJOR_MODE_LF_EDGE_DETECT) + // lf_ed_threshold <= 127; // default threshold + // hitag_setup_fpga() sets the threshold straight after its own conf word + // write, so repeating that write here threw the setting away and -t had no + // measurable effect at any value. + // Hold the envelope follower across our own answer. + // + // Our load modulation drives the same min/max tracker the edge detector + // slices against, so a strong load pins it and leaves us deaf for a while + // after every frame we send. Measured against a genuine Paxton reader: we + // heard 96 of its 218 START_AUTH polls, missing the second of every pair, + // and its follow up command arrives about 269 T0 after our answer - the + // datasheet allows as little as 90 - so we would have missed that too. + // + // Modulating less fixes the deafness and costs us the reader: with the + // lightest load a Proxmark reader 1 cm away heard nothing at all, + // RXFAIL no_signal=127. Freezing the tracker instead keeps the load that + // works and takes the self-interference out of the reference. The hold is + // retriggerable and releases about 340 us after our last transition, which + // is inside t_WAIT2 either way. + hitag_setup_fpga(weak | sensitive | slope | FPGA_LF_EDGE_DETECT_HOLD_TRACKER, + threshold, ledcontrol); + uint8_t active_threshold = threshold; - // use malloc - initSampleBufferEx(&signal_size, true); + // Slope mode is not auto-tuned. + // + // hitag_autotune_threshold() scores candidates by edge rate, and in slope mode + // a low threshold produces an edge storm - measured, 1602 edges and not one + // decodable frame - which that metric reads as the best candidate. It also + // runs before any reader traffic exists, so there is nothing but noise to tune + // on. Use a value measured to work instead; -t overrides it. + if ((slope != 0) && (threshold == 0)) { + active_threshold = HITAG2_SIM_THRESHOLD; + FpgaSendCommand(FPGA_CMD_SET_EDGE_DETECT_THRESHOLD, active_threshold); + Dbprintf("Slope detect threshold %u", active_threshold); + } else if (threshold == 0) { + uint8_t tuned = hitag_autotune_threshold(); + FpgaSendCommand(FPGA_CMD_SET_EDGE_DETECT_THRESHOLD, tuned); + active_threshold = tuned; + Dbprintf("Edge detect threshold auto-tuned to %u", tuned); + } - if (ledcontrol) { - LED_D_ON(); - LED_A_OFF(); + // hitag_setup_fpga() uses gpio_fpga_mod_only_setup(), which claims SSC_DOUT + // but leaves SSC_CLK with the SSC peripheral. SimulateTagLowFrequency(), + // the LF tag simulator that is known to work on this hardware, claims both + // via gpio_fpga_mod_feedback_setup() so the peripheral cannot drive the pin + // while we modulate. Match it. + gpio_fpga_mod_feedback_setup(); + Gpio_SSC_DOUT_Low(); + + int overflow = 0; + + // TEMP DIAGNOSTIC: counters only, reported after the loop so nothing is + // printed while the exchange is live (hw dbg perturbs the timing). + uint32_t d_loops = 0, d_frames = 0, d_bits5 = 0, d_answers = 0; + uint32_t last_rx_ts = 0, d_meas_n = 0, d_rearm_n = 0; + + // Per-length command census, so a run can be judged without the trace. + // + // The trace buffer fills long before the post-answer search settles - one + // 70 second run against a Paxton reader had the trace end at about 4 seconds + // while the first complete transaction did not happen until 23 - so counting + // "did a full read happen" from `trace list` reports failure on runs that + // actually succeeded. These count the whole run. + // + // d_auth_short is the one that matters: a 64 bit challenge arriving as 60..63 + // bits is the post-answer threshold dropping the last edges, and it is the + // difference between a reader that authenticates and one that gives up. + uint32_t d_auth64 = 0, d_auth_short = 0, d_pwd_ok = 0, d_read_ok = 0; + uint32_t d_thr_steps = 0, d_post_steps = 0, d_post_eval = 0; + uint8_t d_span = 0; + bool thr_measured = false; + uint8_t d_p50 = 0, d_p90 = 0, d_p99 = 0, d_pmax = 0; + uint32_t d_nsteps = 0, d_nbig = 0, d_meas = 0; + + // TEMP INSTRUMENT: what the receiver actually sees in the window right after + // we answer. Nothing is printed while the exchange is live - `hw dbg` and + // any Dbprintf inside the loop move every timing this is meant to measure - + // so it is all stored and dumped once the loop has ended. +#define SIMSNAP 1 + static uint16_t s_iv[SIMSNAP][8]; + static uint8_t s_ivn[SIMSNAP]; + static uint16_t s_rxl[SIMSNAP]; + static uint32_t s_gap[SIMSNAP]; // our answer's end -> next frame's first edge + static uint32_t s_wait[SIMSNAP]; // rx_end -> answer start (should be t_wait_resp - T_EOF) + static uint32_t s_txdur[SIMSNAP]; // how long our answer took, in T0 + static uint32_t s_rearm[SIMSNAP]; // answer end -> capture re-armed + static uint16_t s_skip[SIMSNAP]; // empty receive windows before that frame + static uint32_t s_clk[SIMSNAP]; // carrier half cycles seen in the 300 T0 after our answer + static uint16_t s_it[SIMSNAP][8]; // receive loop polls between one edge and the next +#define ADCSNAP 8 + static uint8_t s_adc_mn[ADCSNAP], s_adc_mx[ADCSNAP]; + static bool s_adc_valid = false; + s_adc_valid = false; // static, so clear it or a later run dumps stale data + uint8_t s_nsnap = 0; + uint32_t d_listen5 = 0; + + // Adaptive slope threshold. + // + // A fixed step has to be re-found every time the coupling changes - measured + // across one session it moved 30, 31, 32, 34, and outside a two or three count + // window it either chatters or resolves nothing. Tuning it at startup does + // not work either: hitag_autotune_threshold() scores candidates by edge rate, + // and in slope mode the chattering end wins, and there is no reader traffic to + // judge on yet anyway. + // + // So tune on real traffic against something known: a Hitag 2 reader opens with + // START_AUTH, five bits of 0x18. Step through candidates until that decodes, + // then hold; if it stops decoding for a while, resume searching. Nothing here + // guesses what the data should be - it only asks whether the framing came out + // valid, which is the same check the command dispatch already applies. + // Known good values first, then fill in the range. + // + // Two thresholds have been measured to work, each on a different rig: 20 with + // a genuine Paxton reader, where its 64 bit challenge arrives whole instead of + // sliced into 21..23 bit fragments, and 32 with a Proxmark reader a centimetre + // away, where the coupling is far stronger and 20 chatters. Trying those two + // first means the common cases settle in at most two scoring windows instead + // of walking the list; the rest are there for a rig that is neither. + // Only the two values known to work. + // + // 20 with a genuine Paxton reader, where its 64 bit challenge arrives whole + // instead of sliced into 21..23 bit fragments; 32 with a Proxmark reader a + // centimetre away, where the coupling is far stronger and 20 chatters. The + // intermediate values were never measured to be right anywhere, and every + // candidate costs a scoring window out of the reader's patience - measured, + // three `lf hitag read` attempts were spent tuning before one succeeded. + // + // This is only the fallback: it runs when the measurement below found no real + // modulation to work from. + static const uint8_t thr_cand[] = { HITAG2_SIM_THRESHOLD, 20 }; + uint8_t thr_idx = 0; + uint16_t thr_seen = 0, thr_hit = 0; + uint8_t thr_best_idx = 0; + uint16_t thr_best_hit = 0; + bool thr_locked = (threshold != 0); // an explicit -t is taken as given + + // A second threshold, for the window right after we answer. + // + // START_AUTH arrives on a settled envelope; the reader's next frame arrives + // while ours is still recovering from our own modulation, which is a different + // signal to slice. One threshold cannot suit both, so the post answer window + // gets its own, tuned the same way - on whether the framing came out at a + // length the protocol has (10 for a read, 32 for a password), never on whether + // the contents match what we expect, which would just be deciding the answer + // in advance. + // Two values, the same two the main sweep uses. + // + // This list was briefly widened to { 20, 16, 12, 24, 28, 32 } on the theory + // that a 64 bit challenge arriving as 61 bits meant the step was still too + // coarse and the search should reach lower. Measured, that made it worse, + // not better: two 40 second runs against a Paxton reader decoded no command + // of any length at all - auth64=0, authshort=0, pwd_ok=0, read_ok=0 - and + // never locked, because six candidates means most of the run is spent on a + // value that cannot work, and the reader gives up long before the sweep comes + // back round. + // + // 20 and 32 are the only two values measured to work on any rig, so they are + // the only two offered. A short list is not a limitation here, it is the + // point: settling is what the reader is waiting for. + static const uint8_t post_cand[] = { 20, 32 }; + uint8_t post_idx = 0; + uint8_t post_thr = post_cand[0]; + uint16_t post_bad = 0; + bool post_active = false; + bool post_locked = false; + + bool snap_next = false; + uint16_t snap_skipped = 0; + uint32_t last_tx_end = 0; + + // our answer is traced after the following receive, see below + bool tx_pending = false; + size_t tx_pending_len = 0; + uint32_t tx_pending_start = 0, tx_pending_end = 0; + uint8_t tx_pending_buf[8] = {0}; + + // TEMP flags bit2: hold the coil load on and do nothing else, so the effect of + // our modulation can be measured directly from the reader's ADC statistics. + if ((flags & 4) != 0) { + // Toggle the load at the Hitag 2 Manchester half-bit rate, continuously. + // + // Holding it statically was the wrong diagnostic: the reader's LOPKD path + // peak detects, so a DC load barely shows (it moved the reader's average + // by 3-4 counts) while a toggling one produces a large swing. EM410x sim + // toggles, and swings the same reader's ADC rail to rail from this coil, + // so this shows whether our toggling is comparable. + DbpString("Hitag 2: toggling coil load at RF/32 (diagnostic)"); + while ((BUTTON_PRESS() == false) && (data_available() == false)) { + WDT_HIT(); + for (uint32_t half = 0; half < HITAG_T_TAG_HALF_PERIOD; half++) { + uint32_t g = 20000; + while ((Gpio_SSC_CLK_Read() == false) && (--g)) { } + while ((Gpio_SSC_CLK_Read() == true) && (--g)) { } + } + Gpio_SSC_DOUT_High(); + for (uint32_t half = 0; half < HITAG_T_TAG_HALF_PERIOD; half++) { + uint32_t g = 20000; + while ((Gpio_SSC_CLK_Read() == false) && (--g)) { } + while ((Gpio_SSC_CLK_Read() == true) && (--g)) { } + } + Gpio_SSC_DOUT_Low(); + } + Gpio_SSC_DOUT_Low(); + hitag_cleanup(ledcontrol); + return; + } + + // Public modes: stop being a Hitag 2 and just talk. + // + // HT2 datasheet rev 2.1 sections 4.2.3 and 4.2.4. Bit 3 of the configuration + // byte picks password or crypto, and bits 2..1 pick between normal Hitag 2 and + // the three read only public modes: + // + // 0x06 Password mode command protocol, plain data after password + // 0x0E Crypto mode command protocol, encrypted data + // 0x02 Public Mode A Manchester 64 T0, pages 4,5 (uEM H400x) + // 0x00 Public Mode B Biphase 32 T0, pages 4..7 (ISO 11784/85) + // 0x04 Public Mode C Biphase 64 T0, pages 4..7 (PCF793X) + // + // "If the read/write device does not send the instruction START_AUTH within + // tWAIT START_AUTH after the Power_Up the transponder begins to send the data + // in one of the public modes" - and past that window it "enters the read-only + // state", so it stops answering commands altogether. The simulator has no + // power up event to time from, the field is already there when it starts, so + // the config byte alone decides: a public mode config goes straight to + // transmitting. Loading a password or crypto config keeps the command + // protocol exactly as before. + const uint8_t cfg = tag.sectors[3][0]; + const uint8_t pubmode = (uint8_t)((cfg & 0x06) >> 1); + + if (pubmode != 3) { + + // Manchester for A, biphase for B and C; 64 T0 per bit for the 2 kbit/s + // modes, 32 for the 4 kbit/s one. + const bool biphase = (pubmode != 1); + const uint8_t period = (pubmode == 0) ? 32 : 64; + + // A sends pages 4 and 5, B and C send pages 4 to 7. + const size_t pages = (pubmode == 1) ? 2 : 4; + const size_t nbits = pages * 8 * HITAG_BLOCK_SIZE; + + uint8_t pub[4 * HITAG_BLOCK_SIZE] = {0}; + for (size_t i = 0; i < pages; i++) { + memcpy(pub + (i * HITAG_BLOCK_SIZE), tag.sectors[4 + i], HITAG_BLOCK_SIZE); } -// lf_reset_counter(); - WDT_HIT(); + Dbprintf("Hitag 2: public mode %c, config 0x%02x, %s %u T0, pages 4..%u", + (pubmode == 1) ? 'A' : ((pubmode == 0) ? 'B' : 'C'), + cfg, biphase ? "biphase" : "manchester", period, 3 + pages); - /* - // only every 1000th times, in order to save time when collecting samples. - if (checked == 100) { - if (data_available()) { - checked = -1; - break; - } else { - checked = 0; - } - } - ++checked; - */ + while ((BUTTON_PRESS() == false) && (data_available() == false)) { + WDT_HIT(); + hitag_tag_send_public(pub, nbits, period, biphase, ledcontrol); + + // Public Mode C puts a Program Mode Check between blocks; A and B + // send the pages back to back with no gap at all. + // + // Unloaded for the whole phase. The datasheet gives the PMC only as + // a waveform drawing with Thi = 64 T0, Tlow1 = 128 T0 and Tlow2 = 192 + // T0 - which do sum to the 384 T0 t_PMC in its timing table - but the + // drawing does not survive text extraction, so the exact shape is not + // known here. Leaving the coil loaded across it, which is what + // happened when the level was simply held from the last bit, put a + // 384 T0 DC load in the middle of the stream and the reader's demod + // could not recover a bitstream at all. + if (pubmode == 2) { + // Timed on the precision counter, not lf_wait_periods(): that one + // counts ADC samples, and simulation runs the FPGA edge detect + // path rather than the ADC path, so it is not a usable clock here. + Gpio_SSC_DOUT_Low(); + const uint16_t t_pmc = GetPrecisionCounterRaw(); + while (GetPrecisionCounterDelta(t_pmc) < (HITAG2_T_PMC * T0)) { } + } + } + + Gpio_SSC_DOUT_Low(); + hitag_cleanup(ledcontrol); + return; + } + + while ((BUTTON_PRESS() == false) && (data_available() == false)) { + + uint32_t start_time = 0; size_t rxlen = 0, txlen = 0; - // Keep administration of the first edge detection - bool waiting_for_first_edge = true; + d_loops++; + WDT_HIT(); - // Did we detected any modulaiton at all - bool detected_modulation = false; + // Leaving the field re-arms the threshold measurement. + // + // The reader going away ends the session, and is the moment to forget what + // was learned from it: the next field may be a different reader at a + // different distance, and the two readers here want different thresholds, + // 20 and 32, so carrying the old decision across is wrong. This is what + // makes the normal way of using the simulator work - started away from any + // reader and then presented to one - rather than only the desktop case + // where it was already sitting on the reader when `sim` was typed. + // + // Silence is the field detector. Watching the clock instead does not + // work: this file used to assert that TIMESTAMP is carrier derived and + // stops advancing when the field goes away, and that is simply untrue - + // GetTimestamp() reads TC2 clocked from MCK/32 and only scales the result + // into carrier periods, so it is free running wall time and never stalls. + // A re-arm built on it can never fire, and measured, never did. + // + // A reader in range talks: a Paxton polls every 18875 T0, and a Proxmark + // reader is bursty but never quiet for long. So no frame at all for a + // second means no reader, which needs no ADC and cannot disturb a receive. + if ((threshold == 0) && thr_measured && + ((TIMESTAMP - last_rx_ts) > HITAG2_FIELD_GONE_T0)) { + thr_measured = false; + d_rearm_n++; + last_rx_ts = TIMESTAMP; + } - // Use the current modulation state as starting point - uint8_t reader_modulation = lf_get_reader_modulation(); - // Receive frame, watch for at most max_nrzs periods - // Reset the number of NRZ samples and use edge detection to detect them - size_t nrzs = 0; - while (nrzs < max_nrzs) { - // Get the timing of the next edge in number of wave periods - size_t periods = lf_count_edge_periods(128); - // Just break out of loop after an initial time-out (tag is probably not available) - // The function lf_count_edge_periods() returns 0 when a time-out occurs - if (periods == 0) { - break; + // Receive a command from the reader + // Hitag 2 counts the opening gap as the frame's first '1' bit + + hitag_tag_receive_frame_ex(rx, sizeof(rx), &rxlen, &start_time, ledcontrol, &overflow, true); + if (rxlen > 0) { d_frames++; last_rx_ts = TIMESTAMP; } + if (rxlen == 64) { d_auth64++; } + if ((rxlen >= 56) && (rxlen <= 63)) { d_auth_short++; } + if (rxlen == 5) { d_bits5++; } + + // Judge the frame that followed our answer, then go back to the settled + // threshold for the next START_AUTH. + if (post_active) { + + // A frame of an illegal length does not spend the post-answer window. + // + // Our own modulation tail comes back as a 1 or 2 bit frame a few T0 + // after we stop transmitting, and it used to arrive first, clear + // post_active, and put the main threshold back - so the reader's real + // command, which follows it, was judged outside the window that exists + // precisely for it. Traced against a Paxton: + // + // Tag 32: 06 F9 07 C2 our answer, ends 8753 + // Rdr 1: 00 9724 self-echo, spends the window + // Rdr 8: FE 9999 the READ PAGE, now mis-sliced + // + // The window belongs to the next real frame, so hold it open until one + // arrives. See the same reasoning at the dispatcher, which discards + // these frames rather than letting them reset the session. + const bool legal_len = (rxlen == 5) || (rxlen == 10) || + (rxlen == 32) || (rxlen == 64); + if ((rxlen > 0) && (legal_len == false)) { + goto post_hold; } - if (ledcontrol) LED_A_ON(); - - // Are we dealing with the first incoming edge - if (waiting_for_first_edge) { - - // Register the number of periods that have passed - response = 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_modulation = true; - } - - // 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++] = reader_modulation; - if (nrzs < max_nrzs) { - nrz_samples[nrzs++] = reader_modulation; + post_active = false; + d_post_eval++; + if ((rxlen == 64) || (rxlen == 32) || (rxlen == 10)) { + // A protocol length: this candidate works, hold it. + // + // 64 belongs here and its absence hid the whole problem. A + // Paxton reader answers our UID with a 64 bit crypto challenge, + // and with only 32 and 10 accepted, a candidate that sliced that + // challenge perfectly scored as a failure and was stepped away + // from. + // + // Deliberately not also requiring ht2_intervals_sane() here. It + // was tried and measured worse - 7 of 10 authentications against + // 9 - because so few candidates satisfy it on the recovering + // envelope that the search never settles. The strict check earns + // its place on the short START_AUTH, where it is cheap to satisfy. + post_bad = 0; + post_locked = true; + } else if (post_locked) { + // Hold through the odd bad frame before giving up on a candidate + // that has proved itself, so noise does not send it wandering. + if (++post_bad > 2) { + post_bad = 0; + post_locked = false; } - // Invert tag modulation state - reader_modulation ^= 1; - } else if (periods > 0 && periods <= 24) { - // Detected one bit and a modulation switch - // NRZ modulation: (1 => -|) or (0 _|) - nrz_samples[nrzs++] = reader_modulation; - reader_modulation ^= 1; } else { - reader_modulation ^= 1; - // The function lf_count_edge_periods() returns > 64 periods, this is not a valid number periods - Dbprintf("Detected unexpected period count: %zu", periods); - break; + // Still searching - walk the candidates. + // + // This used to be gated on the measurement block not having run. + // That block no longer decides the threshold, so the gate only + // switched the search off permanently. + // + // Stepping directionally instead was tried, on the theory that + // hearing nothing means the step is too high to slice anything and + // a wrong length means it is low enough to pick up noise. It + // measured worse, 5 of 12 against 10 of 15, and the reason is + // instructive: hearing nothing after we answer is usually our own + // post-transmission deafness, not the threshold, so the search + // reads it as "go lower" and walks 32, 28, 24, 20, 16 chasing a + // signal that is not there yet. + post_idx = (post_idx + 1) % ARRAYLEN(post_cand); + post_thr = post_cand[post_idx]; + d_post_steps++; } + if (threshold == 0) { + FpgaSendCommand(FPGA_CMD_SET_EDGE_DETECT_THRESHOLD, active_threshold); + } +post_hold: + ; } - if (ledcontrol) LED_D_OFF(); + // Reference for the T_wresp wait below. TIMESTAMP is free running, so + // unlike the precision counter it needs no reset - resetting that one + // either spins inside the capture loop or stalls us on the stream of + // one bit noise frames, and both cost us real reader bits. + // The receive above returns once the line has been quiet for + // HITAG_T_EOF periods, so that much of the wait is already spent. + uint32_t rx_end = TIMESTAMP; - // If there is no response, just repeat the loop - if (!detected_modulation) continue; - - if (ledcontrol) LED_A_OFF(); - - // 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) { - if (nrzs >= max_nrzs) { - Dbprintf("max_nrzs (%d) is odd? Must be even!", max_nrzs); // should be a static assert above - continue; - } - nrz_samples[nrzs++] = reader_modulation; + // Always snapshot the very first frame with edges, answered or not, so a + // reader we never reply to - the writer, while it cannot get past + // START_AUTH - can still be seen at the interval level. + if ((s_nsnap < SIMSNAP) && (snap_next == false) && (g_hitag_rx_iv_count > 0) && (rxlen >= 30) && (tag.state == TAG_STATE_WRITING)) { + snap_next = true; + snap_skipped = 0; + last_tx_end = rx_end; } - if (ledcontrol) LED_B_ON(); - - // decode bitstream - manrawdecode((uint8_t *)nrz_samples, &nrzs, true, 0); - - // Verify if the header consists of five consecutive ones - if (nrzs < 5) { - Dbprintf("Detected unexpected number of manchester decoded samples [%d]", nrzs); - continue; - } 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 (snap_next) { + // The receive right after an answer covers only HITAG_T_EOF (80 T0) + // of silence and returns empty - the reader does not start its next + // command until ~276 T0. Keep looking until a window actually sees + // edges, or until the reader has plainly given up. + bool got = (g_hitag_rx_iv_count > 0); + bool expired = ((TIMESTAMP - last_tx_end) > 6000); + if (got || expired) { + snap_next = false; + if (s_nsnap < SIMSNAP) { + s_rxl[s_nsnap] = (uint16_t)rxlen; + s_gap[s_nsnap] = (start_time != 0) ? (start_time - last_tx_end) : 0; + s_skip[s_nsnap] = snap_skipped; + uint32_t n = g_hitag_rx_iv_count; + if (n > ARRAYLEN(s_iv[0])) n = ARRAYLEN(s_iv[0]); + s_ivn[s_nsnap] = (uint8_t)n; + for (uint32_t k = 0; k < n; k++) { + s_iv[s_nsnap][k] = g_hitag_rx_iv[k]; + s_it[s_nsnap][k] = g_hitag_rx_it[k]; + } + s_nsnap++; } + } else { + snap_skipped++; } } - // 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++; + if (tx_pending) { + LogTraceBits(tx_pending_buf, tx_pending_len, tx_pending_start, tx_pending_end, false); + tx_pending = false; } - // Check if frame was captured - if (rxlen > 4) { + // Every captured frame goes through the stop/enable capture cycle below, + // noise included: skipping it for short frames changes the capture + // timing enough to misread the following reader bits. + if (rxlen > 0) { - LogTraceBits(rx, rxlen, response, response, true); + LogTraceBits(rx, rxlen, start_time, TIMESTAMP, true); + + // Stop the capture while we answer. Leaving it clocked was tried, on + // the grounds that cycling it is slow, but our own modulation then + // fills it: the reader's password frame came back as 7 bits holding + // only its last byte (46 of BD F5 E8 46), because capture did not + // recover until ~1150 T0 after our answer had finished. + StopLoEdgeCapture(); // Process the incoming frame (rx) and prepare the outgoing frame (tx) - hitag2_handle_reader_command(rx, rxlen, tx, &txlen); + // Set the threshold from the reader's own modulation depth, once. + // + // The threshold is a slew rate discriminator - how many ADC counts the + // envelope must move within 32 us to count as an edge - so the value + // that works scales with how strongly this antenna is coupled to the + // reader. That is why no constant suits every rig: a Proxmark reader + // a centimetre away wants about 32, a genuine Paxton reader about 20, + // and the wrong one either truncates the reader's long commands or + // chatters on ringing. + // + // Triggered by the first received frame, so the reader is known to be + // talking - measuring at start up returns 3 counts of idle ripple. + // Once only, and from reader traffic before this simulator has + // answered anything, which is what makes it different from the + // continuous version recorded as a failure in lf_edge_detect.v: that + // one was normalising against a span our own load modulation drove. + if ((slope != 0) && (threshold == 0) && (thr_measured == false)) { - // Wait for HITAG_T_WAIT_1 carrier periods after the last reader bit, - // not that since the clock counts since the rising edge, but T_Wait1 is - // with respect to the falling edge, we need to wait actually (T_Wait1 - T_Low) - // periods. The gap time T_Low varies (4..10). All timer values are in - // terms of T0 units (HITAG_T_WAIT_1_MIN - HITAG_T_LOW ) - lf_wait_periods(HITAG_T_WAIT_1_MIN); + const uint32_t meas_t0 = TIMESTAMP; - // Send and store the tag answer (if there is any) - if (txlen) { - // Transmit the tag frame - lf_manchester_send_bytes(tx, txlen, ledcontrol); + // Wait for the field, then measure - do not wait for a frame. + // + // Triggering on a decoded frame is circular: decoding one needs a + // working threshold, which is the thing being measured. Entering + // the field is the event that actually matters and it needs no + // decoding at all - the envelope simply goes from nothing to a + // carrier, so a level well above the noise floor says the reader + // is there and its traffic is about to arrive. - // Store the frame in the trace - LogTraceBits(tx, txlen, 0, 0, false); + // Measure the same quantity the detector measures. + // + // lf_edge_detect.v fires when |v[i] - v[i-32]| reaches the + // threshold, so sample exactly that and take a high percentile of + // it. max - min was tried first and is too fragile: it is set by + // single outlying samples, and back to back runs on an unchanged + // rig measured spans of 124, 137, 157 and 158 - a 27% spread that + // lands straight on the threshold. A percentile cannot be moved + // by one sample, and being in the detector's own units means the + // number needs no interpretation. + uint8_t ring[32] = {0}; + uint8_t rp = 0; + uint16_t hist[64] = {0}; + uint32_t nsteps = 0, nbig = 0; + + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | weak); + + // Field present? An unpowered coil sits near zero; a reader's + // carrier lifts the envelope a long way above that. Give it a + // bounded wait so a simulator started with no reader in front of + // it still returns and runs. + bool in_field = false; + for (uint32_t i = 0; i < 100000; i++) { + uint32_t g = 20000; + while ((FPGA_SSC_RX_Ready() == false) && (--g)) { } + if (g == 0) { + break; + } + if ((uint8_t)FPGA_SSC_RX_Value() > 40) { + in_field = true; + break; + } + } + + for (uint32_t i = 0; (i < 200000) && in_field; i++) { + uint32_t g = 20000; + while ((FPGA_SSC_RX_Ready() == false) && (--g)) { } + if (g == 0) { + break; + } + const uint8_t v = (uint8_t)FPGA_SSC_RX_Value(); + const uint8_t old = ring[rp]; + ring[rp] = v; + rp = (uint8_t)((rp + 1) & 31); + + if (nsteps < 0xFFFFFFFF) { + const uint8_t step = (v > old) ? (uint8_t)(v - old) : (uint8_t)(old - v); + hist[step >> 2]++; + nsteps++; + if (step >= 60) { + nbig++; + } + } + + // Keep going until the window actually contains the reader's + // gaps, not just however many samples. + // + // A fixed sample count measures whatever happened to be on the + // air. Paxton polls every 151 ms, so a 40 ms window often + // catches nothing but idle ripple and the percentile then + // describes noise: measured on one rig, back to back runs gave + // spans of 252 and 144, and thresholds of 31 and 18 from the + // same coupling. Counting the big steps instead means the + // measurement ends when it has seen enough real modulation to + // describe, whenever that is. + if ((nbig >= 300) || (nsteps >= 190000)) { + break; + } + } + + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | weak | sensitive | slope); + + // Walk the histogram down from the largest bin, recording the + // step size at each percentile on the way. The single number the + // threshold is derived from is not enough to understand a rig: + // two rigs wanting 20 and 32 differ in the SHAPE of this + // distribution, not just its tail, so keep the shape and report + // it. Ripple and noise fill the bins near zero, the reader's gap + // transitions form the tail. + // Clear the percentiles before every walk. + // + // They are latched with "if still zero", which was safe only while + // this block ran exactly once per simulation. Now that a failed + // attempt leaves thr_measured clear so the next field entry can + // retry, stale values survive into the next walk, big is never + // assigned, and span comes out 0 - which fails the validity check + // below, which schedules another retry, forever. One attempt made + // outside a field poisoned every attempt after it: measured, the + // threshold stayed at its 32 default with measured=0 on a rig that + // had reported span=176 a moment earlier. + d_p50 = 0; + d_p90 = 0; + d_p99 = 0; + d_pmax = 0; + + uint32_t acc = 0; + uint8_t big = 0; + for (int b = 63; b >= 0; b--) { + acc += hist[b]; + const uint8_t sz = (uint8_t)(b << 2); + if ((d_p50 == 0) && (acc >= (nsteps / 2))) d_p50 = sz; + if ((d_p90 == 0) && (acc >= (nsteps / 10))) d_p90 = sz; + if ((d_p99 == 0) && (acc >= (nsteps / 100))) { + d_p99 = sz; + big = sz; + } + if ((d_pmax == 0) && (hist[b] > 0)) d_pmax = sz; + } + d_nsteps = nsteps; + d_nbig = nbig; + + const uint8_t span = big; + d_span = span; + + // Only accept a measurement taken in a reader's field. + // + // This used to be latched at the top of the block, unconditionally + // and once per run, which made the whole decision depend on where + // the Proxmark happened to be when `sim` was typed. Started on a + // reader, as in a desktop test, it measured properly; started away + // from the field, which is the normal way to use it, there was + // nothing to measure, and it locked a threshold chosen from an + // empty window and never looked again - so presenting the tag to + // the reader afterwards ran on a decision made before the reader + // existed. Identical firmware then passes or fails depending on + // the order of two physical actions, which is exactly the + // irreproducibility this cost a long time chasing. + if ((in_field == false) || (span == 0)) { + // Nothing to learn from. Leave thr_measured clear so entering + // a field re-runs this. + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | weak | sensitive | slope); + FpgaSendCommand(FPGA_CMD_SET_EDGE_DETECT_THRESHOLD, active_threshold); + goto meas_done; + } + thr_measured = true; + d_meas_n++; + d_meas = TIMESTAMP - meas_t0; + + // Only trust a measurement with a real modulation step in it. If + // the tail is small there was nothing but ripple in the window, so + // leave thr_locked clear and let the candidate sweep below do the + // work instead of acting on a number that means nothing. + // The measurement no longer picks the threshold, only the order + // the two candidates are tried in. + // + // It used to set it outright, as span/4 clamped to 14..40. That + // is measurably wrong. The estimator itself is reproducible - + // three runs against a genuine Paxton reader gave a 99th + // percentile of 180, 184 and 168 - but forcing each candidate by + // hand on that same rig shows what those numbers should have + // produced: + // + // -t 20 188 frames 110 START_AUTH 94 answers + // -t 26 108 frames 95 START_AUTH 95 answers + // -t 32 94 frames 94 START_AUTH 94 answers + // -t 40 194 frames 0 START_AUTH 0 answers + // + // 32 is exactly right, and 40 does not decode a single command - + // yet span/4 turns 180 into 45 and the clamp lands it on 40. No + // divisor fitted on one rig can be trusted to choose between 20 + // and 32 when the statistic it reads barely moves between them, + // 168..184, and the outcome swings from perfect to dead. + // + // The frame lengths do separate them, cleanly: at 32 every frame + // that arrives has a legal length, at 20 four in ten are noise, + // and at 40 nothing decodes at all. So the candidate sweep below + // decides, and the modulation depth is used only to guess which of + // the two to try first - a wrong guess costs one scoring window, + // not the run. + // + // Ordering the candidates by coupling strength was tried here and + // removed. The idea was that a weakly coupled rig wants 20 and a + // strongly coupled one 32, with the sweep left to correct a wrong + // guess. Measured on both rigs available, 20 is not the answer to + // either: + // + // rig span -t 20 -t 32 + // pm3 - paxton 172 59% legal frames 100% legal frames + // pm3 - pm3 224 0 of 8 pages 8 of 8 pages + // + // Both measure well above any boundary that would have selected + // the weak branch, so it was never once taken, and a boundary + // fitted on no weak samples at all is a guess wearing a constant's + // clothing. 32 is the only value measured to work anywhere, so it + // is simply tried first; 20 stays in the list for a rig neither of + // these represents, and the sweep will find it in one window. + // + // span is left measured because it is worth seeing in the log, but + // nothing is decided from it. + // Two rigs, two values, one number to tell them apart. + // + // The modulation depth does separate the rigs - it just had to be + // read against the right objective. Scored on how cleanly the + // reader's polls decode, a Paxton rig looks like it wants 32; but + // decoding polls is not the job, and against reader ACCEPTANCE it + // wants 20, which is where the earlier fit went wrong. + // + // 44 measurements, all runs on both rigs: + // + // rig A 112, 168..196 (14 samples), one 216 + // rig B one 216, 224..240 (28 samples) + // + // A boundary at 210 places 42 of the 44 correctly; the two 216 + // samples, one from each rig, are the only crossings. Everything + // else clears it by 14 counts or more. + // + // Decide once, here, and hold. No sweep: a sweep costs the reader + // a scoring window per candidate, and the reader is not waiting - + // measured, a six candidate post-answer sweep spent 23 seconds + // before its first complete transaction and two 40 second runs + // never decoded a single command. This is a comparison, and it is + // finished before the reader's second poll. + active_threshold = (span >= HITAG2_SPAN_STRONG) ? 32 : 20; + thr_locked = true; + thr_best_idx = (active_threshold == 32) ? 0 : 1; + thr_idx = thr_best_idx; + + // The post-answer window follows it. That search existed because + // the main threshold was a guess; with the sweep judging real + // framing there is nothing left for it to discover, and left + // running it never settles - measured, 3810 candidate steps in a + // single run, every one reprogramming the FPGA mid-receive. + post_thr = active_threshold; + post_locked = true; + + FpgaSendCommand(FPGA_CMD_SET_EDGE_DETECT_THRESHOLD, active_threshold); +meas_done: + ; + } + + hitag2_handle_reader_command(rx, rxlen, tx, &txlen); + + // Adaptive threshold: score each candidate on whether the reader's + // commands can actually be ACTED ON, then keep the best. + // + // Judging on frame length alone is not enough. A Hitag 2 reader frame + // is 5, 10, 32 or 64 bits, and it is tempting to score on that - but a + // slightly wrong threshold produces frames of plausible length and + // wrong content, which scores perfectly and still fails: measured on + // two Proxmarks, length scoring locked at 24 with a flawless window + // and managed 1 read of 3, where 32 does 3 of 3. + // + // Answering is the stronger signal because it is semantic. We only + // answer a 32 bit password if it matched page 1, and a 10 bit command + // if its address survived the datasheet's inverted-address check, so + // an answer to anything longer than a START_AUTH means the frame + // arrived intact. START_AUTH itself is excluded: five bits decode at + // almost any threshold and answering one proves nothing, which is + // exactly how the original lock-on-START_AUTH search settled on a + // value far too coarse for everything else. + // + // Tuning runs once per simulation, at the start of the conversation: + // thr_locked is never cleared again, so a threshold that has proved + // itself is not re-judged while the reader is mid exchange. + if ((slope != 0) && (threshold == 0) && (thr_locked == false) && (rxlen > 5)) { + + // Score on whether the frame could be ACTED ON, not on its length. + // + // Length purity was tried here and is wrong for a short exchange. + // It reads well in bulk - against a Paxton reader polling for + // twenty seconds, 100% of frames are a legal length at 32, 59% at + // 20 and 0% at 40 - but `lf hitag read` is one brief burst, and + // scoring every arrival means a single noise frame inside the + // eight frame window moves the sweep off a threshold that was + // working, in the middle of the read. Measured on two Proxmarks: + // 8 of 8 pages became 0 of 8, three runs in a row, with the sweep + // ending on 20 every time. + // + // Answering is the stronger signal because it is semantic, and it + // separates the two rigs where length does not. With a Proxmark + // reader at -t 20, 94 START_AUTH frames decode and not one command + // is ever answered - perfectly legal lengths, nothing behind them: + // + // -t 20 121 frames 94 START_AUTH 0 answers 0 of 8 pages + // -t 32 18 frames 1 START_AUTH 10 answers 8 of 8 pages + // + // We answer a 32 bit password only if it matched page 1, and a 10 + // bit command only if its address survived the datasheet's + // inverted-address check, so an answer means the frame arrived + // intact. START_AUTH is excluded from the window for the reason + // it always was: five bits decode almost anywhere, and we answer + // only every second one by design, so counting them would score a + // flawless poll train at half marks. + const bool legal = (rxlen == 10) || (rxlen == 32) || (rxlen == 64); + + thr_seen++; + if (legal && (txlen > 0)) { + thr_hit++; + } + + if (thr_seen >= HITAG2_THR_WINDOW) { + + if (thr_hit >= thr_best_hit) { + thr_best_hit = thr_hit; + thr_best_idx = thr_idx; + } + + if (thr_hit == thr_seen) { + // every command acted on - nothing better to find + thr_locked = true; + } else { + thr_idx++; + if (thr_idx >= ARRAYLEN(thr_cand)) { + // swept the list, settle on the best it saw + thr_idx = thr_best_idx; + thr_locked = true; + } + active_threshold = thr_cand[thr_idx]; + FpgaSendCommand(FPGA_CMD_SET_EDGE_DETECT_THRESHOLD, active_threshold); + d_thr_steps++; + } + + thr_seen = 0; + thr_hit = 0; + } + } + + if (listen_only) { + txlen = 0; + + // Listening to a genuine tag: capture the envelope across the + // window where its answer falls, so its modulation shape can be + // compared with ours. t_WAIT1 is ~200 T0 after the command, and + // the answer runs 1184 T0, so start straight away and let the + // 1536 T0 capture cover it. + d_listen5++; + if (((flags & 8) != 0) && (rxlen == 5) && (s_adc_valid == false)) { + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | weak); + for (uint32_t i = 0; i < ADCSNAP; i++) { + uint8_t mn = 255, mx = 0; + for (uint32_t k = 0; k < 16; k++) { + uint32_t g = 20000; + while ((FPGA_SSC_RX_Ready() == false) && (--g)) { } + uint8_t v = (uint8_t)FPGA_SSC_RX_Value(); + if (v < mn) mn = v; + if (v > mx) mx = v; + } + s_adc_mn[i] = mn; + s_adc_mx[i] = mx; + } + s_adc_valid = true; + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | weak | sensitive | slope); + if (active_threshold != 127) { + FpgaSendCommand(FPGA_CMD_SET_EDGE_DETECT_THRESHOLD, active_threshold); + } + } + } + + // Wait T_wresp carrier periods after the last reader bit. The counter + // runs from the rising edge while T_wait1 is specified from the falling + // edge, so wait (T_WAIT_1 - T_LOW) periods. All values are in T0 units. + // Send and store the tag answer (if there is any). A Hitag 2 tag + // answers Manchester at 4 kbit/s behind a five bit start-of-frame. + if (txlen > 0) { + + // Answer T_wresp after the reader's last bit, not immediately. + // Only on frames we actually answer: waiting on the noise frames + // leaves the receiver blind and drops the next reader command. + // TIMESTAMP counts carrier periods. rx_end was taken once the + // receiver gave up, which is HITAG_T_EOF periods after the + // reader's last bit, so only the remainder is waited here. + // Aim for the middle of the 199..206 window rather than its edge. + // rx_end was taken once the receiver gave up, HITAG_T_EOF periods + // after the reader's last edge, so only the remainder is waited. + // There is no send lead-in any more, the frame starts immediately. + // bounded: TIMESTAMP is derived from the carrier, so it stops + // advancing the moment the reader's field goes away. An + // unbounded spin here wedges the device with no way back. + uint32_t guard = 200000; + while ((TIMESTAMP - rx_end) < (uint32_t)(s_t_wait_resp - HITAG_T_EOF)) { + WDT_HIT(); + if (--guard == 0) { + break; + } + } + + start_time = TIMESTAMP; + if (s_nsnap < SIMSNAP) { + s_wait[s_nsnap] = start_time - rx_end; + } + // Clock the answer off the reader's carrier, not our timer +hitag_tag_send_frame_mc4k_sync(tx, txlen, sof_bits, ledcontrol); + + last_tx_end = TIMESTAMP; + if (s_nsnap < SIMSNAP) { + s_txdur[s_nsnap] = last_tx_end - start_time; + } + snap_next = true; + snap_skipped = 0; + + // TEMP DIAGNOSTIC (flags bit3): what does the envelope actually + // do while we are deaf? + // + // The edge detect mode gives us edges or nothing, and after our + // own answer it gives nothing for about 1200 T0 - but that says + // nothing about whether the signal is missing or the detector is + // asleep. Switching to raw ADC streaming for that window shows + // the envelope itself: min and max over each group of samples, so + // both the level and the reader's modulation depth are visible. + // It costs the window we are blind in anyway. + if ((flags & 8) != 0) { + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | weak); + for (uint32_t i = 0; i < ADCSNAP; i++) { + uint8_t mn = 255, mx = 0; + for (uint32_t k = 0; k < 16; k++) { + uint32_t g = 20000; + while ((FPGA_SSC_RX_Ready() == false) && (--g)) { } + uint8_t v = (uint8_t)FPGA_SSC_RX_Value(); + if (v < mn) mn = v; + if (v > mx) mx = v; + } + s_adc_mn[i] = mn; + s_adc_mx[i] = mx; + } + s_adc_valid = true; + } + + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | weak | sensitive | slope); + if (active_threshold != 127) { + FpgaSendCommand(FPGA_CMD_SET_EDGE_DETECT_THRESHOLD, active_threshold); + } + + + if ((slope != 0) && (threshold == 0)) { + FpgaSendCommand(FPGA_CMD_SET_EDGE_DETECT_THRESHOLD, post_thr); + post_active = true; + } + + // Let our own coil release pass before arming the detector. + // + // Re-arming at once makes the detector's first event our own + // modulation ending, which is why every answer used to be + // followed in the trace by a spurious one bit frame beginning + // 2 T0 after it: + // + // 3896513 | 3897731 | Tag |32: 06 F9 07 C2 our answer + // 3897733 | 3897815 | Rdr | 1: 00 2 T0 later + // 3897919 | 3898223 | Rdr |10: E0 C0 the real command + // + // One edge, then HITAG_T_EOF of quiet closes it as a frame. It + // was harmless - discarded at the dispatcher, held out of the + // post-answer window - but it is not a reader frame, and the + // honest fix is to not manufacture it rather than to filter it + // out of the trace afterwards. + // + // t_WAIT2 (HT2 datasheet 3.5) guarantees the reader cannot begin + // its next command until 90 T0 after our answer ends, so blanking + // a short window costs nothing real. The release transient is + // over within a few T0 - the slope detector compares across 32 us, + // which is 4 T0 - so this has wide margin at both ends. + // Bounded, like every other wait in this file. An unbounded + // spin here wedged the device hard enough to need a reflash: if + // the timestamp is not advancing at this point the condition + // never clears, and there is no WDT_HIT() inside to save it. + uint32_t tail_spin = 20000; + while (((TIMESTAMP - last_tx_end) < HITAG2_TX_TAIL_GUARD) && (--tail_spin)) { } + + // Back to listening: the reader may start its next frame only + // t_WAIT2 (90 T0) after our answer ends. + // + // TEMP DIAGNOSTIC (flags bit6): EnableLoEdgeCapture() only sets + // CLKEN|SWTRG. StartLoEdgeCapture() additionally re-routes + // SSC_FRAME to the timer input and rewrites TC_CMR, so if the + // answer disturbed any of that, only the full form restores it. + if ((flags & 64) != 0) { + StartLoEdgeCapture(); + } else { + EnableLoEdgeCapture(); + } + + // Throw away the edge event latched while we were transmitting. + // + // Our own answer, and the FPGA's idle re-arm that follows it, both + // leave an edge flag set in TC_SR. Re-enabling capture does not + // clear it, so the first thing the receive loop sees is that stale + // event - reported as a 1 bit frame whose 80 T0 EOF timeout then + // runs past the reader's next command. + // + // It is not an analogue artefact at a fixed time: it tracks the + // blanking window exactly. With HITAG2_TX_TAIL_GUARD at 32 it was + // traced 48 T0 after our answer, and at 84 it moved to 1 T0 after - + // always immediately on re-enable. Widening the guard therefore + // cannot remove it; reading the status once does, and costs + // nothing. + (void)GetLoEdgeCaptureStatus(); + + if (s_nsnap < SIMSNAP) { + s_rearm[s_nsnap] = TIMESTAMP - last_tx_end; + } + + // The reader starts its next frame only ~276 T0 after our answer + // ends (measured: it opens 1582 T0 after the START_AUTH it just + // sent). Anything done here is done deaf, and edges that arrive + // meanwhile only latch the most recent one, so the start of the + // reader's frame is lost. Defer our own trace write until after + // the next receive has returned. + tx_pending = true; + tx_pending_len = txlen; + tx_pending_start = start_time; + tx_pending_end = TIMESTAMP; + memcpy(tx_pending_buf, tx, (txlen + 7) / 8); + d_answers++; + if (rxlen == 32) { d_pwd_ok++; } + if (rxlen == 10) { d_read_ok++; } + + } else { + EnableLoEdgeCapture(); } - // Reset the received frame and response timing info memset(rx, 0x00, sizeof(rx)); - response = 0; if (ledcontrol) LED_B_OFF(); } + + // Carry the timer overflow, it is 0 whenever a frame was received + overflow += (GetLoEdgeCaptureCount() / T0); + ResetLoEdgeCapture(); } - lf_finalize(ledcontrol); + Dbprintf("LISTEN blocks=%u adc_valid=%u flags=%u", d_listen5, s_adc_valid, flags); - // release allocated memory from BigBuff. - BigBuf_free(); + if (s_adc_valid) { + for (uint32_t k = 0; k < ADCSNAP; k += 8) { + Dbprintf(" env[%u] %u-%u %u-%u %u-%u %u-%u %u-%u %u-%u %u-%u %u-%u", + k * 16, + s_adc_mn[k], s_adc_mx[k], s_adc_mn[k + 1], s_adc_mx[k + 1], + s_adc_mn[k + 2], s_adc_mx[k + 2], s_adc_mn[k + 3], s_adc_mx[k + 3], + s_adc_mn[k + 4], s_adc_mx[k + 4], s_adc_mn[k + 5], s_adc_mx[k + 5], + s_adc_mn[k + 6], s_adc_mx[k + 6], s_adc_mn[k + 7], s_adc_mx[k + 7]); + } + } + + for (uint8_t i = 0; i < s_nsnap; i++) { + Dbprintf("SNAP%u wait=%u txdur=%u rearm=%u gap=%u rxlen=%u edges=%u skip=%u clk300=%u", + i, s_wait[i], s_txdur[i], s_rearm[i], s_gap[i], s_rxl[i], s_ivn[i], s_skip[i], s_clk[i]); + // The first two exchanges: the START_AUTH the threshold locked on, and the + // password that follows. More than that overruns the print path. + for (uint8_t k = 0; k < s_ivn[i] && k < 12; k += 4) { + uint16_t v[4] = {0}, w[4] = {0}; + for (uint8_t j = 0; j < 4 && (k + j) < s_ivn[i]; j++) { + v[j] = s_iv[i][k + j]; + w[j] = s_it[i][k + j]; + } + Dbprintf(" T0/polls [%u] %u/%u %u/%u %u/%u %u/%u", + k, v[0], w[0], v[1], w[1], v[2], w[2], v[3], w[3]); + } + } + + DBG Dbprintf("TXSTAT frames=%u samples=%u bails=%u (a full answer = 1184 samples)", + (unsigned)g_tx_frames, (unsigned)g_tx_samples, (unsigned)g_tx_bails); + // The step distribution goes in THRSTAT rather than a line of its own. + // + // Adding further Dbprintf calls to this burst loses them: two extra lines here + // never appeared at all while the ones either side of them printed every time, + // on a device confirmed to be running the build that contained them. Six + // arguments in an existing line is what reliably gets through. + // + // p50 is the idle carrier, p90 the ripple shoulder, p99 the reader's gap + // transitions. The threshold has to sit between the shoulder and the tail, so + // it is their separation that matters, not any one of them. + DBG Dbprintf("THRSTAT thr=%u p50=%u p90=%u p99=%u max=%u n=%u", + active_threshold, d_p50, d_p90, d_p99, d_pmax, d_nsteps); + DBG Dbprintf("THRSTAT2 span=%u big=%u locked=%u post=%u", + d_span, d_nbig, thr_locked, post_thr); + DBG Dbprintf("THRSTAT3 settle_t0=%u measured=%u rearmed=%u", d_meas, d_meas_n, d_rearm_n); + DBG Dbprintf("POSTSTAT evaluated=%u", d_post_eval); + DBG Dbprintf("SIMSTAT loops=%u edges=%u frames=%u start_auth=%u answers=%u tracelen=%u", + d_loops, (unsigned)g_hitag_edges, d_frames, d_bits5, d_answers, + (unsigned)BigBuf_get_traceLen()); + DBG Dbprintf("SIMSTAT2 auth64=%u authshort=%u pwd_ok=%u read_ok=%u", + d_auth64, d_auth_short, d_pwd_ok, d_read_ok); + + + hitag_cleanup(ledcontrol); + + // release BigBuf, but keep emulator memory for eview / esave + BigBuf_free_keep_EM(); DbpString("Sim stopped"); // reply_ng(CMD_LF_HITAG_SIMULATE, (checked == -1) ? PM3_EOPABORTED : PM3_SUCCESS, (uint8_t *)tag.sectors, tag_size); } +static bool ht2_receive(uint32_t *resp_start, uint32_t *resp_duration, uint8_t *nrz_samples, size_t *samples); + +// TEMP INSTRUMENT: the half-bit period counts ht2_receive() measured for the most +// recent answer. A tag half bit is 16 carrier periods and two of them 32, and the +// classifier splits at 24 - so the actual values are the only way to tell a +// misclassified gap from a genuinely missing edge. +static uint8_t g_ht2_per[16]; +static uint32_t g_ht2_per_n; +static void ht2_normalise_head(uint8_t *nrz_samples, size_t *nrzs); + void ReaderHitag(const lf_hitag_data_t *payload, bool ledcontrol) { + uint32_t d_txreal[4] = {0}, d_txnom[4] = {0}, d_txbits[4] = {0}; + uint8_t d_txn = 0; + uint32_t d_norx = 0, d_nodec = 0; + uint16_t d_lastn = 0; uint32_t command_start = 0, command_duration = 0; uint32_t response_start = 0, response_duration = 0; @@ -1585,8 +3280,6 @@ void ReaderHitag(const lf_hitag_data_t *payload, bool ledcontrol) { size_t tag_size = 48; bool bStop = false; - // Raw demodulation/decoding by sampling edge periods - size_t periods = 0; // Reset the return status bSuccessful = false; @@ -1641,6 +3334,8 @@ void ReaderHitag(const lf_hitag_data_t *payload, bool ledcontrol) { blocknr = 0; bPwd = false; bAuthenticating = false; + pwd_retries = 0; + crypto_retries = 0; break; } case HT2F_AUTHENTICATE: { @@ -1664,6 +3359,7 @@ void ReaderHitag(const lf_hitag_data_t *payload, bool ledcontrol) { blocknr = 0; bCrypto = false; bAuthenticating = false; + crypto_retries = 0; break; } case HT2F_TEST_AUTH_ATTEMPTS: { @@ -1705,16 +3401,35 @@ void ReaderHitag(const lf_hitag_data_t *payload, bool ledcontrol) { } else if (payload->cmd <= HT2_LAST_CMD) { // hitag 2 settings t_wait_1 = HITAG_T_WAIT_1_MIN; - t_wait_2 = HITAG_T_WAIT_2_MIN; + + // t_WAIT2 is a minimum (HT2 datasheet 3.5, "at least 90"), so a reader may + // take longer and a real tag does not care. Take longer. + // + // Measured against a Proxmark simulating a tag: its answer disturbs its own + // LF front end, and the envelope is still recovering ~580 T0 later when the + // next command would arrive. A 10 bit READ PAGE rides through that intact, + // but a 32 bit password spans ~830 T0 of the recovery ramp and loses an + // edge partway along - 30 or 31 bits of 32, every time. Waiting until the + // envelope has settled costs ~9 ms per exchange against a genuine tag and + // makes the difference between an exchange that completes and one that + // cannot. + t_wait_2 = 1200; tag_size = 48; DBG DbpString("Configured for " _YELLOW_("Hitag 2") " reader"); } // init as reader lf_init(LF_ADC_READER, LF_ADC_WAV_REVERSED, ledcontrol); + + // The timestamp counter has to be running before anything reads TIMESTAMP. + // Only the sniffer and the simulator ever started it, so in the reader every + // TIMESTAMP was whatever TC2 happened to hold: response_start, and the frame + // timestamps handed to LogTraceBits, were meaningless - which is why the + // reader's own `lf hitag list` came out as rows of 0 | 65535 and + // 4294967235 | 65474, with none of its own frames placed against them. + StartTimestamp(); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - uint8_t tag_modulation; size_t max_nrzs = (8 * HITAG_FRAME_LEN + 5) * 2; // up to 2 nrzs per bit uint8_t nrz_samples[max_nrzs]; bool turn_on = true; @@ -1722,23 +3437,43 @@ void ReaderHitag(const lf_hitag_data_t *payload, bool ledcontrol) { int16_t checked = 0; uint32_t signal_size = 10000; + // TEMP INSTRUMENT: how long one pass of this loop actually takes, so the USB + // poll interval below can be argued from a measurement rather than a guess. + uint32_t d_iter = 0, d_max = 0; + uint16_t d_t0 = GetPrecisionCounterRaw(), d_prev = 0; + while (bStop == false && BUTTON_PRESS() == false) { + { + uint16_t now = GetPrecisionCounterRaw(); + if (d_iter != 0) { + uint32_t dt = (uint16_t)(now - d_prev) / T0; + if (dt > d_max) { + d_max = dt; + } + } + d_prev = now; + d_iter++; + } + // use malloc initSampleBufferEx(&signal_size, true); WDT_HIT(); - // only every 1000th times, in order to save time when collecting samples. - if (checked == 4000) { - if (data_available()) { - checked = -1; - break; - } else { - checked = 0; - } + // Poll USB every pass. + // + // This used to fire only every 4000th iteration, to save time while + // collecting samples. One iteration here is a whole exchange - wait, + // transmit a frame, wait, receive the answer - so 4000 of them is about a + // minute during which the Proxmark answers nothing at all: a client that + // gives up and sends CMD_BREAK_LOOP is not heard, `hw ping` from a second + // client times out, and the device looks wedged until it comes back on its + // own. data_available() is a cheap status read next to an LF exchange. + if (data_available()) { + checked = -1; + break; } - ++checked; // By default reset the transmission buffer tx = txbuf; @@ -1792,174 +3527,151 @@ void ReaderHitag(const lf_hitag_data_t *payload, bool ledcontrol) { } // Transmit the reader frame - command_duration = hitag2_reader_send_frame(tx, txlen); + // TEMP INSTRUMENT: how long the frame really took, against the nominal + // count hitag2_reader_send_frame() returns. The bit loop waits on ADC + // sample counts, so if it is running slow it misses samples and each + // "period" costs more real time - which stretches the frame on the air. + { + uint16_t t_tx = GetPrecisionCounterRaw(); + command_duration = hitag2_reader_send_frame(tx, txlen); + uint32_t real = (uint16_t)(GetPrecisionCounterRaw() - t_tx) / T0; + if (d_txn < 4) { + d_txreal[d_txn] = real; + d_txnom[d_txn] = command_duration; + d_txbits[d_txn] = txlen; + d_txn++; + } + } response_start = command_start + command_duration; // Let the antenna and ADC values settle - // And find the position where edge sampling should start - lf_wait_periods(t_wait_1 - t_wait_1_guard); + // And find the position where edge sampling should start. + // + // Refresh the ADC reference before listening. + // + // lf_count_edge_periods() slices at adc_avg +/- 20, and that average is + // taken once in lf_init() and never renewed - so by the time we listen for + // an answer to a 32 bit command, the reference predates both the field + // settling and our own 890 T0 transmission. That is the reader side twin + // of the simulator's post-transmission deafness, and it is why the tag's + // first answer decodes and its second one does not. + // + // lf_sample_mean() consumes exactly 32 carrier periods, so take them out of + // the wait rather than adding to it and leave the turnaround unchanged. + // + // Take it at the END of the wait, not the start. Both orders cost the + // same 32 periods and leave the turnaround identical, but the reference + // has to describe the envelope the answer will actually ride on. Sampled + // first, it is taken ~170 T0 earlier, while the field is still recovering + // from our own transmission, and the +/- 20 slicing band then sits below + // the settled level - which is where the missed edges come from. + // Measured symptom: the merges cluster in the first few intervals of the + // answer, 16 15 17 15 17 30 18 ..., and the frame lands on 35 bits. + lf_wait_periods(t_wait_1 - t_wait_1_guard - 32); + lf_sample_mean(); + + // Start listening from a known modulation state. + // + // ht2_receive() opens with lf_get_tag_modulation(), which reports whatever + // `rising_edge` was left at - and nothing reset it, so after our own + // transmission it reflects the last edge of *that*, not the tag's answer. + // When it comes out 0 the receive concludes it missed the first period and + // synthesises a leading sample, which shifts every Manchester pair after + // it. Measured against a simulator: its answer arrived as 76 samples of + // 1,0,1,1,0,1,0,1... where the genuine fob gives 1,0,1,0,1,0,1,0... - the + // same stream with one sample inserted - so the SOF check failed and the + // whole read was abandoned. It happens after a 32 bit command and not + // after a 5 bit one, which is why the UID reads and the password does not. + lf_reset_counter(); response_start += t_wait_1 - t_wait_1_guard; - // 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; - } - - if (tag_modulation == 0) { - // hitag replies always start with 11111 == 1010101010, if we see 0 - // it means we missed the first period, e.g. if the signal never crossed 0 since reader signal - // so let's add it: - nrz_samples[nrzs++] = tag_modulation ^ 1; - // Register the number of periods that have passed - // we missed the begin of response but we know it happened one period of 16 earlier - response_start += periods - 16; - response_duration = response_start; - } else { - // Register the number of periods that have passed - response_start += periods; - response_duration = response_start; - } - // 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) { - DBG Dbprintf("Detected timeout after [" _YELLOW_("%zu") "] 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; - if (nrzs < max_nrzs) { - nrz_samples[nrzs++] = tag_modulation; - } - response_duration += periods; - // 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; - response_duration += periods; - tag_modulation ^= 1; - } else { - // The function lf_count_edge_periods() returns > 64 periods, this is not a valid number periods - DBG Dbprintf("Detected unexpected period count: " _RED_("%zu"), periods); - break; - } + // Receive the tag's answer through the shared implementation. + // + // This used to be a second, near duplicate copy of the receive loop, and + // the two drifted: fixes that made `lf hitag reader` reliable never + // reached this path, so a dump would decode the UID only occasionally and + // otherwise stop dead - the reader's own trace showed its START_AUTH and + // nothing else, never reaching the password. One implementation, one set + // of fixes. + if (ht2_receive(&response_start, &response_duration, nrz_samples, &nrzs) == false) { + DBG DbpString("No tag answer"); + d_norx++; + // Report it as no answer. rxlen otherwise still holds the length of + // the *previous* frame, so the state machine is handed a stale 32 and + // walks on as though the tag had replied. + rxlen = 0; + continue; } - // 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) - LogTraceBits(tx, txlen, command_start, command_start + command_duration, true); + ht2_normalise_head((uint8_t *)nrz_samples, &nrzs); - // Reset values for receiving frames - memset(rx, 0x00, sizeof(rx)); - rxlen = 0; - - // If there is no response - if (detected_tag_modulation == false) { - checked = -1; - goto out; - } - - // 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) { - - if (nrzs >= max_nrzs) { - DBG Dbprintf("max_nrzs ( " _YELLOW_("%zu") " ) is odd? Must be even!", max_nrzs); - continue; - } - nrz_samples[nrzs++] = tag_modulation; - } - - if (ledcontrol) LED_B_ON(); // decode bitstream manrawdecode((uint8_t *)nrz_samples, &nrzs, true, 0); // decode frame + // + // Shared with the UID path rather than repeated here. This used to demand + // exactly five leading ones and pack from a fixed offset of five, which + // breaks whenever the head of the answer is disturbed - and it routinely + // is, since the first half bit can be lost on an idle line and a receiver + // that synthesises a replacement shifts every pair after it. The result + // was a payload short by one bit and shifted left: a tag answering + // CE129911 decoded as 9C253222. - // Verify if the header consists of five consecutive ones - if (nrzs < 5) { - DBG Dbprintf("Detected unexpected number of manchester decoded samples [%zu]", nrzs); - break; - } else { - - size_t i; - for (i = 0; i < 5; i++) { - if (nrz_samples[i] != 1) { - DBG Dbprintf("Detected incorrect header, the bit [%zu] is zero instead of one, abort", i); - break; + if (ht2_packbits(nrz_samples, nrzs, rx, &rxlen) == false) { + DBG Dbprintf("Could not decode the tag answer, %u samples", (unsigned)nrzs); + d_nodec++; + d_lastn = (uint16_t)nrzs; + if (d_nodec == 1) { + for (uint32_t k = 0; (k + 9) < g_ht2_per_n; k += 10) { + Dbprintf("PER[%2u] %3u %3u %3u %3u %3u %3u %3u %3u %3u %3u", k, + g_ht2_per[k], g_ht2_per[k+1], g_ht2_per[k+2], g_ht2_per[k+3], g_ht2_per[k+4], + g_ht2_per[k+5], g_ht2_per[k+6], g_ht2_per[k+7], g_ht2_per[k+8], g_ht2_per[k+9]); } } - if (i < 5) { - break; - } + // One frame we could not decode is not the end of the exchange. + // Breaking out abandoned the whole read on a single bad frame, which + // is why the reader gave up the moment the tag answered its password - + // and why the retry in hitag2_password() never got a chance to fire. + rxlen = 0; + continue; } - // Pack the response into a byte array - for (size_t i = 5; i < nrzs && rxlen < (sizeof(rx) << 3); i++) { - - uint8_t bit = nrz_samples[i]; - if (bit > 1) { // When Manchester detects impossible symbol it writes "7" - DBG Dbprintf("Error in Manchester decoding, abort"); - break; - } - - rx[rxlen >> 3] |= bit << (7 - (rxlen % 8)); - rxlen++; - } - - // skip spurious bit - if (rxlen % 8 == 1) { - rxlen--; - } // Check if frame was captured and store it - LogTraceBits(rx, rxlen, response_start, response_start + response_duration, false); + // response_duration is accumulated from response_start and is therefore + // already an absolute end time, not a length; adding response_start to it + // again put the end of every tag frame at roughly twice the real time. + LogTraceBits(rx, rxlen, response_start, response_duration, false); // TODO when using cumulative time for command_start, pm3 doesn't reply anymore, e.g. on lf hitag reader --23 -k 4F4E4D494B52 // Use delta time? -// command_start = response_start + response_duration; + // TODO when using cumulative time for command_start, pm3 doesn't reply anymore, e.g. on lf hitag reader --23 -k 4F4E4D494B52 + // Use delta time? + // command_start = response_start + response_duration; + // + // Confirmed on hardware: making this cumulative stops the reader reading + // a tag at all - 0 UID reads out of 12 against a simulator that answered + // all 12 START_AUTHs, where the same test read the UID before the change. + // The non monotonic trace (reader frames printing as 4294967015) is the + // lesser evil until the timing is reworked properly. command_start = 0; nrzs = 0; } out: + + DBG Dbprintf("RXFAIL no_signal=%u undecodable=%u last_samples=%u", d_norx, d_nodec, d_lastn); + for (uint8_t i = 0; i < d_txn; i++) { + Dbprintf("TXFRAME %u bits: real=%u T0 nominal=%u T0", d_txbits[i], d_txreal[i], d_txnom[i]); + } + + DBG Dbprintf("RDRLOOP passes=%u span=%u T0 max_pass=%u T0", + d_iter, (unsigned)((uint16_t)(GetPrecisionCounterRaw() - d_t0) / T0), d_max); + + StopTimestamp(); lf_finalize(ledcontrol); // release allocated memory from BigBuff. @@ -1974,16 +3686,23 @@ out: , (uint8_t *)tag.sectors , tag_size ); + } void WriterHitag(const lf_hitag_data_t *payload, bool ledcontrol) { + uint32_t d_txreal[4] = {0}, d_txnom[4] = {0}, d_txbits[4] = {0}; + uint8_t d_txn = 0; + // TEMP INSTRUMENT: why an answer was not taken. d_noans counts silent + // windows, d_badn the decodes that failed and d_badnrz their sample counts. + uint16_t d_noans = 0, d_badn = 0, d_badnrz[6] = {0}, d_badraw[6] = {0}; + uint8_t d_badper[12] = {0}, d_badpern = 0; uint32_t command_start = 0; uint32_t command_duration = 0; uint32_t response_start = 0; uint32_t response_duration = 0; - uint8_t rx[HITAG_FRAME_LEN]; + uint8_t rx[HITAG_FRAME_LEN] = {0}; size_t rxlen = 0; uint8_t txbuf[HITAG_FRAME_LEN]; @@ -1998,7 +3717,6 @@ void WriterHitag(const lf_hitag_data_t *payload, bool ledcontrol) { bool bStop = false; // Raw demodulation/decoding by sampling edge periods - size_t periods = 0; // iceman: Hitag2 is filled with static global vars. // these following are globals status indicator :-| @@ -2051,6 +3769,14 @@ void WriterHitag(const lf_hitag_data_t *payload, bool ledcontrol) { // init as reader lf_init(LF_ADC_READER, LF_ADC_WAV_REVERSED, ledcontrol); + + // The timestamp counter has to be running before anything reads TIMESTAMP. + // Only the sniffer and the simulator ever started it, so in the reader every + // TIMESTAMP was whatever TC2 happened to hold: response_start, and the frame + // timestamps handed to LogTraceBits, were meaningless - which is why the + // reader's own `lf hitag list` came out as rows of 0 | 65535 and + // 4294967235 | 65474, with none of its own frames placed against them. + StartTimestamp(); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // Tag specific configuration settings (sof, timings, etc.) @@ -2074,12 +3800,16 @@ void WriterHitag(const lf_hitag_data_t *payload, bool ledcontrol) { } else if (payload->cmd <= HT2_LAST_CMD) { // hitag 2 settings t_wait_1 = HITAG_T_WAIT_1_MIN; - t_wait_2 = HITAG_T_WAIT_2_MIN; + // Same as the reader path: t_WAIT2 is a minimum, so wait past the + // simulator's post-answer recovery. Left at 90 here, the writer's + // password landed while a simulated tag was still deaf and came back as a + // garbled 30 bit frame spanning 3023 T0, so the exchange died straight + // after the UID. + t_wait_2 = 1200; tag_size = 48; DBG DbpString("Configured for " _YELLOW_("Hitag 2") " writer"); } - uint8_t tag_modulation; size_t max_nrzs = (8 * HITAG_FRAME_LEN + 5) * 2; // up to 2 nrzs per bit uint8_t nrz_samples[max_nrzs]; size_t nrzs = 0; @@ -2092,16 +3822,19 @@ void WriterHitag(const lf_hitag_data_t *payload, bool ledcontrol) { // use malloc initSampleBufferEx(&signal_size, true); - // only every 4000th times, in order to save time when collecting samples. - if (checked == 4000) { - if (data_available()) { - checked = -1; - break; - } else { - checked = 0; - } + // Poll USB every pass. + // + // This used to fire only every 4000th iteration, to save time while + // collecting samples. One iteration here is a whole exchange - wait, + // transmit a frame, wait, receive the answer - so 4000 of them is about a + // minute during which the Proxmark answers nothing at all: a client that + // gives up and sends CMD_BREAK_LOOP is not heard, `hw ping` from a second + // client times out, and the device looks wedged until it comes back on its + // own. data_available() is a cheap status read next to an LF exchange. + if (data_available()) { + checked = -1; + break; } - ++checked; WDT_HIT(); @@ -2141,13 +3874,28 @@ void WriterHitag(const lf_hitag_data_t *payload, bool ledcontrol) { } // Transmit the reader frame - command_duration = hitag2_reader_send_frame(tx, txlen); + // TEMP INSTRUMENT: how long the frame really took, against the nominal + // count hitag2_reader_send_frame() returns. The bit loop waits on ADC + // sample counts, so if it is running slow it misses samples and each + // "period" costs more real time - which stretches the frame on the air. + { + uint16_t t_tx = GetPrecisionCounterRaw(); + command_duration = hitag2_reader_send_frame(tx, txlen); + uint32_t real = (uint16_t)(GetPrecisionCounterRaw() - t_tx) / T0; + if (d_txn < 4) { + d_txreal[d_txn] = real; + d_txnom[d_txn] = command_duration; + d_txbits[d_txn] = txlen; + d_txn++; + } + } // global write state variable used // tearoff occurred if ((writestate == WRITE_STATE_PROG) && (tearoff_hook() == PM3_ETEAROFF)) { reply_ng(CMD_LF_HITAG2_WRITE, PM3_ETEAROFF, NULL, 0); - lf_finalize(ledcontrol); + StopTimestamp(); + lf_finalize(ledcontrol); BigBuf_free(); return; } @@ -2155,85 +3903,55 @@ void WriterHitag(const lf_hitag_data_t *payload, bool ledcontrol) { response_start = command_start + command_duration; // Let the antenna and ADC values settle - // And find the position where edge sampling should start - lf_wait_periods(t_wait_1 - t_wait_1_guard); + // And find the position where edge sampling should start. + // + // Refresh the ADC reference before listening. + // + // lf_count_edge_periods() slices at adc_avg +/- 20, and that average is + // taken once in lf_init() and never renewed - so by the time we listen for + // an answer to a 32 bit command, the reference predates both the field + // settling and our own 890 T0 transmission. That is the reader side twin + // of the simulator's post-transmission deafness, and it is why the tag's + // first answer decodes and its second one does not. + // + // lf_sample_mean() consumes exactly 32 carrier periods, so take them out of + // the wait rather than adding to it and leave the turnaround unchanged. + // + // Take it at the END of the wait, not the start. Both orders cost the + // same 32 periods and leave the turnaround identical, but the reference + // has to describe the envelope the answer will actually ride on. Sampled + // first, it is taken ~170 T0 earlier, while the field is still recovering + // from our own transmission, and the +/- 20 slicing band then sits below + // the settled level - which is where the missed edges come from. + // Measured symptom: the merges cluster in the first few intervals of the + // answer, 16 15 17 15 17 30 18 ..., and the frame lands on 35 bits. + lf_wait_periods(t_wait_1 - t_wait_1_guard - 32); + lf_sample_mean(); + + // Start listening from a known modulation state. + // + // ht2_receive() opens with lf_get_tag_modulation(), which reports whatever + // `rising_edge` was left at - and nothing reset it, so after our own + // transmission it reflects the last edge of *that*, not the tag's answer. + // When it comes out 0 the receive concludes it missed the first period and + // synthesises a leading sample, which shifts every Manchester pair after + // it. Measured against a simulator: its answer arrived as 76 samples of + // 1,0,1,1,0,1,0,1... where the genuine fob gives 1,0,1,0,1,0,1,0... - the + // same stream with one sample inserted - so the SOF check failed and the + // whole read was abandoned. It happens after a 32 bit command and not + // after a 5 bit one, which is why the UID reads and the password does not. + lf_reset_counter(); response_start += t_wait_1 - t_wait_1_guard; - // 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; - } - - if (tag_modulation == 0) { - // hitag replies always start with 11111 == 1010101010, if we see 0 - // it means we missed the first period, e.g. if the signal never crossed 0 since reader signal - // so let's add it: - nrz_samples[nrzs++] = tag_modulation ^ 1; - // Register the number of periods that have passed - // we missed the begin of response but we know it happened one period of 16 earlier - response_start += periods - 16; - response_duration = response_start; - } else { - // Register the number of periods that have passed - response_start += periods; - response_duration = response_start; - } - // 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) { - DBG Dbprintf("Detected timeout after [" _YELLOW_("%zu") "] 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; - if (nrzs < max_nrzs) { - nrz_samples[nrzs++] = tag_modulation; - } - response_duration += periods; - // 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; - response_duration += periods; - tag_modulation ^= 1; - } else { - // The function lf_count_edge_periods() returns > 64 periods, this is not a valid number periods - DBG Dbprintf("Detected unexpected period count: " _RED_("%zu"), periods); - break; - } - } - - // Wait some extra time for flash to be programmed + // Receive the tag's answer through the shared implementation. + // + // This used to be a second, near duplicate copy of the receive loop, and + // the two drifted exactly as the reader's copy had: the first edge + // compensation, the even sample padding and the head normalisation all + // had to be written twice, and this copy never got the later fixes. One + // implementation, one set of fixes. + bool got_answer = ht2_receive(&response_start, &response_duration, nrz_samples, &nrzs); // 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 @@ -2245,81 +3963,74 @@ void WriterHitag(const lf_hitag_data_t *payload, bool ledcontrol) { rxlen = 0; // If there is no response, just repeat the loop - if (detected_tag_modulation == false) { + if (got_answer == false) { + d_noans++; continue; } - // 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) { - - if (nrzs >= max_nrzs) { - Dbprintf("max_nrzs ( " _YELLOW_("%zu") " ) is odd? Must be even!", max_nrzs); - continue; - } else { - nrz_samples[nrzs++] = tag_modulation; - } - } - if (ledcontrol) LED_B_ON(); + ht2_normalise_head((uint8_t *)nrz_samples, &nrzs); + + const uint16_t d_raw = (uint16_t)nrzs; + // decode bitstream manrawdecode((uint8_t *)nrz_samples, &nrzs, true, 0); - // decode frame - - // Verify if the header consists of five consecutive ones - if (nrzs < 5) { - DBG Dbprintf("Detected unexpected number of manchester decoded samples [%zu]", nrzs); - break; - } else { - - size_t i; - for (i = 0; i < 5; i++) { - if (nrz_samples[i] != 1) { - DBG Dbprintf("Detected incorrect header, the bit " _YELLOW_("%zu") " is zero instead of one, abort", i); - break; + // Decode the frame with the shared packer rather than a private copy. + // + // The copy that used to be here had the same two faults the reader path + // did, and one of its own: it demanded exactly five leading ones and + // packed from a fixed offset of five, so it could not cope with a frame + // whose head was disturbed; it ORed into rx without clearing it, so every + // frame accumulated the ones of all its predecessors; and rx itself was + // never initialised, so the first frame ORed onto stack garbage. The + // "skip spurious bit" fudge below it was papering over the same thing. + if (ht2_packbits(nrz_samples, nrzs, rx, &rxlen) == false) { + if (d_badn < ARRAYLEN(d_badnrz)) { + d_badnrz[d_badn] = (uint16_t)nrzs; + d_badraw[d_badn] = d_raw; + } + if (d_badpern == 0) { + d_badpern = (g_ht2_per_n > ARRAYLEN(d_badper)) ? ARRAYLEN(d_badper) : (uint8_t)g_ht2_per_n; + for (uint8_t k = 0; k < d_badpern; k++) { + d_badper[k] = g_ht2_per[k]; } } - - if (i < 5) { - break; - } + d_badn++; + DBG Dbprintf("Could not decode the tag answer, %u samples", (unsigned)nrzs); + // One frame we could not decode is not the end of the exchange. + // Breaking out abandoned the whole read on a single bad frame, which + // is why the reader gave up the moment the tag answered its password - + // and why the retry in hitag2_password() never got a chance to fire. + rxlen = 0; + continue; } - // Pack the response into a byte array - for (size_t i = 5; i < nrzs && rxlen < (sizeof(rx) << 3); i++) { - - uint8_t bit = nrz_samples[i]; - - // When Manchester detects impossible symbol it writes "7" - if (bit > 1) { - DBG Dbprintf("Error in Manchester decoding, abort"); - break; - } - - // >> 3 instead of div by 8 - rx[rxlen >> 3] |= bit << (7 - (rxlen % 8)); - rxlen++; - } - - // skip spurious bit - if (rxlen % 8 == 1) { - rxlen--; - } - - // Check if frame was captured and store it - LogTraceBits(rx, rxlen, response_start, response_start + response_duration, false); + // Check if frame was captured and store it. + // response_duration is accumulated from response_start and is therefore + // already an absolute end time, not a length; adding response_start to it + // again put the end of every tag frame at roughly twice the real time. + LogTraceBits(rx, rxlen, response_start, response_duration, false); command_start = 0; nrzs = 0; } out: + for (uint8_t i = 0; i < d_txn; i++) { + Dbprintf("TXFRAME %u bits: real=%u T0 nominal=%u T0", d_txbits[i], d_txreal[i], d_txnom[i]); + } + if (d_badpern) { + DBG Dbprintf("WRXPER %u %u %u %u %u %u %u %u %u %u %u %u", + d_badper[0], d_badper[1], d_badper[2], d_badper[3], + d_badper[4], d_badper[5], d_badper[6], d_badper[7], + d_badper[8], d_badper[9], d_badper[10], d_badper[11]); + } + DBG Dbprintf("WRXSTAT silent=%u undecodable=%u bits: %u %u %u %u raw: %u %u %u %u", + d_noans, d_badn, d_badnrz[0], d_badnrz[1], d_badnrz[2], d_badnrz[3], + d_badraw[0], d_badraw[1], d_badraw[2], d_badraw[3]); + + StopTimestamp(); lf_finalize(ledcontrol); // release allocated memory from BigBuff. @@ -2379,12 +4090,26 @@ static bool ht2_receive(uint32_t *resp_start, uint32_t *resp_duration, uint8_t * // Keep administration of the first edge detection bool waiting_for_first_edge = true; + // set once the first edge has been taken, until the interval after it has been + // seen and can confirm or reject it - see the resolution below + bool first_edge_pending = false; + + // set when a half bit sample is synthesised at the head, see the tail fix below + bool inserted_leading = false; + // Did we detected any modulaiton at all bool detected_tag_modulation = false; // Reset the number of NRZ samples and use edge detection to detect them size_t nrzs = 0; + // Bound the loop independently of nrzs. Re-anchoring below resets nrzs, and + // the loop condition is written in terms of it, so without this a re-anchor + // makes the receive unbounded and the command never returns. + uint32_t spins = 4 * HT2_MAX_NRSZ; + + g_ht2_per_n = 0; + // Use the current modulation state as starting point uint8_t tag_modulation = lf_get_tag_modulation(); @@ -2392,6 +4117,10 @@ static bool ht2_receive(uint32_t *resp_start, uint32_t *resp_duration, uint8_t * while (nrzs < HT2_MAX_NRSZ) { + if (spins-- == 0) { + break; + } + // Get the timing of the next edge in number of wave periods size_t periods = lf_count_edge_periods(128); @@ -2408,6 +4137,7 @@ static bool ht2_receive(uint32_t *resp_start, uint32_t *resp_duration, uint8_t * // it means we missed the first period, e.g. if the signal never crossed 0 since reader signal // so let's add it: nrz_samples[nrzs++] = tag_modulation ^ 1; + inserted_leading = true; // Register the number of periods that have passed // we missed the begin of response but we know it happened one period of 16 earlier resp_start += (periods - 16); @@ -2421,6 +4151,22 @@ static bool ht2_receive(uint32_t *resp_start, uint32_t *resp_duration, uint8_t * // Indicate that we have dealt with the first edge waiting_for_first_edge = false; + + // Defer judging this edge until the next interval is known. + // + // The reader starts sampling t_wait_1_guard before the answer is due, + // so the first edge it sees may be the idle line rather than the tag. + // The two are trivially told apart by what follows: a real first half + // bit runs about 16 carrier periods, while a false start is followed by + // a gap of only a few. Measured against a simulator, that false start + // showed up as a 3..6 period interval and cost the frame a half bit - + // answers arrived as 70..74 samples where 74 is right, and + // ht2_packbits() rejected them. + // + // Deciding one interval late costs nothing and needs no state to be + // rewound, which is what made re-anchoring lose samples. + first_edge_pending = true; + // 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 @@ -2432,7 +4178,61 @@ static bool ht2_receive(uint32_t *resp_start, uint32_t *resp_duration, uint8_t * break; } } - // Evaluate the number of periods before the next edge + // Measured, so it is not retried blind: re-anchoring the frame when the + // first measured gap is too short to be a half bit does clean the period + // sequence perfectly - 16 16 15 17 15 17 instead of 16 6 18 15 17 - but it + // costs samples. The frame fell from 37 decoded bits to 35, under the 36 + // that ht2_packbits() needs, and failures went from 4 to 84. The + // diagnosis is right; discarding the edge is the wrong remedy. + + // Resolve the deferred first edge, now that we can see what followed it. + if (first_edge_pending) { + first_edge_pending = false; + + if (periods <= 10) { + // A false start: the edge we anchored on was the idle line, and + // this short gap is the distance to the real one. Drop the sample + // that edge produced and anchor here instead, keeping the + // modulation state that goes with it. + if (nrzs > 0) { + nrzs--; + } + tag_modulation ^= 1; + resp_start += periods; + resp_duration = resp_start; + continue; + } + } + + if (g_ht2_per_n < ARRAYLEN(g_ht2_per)) { + g_ht2_per[g_ht2_per_n++] = (periods > 255) ? 255 : (uint8_t)periods; + } + + // Evaluate the number of periods before the next edge. + // + // A tag half bit is 16 carrier periods and a doubled one 32; measured + // against a simulator the answer sits at 15..18 and 30..33, with an + // occasional glitch of about 6 right at the start that this accepts as a + // half bit and which then shifts every Manchester pair after it. + // + // Two ways of rejecting it were tried and both are worse. Dropping the + // glitch inverts the polarity of everything that follows, because the + // signal really did change state - the reader ended up restarting the + // exchange over and over, 97 START_AUTHs for 49 answers. Carrying it into + // the next interval keeps the polarity but lands on 24 periods, which is + // ambiguous between one half bit and two, and the sample count fell from + // 74 to 70. Needs the glitch not to be produced, rather than classified. + // + // A third was tried and is worse still: reading a doubled interval in the + // first ten half bits as a missed edge instead - two alternating samples + // and no polarity flip - on the reasoning that the answer's SOF is five + // '1' bits, so strictly alternating, so it cannot contain a doubled half + // bit. Writes went from 5 of 6 to 0 of 6. The premise is sound but the + // window is not: answers on this rig arrive as 16 15 17 15 17 15 17 30 33 + // 31 18 ..., three doubled intervals in a row while nrzs is still under + // ten, so the tenth sample is already well past the SOF and the rule fires + // on real payload. A missed edge cannot be told from a doubled half bit + // by position, only by an SOF boundary we do not actually know. if (periods > 24 && periods <= 64) { // Detected two sequential equal bits and a modulation switch // NRZ modulation: (11 => --|) or (11 __|) @@ -2468,13 +4268,68 @@ static bool ht2_receive(uint32_t *resp_start, uint32_t *resp_duration, uint8_t * // 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 a sample was synthesised at the head, every pair after it is shifted by + // one and the final pair loses its second half. manrawdecode() cannot + // classify that pair, writes the impossible symbol 7, and packing stops a bit + // early - a tag answering CE129911 decodes as CE129910. + // + // That missing half carries no information. Manchester pairs are (1,0)='1' + // and (0,1)='0', so the first half alone determines the bit and the second is + // simply its complement. Synthesising it completes the pair and recovers the + // last bit, no closing edge required. + if (inserted_leading && nrzs && ((nrzs + 2) < HT2_MAX_NRSZ)) { + // Two samples, forming one legal pair, not one. + // + // The synthesised head shifts the pairing, and manrawdecode() picks its + // own alignment on top of that, so a single filler can still leave the + // closing symbol without a partner - the payload then lands one bit short + // (31 of 32) and is thrown away. A whole pair gives the decoder slack + // whichever alignment it settles on. + const uint8_t last = nrz_samples[nrzs - 1]; + nrz_samples[nrzs++] = (last != 0) ? 0 : 1; + nrz_samples[nrzs++] = last; + } + if ((nrzs % 2) != 0) { if (nrzs >= HT2_MAX_NRSZ) { return false; } - nrz_samples[nrzs++] = tag_modulation; + // Complete the pair with the complement of its first half, not with the + // current line level. Manchester pairs are (1,0)='1' and (0,1)='0', so + // the second half is always the inverse of the first; appending the level + // instead can produce (1,1) or (0,0), which manrawdecode() then flags as + // an impossible symbol and the payload comes up a bit short. + nrz_samples[nrzs] = (nrz_samples[nrzs - 1] != 0) ? 0 : 1; + nrzs++; + } + + // Whatever happened above, the closing pair has to be a legal one. The last + // half bit of a tag's answer has no transition after it - nothing follows, so + // the line simply returns to idle - and the demodulator can be left holding a + // duplicated sample. The first half already determines the bit, so rewriting + // the second as its complement recovers it rather than discarding the pair. + if ((nrzs >= 2) && (nrz_samples[nrzs - 1] == nrz_samples[nrzs - 2])) { + nrz_samples[nrzs - 1] = (nrz_samples[nrzs - 2] != 0) ? 0 : 1; + } + + // A Hitag 2 answer opens with a SOF '1', which in half bit samples is (1,0), + // so the very first sample must be a 1. If it is not, an extra sample has + // been prepended - the first edge compensation above does exactly that - and + // manrawdecode() then has to guess the pairing. It guesses by counting + // (bits[i] == bits[i+1]) errors for both alignments, which on a short frame + // can tie or come out backwards; picking alignment 1 drops both the first + // sample and the tail, yielding 36 symbols with a spurious leading zero and a + // payload one bit short. + // + // Dropping that leading sample makes alignment 0 the correct one, so the + // guess cannot go wrong. + if (nrzs && (nrz_samples[0] != 1)) { + for (size_t k = 1; k < nrzs; k++) { + nrz_samples[k - 1] = nrz_samples[k]; + } + nrzs--; } *samples = nrzs; @@ -2482,39 +4337,185 @@ static bool ht2_receive(uint32_t *resp_start, uint32_t *resp_duration, uint8_t * return detected_tag_modulation; } +// A Hitag 2 answer opens with a SOF '1', whose first half bit sample is a 1. +// Anything else means a sample was prepended - the first edge compensation in +// ht2_receive() does exactly that - and manrawdecode() would then have to guess +// the pairing. It guesses by counting (bits[i] == bits[i+1]) errors for both +// alignments, which on a short frame can tie or come out backwards; picking +// alignment 1 drops both the first sample and the tail, yielding 36 symbols with +// a spurious leading zero and a payload one bit short - a tag answering CE129911 +// read back as 9C253222. Dropping the leading sample makes alignment 0 correct +// by construction, so the guess cannot go wrong. +// +// Every Hitag 2 decode path needs this, so it lives here rather than being +// copied: ht2_tx_rx() lacked it, which is the brute force path behind +// `lf hitag chk`, `crack2` and `lookup`, where a mis-decode is a wrong verdict +// on a key rather than a visibly wrong read. +static void ht2_normalise_head(uint8_t *nrz_samples, size_t *nrzs) { + if (*nrzs && (nrz_samples[0] != 1)) { + for (size_t k = 1; k < *nrzs; k++) { + nrz_samples[k - 1] = nrz_samples[k]; + } + (*nrzs)--; + } +} + bool ht2_packbits(uint8_t *nrz_samples, size_t nrzs, uint8_t *rx, size_t *rxlen) { - // Verify if the header consists of five consecutive ones + if (nrzs < 5) { return false; } - // detect hitag 2 header - if (memcmp(nrz_samples, "\x01\x01\x01\x01\x01", 5)) { + // A Hitag 2 answer is a SOF of ones followed by a 32 bit payload: 37 bits. + // + // The head is the anchor, not the length. Sampling starts a known t_WAIT1 + // after the reader's command, and the normalisation above guarantees that + // sample `start` is the first half bit of the SOF, so the SOF is simply the + // datasheet's five bits at the front and anything past 37 is tail junk. + // + // Deriving the SOF as (length - 32) instead was wrong, and only looked right + // because it was calibrated against this repo's own simulator, which answers + // in exactly 37. A genuine Paxton fob measured on this rig gives 76 raw + // samples - 38 bits - with the surplus bit at the TAIL, so that rule skipped + // six bits instead of five, dropped the first payload bit and took a spurious + // one at the end: CE129911 read back as 9C253223, the same value shifted left + // once. The one case where the head really is short is 36 bits, where the + // opening half bit was lost and only four SOF bits survive. + // + // Do not instead try several alignments and keep whichever packs cleanly: + // more than one can pack a full 32 bits, and picking the wrong one hands back + // a plausible but wrong UID. Refusing to decode is far better than that. + size_t start = 0; + if (nrz_samples[0] != 1) { + // a leading non-one is only ever the spurious sample, never part of a SOF + start = 1; + } + + if (nrzs <= start) { return false; } - // Pack the response into a byte array - for (size_t i = 5; i < nrzs && *rxlen < (HITAG_FRAME_LEN << 3); i++) { + const size_t remaining = nrzs - start; - uint8_t bit = nrz_samples[i]; + // Which payload length is this? + // + // A tag answers either 32 bits of page data or, acknowledging a WRITE PAGE, a + // 10 bit echo of the command. This only ever accepted the 32 bit case, so the + // reader threw away its own write acknowledgement - the simulator's trace + // showed it echoing WRITE PAGE (4) correctly and the write failing anyway. + // + // A whole answer is SOF + payload, so the total picks the length out; the SOF + // match below then still has to agree. + size_t payload = 0; + if ((remaining >= 36) && (remaining <= 39)) { + payload = 32; + } else if ((remaining >= 14) && (remaining <= 17)) { + payload = 10; + } else { + return false; + } - // When Manchester detects impossible symbol it writes "7" + // Do NOT widen this to 35 with a three bit SOF. + // + // It is tempting: the reader loses an edge in the tag's answer now and then, + // two half bits merge and the frame arrives two bits short, and 35 looks like + // a complete 32 bit payload behind a clipped header. Measured, it lifts reads + // from 3 of 6 to 6 of 6 and writes from 1 of 3 to 3 of 3. + // + // And it is wrong. Three surviving header ones are not distinctive enough, so + // frames mis-frame and decode to plausible but incorrect values: in that same + // run the UID came back as BD F5 E8 46 - the password - and other blocks as + // zeroes. Silent corruption is far worse than a refused frame, which the + // caller retries anyway. The comment above about not keeping whichever + // alignment packs cleanly is the same lesson; this is the second time. + + // Match the SOF rather than inferring its length from the frame length. + // + // The datasheet SOF is five ones, and a frame that lost its first half bit + // carries four. Deriving the length from the total gets that right when the + // loss also shortens the frame - 36 bits, so four - and wrong when a spurious + // bit at the tail makes up the difference. Measured against a simulator: the + // config answer arrived as 37 bits whose stream was the expected one shifted + // left by one, so it held four SOF ones and a surplus bit at the end, and + // assuming five failed the check at bit four on an answer that was otherwise + // perfect. + // + // So try five and fall back to four. This matches a known pattern, it does + // not guess at data: whichever length is used, the SOF bits still have to be + // ones and the payload still has to be a full 32 bits. + // Prefer the length-implied SOF, and only fall back to the other. + // + // Trying five first regardless is ambiguous whenever the payload itself starts + // with a one: four surviving SOF bits plus that one look like five, and the + // frame decodes shifted left by a bit. Measured against a simulator, exactly + // the blocks beginning with a 1 came back wrong - BDF5E846 as 7BEBD08D, + // B6447420 as 6C88E841, 96000010 as 2C000021 - while every block beginning + // with a 0 was right. + // + // A whole answer is 5 + 32 = 37 bits, so the length says which to try first; + // the pattern check then still has to agree. + const size_t first = (remaining >= (payload + 5)) ? 5 : 4; + size_t sof = 0; + for (size_t n = 0; n < 2; n++) { + + const size_t cand = (n == 0) ? first : (9 - first); + + if (remaining < (cand + payload)) { + continue; + } + + bool ok = true; + for (size_t k = 0; k < cand; k++) { + if (nrz_samples[start + k] != 1) { + ok = false; + break; + } + } + + if (ok) { + sof = cand; + break; + } + } + + if (sof == 0) { + return false; + } + + size_t len = 0; + + // Clear the payload bytes before packing into them. + // + // The loop below ORs each bit in, so a buffer the caller reuses across frames + // accumulates every frame that came before it. ReaderHitag() does reuse one: + // the UID answer CE129911 packed correctly, then the config answer 06F907C2 + // ORed on top of it and came back as CEFB9FD3, and every page after that read + // as the same growing OR - which is why a dump printed one identical value + // for all eight blocks. + memset(rx, 0, (payload + 7) / 8); + + // exactly the payload, and no more: a surplus bit at the tail is junk + for (size_t i = start + sof; (i < nrzs) && (len < payload); i++) { + + const uint8_t bit = nrz_samples[i]; + + // manrawdecode() writes 7 for a pair it could not resolve if (bit > 1) { break; } - rx[*rxlen >> 3] |= bit << (7 - (*rxlen % 8)); - *rxlen = *rxlen + 1; + rx[len >> 3] |= bit << (7 - (len % 8)); + len++; } - // skip spurious bit - if (*rxlen % 8 == 1) { - *rxlen = *rxlen - 1; + // anything short of the full payload is a failed decode, not a short frame + if (len != payload) { + return false; } + + *rxlen = len; return true; -} - -int ht2_read_uid(uint8_t *uid, bool ledcontrol, bool send_answer, bool keep_field_up) { +}int ht2_read_uid(uint8_t *uid, bool ledcontrol, bool send_answer, bool keep_field_up) { g_logging = false; @@ -2630,6 +4631,8 @@ int ht2_tx_rx(uint8_t *tx, size_t txlen, uint8_t *rx, size_t *rxlen, bool ledcon goto out; } + ht2_normalise_head(samples, &nrzs); + // decode raw samples from Manchester Encoded to bits if (manrawdecode(samples, &nrzs, true, 0)) { goto out; diff --git a/armsrc/hitag2.h b/armsrc/hitag2.h index 58314a8f9..d90351092 100644 --- a/armsrc/hitag2.h +++ b/armsrc/hitag2.h @@ -22,9 +22,9 @@ #include "common.h" #include "hitag.h" -void SniffHitag2(bool ledcontrol); +void SniffHitag2(bool ledcontrol, uint8_t threshold); void hitag_sniff(void); -void SimulateHitag2(bool ledcontrol); +void SimulateHitag2(uint8_t threshold, uint16_t twait, uint8_t flags, uint8_t sof, uint8_t duty, bool ledcontrol); void ReaderHitag(const lf_hitag_data_t *payload, bool ledcontrol); void WriterHitag(const lf_hitag_data_t *payload, bool ledcontrol); diff --git a/armsrc/hitag2_crack.c b/armsrc/hitag2_crack.c index e5dea8a64..1c9af611e 100644 --- a/armsrc/hitag2_crack.c +++ b/armsrc/hitag2_crack.c @@ -19,6 +19,9 @@ #include "hitag2_crack.h" + +// How many times the crypto probe retries before deciding the tag is refusing. +#define HT2_CRACK_PROBE_TRIES 8 #include "hitag2/hitag2_crypto.h" #include "hitag2.h" #include "proxmark3_arm.h" @@ -365,6 +368,22 @@ void ht2_crack2(uint8_t *nrar_hex) { // find a valid encrypted command uint8_t e_firstcmd[10] = {0}; if (hitag2crack_find_valid_e_cmd(e_firstcmd, c2->nrar) == false) { + + // Say why, because the two causes need different fixes. + // + // Every guess replays the nR aR and waits for the tag's encrypted page 3. + // A password mode tag never answers a 64 bit authentication at all - that + // is the datasheet behaviour, selected by bit 3 of the configuration byte + // - and neither does a crypto tag given a pair captured from some other + // card or key. Without this the attack just reported "fail". + // + // Probing once up front was tried instead and removed: the exchange misses + // often enough that a short probe rejected a card this attack then cracked + // successfully. The full sweep is the reliable test, so report after it. + // Reading the configuration byte would be better still, but that needs the + // authentication we are trying to establish. + DbpString("no encrypted command was answered"); + DbpString(" tag is not in crypto mode, or this nR aR is not valid for it"); BigBuf_free(); reply_ng(CMD_LF_HITAG2_CRACK_2, PM3_EFAILED, NULL, 0); return; diff --git a/armsrc/hitagS.c b/armsrc/hitagS.c index d5b996d57..8abc99430 100644 --- a/armsrc/hitagS.c +++ b/armsrc/hitagS.c @@ -371,28 +371,39 @@ static void hts_handle_reader_command(uint8_t *rx, const size_t rxlen, /* * Emulates a Hitag S Tag with the given data from the .hts file */ -void hts_simulate(bool tag_mem_supplied, int8_t threshold, const uint8_t *data, bool ledcontrol) { +void hts_simulate(int8_t threshold, bool ledcontrol) { int overflow = 0; uint8_t rx[HITAG_FRAME_LEN] = {0}; size_t rxlen = 0; uint8_t tx[HITAG_FRAME_LEN]; size_t txlen = 0; - // free eventually allocated BigBuf memory - BigBuf_free(); - BigBuf_Clear_ext(false); + // keep emulator memory, that is where eload put the tag content + BigBuf_free_keep_EM(); + BigBuf_Clear_keep_EM(); DbpString("Starting Hitag S simulation"); tag.pstate = HT_READY; tag.tstate = HT_NO_OP; - // read tag data into memory - if (tag_mem_supplied) { - DbpString("Loading hitag S memory..."); - memcpy(tag.data.pages, data, HITAGS_MAX_BYTE_SIZE); + // Take the tag content from emulator memory, where `lf hitag eload -s` put + // it. An all-zero emulator memory means nothing was loaded, so keep whatever + // the last read left behind rather than simulating a tag of all zeroes. + uint8_t *em = BigBuf_get_EM_addr(); + bool em_empty = true; + for (size_t i = 0; i < HITAGS_MAX_BYTE_SIZE; i++) { + if (em[i] != 0) { + em_empty = false; + break; + } + } + + if (em_empty) { + DbpString("Emulator memory is empty, simulating the last read tag"); } else { - // use the last read tag + DbpString("Loading Hitag S memory from emulator memory..."); + memcpy(tag.data.pages, em, HITAGS_MAX_BYTE_SIZE); } // max_page @@ -462,8 +473,8 @@ void hts_simulate(bool tag_mem_supplied, int8_t threshold, const uint8_t *data, } hitag_cleanup(ledcontrol); - // release allocated memory from BigBuff. - BigBuf_free(); + // release BigBuf, but keep emulator memory for eview / esave + BigBuf_free_keep_EM(); DbpString("Sim stopped"); } diff --git a/armsrc/hitagS.h b/armsrc/hitagS.h index 5c2008b31..0e26bfe97 100644 --- a/armsrc/hitagS.h +++ b/armsrc/hitagS.h @@ -24,7 +24,7 @@ #include "common.h" #include "hitag.h" -void hts_simulate(bool tag_mem_supplied, int8_t threshold, const uint8_t *data, bool ledcontrol); +void hts_simulate(int8_t threshold, bool ledcontrol); void hts_read(const lf_hitag_data_t *payload, bool ledcontrol); void hts_write_page(const lf_hitag_data_t *payload, bool ledcontrol); void hts_check_challenges(const uint8_t *data, uint32_t datalen, bool ledcontrol); diff --git a/armsrc/hitag_common.c b/armsrc/hitag_common.c index 5e9c3b046..cab89ea68 100644 --- a/armsrc/hitag_common.c +++ b/armsrc/hitag_common.c @@ -30,15 +30,86 @@ #include "commonutil.h" #include "hitag2/hitag2_crypto.h" #include "lfadc.h" +#include "lfsampling.h" #include "crc.h" #include "protocols.h" #include "appmain.h" // tearoff_hook() // Initialize FPGA and timer for Hitag operations +// A short settle after an FPGA mode change. Deliberately a plain busy loop: +// hitag_setup_fpga() calls StopTicks() first, so WaitMS()/SpinDelay() have no +// timebase there and simply hang - that wedged the device hard enough to need a +// replug. Roughly a few milliseconds at 48 MHz, which is all the FPGA needs. +// HITAG_RX_IDLE_GUARD now lives in hitag_common.h - SniffHitag2() needs it too. + +static void hitag_settle(void) { + for (volatile uint32_t i = 0; i < 200000; i++) { + if ((i & 0x3FF) == 0) { + WDT_HIT(); + } + } +} + +// Pick an edge detect threshold by measuring, rather than making the user guess. +// +// The usable window is narrow and reader dependent: against a Paxton reader +// 5..25 all worked, 30 was marginal and 40 received nothing, while the FPGA's +// own default of 127 received nothing at all. Asking the user to find that by +// hand is not reasonable, so sample the edge rate at a spread of candidates and +// keep the most noise-rejecting one that still sees a healthy share of them. +// +// Must run with the FPGA already in edge detect and the capture timer started. +uint8_t hitag_autotune_threshold(void) { + + static const uint8_t cand[] = { 8, 12, 16, 20, 24, 28, 32 }; + uint32_t seen[ARRAYLEN(cand)] = {0}; + uint32_t best_seen = 0; + + for (uint32_t i = 0; i < ARRAYLEN(cand); i++) { + + FpgaSendCommand(FPGA_CMD_SET_EDGE_DETECT_THRESHOLD, cand[i]); + hitag_settle(); + + uint32_t before = g_hitag_edges; + + // a few bounded receive passes is enough to gauge the edge rate + for (uint32_t k = 0; k < 3; k++) { + uint8_t rx[HITAG_FRAME_LEN] = {0}; + size_t rxlen = 0; + uint32_t start_time = 0; + int overflow = 0; + hitag_tag_receive_frame_ex(rx, sizeof(rx), &rxlen, &start_time, false, &overflow, true); + ResetLoEdgeCapture(); + } + + seen[i] = g_hitag_edges - before; + if (seen[i] > best_seen) { + best_seen = seen[i]; + } + } + + // Nothing at all means no reader is present; leave a value that works once + // one shows up rather than picking the most sensitive setting and chattering. + if (best_seen == 0) { + return 20; + } + + uint8_t chosen = cand[0]; + for (uint32_t i = 0; i < ARRAYLEN(cand); i++) { + if (seen[i] >= (best_seen / 2)) { + chosen = cand[i]; + } + } + return chosen; +} + void hitag_setup_fpga(uint16_t conf, uint8_t threshold, bool ledcontrol) { StopTicks(); - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + // the EM-preserving variant: the plain FpgaDownloadAndGo() wipes all of + // BigBuf, emulator memory included, whenever the LF bitstream is not + // already cached, which would discard what `lf hitag eload` just wrote + FpgaDownloadAndGo_keep_EM(FPGA_BITSTREAM_LF); // Clean up trace and prepare it for storing frames set_tracing(true); @@ -46,17 +117,53 @@ void hitag_setup_fpga(uint16_t conf, uint8_t threshold, bool ledcontrol) { if (ledcontrol) LED_D_ON(); + // Bring the LF front end up the same way lf_init() and LFSetupFPGAForADC() do, + // in the same order. Two steps were missing here and both matter: + // + // - the divisor has to be sent BEFORE the conf word, not after. Setting the + // major mode last is what latches it, so programming the divisor afterwards + // left the sampling clock unconfigured. + // - FpgaSetupSsc() was never called at all, so the ADC sample stream the edge + // detector works from was never set up. + // + // The symptom was a detector free running at ~52 kHz - 633k edges in 12 s with + // nothing framed, and no value of the threshold making any measurable difference. + // Running any command that calls lf_init() (`lf read`, say) fixed it until the + // next boot, which is what made it look like the device needed reflashing. + // Bring the LF ADC front end up first, exactly as lf_init()/LFSetupFPGAForADC() + // do, before switching the FPGA into edge detect. Without this the peak + // detector is never initialised and the edge detector free runs; running any + // command that goes through lf_init() (`lf read`) fixed it until the next boot, + // which is what made it look like the device needed reflashing. reader_field + // is false here: this is a tag simulator, it must not energise the coil. + LFSetupFPGAForADC(LF_DIVISOR_125, false); + hitag_settle(); + + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_125); //125kHz + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | conf); + if (threshold != 127) FpgaSendCommand(FPGA_CMD_SET_EDGE_DETECT_THRESHOLD, threshold); + + // Connect the A/D to the peak-detected low-frequency path. + SetAdcMuxFor(ADC_MUXSEL_LOPKD); + + // Set up the SSC so the ADC samples actually stream to the FPGA. + FpgaSetupSsc(FPGA_MAJOR_MODE_LF_READER); + + // Give the front end a moment to settle before anything reads from it. + hitag_settle(); + // Configure the timers via the HAL: a precision counter (T0 timing), an // input capture (tag frame edges) and a timestamp counter (trace timing). + // + // The input capture goes LAST, after the FPGA is configured. StartLoEdgeCapture() + // claims SSC_FRAME for TC1 via PIO_BSR, and the FpgaWriteConfWord()/FpgaSendCommand() + // bit-bang that follows drives the same SSC lines, which undid that routing: + // the detector then free ran at ~52 kHz (633k edges in 12 s) with nothing framed, + // and the edge detect threshold had no measurable effect at any value. + // SniffHitag2(), which does frame reader traffic, has always ordered it this way. StartPrecisionCounter(); - StartLoEdgeCapture(); StartTimestamp(); - - // Set fpga in edge detect with/without reader field, we can modulate as reader/tag now - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | conf); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_125); //125kHz - if (threshold != 127) FpgaSendCommand(FPGA_CMD_SET_EDGE_DETECT_THRESHOLD, threshold); - SetAdcMuxFor(ADC_MUXSEL_LOPKD); + StartLoEdgeCapture(); // Configure output and enable pin that is connected to the FPGA (for modulating) gpio_fpga_mod_only_setup(); @@ -76,8 +183,11 @@ void hitag_cleanup(bool ledcontrol) { // Reader functions static void hitag_reader_send_bit(int bit, bool ledcontrol) { - // Reset clock for the next bit - ResetPrecisionCounter(); + // Time this bit from its own start. Taking a reference and measuring the + // difference leaves the free running counter alone, so nothing here depends + // on a reset having landed, and the shared reference that the receive path + // measures "time since the last edge" against is left where it was. + const uint16_t t_ref = GetPrecisionCounterRaw(); if (ledcontrol) LED_A_ON(); @@ -86,16 +196,16 @@ static void hitag_reader_send_bit(int bit, bool ledcontrol) { Gpio_SSC_DOUT_High(); // Wait for 4-10 times the carrier period - while (GetPrecisionCounter() < T0 * HITAG_T_LOW) {}; + while (GetPrecisionCounterDelta(t_ref) < T0 * HITAG_T_LOW) {}; Gpio_SSC_DOUT_Low(); if (bit == 0) { // Zero bit: |_-| - while (GetPrecisionCounter() < T0 * HITAG_T_0) {}; + while (GetPrecisionCounterDelta(t_ref) < T0 * HITAG_T_0) {}; } else { // One bit: |_--| - while (GetPrecisionCounter() < T0 * HITAG_T_1) {}; + while (GetPrecisionCounterDelta(t_ref) < T0 * HITAG_T_1) {}; } if (ledcontrol) LED_A_OFF(); @@ -106,18 +216,18 @@ void hitag_reader_send_frame(const uint8_t *frame, size_t frame_len, bool ledcon if (send_sof) { hitag_reader_send_bit(0, ledcontrol); - // Reset clock for the code violation - ResetPrecisionCounter(); + // Time the code violation from its own start, see hitag_reader_send_bit() + const uint16_t t_sof = GetPrecisionCounterRaw(); if (ledcontrol) LED_A_ON(); // SOF is HIGH for HITAG_T_LOW Gpio_SSC_DOUT_High(); - while (GetPrecisionCounter() < T0 * HITAG_T_LOW) {}; + while (GetPrecisionCounterDelta(t_sof) < T0 * HITAG_T_LOW) {}; // Then LOW for HITAG_T_CODE_VIOLATION Gpio_SSC_DOUT_Low(); - while (GetPrecisionCounter() < T0 * HITAG_T_CODE_VIOLATION) {}; + while (GetPrecisionCounterDelta(t_sof) < T0 * HITAG_T_CODE_VIOLATION) {}; if (ledcontrol) LED_A_OFF(); } @@ -157,8 +267,25 @@ void hitag_reader_receive_frame(uint8_t *rx, size_t sizeofrx, size_t *rxlen, uin // Skip SOF bits bool sof_received = false; - // 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. + // + // Bounded, for the same reason the tag side receive is. The precision + // counter is reset on every edge below, so the T_PROG_MAX bound only expires + // while the line is quiet: when the edge detector chatters - which it does + // with no clean carrier to work with - edges keep arriving, the counter keeps + // being reset, and this loop never returns. Nothing in it polls the button + // or USB, so the Proxmark stops answering entirely and only a replug brings + // it back. Two devices were lost that way while measuring. + uint32_t guard = HITAG_RX_IDLE_GUARD; while (GetPrecisionCounter() < (T0 * HITAG_T_PROG_MAX)) { + + if (--guard == 0) { + break; + } + if ((guard & 0x3FF) == 0) { + WDT_HIT(); + } + // Check if edge in tag modulation is detected if (GetLoEdgeCaptureStatus() == next_edge) { next_edge = next_edge == LO_EDGE_RISING ? LO_EDGE_FALLING : LO_EDGE_RISING; @@ -172,7 +299,7 @@ void hitag_reader_receive_frame(uint8_t *rx, size_t sizeofrx, size_t *rxlen, uin uint32_t rb = GetLoEdgeCaptureFalling() / T0; // For debug, save the edges for decoding manual - if (rb_i < sizeof(edges)) { + if (rb_i < ARRAYLEN(edges)) { edges[rb_i++] = rb; } @@ -373,6 +500,319 @@ int hitag_reader_transfer(const uint8_t *tx, size_t txlen, uint8_t *rx, size_t s } // Tag functions - depends on modulation type +// Wait n carrier periods by counting SSC_CLK edges. The FPGA drives ssp_clk from +// cross_lo, the carrier zero crossing, so this tracks the reader's clock instead of +// our own timer. A real tag derives its bit timing from the field for the same +// reason: over a 37 bit answer even a small carrier offset accumulates into enough +// drift to corrupt the later bits. Needs SSC_CLK configured as an input, see +// gpio_fpga_mod_feedback_setup(). +static void hitag_wait_carrier(uint16_t periods) { + while (periods--) { + while (Gpio_SSC_CLK_Read() == false) { WDT_HIT(); } + while (Gpio_SSC_CLK_Read() == true) { WDT_HIT(); } + } +} + +// Manchester at 4 kbit/s, clocked off the carrier rather than the ARM timer. +// +// The sense matters: HT2 datasheet 3.3.1 says "The first bit of the transmitted +// data always starts with the Modulator ON (loaded) state", so a '1' begins +// loaded. Loaded is DOUT *high* here - lo_edge_detect.v has +// wire tag_modulation = ssp_dout & !lf_field; +// assign pwr_oe2 = tag_modulation; assign pwr_oe4 = tag_modulation; +// so in tag mode (lf_field 0) a high DOUT switches the load transistors on. +// +// Do not reach for the SHORT_COIL()/OPEN_COIL() macros in util.h here: they map +// SHORT_COIL to DOUT low, which is the opposite of what this FPGA mode does, and +// following their naming inverts the whole answer. +void hitag_tag_send_bit_mc4k_sync(int bit, bool ledcontrol) { + if (ledcontrol) LED_A_ON(); + + if (bit) { + // loaded, then unloaded + Gpio_SSC_DOUT_High(); + hitag_wait_carrier(16); + Gpio_SSC_DOUT_Low(); + hitag_wait_carrier(16); + } else { + // unloaded, then loaded + Gpio_SSC_DOUT_Low(); + hitag_wait_carrier(16); + Gpio_SSC_DOUT_High(); + hitag_wait_carrier(16); + } + + if (ledcontrol) LED_A_OFF(); +} + +// Carrier-synchronised frame send for the Hitag 2 simulator. +// +// One write per carrier period, latched right after the SSC_CLK edge, so the +// transitions land on carrier boundaries instead of wherever a polling loop +// happens to finish. Levels are computed inline: a prebuilt sample buffer was +// tried, copying SimulateTagLowFrequencyEx() more literally, and it destabilised +// the device without improving the modulation. +// +// Manchester, 32 T0 per bit. A '1' is loaded for the first half then unloaded, +// a '0' is the reverse; HT2 datasheet 3.3.1 requires the first bit to begin +// loaded. Loaded is DOUT high: lo_edge_detect.v ties pwr_oe2/pwr_oe4 to +// ssp_dout, so a high DOUT switches the load transistors on. Do not go by the +// SHORT_COIL/OPEN_COIL names in util.h, they read backwards for this FPGA mode. +// +// Every wait is bounded. ssp_clk is the carrier zero crossing and stops dead +// when the reader's field goes away; an unbounded spin here wedges the device +// with no way back, since this loop cannot poll data_available() for `hw break`. +#define HITAG_CLK_WAIT_GUARD 20000 + + +// Which SSC_DOUT level actually loads the coil. lo_edge_detect.v ties +// pwr_oe2/pwr_oe4 straight to ssp_dout, so a high DOUT should mean loaded, but +// that is a reading of the verilog rather than a measurement - hence the switch. +static bool s_invert_mod = false; + +// How many of the 16 carrier periods in a loaded half bit actually switch the +// coil load on. 16 is the real thing, a full-depth load; anything less trades +// depth for a smaller disturbance of our own receive path, which goes deaf for +// the length of the answer once its envelope follower has been slammed. +static uint8_t s_mod_duty = HITAG_T_TAG_HALF_PERIOD; + +// TEMP: does the answer burst actually drive the coil? Continuous toggling +// swings the reader's ADC rail to rail, so if a real answer does not, the send +// path is not doing what the diagnostic loop does. +uint32_t g_tx_samples, g_tx_bails, g_tx_frames; + +// Edges the FPGA edge detector has handed us since the last reset. Cheap to +// keep (one increment on a path that already runs per edge) and it settles the +// question the simulator kept raising: zero here means no signal is reaching us +// at all, so a run with no frames says nothing about the simulation itself. +uint32_t g_hitag_edges; + +// TEMP INSTRUMENT: raw edge intervals (T0) of the most recent receive, kept so a +// caller can dump them *after* the exchange has finished. Printing from inside +// the receive loop changes the timing it is meant to measure, so nothing here +// prints; it is a plain store on a path that already runs once per edge. +uint16_t g_hitag_rx_iv[HITAG_RX_IV_MAX]; +uint16_t g_hitag_rx_it[HITAG_RX_IV_MAX]; +uint32_t g_hitag_rx_iv_count; + + + + +void hitag_edges_reset(void) { + g_hitag_edges = 0; +} + + + +void hitag_tag_set_mod_polarity(bool invert) { + s_invert_mod = invert; +} + +void hitag_tag_set_mod_duty(uint8_t duty) { + s_mod_duty = (duty == 0 || duty > HITAG_T_TAG_HALF_PERIOD) ? HITAG_T_TAG_HALF_PERIOD : duty; +} + +// Hitag 2 public (read only) modes, HT2 datasheet rev 2.1 sections 4.2.3 and 4.2.4. +// +// Once the transponder has gone past t_WAIT START_AUTH without being addressed it +// stops behaving like a Hitag 2 and just talks: it "cyclically transmits page 4 +// to page 7 in plain mode to the read/write device without a start sequence as +// long as the transponder is in the field". So there is no SOF, no framing and +// no answer timing to hit - the caller loops over this and the only thing that +// matters is that the bit period is right and the code is right. +// +// Public Mode A Manchester 64 T0 2 kbit/s pages 4,5 (emulates uEM H400x) +// Public Mode B Biphase 32 T0 4 kbit/s pages 4..7 (ISO 11784/11785) +// Public Mode C Biphase 64 T0 2 kbit/s pages 4..7 (emulates PCF793X) +// +// Manchester follows the same convention as the command mode answer above: a '1' +// loads the first half of the bit, a '0' the second. +// +// Biphase here is the differential code: the level always flips at a bit +// boundary, and a '0' flips again in the middle of the bit. That is the ISO +// 11784/11785 convention, which is what Public Mode B claims compliance with, but +// the datasheet only draws it and the drawing does not survive text extraction - +// so if a reader decodes B or C inverted, this is the line to flip. +void hitag_tag_send_public(const uint8_t *frame, size_t frame_len, uint8_t period, bool biphase, bool ledcontrol) { + + if ((frame_len == 0) || (period == 0)) { + return; + } + + const uint8_t half = period / 2; + const size_t total = frame_len * period; + const uint8_t duty = (uint8_t)(((uint16_t)s_mod_duty * half) / HITAG_T_TAG_HALF_PERIOD); + + g_tx_frames++; + + if (ledcontrol) LED_A_ON(); + + // Carries across bits, so a differential code stays differential from one + // call to the next - the pages are sent back to back with no gap. + static bool s_bp_level = false; + + const uint16_t t_frame = GetPrecisionCounterRaw(); + + for (size_t sample = 0; sample < total; sample++) { + + const size_t idx = sample / period; + const size_t phase = sample % period; + const uint16_t deadline = (uint16_t)((sample + 1) * T0); + + const int bit = TEST_BIT_MSB(frame, idx); + + bool loaded; + + if (biphase) { + // One flip at the boundary, a second mid bit for a '0'. + if (phase == 0) { + s_bp_level = !s_bp_level; + } else if ((phase == half) && (bit == 0)) { + s_bp_level = !s_bp_level; + } + loaded = s_bp_level; + } else { + loaded = bit ? (phase < half) : (phase >= half); + } + + // Same shallow load knob the command mode answer uses, but scaled. + // + // s_mod_duty is expressed against the command mode answer's 16 T0 half + // bit, and defaults to exactly that - full duty, clamp never fires. The + // 2 kbit/s public modes have a 32 T0 half bit, so applying it unscaled + // loaded only the first half of every half bit and left the modulation + // at half duty by accident. + if (loaded && ((phase % half) >= duty)) { + loaded = false; + } + + // Same carrier-plus-deadline pacing as hitag_tag_send_frame_mc4k_sync(): + // wait on ssp_clk while it is healthy, fall through on the timer if it + // drops out, so our own load modulation cannot stretch the bit rate. + while (Gpio_SSC_CLK_Read() == false) { + if (GetPrecisionCounterDelta(t_frame) >= deadline) { + g_tx_bails++; + break; + } + } + + g_tx_samples++; + + if (loaded != s_invert_mod) { + Gpio_SSC_DOUT_High(); + } else { + Gpio_SSC_DOUT_Low(); + } + + while (Gpio_SSC_CLK_Read() == true) { + if (GetPrecisionCounterDelta(t_frame) >= deadline) { + break; + } + } + } + + // Deliberately no Gpio_SSC_DOUT_Low() here. The public modes send the pages + // "cyclically ... without a start sequence", so one pass runs straight into + // the next; dropping the load between passes put a gap at the wrap and cost + // the bit there. Measured: the reader recovered the 64 bit pattern exactly + // except for one undecodable Manchester pair per cycle, always at the wrap, + // which was enough to stop lf em 410x demod parsing it. The caller clears + // DOUT once the whole loop ends. + + if (ledcontrol) LED_A_OFF(); +} + +void hitag_tag_send_frame_mc4k_sync(const uint8_t *frame, size_t frame_len, int sof_bits, bool ledcontrol) { + + const size_t nbits = (size_t)sof_bits + frame_len; + + const size_t total = nbits * HITAG_T_TAG_FULL_PERIOD; + + g_tx_frames++; + + if (ledcontrol) LED_A_ON(); + + Gpio_SSC_DOUT_Low(); + + // Time the frame against the free running counter as well as the carrier. + // + // Waiting only on ssp_clk feeds our own modulation back into our own bit + // timing: loading the coil is what suppresses the carrier the zero crossing + // detector is watching, so a sample whose edge is missed waits for the next + // one and the frame stretches. Measured against a Paxton reader, every + // sample went out - 251008 for 212 frames, exactly 1184 each, no bails - yet + // the answer took 1537 T0 instead of 1200, so 28% of samples cost an extra + // carrier period and the Manchester rate fell from 4 kbit/s to 3.1. A real + // reader will not decode that, which is why nothing came back but polling. + // + // Each sample now also carries a deadline, one carrier period after the last, + // measured from the start of the frame. While the carrier is healthy its + // edge arrives first and nothing changes; when it drops out we carry on from + // the timer instead of waiting, so the frame can never run long. + const uint16_t t_frame = GetPrecisionCounterRaw(); + + for (size_t sample = 0; sample < total; sample++) { + + const size_t idx = sample / HITAG_T_TAG_FULL_PERIOD; + const size_t phase = sample % HITAG_T_TAG_FULL_PERIOD; + const uint16_t deadline = (uint16_t)((sample + 1) * T0); + + const int bit = (idx < (size_t)sof_bits) + ? 1 + : TEST_BIT_MSB(frame, idx - (size_t)sof_bits); + + bool loaded = bit ? (phase < HITAG_T_TAG_HALF_PERIOD) + : (phase >= HITAG_T_TAG_HALF_PERIOD); + + // Shallower load: switch on for only the first s_mod_duty periods of the + // loaded half bit. The envelope the reader sees is a low pass of this, + // so the Manchester transition is still there, just less deep. + if (loaded && ((phase % HITAG_T_TAG_HALF_PERIOD) >= s_mod_duty)) { + loaded = false; + } + + bool lost_clock = false; + + while (Gpio_SSC_CLK_Read() == false) { + if (GetPrecisionCounterDelta(t_frame) >= deadline) { + lost_clock = true; + break; + } + } + if (lost_clock) { + // The carrier did not come back in time. Keep the frame on schedule + // rather than abandoning it: a stretched answer is worse than one + // sample placed by the timer. + g_tx_bails++; + } + + g_tx_samples++; + + if (loaded != s_invert_mod) { + Gpio_SSC_DOUT_High(); + } else { + Gpio_SSC_DOUT_Low(); + } + + while (Gpio_SSC_CLK_Read() == true) { + if (GetPrecisionCounterDelta(t_frame) >= deadline) { + break; + } + } + } + + // TEMP EXPERIMENT: the trailing half-period hold is disabled. + // + // It was added so our own decoder had a closing edge for the last half bit. + // A reader may instead see it as a surplus bit at the tail, which makes a + // frame that lost its leading half bit come out at 37 bits with a true SOF of + // 4 - and that is undecidable from the frame alone when the payload starts + // with a 1. + Gpio_SSC_DOUT_Low(); + + if (ledcontrol) LED_A_OFF(); +} + static void hitag_tag_send_bit(int bit, hitag_mod_t modulation, bool ledcontrol) { // Reset clock for the next bit ResetPrecisionCounter(); @@ -469,28 +909,102 @@ static void hitag_tag_send_bit(int bit, hitag_mod_t modulation, bool ledcontrol) if (ledcontrol) LED_A_OFF(); } -void hitag_tag_receive_frame(uint8_t *rx, size_t sizeofrx, size_t *rxlen, uint32_t *start_time, bool ledcontrol, int *overflow) { - lo_edge_t next_edge = LO_EDGE_FALLING; +void hitag_tag_receive_frame_ex(uint8_t *rx, size_t sizeofrx, size_t *rxlen, uint32_t *start_time, bool ledcontrol, int *overflow, bool sof_is_bit) { uint8_t edges[160] = {0}; uint32_t rb_i = 0; - // Receive frame, watch for at most T0*EOF periods + g_hitag_rx_iv_count = 0; + + // How many polls of this loop went by between one edge and the next. A + // merged interval with roughly twice the usual poll count means the loop kept + // running and the edge detector simply never fired; the same poll count as a + // single bit means we stalled and missed it. One increment per iteration, so + // it does not change what it measures. + uint32_t it = 0; + + // Receive frame, watch for at most T0*EOF periods. + // + // StartLoEdgeCapture() clocks TC1 from MCK/32, not from the carrier, so the + // counter free runs; what holds it down is the external trigger, which + // resets it on every falling edge of SSC_FRAME. When the edge detector has + // no clean carrier to work with it fires continuously, the counter never + // reaches the EOF limit, and without a bound this loop never returns - the + // caller then never gets back to its data_available()/BUTTON_PRESS() check + // and the device wedges with no way back short of a replug. Returning early + // with nothing received costs nothing, the simulator just listens again. + // Has the opening gap of a frame been taken yet? Only the very first edge + // may be recovered from a rising event, see the comment further down. + bool frame_open = false; + + uint32_t guard = HITAG_RX_IDLE_GUARD; while (GetLoEdgeCaptureCount() < T0 * HITAG_T_EOF) { - // Check if edge in modulation is detected - if (GetLoEdgeCaptureStatus() == next_edge) { - next_edge = next_edge == LO_EDGE_RISING ? LO_EDGE_FALLING : LO_EDGE_RISING; + it++; - // only use INPUT_CAPTURE_EVT_RB falling edge for now - if (next_edge == LO_EDGE_FALLING) { - continue; - } + if (--guard == 0) { + break; + } + if ((guard & 0x3FF) == 0) { + WDT_HIT(); + } + + // Act on every falling edge, without demanding a rising edge in between. + // + // GetLoEdgeCaptureStatus() reads TC_SR once, which clears LDRAS and LDRBS + // together and reports rising in preference, so when both edges land in + // one poll the falling event is destroyed. Tracking an expected edge and + // skipping anything that did not match turned that single lost edge into + // a permanent desync, discarding every later falling edge of the frame. + lo_edge_t ev = GetLoEdgeCaptureStatus(); + + // Recover the falling edge that opens a frame. + // + // GetLoEdgeCaptureStatus() reads TC_SR once, which clears LDRAS and + // LDRBS together and reports rising in preference. Inside a frame this + // loop polls about four times per T0, so the two edges of a gap are seen + // separately - but the frame's FIRST gap arrives while we are between + // calls, waiting out the idle, and by the first poll both its falling and + // its rising have landed. Rising wins and the falling event is destroyed. + // + // Measured on this rig: the first event of every reader frame is a rising + // edge carrying RA = 10 T0, which is the reader's t_low - proof that the + // falling edge really happened one t_low earlier. The next falling edge + // is the SECOND gap, and its interval - the first bit's period - is then + // swallowed by the idle carried in *overflow and read as the frame + // opener. The first bit was therefore never measured at all, and the + // opener below fabricated it as '1'. That is invisible for START_AUTH + // (11000), for a password starting 0xB and for WRITE PAGE (0xA2), and it + // stored 0x91223344 when the reader wrote 0x11223344. + // + // TC_RB still holds the destroyed edge's capture, so taking the rising + // event as that falling edge recovers it exactly. Only before the frame + // has opened: once bits are arriving the polls are fast enough to see + // both edges, and converting them there would double every gap. + if ((ev == LO_EDGE_RISING) && (frame_open == false)) { + ev = LO_EDGE_FALLING; + } + + if (ev == LO_EDGE_FALLING) { // Retrieve the new timing values uint32_t rb = GetLoEdgeCaptureFalling() / T0 + *overflow; *overflow = 0; - edges[rb_i++] = rb; + // Past this point the polls are fast enough to see both edges of a + // gap, so no further rising event may be taken for a falling one. + frame_open = true; + + g_hitag_edges++; + + if (rb_i < ARRAYLEN(edges)) { + edges[rb_i++] = rb; + } + + if (g_hitag_rx_iv_count < HITAG_RX_IV_MAX) { + g_hitag_rx_it[g_hitag_rx_iv_count] = (it > 0xFFFF) ? 0xFFFF : (uint16_t)it; + g_hitag_rx_iv[g_hitag_rx_iv_count++] = (rb > 0xFFFF) ? 0xFFFF : (uint16_t)rb; + } + it = 0; if (ledcontrol) LED_B_INV(); @@ -501,11 +1015,94 @@ void hitag_tag_receive_frame(uint8_t *rx, size_t sizeofrx, size_t *rxlen, uint32 // Capture reader frame if (rb >= HITAG_T_STOP) { - // Hitag µ SOF - if (*rxlen != 0 && *rxlen != 1) { - // DBG DbpString("weird0?"); - break; + + // Only an interval at the very start opens a frame. One that + // turns up mid frame is a dropped edge, not a boundary: two bit + // periods merge into a single gap over HITAG_T_STOP. Bailing out + // there truncated the reader's 32 bit password to 6 bits, having + // received textbook intervals up to that point (22 19 20 28 29 21). + // Skip it and keep going; the frame still closes on the EOF + // timeout, which is what actually delimits frames here. + if (*rxlen != 0) { + + // Recover the bits the merged gap swallowed. + // + // A dropped edge joins two or three bit periods into one gap. + // Skipping it, as this used to, throws those bits away - which + // is exactly why a 64 bit AUTH arrives as 61..63 and crypto + // never authenticates. Measured intervals in a failing frame + // are textbook otherwise, 17..19 for '0' and 25..27 for '1', + // with a single oversized gap among them: + // + // ... 17 71 25 27 ... 71 = 27+27+17, three bits + // ... 17 49 20 19 ... 49 = two bits + // + // So decompose the gap into the run of nominal bit periods + // that best fits its length. Where the fit is all-ones or + // all-zeroes the result is exact; a mixed run has an order + // this cannot know, and is emitted ones-first as a guess. A + // wrong guess fails authentication exactly as the dropped + // bits already did, so this can only improve on discarding. + // Only inside a frame that already carries real content. + // + // Without this the rule fabricates bits out of noise: a stray + // edge opens a frame, the long gap that follows is "recovered" + // into two or three invented bits, and what should have been + // discarded becomes a 4 bit frame. Measured against a Paxton, + // that cost the whole exchange - 69 fabricated 4 bit frames, + // not one password or read command answered, where the same + // build without the rule ran 206 passwords and 824 reads. + // + // A dropped edge only matters in the long frames it actually + // damages: the reader's shortest real command is 5 bits and + // the loss shows up around bit 40 of a 64 bit AUTH, so + // requiring a byte of frame first protects START_AUTH while + // leaving every frame the rule exists for untouched. + if (*rxlen < 8) { + continue; + } + + uint32_t best_k = 0, best_ones = 0, best_err = 0xFFFFFFFF; + for (uint32_t k = 2; k <= 3; k++) { + for (uint32_t ones = 0; ones <= k; ones++) { + uint32_t sum = ones * HITAG_T_1_NOMINAL + + (k - ones) * HITAG_T_0_NOMINAL; + uint32_t err = (rb > sum) ? (rb - sum) : (sum - rb); + if (err < best_err) { + best_err = err; + best_k = k; + best_ones = ones; + } + } + } + + // Only act on a decomposition that actually fits; a gap that + // matches nothing is noise, and inventing bits from it would + // corrupt a frame that would otherwise merely be short. + if (best_err <= HITAG_T_SPLIT_TOL) { + for (uint32_t b = 0; b < best_k; b++) { + if ((*rxlen / 8) >= sizeofrx) { + break; + } + if (b < best_ones) { + SET_BIT_MSB(rx, *rxlen); + } + (*rxlen)++; + } + } + continue; } + + // The opening gap carries no bit, in any of the three protocols. + // + // A reader frame is N bit gaps followed by an EOF gap, so an N + // bit frame is N+1 falling edges and N intervals between them: + // the first interval is the first bit's period, and the gap that + // opens the frame only starts the clock. This used to count it + // as a '1' for Hitag 2, which was a workaround for the lost + // opening edge recovered above - with the edge back, doing so + // would shift the whole frame by one bit. + (void)sof_is_bit; *rxlen = 0; } else if (rb >= HITAG_T_1_MIN) { // '1' bit @@ -527,13 +1124,28 @@ void hitag_tag_receive_frame(uint8_t *rx, size_t sizeofrx, size_t *rxlen, uint32 Dbprintf("RX %i bits.. start_time:%i edges:", *rxlen, *start_time); Dbhexdump(rb_i, edges, false); } + } -void hitag_tag_send_frame(const uint8_t *frame, size_t frame_len, int sof_bits, hitag_mod_t modulation, bool ledcontrol) { - // The beginning of the frame is hidden in some high level; pause until our bits will have an effect - ResetPrecisionCounter(); - Gpio_SSC_DOUT_High(); +// Hitag S and u framing: the opening gap is a delimiter, not a bit +void hitag_tag_receive_frame(uint8_t *rx, size_t sizeofrx, size_t *rxlen, uint32_t *start_time, bool ledcontrol, int *overflow) { + hitag_tag_receive_frame_ex(rx, sizeofrx, rxlen, start_time, ledcontrol, overflow, false); +} +void hitag_tag_send_frame_ex(const uint8_t *frame, size_t frame_len, int sof_bits, hitag_mod_t modulation, bool ledcontrol, bool lead_in) { + // The beginning of the frame is hidden in some high level; pause until our bits will have an effect. + // Hitag 2 does not want this: it starts modulating straight into the first SOF + // bit from an unloaded line, and the lead-in would swallow that bit's rising + // transition as well as prepending a burst that is not part of the Manchester. + ResetPrecisionCounter(); + + if (lead_in == false) { + Gpio_SSC_DOUT_Low(); + } else { + Gpio_SSC_DOUT_High(); + } + + if (lead_in) switch (modulation) { case AC4K: case MC8K: { @@ -564,3 +1176,8 @@ void hitag_tag_send_frame(const uint8_t *frame, size_t frame_len, int sof_bits, Gpio_SSC_DOUT_Low(); } + +// Hitag S and u keep the lead-in +void hitag_tag_send_frame(const uint8_t *frame, size_t frame_len, int sof_bits, hitag_mod_t modulation, bool ledcontrol) { + hitag_tag_send_frame_ex(frame, frame_len, sof_bits, modulation, ledcontrol, true); +} diff --git a/armsrc/hitag_common.h b/armsrc/hitag_common.h index 7c5721ab0..772c38b8b 100644 --- a/armsrc/hitag_common.h +++ b/armsrc/hitag_common.h @@ -20,7 +20,18 @@ #define HITAG_T_1 28 /* T[1] should be 26..32 */ #define HITAG_T_0_MIN 15 /* T[0] should be 18..22 */ #define HITAG_T_1_MIN 25 /* T[1] should be 26..32 */ +// A histogram taken during simulation put '1' intervals at 23..27 and suggested +// 22 here, but that sample was polluted by the simulator's own artifacts: +// against a genuine fob 22 fragmented the reader frames that 25 decodes +// cleanly. Left at 25 until a histogram from a sniff-only run says otherwise. #define HITAG_T_STOP 36 /* T_EOF should be > 36 */ + +/* Nominal reader bit periods, in T0, measured off a Paxton: '0' lands 17..19 and + * '1' lands 25..27. Used to decompose a gap that swallowed several bits when an + * edge was dropped, and the tolerance is how far the best fit may miss. */ +#define HITAG_T_0_NOMINAL 18 +#define HITAG_T_1_NOMINAL 26 +#define HITAG_T_SPLIT_TOL 4 #define HITAG_T_CODE_VIOLATION 36 /* Hitag µ TFcv should be 34..38 */ #define HITAG_T_EOF 80 /* T_EOF should be > 36 */ @@ -35,6 +46,15 @@ #define HITAG_T_TAG_THREE_HALF_PERIOD 41 #define HITAG_T_TAG_FOUR_HALF_PERIOD 57 +// Bound on the receive spin, see hitag_tag_receive_frame_ex(). The longest +// frame worth receiving is 64 bits of BPLM, about 2050 T0 or 16 ms, so the bound +// has to sit above that or real frames get cut short. It also has to stay small +// enough that a vanished field still returns control promptly: at roughly ten +// cycles an iteration this is some tens of milliseconds, so `hw break` still +// answers quickly. WDT_HIT() is deliberately NOT called every iteration - doing +// that made each idle pass take seconds and left the simulator deaf. +#define HITAG_RX_IDLE_GUARD 200000 + #define HITAG_T_TAG_HALF_PERIOD 16 #define HITAG_T_TAG_FULL_PERIOD 32 @@ -54,7 +74,33 @@ void hitag_reader_receive_frame(uint8_t *rx, size_t sizeofrx, size_t *rxlen, uin int sof_bits); int hitag_reader_transfer(const uint8_t *tx, size_t txlen, uint8_t *rx, size_t sizeofrx, size_t *rxlen, int t_wait, bool ledcontrol, hitag_mod_t modulation, uint8_t sof_bits, uint8_t send_sof); +void hitag_tag_receive_frame_ex(uint8_t *rx, size_t sizeofrx, size_t *rxlen, uint32_t *start_time, + bool ledcontrol, int *overflow, bool sof_is_bit); void hitag_tag_receive_frame(uint8_t *rx, size_t sizeofrx, size_t *rxlen, uint32_t *start_time, bool ledcontrol, int *overflow); +void hitag_tag_send_bit_mc4k_sync(int bit, bool ledcontrol); +void hitag_tag_set_mod_polarity(bool invert); +void hitag_tag_set_mod_duty(uint8_t duty); +uint8_t hitag_autotune_threshold(void); +extern uint32_t g_hitag_edges; +extern uint32_t g_tx_samples, g_tx_bails, g_tx_frames; + +// TEMP INSTRUMENT: raw edge intervals (T0) of the most recent receive. +#define HITAG_RX_IV_MAX 8 +extern uint16_t g_hitag_rx_iv[HITAG_RX_IV_MAX]; +extern uint16_t g_hitag_rx_it[HITAG_RX_IV_MAX]; +extern uint32_t g_hitag_rx_iv_count; +void hitag_edges_reset(void); +void hitag_tag_send_frame_mc4k_sync(const uint8_t *frame, size_t frame_len, int sof_bits, bool ledcontrol); + +// Hitag 2 public (read only) modes: one pass of a raw, unframed bit stream. +// +// `period` is the bit length in carrier periods - 32 for a 4 kbit/s mode, 64 for +// 2 kbit/s - and `biphase` picks the code. There is no SOF and no framing: the +// public modes send the user pages back to back with no start sequence, so the +// caller simply calls this in a loop. +void hitag_tag_send_public(const uint8_t *frame, size_t frame_len, uint8_t period, bool biphase, bool ledcontrol); +void hitag_tag_send_frame_ex(const uint8_t *frame, size_t frame_len, int sof_bits, + hitag_mod_t modulation, bool ledcontrol, bool lead_in); void hitag_tag_send_frame(const uint8_t *frame, size_t frame_len, int sof_bits, hitag_mod_t modulation, bool ledcontrol); #endif diff --git a/armsrc/hitagu.c b/armsrc/hitagu.c index cb67cd31f..d00b60d1d 100644 --- a/armsrc/hitagu.c +++ b/armsrc/hitagu.c @@ -362,16 +362,16 @@ static void htu_handle_reader_command(uint8_t *rx, const size_t rxlen, uint8_t * /* * Simulates a Hitag µ Tag with the given data */ -void htu_simulate(bool tag_mem_supplied, int8_t threshold, const uint8_t *data, bool ledcontrol) { +void htu_simulate(int8_t threshold, bool ledcontrol) { uint8_t rx[HITAG_FRAME_LEN] = {0}; size_t rxlen = 0; uint8_t tx[HITAG_FRAME_LEN] = {0}; size_t txlen = 0; - // Free any allocated BigBuf memory - BigBuf_free(); - BigBuf_Clear_ext(false); + // keep emulator memory, that is where eload put the tag content + BigBuf_free_keep_EM(); + BigBuf_Clear_keep_EM(); DbpString("Starting Hitag µ simulation"); @@ -380,13 +380,24 @@ void htu_simulate(bool tag_mem_supplied, int8_t threshold, const uint8_t *data, tag.max_page = 64; // Default maximum page RESET_AUTHENTICATION(); - // Read tag data into memory if supplied - if (tag_mem_supplied) { - DbpString("Loading Hitag µ memory..."); - // First 6 bytes are the UID (48 bits) - memcpy(tag.uid, data, 6); - // Rest is page data - memcpy(tag.data.pages, data + 6, sizeof(tag.data.pages)); + // Take the tag content from emulator memory, where `lf hitag eload -m` put it: + // UID first, then the pages. The old inline path copied UID + 1024 bytes out + // of the command payload, which is more than an NG frame can ever carry. + uint8_t *em = BigBuf_get_EM_addr(); + bool em_empty = true; + for (size_t i = 0; i < HITAGU_UID_SIZE + sizeof(tag.data.pages); i++) { + if (em[i] != 0) { + em_empty = false; + break; + } + } + + if (em_empty) { + DbpString("Emulator memory is empty, simulating the last read tag"); + } else { + DbpString("Loading Hitag u memory from emulator memory..."); + memcpy(tag.uid, em, HITAGU_UID_SIZE); + memcpy(tag.data.pages, em + HITAGU_UID_SIZE, sizeof(tag.data.pages)); } // Update max_page based on configuration @@ -459,8 +470,8 @@ void htu_simulate(bool tag_mem_supplied, int8_t threshold, const uint8_t *data, } hitag_cleanup(ledcontrol); - // Release allocated memory from BigBuf - BigBuf_free(); + // release BigBuf, but keep emulator memory for eview / esave + BigBuf_free_keep_EM(); DbpString("Simulation stopped"); } diff --git a/armsrc/hitagu.h b/armsrc/hitagu.h index a1144e1e7..cfa676230 100644 --- a/armsrc/hitagu.h +++ b/armsrc/hitagu.h @@ -22,7 +22,7 @@ #include "common.h" #include "hitag.h" -void htu_simulate(bool tag_mem_supplied, int8_t threshold, const uint8_t *data, bool ledcontrol); +void htu_simulate(int8_t threshold, bool ledcontrol); void htu_read(const lf_hitag_data_t *payload, bool ledcontrol); void htu_write_page(const lf_hitag_data_t *payload, bool ledcontrol); int htu_read_uid(uint64_t *uid, bool ledcontrol, bool send_answer); diff --git a/armsrc/lfadc.c b/armsrc/lfadc.c index 09511768a..aef79d6fa 100644 --- a/armsrc/lfadc.c +++ b/armsrc/lfadc.c @@ -22,6 +22,7 @@ #include "ticks_apis.h" #include "fpga_apis.h" #include "dbprint.h" +#include "commonutil.h" // ARRAYLEN #include "appmain.h" // Sam7s has several timers, we will use the source TIMER_CLOCK1 (aka AT91C_TC_CLKS_TIMER_DIV1_CLOCK) @@ -66,6 +67,13 @@ bool lf_test_periods(size_t expected, size_t count) { ////////////////////////////////////////////////////////////////////////////// static uint8_t previous_adc_val = 0; // 0xFF; static uint8_t adc_avg = 0; +// The same average, kept as the raw sum of 32 samples (i.e. avg scaled by 32). +// adc_avg alone is truncated to whole ADC counts, so a threshold built from it +// cannot be placed finer than one count - which is why LIMIT_DEV could not be +// lowered without the edge detector chattering on quantisation noise. +static uint32_t adc_avg_q5 = 0; + +#define LIMIT_DEV_Q5_REPORT (20 * 32) static uint8_t adc_max; static uint8_t adc_min; @@ -87,19 +95,34 @@ void lf_sample_mean(void) { periods++; } } + adc_avg_q5 = adc_sum; // avg * 32, no rounding thrown away adc_avg = adc_sum >> 5; // division by 32 previous_adc_val = adc_avg; - DBG Dbprintf("LF ADC average %u, max %u, min %u, diff %u", adc_avg, adc_max, adc_min, adc_max - adc_min); + DBG Dbprintf("LF ADC average %u, max %u, min %u, diff %u (threshold is +/-%u counts)", + adc_avg, adc_max, adc_min, adc_max - adc_min, (unsigned)(LIMIT_DEV_Q5_REPORT / 32)); } static size_t lf_count_edge_periods_ex(size_t max, bool wait, bool detect_gap) { -#define LIMIT_DEV 20 +// Deviation from the mean that counts as an edge, in 1/32 ADC counts, so the +// threshold is no longer stuck on whole ADC counts the way adc_avg + LIMIT_DEV +// was. 20 counts is the long standing value and is kept here (20 * 32). +// +// Measured, in case it is tempting to lower it: a Proxmark simulating a Hitag 2 +// tag modulates only about 2 counts deep, where a genuine fob clears 20 at the +// same position. Dropping to 6 gained nothing, and 2 only made the detector +// trigger on noise and decode UID FFFFFFFF. The simulator's dip is the problem, +// not this threshold. +// Measured: lowering this from 20 to 10, to let a simulating Proxmark answer +// shallower and so recover faster, stops the reader reading anything at all - +// 0 of 3 UID reads at every modulation duty. The existing note below already +// said 6 gained nothing and 2 triggered on noise; 10 is past the edge too. +#define LIMIT_DEV_Q5 (20 * 32) // timeout limit to 100 000 w/o uint32_t timeout = 100000; size_t periods = 0; - uint8_t avg_peak = adc_avg + LIMIT_DEV; - uint8_t avg_through = adc_avg - LIMIT_DEV; + uint32_t avg_peak_q5 = adc_avg_q5 + LIMIT_DEV_Q5; + uint32_t avg_through_q5 = (adc_avg_q5 > LIMIT_DEV_Q5) ? (adc_avg_q5 - LIMIT_DEV_Q5) : 0; while (BUTTON_PRESS() == false) { WDT_HIT(); @@ -123,6 +146,7 @@ static size_t lf_count_edge_periods_ex(size_t max, bool wait, bool detect_gap) { timeout = 100000; // reset timeout volatile uint8_t adc_val = FPGA_SSC_RX_Value(); // Get current adc value. + if (g_logging) { logSampleSimple(adc_val); } @@ -138,24 +162,24 @@ static size_t lf_count_edge_periods_ex(size_t max, bool wait, bool detect_gap) { } else { if (g_edge_mode == LF_ADC_WAV_REVERSED) { if (rising_edge) { - if ((previous_adc_val > avg_peak) && (adc_val <= previous_adc_val)) { + if ((((uint32_t)previous_adc_val << 5) > avg_peak_q5) && (adc_val <= previous_adc_val)) { rising_edge = false; return periods; } } else { - if ((previous_adc_val < avg_through) && (adc_val >= previous_adc_val)) { + if ((((uint32_t)previous_adc_val << 5) < avg_through_q5) && (adc_val >= previous_adc_val)) { rising_edge = true; return periods; } } } else if (g_edge_mode == LF_ADC_NOT_REVERSED) { if (rising_edge) { - if (adc_val <= adc_avg && adc_val <= avg_through) { + if ((((uint32_t)adc_val << 5) <= adc_avg_q5) && (((uint32_t)adc_val << 5) <= avg_through_q5)) { rising_edge = false; return periods; } } else { - if (adc_val >= avg_peak) { + if (((uint32_t)adc_val << 5) >= avg_peak_q5) { rising_edge = true; return periods; } @@ -273,6 +297,7 @@ void lf_init(lf_adc_init_mode_t init_mode, lf_adc_edge_mode_t edge_mode, bool le } void lf_finalize(bool ledcontrol) { + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); if (ledcontrol) LEDsoff(); } diff --git a/client/src/cmdlfhitag.c b/client/src/cmdlfhitag.c index 141676fa2..296893856 100644 --- a/client/src/cmdlfhitag.c +++ b/client/src/cmdlfhitag.c @@ -845,36 +845,130 @@ static bool ht2_get_uid(uint32_t *uid) { return true; } +// Try to actually read the configuration byte, rather than assume one. +// +// Returns true and fills config/uid if the tag authenticated with this key. +static bool ht2_try_auth_read(uint8_t cmdtype, const uint8_t *key, uint32_t *uid, uint8_t *config) { + + lf_hitag_data_t packet; + memset(&packet, 0, sizeof(packet)); + packet.cmd = cmdtype; + + if (cmdtype == HT2F_PASSWORD) { + memcpy(packet.pwd, key, HITAG_PASSWORD_SIZE); + } else { + memcpy(packet.key, key, HITAG_CRYPTOKEY_SIZE); + } + + clearCommandBuffer(); + SendCommandNG(CMD_LF_HITAG_READER, (uint8_t *)&packet, sizeof(packet)); + + PacketResponseNG resp; + if (WaitForResponseTimeout(CMD_LF_HITAG_READER, &resp, 2000) == false) { + SendCommandNG(CMD_BREAK_LOOP, NULL, 0); + return false; + } + + if (resp.status != PM3_SUCCESS) { + return false; + } + + uint8_t *data = resp.data.asBytes; + *uid = bytes_to_num(data, HITAG_UID_SIZE); + *config = data[HITAG_BLOCK_SIZE * 3]; + return true; +} + static int CmdLFHitagInfo(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "lf hitag info", - "Hitag 2 tag information", - "lf hitag info" + "Hitag 2 tag information\n" + "The configuration byte lives in page 3, which needs authentication.\n" + "Without a key the two factory defaults are tried.", + "lf hitag info\n" + "lf hitag info -k 4D494B52 -> 4 bytes, password mode\n" + "lf hitag info -k 4F4E4D494B52 -> 6 bytes, crypto mode" ); void *argtable[] = { arg_param_begin, + arg_str0("k", "key", "", "key, 4 bytes for password mode, 6 bytes for crypto mode"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); + + uint8_t userkey[HITAG_CRYPTOKEY_SIZE] = {0}; + int ukeylen = 0; + CLIGetHexWithReturn(ctx, 1, userkey, &ukeylen); CLIParserFree(ctx); + // The length picks the mode, so a wrong one is worth catching here rather + // than sending it and reporting a puzzling authentication failure. + if ((ukeylen != 0) && (ukeylen != HITAG_PASSWORD_SIZE) && (ukeylen != HITAG_CRYPTOKEY_SIZE)) { + PrintAndLogEx(ERR, "Key must be %u bytes (password) or %u bytes (crypto), got %i", + HITAG_PASSWORD_SIZE, HITAG_CRYPTOKEY_SIZE, ukeylen); + return PM3_EINVARG; + } + // read UID uint32_t uid = 0; if (ht2_get_uid(&uid) == false) { return PM3_ESOFT; } - // how to determine Hitag types? - // need auth / pwd to get it. - // we could try the default key/pwd and print if successful - // read block3, get configuration byte. + // Read the configuration byte instead of guessing it. + // + // This used to print a hardcoded 0x06, so every tag was reported as + // "Password mode" whatever it actually was - a crypto mode card sitting on + // the antenna was described as password mode, which is worse than saying + // nothing. The configuration lives in page 3 and page 3 needs + // authentication, so try the two factory defaults and report what comes + // back; if neither opens the tag, say the mode is unknown rather than + // inventing one, and point at the command whose job searching actually is. + // + // Deliberately only the two factory values: running the dictionary here was + // tried and removed. `info` should be quick and answer from the tag itself, + // and a key search is what `lf hitag chk` exists for. + static const uint8_t default_pwd[HITAG_PASSWORD_SIZE] = {0x4D, 0x49, 0x4B, 0x52}; // "MIKR" + static const uint8_t default_key[HITAG_CRYPTOKEY_SIZE] = {0x4F, 0x4E, 0x4D, 0x49, 0x4B, 0x52}; // "ONMIKR" - // common configurations. - print_hitag2_configuration(uid, 0x06); // pwd mode enabled / AM - // print_hitag2_configuration(uid, 0x0E); // crypto mode enabled / AM - // print_hitag2_configuration(uid, 0x02); - // print_hitag2_configuration(uid, 0x00); - // print_hitag2_configuration(uid, 0x04); + uint8_t config = 0; + uint32_t cfg_uid = 0; + const char *opened_with = NULL; + + char opened_buf[64] = {0}; + + // A supplied key is tried first, and its length picks the mode: 4 bytes is a + // password, 6 bytes a crypto key. The factory defaults still follow, so + // giving a key that turns out to be wrong is no worse than giving none. + if ((ukeylen == HITAG_PASSWORD_SIZE) && + ht2_try_auth_read(HT2F_PASSWORD, userkey, &cfg_uid, &config)) { + + snprintf(opened_buf, sizeof(opened_buf), "password " _YELLOW_("%s"), + sprint_hex_inrow(userkey, HITAG_PASSWORD_SIZE)); + opened_with = opened_buf; + + } else if ((ukeylen == HITAG_CRYPTOKEY_SIZE) && + ht2_try_auth_read(HT2F_CRYPTO, userkey, &cfg_uid, &config)) { + + snprintf(opened_buf, sizeof(opened_buf), "key " _YELLOW_("%s"), + sprint_hex_inrow(userkey, HITAG_CRYPTOKEY_SIZE)); + opened_with = opened_buf; + + } else if (ht2_try_auth_read(HT2F_PASSWORD, default_pwd, &cfg_uid, &config)) { + opened_with = "default password " _YELLOW_("4D494B52"); + } else if (ht2_try_auth_read(HT2F_CRYPTO, default_key, &cfg_uid, &config)) { + opened_with = "default key " _YELLOW_("4F4E4D494B52"); + } + + if (opened_with != NULL) { + print_hitag2_configuration(uid, config); + PrintAndLogEx(INFO, "Configuration read with %s", opened_with); + } else { + PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information")); + PrintAndLogEx(SUCCESS, "UID...... " _GREEN_("%08X"), uid); + PrintAndLogEx(INFO, "Config... " _YELLOW_("unknown") " ( page 3 needs authentication )"); + PrintAndLogEx(HINT, "Hint: Try `" _YELLOW_("lf hitag chk") "` to search for the key"); + } PrintAndLogEx(INFO, "--- " _CYAN_("Fingerprint")); const char *s = identify_transponder_hitag2(uid); @@ -1328,6 +1422,212 @@ static int CmdLFHitagWriter(const char *Cmd) { return PM3_SUCCESS; } +// Write one page, authenticating with the given credential. +// +// 4 byte credential is a password, 6 byte is a crypto key, matching every other +// Hitag 2 command here. +static int ht2_restore_write_page(uint8_t page, const uint8_t *data, const uint8_t *cred, uint8_t credlen) { + + lf_hitag_data_t packet; + memset(&packet, 0, sizeof(packet)); + packet.page = page; + memcpy(packet.data, data, HITAG_BLOCK_SIZE); + + if (credlen == HITAG_PASSWORD_SIZE) { + packet.cmd = HT2F_PASSWORD; + memcpy(packet.pwd, cred, HITAG_PASSWORD_SIZE); + } else { + packet.cmd = HT2F_CRYPTO; + memcpy(packet.key, cred, HITAG_CRYPTOKEY_SIZE); + } + + clearCommandBuffer(); + SendCommandNG(CMD_LF_HITAG2_WRITE, (uint8_t *)&packet, sizeof(packet)); + + PacketResponseNG resp; + if (WaitForResponseTimeout(CMD_LF_HITAG2_WRITE, &resp, 4000) == false) { + return PM3_ETIMEOUT; + } + return resp.status; +} + +// Is this a configuration byte a Hitag 2 can actually hold? +// +// Bits 7..4 are RFU and are zero on every tag seen; bit 3 picks crypto or +// password; bits 2..1 pick Hitag 2 (11) or one of the read only public modes; +// bit 0 is the encoding. Writing rubbish here is the one page that can make a +// tag useless, so refuse rather than pass it through. +static bool ht2_config_is_sane(uint8_t cfg, const char **why) { + + if ((cfg & 0xF0) != 0) { + *why = "RFU bits 7..4 are not zero"; + return false; + } + return true; +} + +static int CmdLFHitag2Restore(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf hitag restore", + "Write a Hitag 2 dump file back to a tag.\n" + "Pages are written in dependency order: user pages first, then the key\n" + "material in pages 1 and 2, and the configuration in page 3 last - because\n" + "page 3 is what switches the tag's mode, and pages 1 and 2 change the very\n" + "credential needed to write it.\n" + "Page 0 holds the UID and is never written.", + "lf hitag restore -f dump.bin -k 4D494B52\n" + "lf hitag restore -f dump.bin -k 4F4E4D494B52\n" + "lf hitag restore -f dump.bin -> try the factory defaults" + ); + + void *argtable[] = { + arg_param_begin, + arg_str1("f", "file", "", "specify dump filename"), + arg_str0("k", "key", "", "key, 4 bytes for password mode, 6 bytes for crypto mode"), + arg_lit0(NULL, "force", "write even if the configuration byte looks wrong"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + int fnlen = 0; + char filename[FILE_PATH_SIZE] = {0}; + CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); + + uint8_t userkey[HITAG_CRYPTOKEY_SIZE] = {0}; + int ukeylen = 0; + CLIGetHexWithReturn(ctx, 2, userkey, &ukeylen); + bool force = arg_get_lit(ctx, 3); + CLIParserFree(ctx); + + if ((ukeylen != 0) && (ukeylen != HITAG_PASSWORD_SIZE) && (ukeylen != HITAG_CRYPTOKEY_SIZE)) { + + PrintAndLogEx(ERR, "Key must be %u bytes (password) or %u bytes (crypto), got %i", + HITAG_PASSWORD_SIZE, + HITAG_CRYPTOKEY_SIZE, + ukeylen + ); + return PM3_EINVARG; + } + + // load the dump + uint8_t *dump = NULL; + size_t dumplen = 0; + if (loadFile_safe(filename, ".bin", (void **)&dump, &dumplen) != PM3_SUCCESS) { + return PM3_EFILE; + } + + if (dumplen != HITAG2_MAX_BYTE_SIZE) { + PrintAndLogEx(ERR, "Expected %u bytes, got %zu", HITAG2_MAX_BYTE_SIZE, dumplen); + free(dump); + return PM3_EFILE; + } + + const uint8_t new_cfg = dump[HITAG_BLOCK_SIZE * 3]; + const char *why = NULL; + if (ht2_config_is_sane(new_cfg, &why) == false) { + PrintAndLogEx(ERR, "Configuration byte " _RED_("0x%02X") " looks wrong: %s", new_cfg, why); + if (force == false) { + PrintAndLogEx(INFO, "Use `" _YELLOW_("--force") "` to write it anyway"); + free(dump); + return PM3_EINVARG; + } + PrintAndLogEx(WARNING, "--force given, writing it anyway"); + } + + // A public mode is read only, so say so before making it permanent. + if ((new_cfg & 0x06) != 0x06) { + PrintAndLogEx(WARNING, "Configuration " _YELLOW_("0x%02X") " selects a read only public mode", new_cfg); + PrintAndLogEx(WARNING, "The tag will not accept writes afterwards"); + } + + // Find a credential that opens the tag as it is NOW. + uint8_t cred[HITAG_CRYPTOKEY_SIZE] = {0}; + uint8_t credlen = 0; + uint8_t cur_cfg = 0; + uint32_t cur_uid = 0; + + static const uint8_t default_pwd[HITAG_PASSWORD_SIZE] = {0x4D, 0x49, 0x4B, 0x52}; + static const uint8_t default_key[HITAG_CRYPTOKEY_SIZE] = {0x4F, 0x4E, 0x4D, 0x49, 0x4B, 0x52}; + + if ((ukeylen == HITAG_PASSWORD_SIZE) && ht2_try_auth_read(HT2F_PASSWORD, userkey, &cur_uid, &cur_cfg)) { + memcpy(cred, userkey, HITAG_PASSWORD_SIZE); + credlen = HITAG_PASSWORD_SIZE; + } else if ((ukeylen == HITAG_CRYPTOKEY_SIZE) && ht2_try_auth_read(HT2F_CRYPTO, userkey, &cur_uid, &cur_cfg)) { + memcpy(cred, userkey, HITAG_CRYPTOKEY_SIZE); + credlen = HITAG_CRYPTOKEY_SIZE; + } else if (ht2_try_auth_read(HT2F_PASSWORD, default_pwd, &cur_uid, &cur_cfg)) { + memcpy(cred, default_pwd, HITAG_PASSWORD_SIZE); + credlen = HITAG_PASSWORD_SIZE; + PrintAndLogEx(INFO, "Opened with default password " _YELLOW_("4D494B52")); + } else if (ht2_try_auth_read(HT2F_CRYPTO, default_key, &cur_uid, &cur_cfg)) { + memcpy(cred, default_key, HITAG_CRYPTOKEY_SIZE); + credlen = HITAG_CRYPTOKEY_SIZE; + PrintAndLogEx(INFO, "Opened with default key " _YELLOW_("4F4E4D494B52")); + } else { + PrintAndLogEx(FAILED, "Could not authenticate to the tag"); + PrintAndLogEx(HINT, "Hint: Try `" _YELLOW_("lf hitag chk") "` to search for the key"); + free(dump); + return PM3_EFAILED; + } + + PrintAndLogEx(INFO, "Tag UID... " _GREEN_("%08X") ", config " _GREEN_("0x%02X"), cur_uid, cur_cfg); + + // What pages 1 and 2 will make the credential. + // + // The password is page 1. The crypto key is the last two bytes of page 2 + // followed by page 1, which is why writing either page changes both. + uint8_t new_pwd[HITAG_PASSWORD_SIZE] = {0}; + uint8_t new_key[HITAG_CRYPTOKEY_SIZE] = {0}; + memcpy(new_pwd, dump + HITAG_BLOCK_SIZE, HITAG_PASSWORD_SIZE); + new_key[0] = dump[(HITAG_BLOCK_SIZE * 2) + 2]; + new_key[1] = dump[(HITAG_BLOCK_SIZE * 2) + 3]; + memcpy(new_key + 2, dump + HITAG_BLOCK_SIZE, HITAG_BLOCK_SIZE); + + // Page 3 is written last, so the tag is still in its OLD mode at that point + // and wants the new credential expressed in that mode. + const uint8_t *new_cred = (credlen == HITAG_PASSWORD_SIZE) ? new_pwd : new_key; + + // user pages, then key material, then the configuration + const uint8_t order[] = { 4, 5, 6, 7, 2, 1, 3 }; + + for (uint8_t i = 0; i < ARRAYLEN(order); i++) { + + uint8_t page = order[i]; + const uint8_t *pd = dump + (page * HITAG_BLOCK_SIZE); + + // Pages 1 and 2 replace the credential, so page 3 needs the new one. + const uint8_t *use_cred = (page == 3) ? new_cred : cred; + + int res = ht2_restore_write_page(page, pd, use_cred, credlen); + if (res != PM3_SUCCESS) { + PrintAndLogEx(FAILED, "Page %u ( " _RED_("fail") " ) - stopping here", page); + PrintAndLogEx(WARNING, "The tag is part written; pages before this one were changed"); + free(dump); + return res; + } + PrintAndLogEx(SUCCESS, "Page %u %s ( " _GREEN_("ok") " )", page, sprint_hex_inrow(pd, HITAG_BLOCK_SIZE)); + } + + free(dump); + + // Report the credential the tag wants NOW, which follows the configuration + // just written - not the one used to get in. Restoring a crypto dump onto a + // password tag changes which of the two applies, and getting this wrong locks + // the operator out of a tag they just wrote. + PrintAndLogEx(NORMAL, ""); + if ((new_cfg & 0x08) != 0) { + PrintAndLogEx(SUCCESS, "Tag is in " _GREEN_("Crypto") " mode"); + PrintAndLogEx(SUCCESS, "New key... " _GREEN_("%s"), sprint_hex_inrow(new_key, HITAG_CRYPTOKEY_SIZE)); + } else { + PrintAndLogEx(SUCCESS, "Tag is in " _GREEN_("Password") " mode"); + PrintAndLogEx(SUCCESS, "New password... " _GREEN_("%s"), sprint_hex_inrow(new_pwd, HITAG_PASSWORD_SIZE)); + } + + PrintAndLogEx(HINT, "Hint: Try `" _YELLOW_("lf hitag info") "` to verify"); + PrintAndLogEx(NORMAL, ""); + return PM3_SUCCESS; +} + static int CmdLFHitag2Dump(const char *Cmd) { CLIParserContext *ctx; @@ -1672,16 +1972,50 @@ static int CmdLFHitagEload(const char *Cmd) { return PM3_EINVARG; } + // A Hitag u image is the 6 byte UID followed by its pages, and is the largest + // of the four. Everything still fits one NG frame. + #define HITAGU_EIMAGE_SIZE (HITAGU_UID_SIZE + (HITAGU_MAX_PAGE_ADVANCED_PLUS * HITAGU_BLOCK_SIZE)) + // read dump file uint8_t *dump = NULL; - size_t bytes_read = (4 * 64); - int res = pm3_load_dump(filename, (void **)&dump, &bytes_read, (HITAG_BLOCK_SIZE * 64)); + size_t bytes_read = HITAGU_EIMAGE_SIZE; + int res = pm3_load_dump(filename, (void **)&dump, &bytes_read, HITAGU_EIMAGE_SIZE); if (res != PM3_SUCCESS) { return res; } - // check dump len.. - if (bytes_read == HITAG2_MAX_BYTE_SIZE || bytes_read == (HITAG_BLOCK_SIZE * 64)) { + // Validate against the card type the user selected rather than a fixed pair of + // sizes. The old check accepted only 32 or 256 bytes, so a Hitag 1 dump (64) + // and every Hitag u dump were rejected even though -1 and -m were accepted. + size_t expected = HITAG2_MAX_BYTE_SIZE; + const char *tname = "Hitag 2"; + if (use_ht1) { + expected = HITAG1_MAX_BYTE_SIZE; + tname = "Hitag 1"; + } else if (use_hts) { + expected = HITAGS_MAX_BYTE_SIZE; + tname = "Hitag S"; + } else if (use_htm) { + // a u dump is sized by the tag's ICR, so accept anything that fits + expected = 0; + tname = "Hitag \xce\xbc"; + } + + if (use_htm) { + if ((bytes_read < HITAGU_UID_SIZE) || (bytes_read > HITAGU_EIMAGE_SIZE)) { + PrintAndLogEx(ERR, "error, wrong dump file size for %s. got %zu, expected %u..%u", + tname, bytes_read, (unsigned)HITAGU_UID_SIZE, (unsigned)HITAGU_EIMAGE_SIZE); + free(dump); + return PM3_EINVARG; + } + } else if (bytes_read != expected) { + PrintAndLogEx(ERR, "error, wrong dump file size for %s. got %zu, expected %zu", + tname, bytes_read, expected); + free(dump); + return PM3_EINVARG; + } + + { lf_hitag_t *payload = calloc(1, sizeof(lf_hitag_t) + bytes_read); if (payload == NULL) { @@ -1708,8 +2042,6 @@ static int CmdLFHitagEload(const char *Cmd) { clearCommandBuffer(); SendCommandNG(CMD_LF_HITAG_ELOAD, (uint8_t *)payload, 3 + bytes_read); free(payload); - } else { - PrintAndLogEx(ERR, "error, wrong dump file size. got %zu", bytes_read); } free(dump); @@ -1720,18 +2052,41 @@ static int CmdLFHitagEview(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "lf hitag eview", "It displays emulator memory", - "lf hitag eview\n" + "lf hitag eview -2\n" + "lf hitag eview -s\n" ); void *argtable[] = { arg_param_begin, arg_lit0("v", "verbose", "Verbose output"), + arg_lit0("1", "ht1", "Card type Hitag 1"), + arg_lit0("2", "ht2", "Card type Hitag 2 (default)"), + arg_lit0("s", "hts", "Card type Hitag S"), + arg_lit0("m", "htm", "Card type Hitag \xce\xbc"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); bool verbose = arg_get_lit(ctx, 1); + bool use_ht1 = arg_get_lit(ctx, 2); + bool use_ht2 = arg_get_lit(ctx, 3); + bool use_hts = arg_get_lit(ctx, 4); + bool use_htm = arg_get_lit(ctx, 5); CLIParserFree(ctx); + if ((use_ht1 + use_ht2 + use_hts + use_htm) > 1) { + PrintAndLogEx(ERR, "error, specify only one Hitag type"); + return PM3_EINVARG; + } + + // Hitag 2 stays the default so `lf hitag eview` keeps working as before int bytes = HITAG2_MAX_BYTE_SIZE; + if (use_ht1) { + bytes = HITAG1_MAX_BYTE_SIZE; + } else if (use_hts) { + bytes = HITAGS_MAX_BYTE_SIZE; + } else if (use_htm) { + // a Hitag u image is the 6 byte UID followed by its pages + bytes = HITAGU_UID_SIZE + (HITAGU_MAX_PAGE_ADVANCED_PLUS * HITAGU_BLOCK_SIZE); + } // reserve memory uint8_t *dump = calloc(bytes, sizeof(uint8_t)); @@ -1747,14 +2102,15 @@ static int CmdLFHitagEview(const char *Cmd) { return PM3_ETIMEOUT; } - if (verbose) { + // the configuration and Paxton decoding are Hitag 2 specific + if (verbose && ((use_ht1 + use_hts + use_htm) == 0)) { // block3, 1 byte uint8_t config = dump[HITAG2_CONFIG_OFFSET]; uint32_t uid = bytes_to_num(dump, HITAG_UID_SIZE); print_hitag2_configuration(uid, config); print_hitag2_paxton(true, dump); } - print_hitag2_blocks(dump, HITAG2_MAX_BYTE_SIZE); + print_hitag2_blocks(dump, bytes); free(dump); return PM3_SUCCESS; } @@ -1765,14 +2121,21 @@ static int CmdLFHitagSim(const char *Cmd) { "Simulate Hitag transponder\n" "You need to `lf hitag eload` first", "lf hitag sim -2\n" - "lf hitag sim -2 -t 30 -> set edge detect threshold to 30" + "lf hitag sim -2 -t 20 -> set edge detect threshold to 20" ); void *argtable[] = { arg_param_begin, arg_lit0("1", "ht1", "simulate Hitag 1"), arg_lit0("2", "ht2", "simulate Hitag 2"), - arg_int0("t", "threshold", "", "set edge detect threshold (def: 127)"), + arg_int0("t", "threshold", "", "edge detect threshold, 0 = auto (def: 0)"), + arg_int0(NULL, "twait", "", "tag response delay in T0, 0 = default 227"), + arg_lit0(NULL, "invert", "invert load modulation polarity"), + arg_lit0(NULL, "noalt", "answer every START_AUTH, not every second"), + arg_lit0(NULL, "hold", "diagnostic: hold coil load on"), + arg_int0(NULL, "diag", "", "diagnostic flag bits, ORed into flags (32 = slope, now default)"), + arg_int0(NULL, "sof", "", "SOF bits in the tag answer (def: 6)"), + arg_int0(NULL, "duty", "", "carrier periods loaded per half bit, 1..16 (def: 16)"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -1780,9 +2143,31 @@ static int CmdLFHitagSim(const char *Cmd) { bool use_ht1 = arg_get_lit(ctx, 1); bool use_ht2 = arg_get_lit(ctx, 2); bool use_htm = false; // not implemented yet - int threshold = arg_get_int_def(ctx, 3, 127); + int threshold = arg_get_int_def(ctx, 3, 0); + int twait = arg_get_int_def(ctx, 4, 0); + bool invert = arg_get_lit(ctx, 5); + bool noalt = arg_get_lit(ctx, 6); + bool hold = arg_get_lit(ctx, 7); + int diag = arg_get_int_def(ctx, 8, 0); + int sof = arg_get_int_def(ctx, 9, 0); + int duty = arg_get_int_def(ctx, 10, 0); CLIParserFree(ctx); + if (duty < 0 || duty > 16) { + PrintAndLogEx(ERR, "error, duty must be 0..16"); + return PM3_EINVARG; + } + + if (sof < 0 || sof > 200) { + PrintAndLogEx(ERR, "error, sof must be 0..200"); + return PM3_EINVARG; + } + + if (twait < 0 || twait > 4000) { + PrintAndLogEx(ERR, "error, twait must be 0..4000"); + return PM3_EINVARG; + } + if (threshold < 0 || threshold > 255) { PrintAndLogEx(ERR, "error, threshold must be 0..255"); return PM3_EINVARG; @@ -1804,8 +2189,16 @@ static int CmdLFHitagSim(const char *Cmd) { // the tag content comes from emulator memory, this only carries the threshold hitag_sim_t payload = { .tag_mem_supplied = false, - .rfu = 0, + // --diag is documented as "ORed into flags", so OR all of it. Masking it + // with 0xF8 silently dropped bits 0..2, which made --diag 1, 2 and 4 do + // nothing at all while still looking like they had been applied - two + // no-alternation measurements were taken that way before it was noticed. + // The named options set the same bits, so they simply agree. + .flags = (uint8_t)((invert ? 1 : 0) | (noalt ? 2 : 0) | (hold ? 4 : 0) | (diag & 0xFF)), .threshold = (uint16_t)threshold, + .twait = (uint16_t)twait, + .sof = (uint8_t)sof, + .duty = (uint8_t)duty, }; clearCommandBuffer(); @@ -1818,22 +2211,47 @@ static int CmdLFHitagSniff(const char *Cmd) { CLIParserInit(&ctx, "lf hitag sniff", "Sniff the communication between reader and tag\n" "Use `lf hitag list` to view collected data.", - " lf hitag sniff" + " lf hitag sniff\n" + " lf hitag sniff -t 20 -> lower edge detect threshold" ); void *argtable[] = { arg_param_begin, + arg_int0("t", "threshold", "", "edge detect threshold, 0 = default 32"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); + int threshold = arg_get_int_def(ctx, 1, 0); CLIParserFree(ctx); - PrintAndLogEx(INFO, "Press " _GREEN_("pm3 button") " to abort sniffing"); + if (threshold < 0 || threshold > 255) { + PrintAndLogEx(ERR, "error, threshold must be 0..255"); + return PM3_EINVARG; + } + + PrintAndLogEx(INFO, "Press " _GREEN_("pm3 button") " or " _GREEN_("") " to abort sniffing"); PacketResponseNG resp; clearCommandBuffer(); - SendCommandNG(CMD_LF_HITAG_SNIFF, NULL, 0); - WaitForResponse(CMD_LF_HITAG_SNIFF, &resp); + uint8_t payload = (uint8_t)threshold; + SendCommandNG(CMD_LF_HITAG_SNIFF, &payload, sizeof(payload)); + + // Wait the way the other long running LF commands do, rather than blocking + // in WaitForResponse(). Blocking there means the client never reads another + // command, so the device's own data_available() abort can never be reached - + // `hw break` sits unread in the input and the session looks hung even though + // the firmware is willing to stop. + for (;;) { + if (kbd_enter_pressed()) { + SendCommandNG(CMD_BREAK_LOOP, NULL, 0); + PrintAndLogEx(DEBUG, "\naborted via keyboard!"); + break; + } + if (WaitForResponseTimeout(CMD_LF_HITAG_SNIFF, &resp, 1000)) { + break; + } + } + PrintAndLogEx(INFO, "Done!"); PrintAndLogEx(HINT, "Hint: Try `" _YELLOW_("lf hitag list")"` to view captured tracelog"); PrintAndLogEx(HINT, "Hint: Try `" _YELLOW_("trace save -h") "` to save tracelog for later analysing"); @@ -2497,6 +2915,7 @@ static command_t CommandTable[] = { {"sniff", CmdLFHitagSniff, IfPm3Hitag, "Eavesdrop Hitag communication"}, {"view", CmdLFHitagView, AlwaysAvailable, "Display content from tag dump file"}, {"wrbl", CmdLFHitagWriter, IfPm3Hitag, "Write a block (page) in Hitag memory"}, + {"restore", CmdLFHitag2Restore, IfPm3Hitag, "Restore a dump file to a Hitag 2 tag"}, {"-----------", CmdHelp, IfPm3Hitag, "----------------------- " _CYAN_("Simulation") " -----------------------"}, {"eload", CmdLFHitagEload, IfPm3Hitag, "Upload file into emulator memory"}, // {"esave", CmdLFHitagESave, IfPm3Hitag, "Save emulator memory to file"}, diff --git a/client/src/cmdtrace.c b/client/src/cmdtrace.c index 108ea42ab..872c81606 100644 --- a/client/src/cmdtrace.c +++ b/client/src/cmdtrace.c @@ -1099,18 +1099,14 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr if (j == 0) { - // only apply this to lesser than one byte + // Bit count goes in the Bit column, same as the frame above. + // One leading space so the hex lines up under "Data". if (n == 1) { - snprintf(line[0], 120, "%2u: %02X ", nbits, ht2plain[0] >> (8 - nbits)); + snprintf(line[0], 120, " %02X ", ht2plain[0] >> (8 - nbits)); } else { - - if (nbits == 0) { - snprintf(line[0], 120, "%2u: %02X ", (uint16_t)(n * 8), ht2plain[0]); - } else { - snprintf(line[0], 120, "%2u: %02X ", (uint16_t)(((n - 1) * 8) + nbits), ht2plain[0]); - } + snprintf(line[0], 120, " %02X ", ht2plain[0]); } - offset = 4; + offset = 1; } else { snprintf(line[j / 18] + ((j % 18) * 4) + offset, 120, "%02X ", ht2plain[j]); @@ -1119,18 +1115,28 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr num_lines = MIN((n - 1) / TRACE_MAX_HEX_BYTES + 1, TRACE_MAX_HEX_BYTES); + char plain_nbits[8] = {0}; + if (n == 1) { + snprintf(plain_nbits, sizeof(plain_nbits), "%3u ", nbits); + } else if (nbits == 0) { + snprintf(plain_nbits, sizeof(plain_nbits), "%3u ", (uint16_t)(n * 8)); + } else { + snprintf(plain_nbits, sizeof(plain_nbits), "%3u ", (uint16_t)(((n - 1) * 8) + nbits)); + } + for (int j = 0; j < num_lines ; j++) { + bool last = (j == num_lines - 1); if (hdr->isResponse) { - PrintAndLogEx(NORMAL, " | | * |%-*s | %-4s| %s", + PrintAndLogEx(NORMAL, " | | * |%-*s | %s| %s", str_padder, line[j], - " ", + (last) ? plain_nbits : " ", explanation); } else { PrintAndLogEx(NORMAL, " | | * |" _YELLOW_("%-*s")" | " _YELLOW_("%s") "| " _YELLOW_("%s"), str_padder, line[j], - " ", + (last) ? plain_nbits : " ", explanation); } diff --git a/common/lfdemod.c b/common/lfdemod.c index 67f855fbd..33ee616cc 100644 --- a/common/lfdemod.c +++ b/common/lfdemod.c @@ -1657,7 +1657,14 @@ uint16_t manrawdecode(uint8_t *bits, size_t *size, uint8_t invert, uint8_t *alig *alignPos = bestRun; // decode - for (i = bestRun; i < *size; i += 2) { + // + // i + 1 < *size, not i < *size: the body reads bits[i + 1], so the old bound + // ran one pair past the end whenever the chosen alignment left a lone sample + // at the tail (bestRun == 1 with an even size, say). That out of range read + // produced a spurious trailing symbol, marked 7 as an impossible Manchester + // pair, and callers that then stop at the first 7 lost the last real bit - + // a Hitag 2 tag answering CE129911 decoded as CE129910, one bit short. + for (i = bestRun; i + 1 < *size; i += 2) { if (bits[i] == 1 && (bits[i + 1] == 0)) { bits[bitnum++] = invert; diff --git a/common_arm/fpga/fpga_apis.h b/common_arm/fpga/fpga_apis.h index 9897708db..018f4086d 100644 --- a/common_arm/fpga/fpga_apis.h +++ b/common_arm/fpga/fpga_apis.h @@ -107,6 +107,22 @@ #define FPGA_LF_EDGE_DETECT_READER_FIELD ( 1 ) #define FPGA_LF_EDGE_DETECT_TOGGLE_MODE ( 2 ) +// Modulate the coil on the 10k leg alone instead of the 33 Ohm one, for a +// shallower tag answer. Understood by LF_EDGE_DETECT and LF_ADC. +#define FPGA_LF_WEAK_LOAD ( 4 ) + +// Hold the envelope follower while the tag simulator is modulating, so its own +// answer does not drag the slicing levels away from the reader's signal. +#define FPGA_LF_EDGE_DETECT_HOLD_TRACKER ( 8 ) + +// Let the edge detector keep working on a small tracked span, so a reader frame +// riding on a recovering envelope is still sliced instead of being ignored. +#define FPGA_LF_EDGE_DETECT_SENSITIVE ( 16 ) + +// Detect edges from the slope of the signal rather than from a level, so a frame +// riding on a recovering envelope is still resolved. +#define FPGA_LF_EDGE_DETECT_SLOPE ( 32 ) + // Options for the generic HF reader #define FPGA_HF_READER_MODE_RECEIVE_IQ ( 0 ) #define FPGA_HF_READER_MODE_RECEIVE_AMPLITUDE ( 1 ) diff --git a/common_arm/ticks/ticks_apis.h b/common_arm/ticks/ticks_apis.h index e85a5cd55..856eb1623 100644 --- a/common_arm/ticks/ticks_apis.h +++ b/common_arm/ticks/ticks_apis.h @@ -72,10 +72,24 @@ void WaitMS(uint32_t ms); // ------------------------------------------------------------------------- // Free-running precision counter @ 1.5 MHz (12 counts = 1 T0 = 8 us). -void StartPrecisionCounter(void); // configure + start + reset +// +// The counter is never stopped or zeroed while a session is running. It is +// 16 bit, so it wraps every 43.7 ms, and every reading here is a difference: +// unsigned 16 bit subtraction gives the right answer straight across a wrap, for +// any interval shorter than a full turn of the counter. +// +// ResetPrecisionCounter() therefore only moves the reference the plain +// GetPrecisionCounter() is measured from; it does not touch the hardware. That +// keeps all the "time since the last mark" call sites reading the same as +// before, without a software trigger whose effect has to be waited for - waiting +// for the counter to read exactly zero could step over the window and then sit +// out a whole 43.7 ms wrap before zero came round again. +void StartPrecisionCounter(void); // configure + start void StopPrecisionCounter(void); -void ResetPrecisionCounter(void); // software reset to 0 -uint16_t RAMFUNC GetPrecisionCounter(void); // current count (16-bit) +void ResetPrecisionCounter(void); // mark a new reference point +uint16_t RAMFUNC GetPrecisionCounter(void); // ticks since that reference +uint16_t RAMFUNC GetPrecisionCounterRaw(void); // the free running counter itself +uint16_t RAMFUNC GetPrecisionCounterDelta(uint16_t start); // ticks since `start` // Input capture(LF_EDGE_DETECT): rising/falling edges of an external signal. void StartLoEdgeCapture(void); // configure + start + reset diff --git a/common_arm/ticks/ticks_hw_at32.c b/common_arm/ticks/ticks_hw_at32.c index 91b7e769b..d063e6399 100644 --- a/common_arm/ticks/ticks_hw_at32.c +++ b/common_arm/ticks/ticks_hw_at32.c @@ -332,12 +332,19 @@ void StopTimestamp(void) { } uint32_t RAMFUNC GetTimestamp(void) { - if (tmr_flag_get(AT32_TMR_TIMESTAMP, TMR_OVF_FLAG)) { + // Sample the counter on both sides of the overflow check, so a wrap that + // lands between the two cannot make the timestamp go backwards. See the + // AT91 version for why that matters. + uint16_t cv_before = (uint16_t)tmr_counter_value_get(AT32_TMR_TIMESTAMP); + bool overflowed = tmr_flag_get(AT32_TMR_TIMESTAMP, TMR_OVF_FLAG); + uint16_t cv_after = (uint16_t)tmr_counter_value_get(AT32_TMR_TIMESTAMP); + + if (overflowed) { tmr_flag_clear(AT32_TMR_TIMESTAMP, TMR_OVF_FLAG); timestamp_high++; + cv_before = cv_after; } - uint16_t cv = (uint16_t)tmr_counter_value_get(AT32_TMR_TIMESTAMP); - return (((uint32_t)timestamp_high << 16) + cv) / TICKS_PER_CARRIER_PERIOD; + return (((uint32_t)timestamp_high << 16) + cv_before) / TICKS_PER_CARRIER_PERIOD; } #endif // #ifndef AS_BOOTROM diff --git a/common_arm/ticks/ticks_hw_at91.c b/common_arm/ticks/ticks_hw_at91.c index a87e2d915..b06689762 100644 --- a/common_arm/ticks/ticks_hw_at91.c +++ b/common_arm/ticks/ticks_hw_at91.c @@ -220,6 +220,31 @@ uint32_t RAMFUNC GetCountSspClk(void) { // TC2 overflow count, combined with the TC2 counter for ~47 min timing. static uint16_t timestamp_high = 0; + +// Wait for a software trigger to take effect, without ever spinning on an exact +// value. +// +// TC_CV restarts on the next TIMER_CLOCK3 edge, 32 MCK cycles away, and reading +// a timer register costs a good fraction of that. A loop that waits for exactly +// 0 can therefore step straight over the window, and the counter then has to run +// all the way round its 16 bits - 43.7 ms - before zero comes past again. In +// ResetPrecisionCounter(), which the Hitag reader calls once per transmitted +// bit, that turns into a stall long enough that the Proxmark stops answering USB +// and looks like it has hung. Accept any value that is plainly post-reset, and +// give up rather than wait forever. +#define TC_WAIT_RESTART(tc) \ + do { \ + for (uint32_t _i = 0; _i < 256; _i++) { \ + if ((tc)->TC_CV < 4) { \ + break; \ + } \ + } \ + } while (0) + +// Reference the plain GetPrecisionCounter() measures from. See ticks_apis.h: +// this moves, the hardware counter does not. +static uint16_t precision_ref = 0; + void StartPrecisionCounter(void) { // Enable peripheral clock for TC0 (precision counter). AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0); @@ -230,7 +255,8 @@ void StartPrecisionCounter(void) { // TC0: capture mode, default timer source = MCK/32 (TIMER_CLOCK3), no triggers (free-running). AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK; AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - while (AT91C_BASE_TC0->TC_CV != 0) {}; // wait until the reset takes effect + TC_WAIT_RESTART(AT91C_BASE_TC0); // wait until the reset takes effect + precision_ref = 0; } void StopPrecisionCounter(void) { @@ -238,14 +264,21 @@ void StopPrecisionCounter(void) { } void ResetPrecisionCounter(void) { - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - while (AT91C_BASE_TC0->TC_CV != 0) {}; + precision_ref = (uint16_t)AT91C_BASE_TC0->TC_CV; } uint16_t RAMFUNC GetPrecisionCounter(void) { + return (uint16_t)(AT91C_BASE_TC0->TC_CV - precision_ref); +} + +uint16_t RAMFUNC GetPrecisionCounterRaw(void) { return (uint16_t)AT91C_BASE_TC0->TC_CV; } +uint16_t RAMFUNC GetPrecisionCounterDelta(uint16_t start) { + return (uint16_t)(AT91C_BASE_TC0->TC_CV - start); +} + void StartLoEdgeCapture(void) { // Enable peripheral clock for TC1 (input capture). AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC1); @@ -264,7 +297,7 @@ void StartLoEdgeCapture(void) { | AT91C_TC_LDRA_RISING // load RA on rising edge of TIOA | AT91C_TC_LDRB_FALLING; // load RB on falling edge of TIOA AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - while (AT91C_BASE_TC1->TC_CV != 0) {}; // wait until the reset takes effect + TC_WAIT_RESTART(AT91C_BASE_TC1); // wait until the reset takes effect } void StopLoEdgeCapture(void) { @@ -313,9 +346,17 @@ void StartTimestamp(void) { // TC2: capture mode, default timer source = MCK/32 (TIMER_CLOCK3), no triggers (free-running). AT91C_BASE_TC2->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK; AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - while (AT91C_BASE_TC2->TC_CV != 0) {}; // wait until the reset takes effect + TC_WAIT_RESTART(AT91C_BASE_TC2); // wait until the reset takes effect - // Reset the overflow accumulator. + // Reset the overflow accumulator, and the hardware flag it counts. + // + // Reading TC_SR is what clears COVFS. Without this, an overflow left over + // from a previous run is still pending, so the very first GetTimestamp() + // counts it and every timestamp for the rest of the session is 65536 ticks - + // 5461 T0 - too high. It shows up in a trace as a frame whose end is exactly + // start + 65536, followed by rows with negative looking start times where the + // client subtracts the inflated value. + (void)AT91C_BASE_TC2->TC_SR; timestamp_high = 0; } @@ -324,11 +365,30 @@ void StopTimestamp(void) { } uint32_t RAMFUNC GetTimestamp(void) { - // Reading TC_SR clears the COVFS overflow flag. - if (AT91C_BASE_TC2->TC_SR & AT91C_TC_COVFS) { + // Read the counter on both sides of the overflow check. + // + // TC2 is 16 bits at MCK/32, so it wraps every 43.7 ms, and reading TC_SR is + // what latches that wrap into timestamp_high - and clears the flag, so it may + // only be read once. Checking the flag first and reading TC_CV afterwards + // leaves a window: a wrap landing between the two reads is not seen, the low + // half has already restarted near zero, and the result comes back 65536 ticks + // (5461 T0) BELOW the previous one. Timestamps that go backwards break every + // caller that measures with an unsigned difference; the Hitag 2 simulator's + // turnaround, `while ((TIMESTAMP - rx_end) < ...)`, wraps to a huge value and + // stops waiting at once, putting the answer on the air a full frame early. + // + // Sampling either side of the flag read closes it: if the flag is set the + // wrap is at or before the flag read, so the second sample is the one that + // belongs with the incremented high half. + uint16_t cv_before = (uint16_t)AT91C_BASE_TC2->TC_CV; + bool overflowed = (AT91C_BASE_TC2->TC_SR & AT91C_TC_COVFS) != 0; + uint16_t cv_after = (uint16_t)AT91C_BASE_TC2->TC_CV; + + if (overflowed) { timestamp_high++; + cv_before = cv_after; } - return (((uint32_t)timestamp_high << 16) + AT91C_BASE_TC2->TC_CV) / TICKS_PER_CARRIER_PERIOD; + return (((uint32_t)timestamp_high << 16) + cv_before) / TICKS_PER_CARRIER_PERIOD; } #endif // #ifndef AS_BOOTROM diff --git a/fpga/fpga_pm3_lf.bit b/fpga/fpga_pm3_lf.bit index 50c8c6c1f2d4eccc7e33e2cf78e62a85ffcd129a..40d779d26dc61acf5a39ea6d8b4eec5e524c75d9 100644 GIT binary patch literal 42172 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 z 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 literal 42172 zcmeIbeRN#qbuYZnbB@IE%t&)A+qnv#M{ProO#d>5$OW z?d!IJX5H6KbIGHT3^F!&pfn{Z%{w;Et&;j?4YmQB4|6O85ypgx%Wa*+iws2J3hEF6 z4v{~=?{7b6=FE|8(!1WvA6@H>SPM319-Vo<_WteP-urn(v*J_!KSaijpt$6t1)|Le_*(rNl4MXwKj=q8#~{U7=xq8w{{e-*%=+M!4UKT!NseKqIu28kJd~a?g-% zSJHuIBV z;aX{KGhBCwc2mlWriCxeN{iLv0ZJXXh$7n!{T^@LPI`>my=bxN7(HgSdv;o+Xfr?A z(_6H%{2rQjj80Lv7cZJ<1L4l1xtjiopA4IMOTVXVJWgk*$BR#yry*RWg`|EGGdGZa zk92m@Da(J4b&8t(7oLiBkH(J=I+n{{HD1@Q{Ql&Q(UZfiUUW(vQ;&HVSJAiy8wfw; zy4B%vC3%3Kn%yZ=Q_+~c6k7~Gu5lSXq85~+8^lYrTeWDxsyxZ~@5$IPdfVvo;%V~` zy-mrAV0S$gr@oFOJe9$rjIkM_f#|6NGf6$)9JBzE$h0*6%8LnN!On{|hlOZflu5T~u4~gD;fdcSk{3IwPoDAD!nQ1WkWw=0h%tIFnObEx zjmG>Z7v@H_8KJ!mS(-Mw=`uB^Y)re|c4H1&Gi}{U@tpaFsn`9!OD3q=XL^%6f6w5U z|DW!UvMd_?dA94& zRlmkJAF_-S7R+%Y@dVehn&W=hq1o|Vomtn$h61qS4 znn_>3l2mPDPS7bE<8mPAkv2sS`udf03aYlI&ego8Q&9aLijSEQU%!&p$K6M%T}2b- z2tDd0ut|C+DMzX8s|w3k`fHJ_TjuLmGk&=!wSFCe_OAt@#oiS67zfw+Y)*+(Vahn?CwB-6-u0dgJnUWuaexQu3^Nh{Lap8*S&)@b)uv3=e<%!XQ|>;ZCbfTFol>zArq?_2C5`tz7G zpWE!jUQH0U@z=t(Vg$?2!wEovu%@sZt`NR{(X5;FxGpPRaLmvKe+v3FE;=ZtO!D=s za0#3Dz|L2MU(>Zb36s8ld3A3&mGydyPOBa_Hg4WPW3))dfL}uEpmJXE(Ted4K<3$d zd)sMvAW^n~U;g|I*G-^@>%EK8Vw{SUB6M{fBd4@UBz*ny<_)=<>Ce5tFZLdDACsxk zWIkunX1V=MdqAZ9b(izX^xW$1!&{53ukapIF@k=L%Z_a9sOePkt0??&Eq{~VwR)Dt zr;KTO&+U=%`{qph`X!xjSN7`Q%XCt9=VRZ-UVU129ErUd4e;x7?=jJS6u4YweP5Be zTl`FJCU;lE$3=%Dc}>f8y|lYORgNwe&qx@MzU16qkJPZ+j{yew)x=mZ5#5kGOb@FC z1$*5UFIgK^OLo=-*FsFZ0a#{(5C*=j9{x zF|VQDDLH#+0ohq`MBFY~V6mH;{Q2?d9(q!>7BU;?um-XSgYWHXTY1&``2l`;z^^tB z&f#*mNbN3`@_;+&v7+4(#xH1-RY*)?z1meH1KAHUonMcK@atuo&UQD$#Fgb~r)Mt4 zHAU0*5;l4PerX*n!<-&tQ+ZSDUh`FeLITEfjPwY^4}?M5H(4d9pkR~5|VKCiq0;7jk)RdUUXb6)lLYBTf#A2BX7ko7EU z%+KK`z_0tv0KX;~wp7%^K4c)X6@*7&6Cz$yfL|}_u15RBGYn+QB93^`dWh}eXBq?i z+Cvz!TvckC&_HkBEl$%DZtJp04ZmjN+cUa9|4VlaegYf@@19#?cL(@o?5Os6LZS1^ z;(N^r^``3Tk2enn`1K&2X0-A)mT3cBO0faV&uO{af!(O$S6vdLz_>@HEkuYz%L%OkeN0_~WM+ESEg4}DZb zR=~(eUW*a?L-Z@4)z(bnB>-7ZIrg8;f1$V3wT0NyXn&Adzk{$clB!KK)wI~b27~t2v@EjI+4YKz|?IKM&Kjs^R7u zemxHSTIkvEAzJ{xa#nxtMOma)s^OPA7nTHLpGD&P#_nut@hn%2XLsAl7iTSw1o#E3 z?sQwWg5L{gyVNjZzDB1q1uwSey!ds>>B+#?`Z;@Fw%)y3cMRt^b|xUeGf%tUr_RY( z$(*v@A>dbfFu<>M^r!(p3ixIHgyuWghrfXCERhiv;FqD-6m5WCFqQe{f|x{`ghb;2 zzgWN4dr^W9`S)g$k|f4xm$*Vj(gA)otj7{`dzaxo#&hrsV9;36X5tril-^@(1|dYt z0N)Ct1^5->U#G=x_#37VWbq^Bl<#lM;9q-Hq8uG*sxYz#-Py<6*OvXHTncH?F=|s^Zt< z)lr(?YUG)zy)exZh*TeY*<>)%`FU}sd zz>Q|mSn_vi{ssJMOk*Fu4Z$a3HU!r^EVv0(`4>i^muW0s#uDfi{GnO$^=k(IdY7)| z`I)3s0s}0VulwsYlYg;)n1y|2AcOTg?9cNI{Uj{4sP{9-qQk!V7z41{mH`z$=U7Y6@a{MtwJWz-Q%v{jEDh2@t# z&u8&3S4KZWA^JSme#l&~O!v8; z$K~^{#Ekj*vOo5cc*b9g!n|rX(4T#-?pT|Bf^Ov=PWt+lG-~)oZ!X&}zu3fSAp3SxMJR}a{#qm}@eSzL7FMend+eaE zU%)R76Mj5_NljKDu)sn;-Yj|SBle}5e>H9}zvUCLbs%EDQrBkV8_d@QHv#|hZGw+q zmR6Z^)k~@HFPagL0)912iw^mCzNhW>antkHi}_c;2OnwH-9QhUt{sbhS-kGgGf}t= zx;pDYalieLSg`D(ekhU4{c$A}HD=llf@9828tG1Tia3PuPyVt-8I29cIBk znQtG#dR4w_2LJkN0$EFlKX*?!@KQzq3KjecEI$jKUcB7e<(%;@dkaR!TcO(wSnIVl z*7oo*S_1nl3ba?XyHK=pm4BteZD7NT!nO6{qK&^6%)fXz7o~d{bKB6ScMCgR5(cEA zUsS;_e=U4FpYlgqFg>%6=cn-D8GUB{6=i$)H3Ewa;TO}c__+C&eWs=J(CW8ZyV0hT z;DOZe%c{l?ohS1xN9+@cc8qJgYlFG?^UU~#9x7NiIPK*A$WGtDF&Q^&r^ER5sN3GR z8F--{qXfsJQa*MU!}tZXaxkt}lBZ~wx1~5IMW>xk3jlpKetFB;xMN&J^E90R#x0zI zUvM3V;>G1J)34Dc)^Dch9a^OHdt9C$;1@kQ1%H04c*A>Az*(9S3$l;NL=hV;gkQUO z=1K5o(=pGuy{k|dNzTA8Sib`B>#)sXLwkd`)OlF76zmO6Vf?bb`t)V=3E-F8<;Bt$ z#MIj#PWOH;-5SC#jaJ}a@{Gi|-uzEk!Pz}4;^1HPS?)9A*GaWR>UBSJcc*8)hj9UZ zJ&Y@aUk_1>in3dXwRjO-y%^qm%4_Hk$JhXI(F1F zHPKx#dd8G>D;vGD@T(DF!@3jHC1aWwh_pO}*p9!)7{5MlHOgqdx56(pkkut*Y6gBi zVa3_JGwtFSmh4_gyjeAN~TseH{HgdP>{2nrnB%1_PI!VTe|I3&Mey% z|L~mnp{7*bE7#;(fmX8T(~bG%A^bW44|WZ@inwTk$JNGrH4FPQ1HTfCUsKLrD`BuJ zYwhi8Cor-Qemy~#%awgi_Zo~}cAuEbjI0D3KI;32j9(AQR*by~V>i$yFBa1ia$yFu zF$2Gr@V7IN?UJc{RQG4?Irz0gx6yG?ha0=FhxssmRea;Ap=rPr=7((y?1mS{FIcvb z=nnC^0-aR$4h>}6RdNP?!ONv+L>%C~>LIMbK9Wl|0pol-#`v`YF!ANyqiBOLxW+Hl zQnqK{*YVu7?*Ef%J#7D4b(Ul6u(hUC+TF7DT>SdPF__Ape~A~Cv!H=2gkSHep2C`G z<2~z)x~LqRZef4Evw(O)2)`a$i~X}KSJFU+ZhQ_xi;RCdj9(Aa0#(7>D?PO7lY1O! zarg;ts&{CZdP^fr3f&u1{?#93EJ+BzPJ$ixWc~ctKqu4W4mzYd-S~90lK=9M|Js{t zFCg3X3j9NCt-ZjVK>_ehSMy)vb>lVsV*a%bDG*YK<)TdxKimo0)!xfvSC1vPEBnFT zowT_Q9%HcRANQ6nCtL;iOISQDHr;M&>0QW6{RcF;^*!iRPKxJsm2eBM!Vby*aCjNCvU$G zu$2)%Ubb=I#sZ$${(CaEO&)c5nsz-$i)BL^HUaU&QoO@#65JilzrgXW_yMy-r>!1Z zcmTtB*TH&C)$nVaMzPANv>BtPsKahd1K*#c4hg8K7M>AZkJHjk#jw?!Z%>V-0?WVS?I{ziQo`4aAR5o{!{?1o87rBK>3PKG2TRc)eptp=Y$uy}${jEoIutWP8qx0Z z$DTp{Yk(oi5o5H85;Exsiv|E>Q3o*@trx&AfsaZfcPA!pfZ$<%+UPqFHap_BD*qaz zXGOYi%e@FO9iX(_!g%^DC9?6nsN}!a89Ttpx-*PlHr)8k1^Fn0-ToV9;uq$pJ~m_` zI7~|@rlPJtW4T)V@Z)q_p|ubxBz~gy%ho)w>1ugbUu!-x5eedlpHhRv?i5t-d9~Z! zF_~N{7K+Wvof=Lf#;E7HU@X9XZuKIF#nB_OWz_D=HMiU@Tc+;l&n12R0{;@^rzzy5LH z7vhI63;__QYw^ST>9%HUoBl*I-QIiUGr*>4wROb<<9GJg;)g}fJm%mMr(JZO?3=|= zn1-YOd9a!JIO9F>gM~hQ?{zb5B~=}r_#q`U1mECW;@EU zN6bm_lTydMHuT+JQ$@d^lfCdRiXR0WGZ)UAugQPoaSdUBTE7fu3UPqWk=WGW;_M6e zb-t47HB9piOFf8~DW_4NJFd51H92|8lc?o3U4m*jh+? zc@VB>El}cR`{7#rkZ37}m@Ens!w}F$Sp|Rs8xTXU1#y0v^$QNNJ&vs&E4I2c39h?^ zYWXkrh+zHtVGob9!1#64cv8ZE1pEsgzUnE*r^T)GQ}vN@!?<}8`qgy*o(&ol6g%Yt63h;~Oy#W-~JL*&J52;HvsKM9id8I8j1^6X73c597P7S|DSFJ;+bDI9A z-0uO%0{miFN3}))_&!ZntN3>F4LXwR_EN@`;$o6n@fq_;m331ST7K<>A_ok zy{NTbzzE7+eDZ<&9KK%%`=Wc>G3 zDQo@izwp{)Ln}&rjZT z>433>wnWSprX6Ii_x3Rw}a}F}jAY%Qwd;C4`(btKo;zh%v z$=otX7U6 zHT=@`8(Hk1%eCpYnSX7f?b7~M#GMg8?2VShp7j5qkID$zsBd_#%-j>oe-${IvC79U zfSn_L&M(Z^O(FbJ=re&K7HAUDWe_osj!?&380rAODzzDaE!e{@7?3$ovt`{Y;&+GR zhe&(LxD&YvaJ*Oo$j0dTVIXy1E&t`Gz2HYNRwl^y#4Gl2F9a2-;8#$;k+1&@{jIT3 zX8P;L3XEUqd=0;ta(alS0+;1SrF~c&(qNY<2KY612f7MdH`iQ2Ka|XKm%o~QR%s%Z zv|KhWmHG`X?O@n?ST4+)Z-_UO7@&jt4Zn@!#}8u)YkG*TaT~|XvKa3J5mV7>{>$QA z$wD<;5c3Icp#ng^PIs~JaxTK(gzxg>hyRjvn^e7Wh6#J@2dMFIJs9%}e!0xQ#Dem0 zIdQG6%aHoTX%`!N97L?*A13|yVHULO>olf5?lxx3m#`1h<WA?g8cx?s}y3VlBRpRx_FneRyW^HZ@Src;X_qBbKI&5F50 z8<(~W*`F3iz1vVomb^Jq!4$*~1=NWBrT9ZFIQ@umf~)f4F`Fl`0f% z6B794DlFyGl)JHw^{d(UTR47*`VATXE)e8L%N7s)&b{Vj?^E(BwqpT)0k*hW1GY|{ zl-PdTjS~dHgZCcb*D*u;{N>GXpX^T6Sc08DNQ=DGm#g?yi68byUCe5Z60)HnPKY}S z0I5B_q52KjOc$ZWq_a7eD1(}L5{v6$kGa0TVUvy@Qq-+)1AY|@&@Rt`V}@~6^UGv& ztP=WF0PTYN?L~^vuY(9|0?|nLev4nfLGi4{uWLyg5EKS@K(xsVw9n?%oun6XJ>{*_ ztw@9oKseI+p8X5eLk*$$;j2x<1MMxVz`rbnLs>XR-%&_3gID_V%=H_biv&+$`VWDV zCI#%~S)ush2vUAr--2I%ECxj@Ko~LFvv^OC|2jnDsyn$=ndR|mr#lwkW*(x~vfX_R zq4;6ZI&*K&#G2!C!0`uqM&r|SPCIAvm&tgDe-(I5$Ku6S?UQ&Y8#{)&9UYnM^YxVR zYp;tajS>|Da&PZ3y2EP!WV9&WBFTHK4E}}TxER+c6}Ln9nD~LajqqD(vB6(2*Z7de z0PTMFaX zCK}DA_r}`IqX^q1zoKhbq7X6QU!4D9+O>SK^So8zU(Z4Z*WA0j7C*H1TH9$@-QYIe0U@b@ z%)lNSuEh_zY$G8t^Yt3Lhtr8R2yAVRXwE5DtxT8f6WD%sG+k&O~R# z58*!x@GsW|hi}@dTJ@Sb!1pSC)p7pofsy1y?(JIh-(v|f!TJ#K7z zuogeGH(uD%m$^9t{5D&PzATY^Ny6#+MRi;?{Gu0{dPZW;noATCMk}^XnQ8i^-C2aq^j2sc&VN12YNeo7tY7G}OaDf@4qz=jvyW{Z>JP17SsJ#OfBE<|SEKM$ zjeosGhp;-F{~}GqUNiT5FSy{#Z?&da1UbFoD|l#=eG zxA7i4$@_gCuYc;-YXW4q&}dNDoqDPa&!%d0gc>Nh+Um?Z(~%(oaf?EyRKP zNU>ut>3MdICc1rSVHuYHr7DoI@JHo8K>X0JW90fn#1B=hNsK#h&+YP}i_9(7+qBDT zOq=%z{wl-|IW&E(jF%B>;&EYXz3ZN7?ip%0UW*@=d1uNsBSsqwUi|CWtN)hm@U}i~ z{;BUDqW;j@V<7h4*VL@z^U)i{A-dg0{b9NqKjivD4YkvvLLS$OpQ=YxOF8=2HU8x} z#j%tTwS|E=Hi%fV>5%m|7W{j!Zgi?Z1}uLhgkNol7V7-haX>&yM(2vB)d0=!vz_`G_{C~9 zr-&VWHS1T|DuG`#ZVc6L6qw5ZwwR~r&QGm4v8+eNQ9N1S&uhx{hg_W=&(CS2eOC9f zt$EW@ujwZ>{^b$VuFVCJro9YXD$yc`X^D!G8RWkv=uXkH4C9&$AVZ%yez*<%3qp;5 zLFXR8*uSt?=l<{!@Qbd%L{SL8(4TA^X)jsn^A*->w2KR7s`c~64j#@Y*I+Gd1~N28 z{UHX3C!zX{O11oyTd_YL0zn--Q2~Cj8xIrbf_CW?e?d&s9kgA+0tE5H)j}!lA9DUH z9gfRcwAvYt1lqn{F$(RF#$L z?i|dzUa`ZD-C>T9SMEpycWU(;_OI`GytFVK{e?KAt{q$WSMle?X}WdlvJn3oLfm+X zm)g_1TKvR^E!TdQx~BAdT%Motx+Ltzc6&sLZ7ihh;T-hcXlE`Q@GmJ8wNcWJ9LVLV z;Mf$2**L>;B$9?QR`9E_Z}9FG6jO_D(F6IGa%L%ANE`26;3BCM;$KhE9xs(1JS6_v zDSB;b(-KcPT~2$tR)4tHkN5I=9d&df3=0RLVXB5-$LJ}-X|HrNCLn-_%}M+X5>E(* zm_hxE+c=9ig=NDJ@?X~A0r!Y~6*5+X zpLUPhSBXXm+cJfH7}OtrhYqTaBImyq5!0uh5BB~5Mg znqcc{{7Z)oVJbf&4v1ZTUgm_+k=b$<|4PVJPSX`)Q#sKG*lM%DN-{I?i^GPfHU!CX zTR&|dfv^vD9&G~tWfeB2T2@AH7@b?#nB2B9$pYG}w8Q*MO`=*JwB1$XZU^c&qG^Rf z1v{l`_*IP`atS)@Jk0xq^(*Q*2ul*+*D-pYcFP4N^UDHZc^NC2ZAd(I0u;;||3cs_ z0gXZyZ`j&yB>h0*e2xqR`1K48C^tK+SzHgyb+hQI1#HszHR}7B$bVT#dr7EOTW*tr z03wDq^Szn;i_?n>?pyvPdN$jUjeXs069?RmKJ=%?zr+a_`LBC)T$F>l7mYb53j6;Q zZ36sKh@+>W@t7Yko3=s3n16MEe}(He?ywUoSr&WgE<)PN6+T2eSAoBwJ>fLB> zTY+d{v%KBe7PD`TqJE=!!HQ^ze{G>br!a0O5}(Npx!V-FiYO?9Z-{>#q5&6?Z6PG( zp>xS*v0CjetaqVb0slh&%j=kq?TP+{dak@{x@*tI1$0Vw-v@B1a6JWmdy~2{@%zn@ z{LiuwnoOOAu`#X?e*Kgl@z$@7&b20CE>icPegmLT0B{8SYdyTdgv<;zwYan(X&?RMiCd{iZ3 z)(iJ^x~UL;A>4Nlj$>rJE2a4IP7 zE!TElVq5|L+QGBot+{)1iVhkbk9`k*P0KX7F{NaLfbS=#L*HufEh_!J2Mu1;2nsT}* zj=GB#@H#|{Ob>i8E%D^AV7T!47oP$+V4jxmINHs?dPz;hO7&T8Gg3Dxo>Oi)R?yP| zI=PqEU80~dgkSfPA2!7K$``4H8a&}>-ARV<>w9#&`XjD3J{Z59(2>}Q?n>rI95>l3so(cXtW))+hv6F zU;98tVtG;JU&dnk2eFXzUm#)dA=3-ud#5_gdHI)HIu zfZRq8u!dhW4BE9yHI?ln)LIQ_!+?bF3$~8d%Zs?Hd~6w$pbP15)P2@^!S#nsOE1bN zj@$o0C`9D>(KW!pZa=Pt`gx)0ZN8QJvkUz({r+qT;}_R&R6o+^0uVoR_j4jFz^`ot zwk6_YgX!KwMyCZ>_X9y;{8}pRa$C9n@Vj(JVSWKdZ>fI}EQDWwrUtWZQwV+Zl2WdV ztz|RWR}cdHnu{%Zxq>zwMF{T7vi+4vvkfd5vP1aQP2X1!6=27101;c%5<9*8Li%;7 zXD9MsulxFC<9-0J61D(L#86DN7n>GXkjIk{esTRFc-+;11#IJK2)`ccEZ8SnYxu?5 zMA596M;q-0efFD(4L;&r#r+B5hxg;jg8JyEbItUR=xU@NZGgG?WC*{;-Q9L75lz7r zDU{b|FD!~#YWF~!Y7XJof2UK0?n2zY$P#6vdu{vi%}MvnFbax7_%$I<^xibzrHlnCH5I}y+LuFatC;wXeFr7;nW7l6fK3Ya zD!{KcxzB6ghOLzXm9B7*$9TQarix#U*mdC4F3@X$l7yukW^&DI8pIE?&;s;1kI_G8 z08fjpN!=feE5I*QuW_|uxwT}UCiuN<-nq{Z0{r57o6hp;jCm;p1dyj7`0-wIN@|_KxU1mrJj_+_Anu8Wg^VgU^fCrb8zi!`8P=u-&4R>MEUxGd2~ zgBiDs;e5)$>GFYSy0?N~Q^uuqd#q>mSdj1PT#zYB@?L>k#t-OcNf4#*!ylf_6ZxBdyO;jXOcdj9X zU+kH~vl@mrK``R%CqNK0`4`H$xqjnSg^j%~{>?dU4lHdMPlEX2O|(xWvIrZ#>g*Hk z+0FMgfiF`#p5TRgp8fO7!5JvHj^JqAhEF}$_!nDs2``r+0I@h^oj79eMS)*+JUx8> zhBZyM5PDeYJcyVW=TU_43zpvkY?V+yzfXtP=Df&SDbeRw{JnZ#osSL{U_vlnq#Uyi zZF=NLjek+u=3`$l?`6_{uM!9(67tIder4+T{Bp}On`{0Vzao98ndB%9@au5Ezvv0X z4}sLj5kzg35iU^i4-tr01N;Kire*9O09))QH0E`Gy8mm8@yq40qyA8jV&Q!pKg4hv z95jZI#khV9Clx=qf5TtXF;Hp0Y<@7!Pi9{b;$QPsC2TlOyIhxP*L?6VM79~f^iLA^ z0~A@~vY4GBAqQlkvIDjbn+(&vdL&36z;>~T>W zc9JUmt5oG*-#}5zg1PAP5qij3Fb07SGGFVVKNb9HruzsdE)_oFJ31iri?s}7+@_*m z*}0e&Sapn)?=-+ZzKJT69uSIk(_MzTd%Df4kN7SZh{+qwY6lqUS z#vg}^ev;uhZQzVEb?;hJ#BXK!J*s+snIQl^zZWk9$bbci^_T}%xVnw?N6uriy@b`7 zz%sQ{G#^QVakSqCdl=vspLl{=6?4b|aWOf7%mv1=%`8(NzlZr3R#0MG<5<(S0RWj^ zQy%Fkw?Kay)^o@L=a)6D&^$%+FODOzyN#dV{*AIZ z2jRyuoa8he;y_1;e<3}j+M#5kUHrt`UIt-F&=Hl$;>nah&z%2)HW|nuDB}TVop%ul zn-sIiw0O(t=l*!}3J#{l!#3Wj9y8{Hi1jAj`|Lz7usg)R__Q+6dw_mMS9|eNbPsRTgg!`iaNdmv+)$mI?+X<;>N)=&t7|6Cd%dfP@Wt!hp z^7VAQE3i1J0rY1t%3p^|+NpTQ_a!+0waZI+c1*2t=ZssPd4ae<4UQFD zj4R+@P4v*f0vF8XF#X-|g7T_$P4)G+54E_N4G3#W9y{m1kURci%z0|H`_Hu4Lm^_! zeJYt2sTuqW^u&t4Y!>A&o3Fthi=LL)V{MFI^;v$;NZl(Ort@Nc-A-2-W@iWRt3z!G z@vl6aIHRGj7iEV#G>{=LOp6s1|1IB+asF$oy1Z;p=f1^ITaK(n@Dt$6_*M38R7T$q z&_=Ut_))u!^{4 z`l%UrHC#@E2WVRMP-7^5i0dE<-EuXXQ`lAD7xa_~iygwRFVVh2st+f*>eP=i0IB=L zpkCWw9yj=N-|2hF2EK8S!8hrfyCZNXW-XE^cP+d=H0nF1t7a2$AQEv zS4Mze22Znpe-zMaHFS=~-CcZbl$$%~cG~E3z`w?P+U3j{v-DM0&MLO^`(*=AxL)u1 z=DIPMi;iWhIsc`@hTj}qLeCc-To*5yuln{-pI?SX4Xf5HZ2^!)hXnFpGU2QW@QdpY z_W`zWThzU?H(Ki?pq6v}?g|JY{Mv^h+e|s{r0-(vy})jv(Y(gL=!9LAsr=?0AYzZQ z4ab26%rk@_ez?;&mAG081H@s&baX5SDI=x7!>Qg|D8A7IG))Hfk-v0tET5l{8R>?ikRMJVC#>PzrW~hC}rm9W(^|!tOmy ze`j3oF(|l$)Uq8Km-O{(#BLJLsB5#Swb9Sg|5Oi^$G|S z$ChK$%iohPv~_L+kiCQ(rLN@@5JCRy3~kLna45M~9LsGjA?ArfL}*((MRK+L*Yj}E z3*#t@Li*JzD4UQ31W!SqbFWnKYiDFLZTFHz?0E1m8G#?JMrNhxLY1rF7cu`5u+NOk z2pg7TgL5XuYqGllLmlM5wt#h}~`f>L57GE#8etyuy9$Sh& z56W!c<}{3_AXm=H@A>O;Eet7{g75xNE|Q``x7tHFM|5{Z^=Q`QszF>V4)=o z0ajw*qpm#;=U>kc_!sIAw;#Z+J4Q%SHV6A?mY$5$hBdQ)|8v@c^We8woD$?lBGvn6)c3s4o zZwVFvTN4_fBTnf4L$S$9VC=nZ5X7?096tnzd%)#--*4gjH`ps^%qMty8MfvyG2A2D z!}S}McJ(o?K+uTR5Q-lvgci~i%fZ7(AQAW#MIoZy%`+C%ZzPfS!fE9%;kXT8D;J&U zy@>9T3rE8E1^wc^y0qh%J(x=#i8hHkQp-{$N=H`u`o;Ad+$M?roEwx^deI}|W7yAd z%>GiWtKwH9hmR(KR`1F0t9^y|+Bp}Br&Uimb)t6v;Z6bmbz~uIf;>q}6oR_ru=BTi zm+h+FALZB2cfOtCdTiKvE^K>`bYf*1JE5QL2JYXGTs>m<0Z$=NbOneQ`eT7x1^kP3 z5N()$4bbHxD#aAMO0dX&;raT-_49&Y4+$kJoMZ?8^4uJ!TDxlbubrsq&{gH9VHlV6 zA--`S;zDb+m{--XrDda9hG@O$x|Nu<4S96-d% zbC%Kz9-d5v;)eoWlQ%+%l&xCarNf2ZkE$ctgwp_Qk`9lZ^Ix0401rR6Jtj7}UntlQ zHqPfgW{2@BM({v9KmZE~g^!5-p0>*?1N;L2LRx2$H>{#vNdE3psp4{%6Frndf6PAq zF7Pjt@oOQ+*&wJm+;|oULV#Z=n^!$9*cOKk!M~=lUSQ(9h)iMT(i zauH$~h*rUFeg4Y^QY&~wccAmpv_KwK;Ym8ke<6MdrpagyBLlSp<>bs-djU@Z{>2&9 zE&_hBzY5%806L|*Ch;V|ug97Bvh~BYhYZj<;6^BaM?>?%;s>3 zo@dw4C47}yh~btp0`)J^ex=c2+}E$l`L9vf|BQQ>7JKnUNMIrV<%RhdkLy}5-VYP^ zE5+kle%ddv#KP5QxzB$5u!|atriFrs>ihsfFh4>4hK?VSEs>GCjUMu#G8}l><^jKg z`gz0;6=+u`(j;~$UAFNOJ(+7QM>f<4`7h3-Yp;ooOq;)^xLRQVV1YoF1+%r5mVw(hj%gM;8b`vwxdXj8*4pv*!!zZBU6 zo-!hV1`OoHG3f9;~I07~Sea3<_znFnvNkj`BV6NsVd1Hc5KabAW_!p0&OU4|% zpLg*`+<5mg2%-EJLK`$(KnnIQVn0fhbwm+DP`|;*$S9mxj6Q4p;yy#sxX=B(H#q-= z`B?#^<~IKPSo>6h&liOG7j>^qHAgSc1^KTxZ{&)^8voj%(Q4s0qZ*+7K7*&Q5aho& ze%RwQ955GQei*-ae&jB`}N+;_l5FbxIe0JZJ}X<&VxKyt)E}SLXiL3 z$!trahaNf)gRgB%wp&36<-g9TYsxt7wS>m1_VA3y{A+m)zc`a+Ex0k#EdI5kUlKQt zjzPZy{>3`@QKi=c2URLMXtzo`z%SGvLcib%w+VarZ`_K0?as6vj-*5Q1)FfS7u#W8 zNl(d|zL#0weV?Rqe-v%~+t#0FaOS8oF6#aa##O;D0|7YB9L36mOX-&YMBiq*xR?ld zu_Dd;2j{SY5%MV#_V6g;Y-|sW)AVZ`NI>TU{5navuM(?+ zJO~_^Y$}6=1ENjD{;GQahH_q~O&i-=kpD_p!$VLqT-&Smy6v`|tDRqdUF7J`U7Q_2 zv>@kt86|ADXv6xc+Wi|NT=wiG9~7y?W_P>7uWJOsNNe@;xFy2{e%W&{E|o6ChBmkH zt}CR9;7wXj%f?=M@4B9!!@R%Ci!!FKY6LFdq!BI4Yas#Za4$z=yUbtEb54h~r7)P} ziDHZ7`1&xKyVAMX6<~j(9%%A0Lnp%WsdBA;qfDm<*x%UvR{iM~+$*w?1KO6pkt2j( zIRBO1^3B#O)QLhz|LXf%$238hiC+U&;zk^6x`Os8z}DY2O~AQzL9(Db4$mRyzi{nF z#-4%=f1irN55k7Ksn+Iev%)fZIFj~2=b+{G@_E~7g z5$0b4(L!&b6GeHRv47dZ(j2~jqx-D$UpTJ^%O7b2Z0%Z>bS^kvAwD(!#lP{?MB&7Dy1#_R6FgFkqK02Z*rd+p z*cjuN>||#W)ZL%45dXSEB=W<_dy>sLautTd&Mh4BQ2cPU7?iH|A;qBMmZD4XHx4u- zOXH4?K3>y;k#@Jp)`aaf&9Syn3vHf6yzcfiA|AIiC4K!Gu`dMNEOI#yqJ?;7^QEIN zq zU|Y0@U&ea^{JKxx-q&)-{>#M03f(Ae?iEL~j}Y!XxH%W#SCMf3Ycw;J>vFfw0)A!d zKgTHS&BQOI3a%ZAn52~J0J7hp-TC!n@Rr9djVU9DZ;X$3aQslvxYyy}XvWv*j9gew zovz{6&oPSb!)uDLb*Hl3<+vI=rtoBZYrwxM_~kJ@DWJUJm3SGXh70LeP1W%0#>IP` z_SrbD^>SkPNP9ZU{Gw7MAMh`ief}4tyZn#Fs{+8Tx9qP4<5$s0QIzmR*YdgGGHf?6 zzyQB)Vi&^L%5G03t?c&)*c9N`w7&XJ;}_on7%!PzKhHo`!!P`q0OntO{tGnO=U>nG zOf&8CWxjs{F;BRJnBISa0RDA|_hD(cP{S|2-nL!A6dbE|^$-vZXIiEyUjNuKj|&4V*YHdK#RrM=APF|GmHEL*ZOm8@KfIrG?wF4)|6|2prQ5`U zaznOu{_9)l^MZ18S|D()T71rUn@W|@=UV&_YnrkV)_@VAByYcCLiOV!L>GUDMeCPe zzk!tTccV$d#a2H5`hnLCPjANGPmzpYI*#r0FW$WbPdJ2MT$Q(#>B$M9(=lvU)5z3> z?%x1xRVfuMVQ%$v&hPZWV{~iywNJIm%_Tt66L2$_f4Kw1#rC=Ss(xAEGFPIO4{7%& zsEr{&N9R@o?1aI~rSo4WVU5v4fUhrjnDAZp>e~HLA7*;eE=Z`vI3X3T#AptIj$|@3lYb%AazuOx_=V)S zBVKejx-A(1*$n=*FdJq5^~7+y9y{HRvt*3jwfLbQ8;pkgV|U2dIs9u4x+<%IM09>8 zerf(ih^BIGqOzvrvV&H8q5K!^r*^(Jip%EP8NXil@oTbne-z>y*;F%PO&)JH-eYgj zpaP;LMSx#?dnfb@vv92pT}rsE*M<9in8Qa*yM9bK30*+_VUYjg zt9X1(j|&A)oG`aCQQBiqAw=y}zdg@q*F9`gOY56J~;)t8%&T8~KGpX0RA zX^{alyY$w|;GB#eCh z;`=wS1bN(~0XruB&I_FZccb%b{0nW?aeb6zqle+>LJkkXkTPjKW&Emy-~yXDO+Vm^ z(NO!jLbu`jH((DX(yzEDP-=TPP2ZEPDl#S9TKsUI4*|y%LT79<$KY$h=jYukd0dQN zC`TdK4cJV7O~+tB5dBtF{o?aqXRk$>;F%NlA(?&r9W70vYokI{<;=a(mu{{ntdw3ElhbTTd0GcF%RF>4Us>P0E5H_+JH)uL>rc#lRQP)g_xD;j z?X?n1}FdpXG<(!~hjm+D$o& z29Ock+>{I97hg*oSIgNyL?SF_7HAw9vCDFyzn=nZLRvYGYoi`ykn+rlk<-bZRTxF( z@27D7>sPc}rb^Mpx^ZkR1BdElTz=KpFI~T3fp)P4sFWSz{$AS7Pb%?4zW-2P+v^C+ zfpL(w)5|DafN)Oz2A5ny(U1t!0(`Cf4E)NZCH$z%6=M_31rx)L41`MkhOR%fb+rbH zYV0n#@Iqkji9+`}9GLpCzkmGtLm%HIuW6$)nW(0lKvYBV!-uJLd-NB%N!stixh#uQuSeuI4-nwvmz@Rid6Kr3fM}Dxe);#$bF^@| zzILPBxGs8G>DPtb<<)1$4?V2TG5APb-ok=;OufBwKWkhie#rT+$~_)j=df@Bb&TDF zdi4od$Wjfz_E5`<_A;bR5!N`A%tkJjPuklKp@#wgx}Tn;2PoMmx&;5R6*~)Ol8YzN z#`Ezj%lM@@3@0oCPx0&)5py0>*%W3YsNaB1IMOi%eNRE(;gF9QU34bb;Y4S|52t1K zq4*9glRg)Kak24a>sP@q#qq;J55Zi3PU1bOEVvBLFQ;R;FRH3v>#e|H2lv@X>^-6yqJ5yBP+xncGOVQNS+;T*iP;!iTCbF082y147Ak z6~8$D#oH#O&}Rr93<&ctod`~bhs=|<3>nfb5sdB-&~|K(GdD*vL2FkZti(5}${ze2+D z!-BiR@k7St^N%ZpUuRECFs_;TubRFGiVxwe{FhGEo!#e9{P66h3>G(pU&x93v}=ZN z!8!P)xeRaGurLF^x>soYV!Ij^MyvXD6Px8MQz~tr!$LX4zhJt<9|et{sp=P7eobK* z6lMyehF%N(_bbops>WRId{BP~tA18jgC`;WrSCsv+I4p08T<==of2h@UtwWJ{tNo$ zz$TpAXYIFC@?Y;W_OtoddHNI7AMQA(t3l^y{HoBdfPV$T4E%Z@yAjTR z5x8d+zrw-{{JJ(+GaAM1*S3(%2oYh4T5=h|kx#RL`_yv0?&uix^{EMDmX7TWSUr+(j^H(nENpwIA=>UTXY;RH5QJsBz_0Pp!p zwa*#-hbTB3R~3}y8qEq%f;KDbdI$OnpGnS(R0UzkfxhC3R2@~v6*GR9e$Shiu3PO3 z{Sbbiq&GWl$zWV0VLmN_?W+j>wNd#0Wi9^LpUxtbm_rf(&PYu#P*JPwWtH!GTGnNa z|4g5yc?#14LC#Yb++<|*lj^vnnZ?Q4CDfp_fXN&-vVxyn5{#?YN)N=`<+cOM9|%f6 zsm`Gy=IUe;c{QQK@}Ib*f3T)$wc4FyTccIssk#o2pUm}KN4I&pw=O%d*8QwKFIN=? z>$0AHqN?NSJ$u}kiS&S;iBO-j1I_OB_UxP$2saHhxYuW92W_%-YmLv+@2Pn;!Du!F zU8m|~b-n71WvVYbx4AAPeA<6PwQ-S>IE!uxg9VO18kYKGi<7acZJxf~{Iq&8`?2PR znjk(spr2H~>*?$3ZXWnt_V=6TJyUnH@`Vd3PrS-{U3a~CvpSl+s=48rKrr~p|J~f+ z&GzT{y6}4{FSHh^7~VYBo9*itiF4E{XY^w?HQ9B_e+^N+aidzB{ZMn=ZGljCqsnAI z+Z?pHPS*7spQGQWd7c)2m*zsC)%r>0yRPe{tZH`aZEQ~#^oGr1z3@a;``l}}c+zV- zIW6$Q&2_PYcv5Rq2W@gcW6u*Tq<=3quh)3OlbNSmOlk0i~DUcZi`dKKrNfrk5lj?V2>{(;2)+VDWTu>D% z<9b?}GxUoU4dJ74t#Q>aBP(shXgN7vO~{h1p9F1Kt+HYLDp4ES=qHs%b;csOx)1Rn z{u2ehP`8LOa*ktp)%Ud4tvm1s{h!@3?*SIlzTjy=Rof7DE!Yl$#X(TQr98D^vh3bYMa*P%rnlSp)EI7gxHO(j`W(+Lt9#^O{nM0nlt}==J=U+&lQ3;|2snJ zC($KO{i3*gJqx4HhlSwRJG)lDFz4;DLvL!KGb{vcuDSJ7KmD6WCVp{(g?p}=xbws{ z8#2$#d2r&`Uj=Op(J$|JK4Q%}aF#H4mRD_Lh2Z!sfDYP-^Vp3FQmg8Fh|YtjjIa(6 zw(?_Jw-^_zPq?$k&k~Zey=t5HeGemb<;SkVae&JeA?pNf=36TVnhGmMW}hom-{Qqc zo36C6`W(Rzbu+Tj*|=PJA`NIK|Ja_as*SHLVMVI7v9d-pT~D*sxq|;5$B-gR_t6zJ zOPwR+^jDF*?!36{1GMMcLy4y6;&Sjrzeu8|X`s1ja{%`&!P8CjcLgwdwxBBCW%Qm0 zmn$BM^54^E^w!|`ocC0}OIm%#T)K{CpDXnG-<6?yTBe+=)oh$A_^+W1Fm47e2LKJB z(nbPL&%x#D6IsC&<9h4nfs3=BXrBGdIf7T|vvIw+S>2!gNb{^`&JikY`p$>TRm2~y zuGhb>UlL=#Q8j1ln~mGf5tQE_x-M&NFfOG}sM+OngzDbFddhtEN>te?8a|Bs=4=^W;%K<>M;5XrYI0KghfM%ik zU4}eYt%4_&@A^&pr7CSOhf9q{TCSY(IYMO)`v{uP(Ps-~KxYeHsf3)03Rl60}Bg}4DdYfv0Chy6c>+HM~@e(nX1}^Cl-{q+8?w$tA!v(Y9l6sHdO;#eJ%croP++q zn1{E$&rk6CmCw7n&TW`h_9ki(i zQNp@h@#BIv=hH#*XRO+$qRUX>K$ipIH|p}t_fX9+;mv1Fr$2Q5_gNo=n^qc~N0)2A z{{FgLYvW7j)8(MeZ_wqS%?B<7T6wMzeAl@j1yBCNwh21+z5>c35i4YV)%(f!ZS>m@ zemeudoq^xZz;9>Zw=?kD8TjoC{Qr0cw7&$03I38i?=+a?c`-Yb(>ZUefA=9?V^WOL zv46MaZ*CwAnNxFXv8>Lf2~u^IQA#{w69B3fq#!H3h>_pwX{^F<^K!Shb4Oe diff --git a/fpga/fpga_pm3_top.v b/fpga/fpga_pm3_top.v index a183d34d2..1aa597c80 100644 --- a/fpga/fpga_pm3_top.v +++ b/fpga/fpga_pm3_top.v @@ -208,6 +208,10 @@ lo_edge_detect le( .cross_lo (cross_lo), .lf_field (conf_word[0]), .lf_ed_toggle_mode (conf_word[1]), + .lf_weak_load (conf_word[2]), + .lf_ed_hold_tracker (conf_word[3]), + .lf_ed_sensitive (conf_word[4]), + .lf_ed_slope (conf_word[5]), .lf_ed_threshold (lf_ed_threshold), .ssp_dout (ssp_dout), @@ -250,6 +254,7 @@ lo_adc la( .adc_d (adc_d), .divisor (divisor), .lf_field (conf_word[0]), + .lf_weak_load (conf_word[2]), .ssp_dout (ssp_dout), .ssp_din (mux3_ssp_din), diff --git a/fpga/lf_edge_detect.v b/fpga/lf_edge_detect.v index 27d7f6901..f200b1e60 100644 --- a/fpga/lf_edge_detect.v +++ b/fpga/lf_edge_detect.v @@ -18,6 +18,10 @@ module lf_edge_detect( input clk, input [7:0] adc_d, input [7:0] lf_ed_threshold, + input freeze, + input sensitive, + input slope_mode, + input data_rdy, output [7:0] max, output [7:0] min, @@ -33,6 +37,7 @@ min_max_tracker tracker( .clk (clk), .adc_d (adc_d), .threshold (lf_ed_threshold), + .freeze (freeze), .min (min), .max (max) ); @@ -44,13 +49,80 @@ assign lowz_threshold = (max + min) / 2 - (max - min) / 8; assign low_threshold = (max + min) / 2 - (max - min) / 4; // heuristic to see if it makes sense to try to detect an edge +// +// The gaps below are span/8, span/4 and span/8, so the default limits require a +// tracked span of more than 64 counts before any edge is reported. That is fine +// for a settled signal and wrong for a recovering one: right after a tag answers, +// the reader's own frame arrives on an envelope ramping from 8 back up to 135, +// where the per bit dips ride on the ramp and the honest tracked span is small. +// The detector then switches itself off exactly when it is needed, which is what +// leaves a Proxmark simulating Hitag 2 deaf across the reader's password. +// +// `sensitive` relaxes the limits so a tight span still counts as workable. It is +// opt in: on a settled signal the wider limits reject noise, and that is worth +// keeping as the default. +wire [7:0] gap_outer = sensitive ? 8'd2 : 8'd8; +wire [7:0] gap_inner = sensitive ? 8'd4 : 8'd16; + wire enabled = (high_threshold > highz_threshold) & (highz_threshold > lowz_threshold) & (lowz_threshold > low_threshold) - & ((high_threshold - highz_threshold) > 8) - & ((highz_threshold - lowz_threshold) > 16) - & ((lowz_threshold - low_threshold) > 8); + & ((high_threshold - highz_threshold) > gap_outer) + & ((highz_threshold - lowz_threshold) > gap_inner) + & ((lowz_threshold - low_threshold) > gap_outer); + +// Slope detection. +// +// Everything above slices against a level derived from the tracked min and max. +// That works on a settled signal and fails on a moving one: right after the tag +// answers, the reader's frame rides on an envelope ramping back up, so a fixed +// level is reached late or not at all. Per the datasheet a '0' is 18..22 T0 and +// a '1' is 26..32, and t_stop is anything over 36 - so two merged '0' bits, at +// 36..44, cannot be told from a stop by duration. The edge has to be produced +// here rather than inferred later. +// +// A gap is a sharp drop whatever the DC level is, so compare each sample against +// one from thirty two 1 MSa/s samples ago - 32 us, two thirds of the 48 us gap - +// and call the edge on the difference. lf_ed_threshold sets how big a step +// counts, so it stays tunable from the ARM. +// +// The baseline has to be a decent fraction of the gap or the step is small and +// the usable threshold band with it: at 16 us, 18 worked and 14 was already +// noise, which is too tight to trust across rigs. Widening it to 64 us, so the +// comparison spans the whole gap, was measured to gain nothing - same 29 bits of +// the reader's 32 - so 32 us stays and the delay line stays half the size. +reg [7:0] hist [0:31]; +reg [4:0] hist_ptr = 0; + +always @(posedge clk) +if (data_rdy) +begin + hist[hist_ptr] <= adc_d; + hist_ptr <= hist_ptr + 1; +end + +wire [7:0] adc_delayed = hist[hist_ptr]; // the oldest entry, 32 samples back + +// How big a step counts as an edge, in ADC counts over the 32 us baseline. +// +// Absolute. Scaling it to the tracked span was tried twice and the tracker's +// span turns out not to be a usable reference: (max - min) >> 3 chatters - 1602 +// edges, no decodable frame - while span/3 goes dead, no edges at all. Those two +// bracket the working step of ~31, so the span is not stable between them; it is +// driven by our own load modulation as well as the reader's, which is exactly +// what makes it the wrong thing to normalise against. min_max_tracker also +// starts at min=255, max=0, so any such expression needs an underflow guard. +// +// Swept against a Proxmark reader: 28 and below chatters, 29 loses a bit, 30..33 +// authenticates, 34 degrades, 36 stops resolving frames. The optimum does drift +// with coupling - 30, then 31..32, then 32..33 across rig changes today - so -t +// is the knob for a different setup. + +wire falling_slope = (adc_delayed > adc_d) && + (({1'b0, adc_delayed} - {1'b0, adc_d}) >= {1'b0, lf_ed_threshold}); +wire rising_slope = (adc_d > adc_delayed) && + (({1'b0, adc_d} - {1'b0, adc_delayed}) >= {1'b0, lf_ed_threshold}); // Toggle the output with hysteresis // Set to high if the ADC value is above the threshold @@ -62,10 +134,40 @@ reg trigger_enabled = 1; reg output_edge = 0; reg output_state; +// How far the signal has to travel before the state output flips. +// +// The default slices on high/low, which are +/- span/4 either side of the mean, +// so every bit has to traverse half the tracked span. A reader's BPLM '0' bit +// only gives 14 T0 of field between its gaps, and on a run of them the envelope +// never climbs back above high_threshold - so the state never returns high, no +// new falling edge is produced, and two bits merge into one interval. Measured +// against a Proxmark reader: the 32 bit password arrived as 29 bits with a single +// 38 T0 interval where two 20 T0 zeroes should have been. +// +// `sensitive` slices on the inner pair instead, +/- span/8, halving the travel +// needed. Left as an option because the wider hysteresis is what rejects noise +// on a settled signal. +// Measured: an asymmetric pair - trigger on low_threshold, re-arm on lowz - was +// tried here and came out worse, 30 bits of the reader's 32 against 31 for the +// symmetric inner pair. Keeping both slices on the inner thresholds. +// Where to slice, when `sensitive` is on. +// +// The default pair sits +/- span/4 either side of the mean, so every bit has to +// traverse half the tracked span. A reader's BPLM '0' only gives 14 T0 of field +// between its gaps, and on a run of them the envelope never climbs back over +// high_threshold - the state never returns high, no new falling edge is produced +// and two bits merge into one interval. +// +// Measured alternatives, on the reader's 32 bit password: +/- span/8 gives 31 +// bits, span/16 the same but less consistently, an asymmetric strict-trigger / +// easy-rearm pair 30, and biasing the band towards the top of the envelope 29. +wire [7:0] hi_slice = sensitive ? highz_threshold : high_threshold; +wire [7:0] lo_slice = sensitive ? lowz_threshold : low_threshold; + always @(posedge clk) begin - is_high <= (adc_d >= high_threshold); - is_low <= (adc_d <= low_threshold); + is_high <= (adc_d >= hi_slice); + is_low <= (adc_d <= lo_slice); is_zero <= ((adc_d > lowz_threshold) & (adc_d < highz_threshold)); end @@ -86,9 +188,52 @@ begin trigger_enabled <= trigger_enabled | is_zero; end -// edge states +// Measured: requiring the slope to hold across two consecutive 1 MSa/s samples +// was tried, to throw away the single sample noise that has the reader's 32 bit +// frame arriving as anything from 30 to 33 bits. It does remove the extra edges +// - nothing over 32 after it - but delays the real ones enough to lose more than +// it saves, 1 authentication in 7 against 2 without. Left undebounced. + +// Return the slope output to idle high after a long flat stretch. +// +// The two slope rules below only ever move output_state on a slope, so it has no +// idle value: it keeps whatever the last edge left it at. Left low - which is +// where a tag's answer tends to leave it - the next gap drives it low again, so +// there is no transition, no falling edge and no counter reset, and only the +// rising edge at the END of that gap re-arms it. The frame's first bit is then +// never measured: `lf hitag sniff` logged the reader's first gap as a rising edge +// carrying ra=254, meaning the capture counter had not been reset for 254 T0. +// +// A gap is 4..10 T0 and a bit period at most 32, so the longest flat stretch +// inside a frame is about 28 T0; between frames it is at least t_EOF, 80 T0. +// 512 samples at 1 MSa/s is 64 T0, comfortably between the two. +reg [9:0] flat = 0; + always @(posedge clk) -if (enabled) +if (data_rdy) +begin + if (rising_slope | falling_slope) + flat <= 0; + else if (flat != 10'd1023) + flat <= flat + 1; +end + +// edge states +// +// Slope mode is not gated on `enabled`: that heuristic asks whether the tracked +// min/max span is wide enough to slice against, which is exactly the judgement +// slope detection does not need. +always @(posedge clk) +if (slope_mode) +begin + if (rising_slope) + output_state <= 1'd1; + else if (falling_slope) + output_state <= 1'd0; + else if (flat == 10'd512) + output_state <= 1'd1; +end +else if (enabled) begin if (is_high) output_state <= 1'd1; diff --git a/fpga/lo_adc.v b/fpga/lo_adc.v index 475cc869f..f20442d4b 100644 --- a/fpga/lo_adc.v +++ b/fpga/lo_adc.v @@ -26,6 +26,7 @@ module lo_adc( input [7:0] adc_d, input [7:0] divisor, input lf_field, + input lf_weak_load, input ssp_dout, output ssp_din, @@ -56,8 +57,10 @@ assign pwr_hi = 1'b0; // low frequency outputs assign pwr_lo = reader_modulation; assign pwr_oe2 = 1'b0; // 33 Ohms -assign pwr_oe3 = tag_modulation; // base antenna load = 33 Ohms -assign pwr_oe4 = 1'b0; // 10k Ohms +// lf_weak_load moves the modulation from the 33 Ohm leg to the 10k one, so the +// depth measured here matches what lo_edge_detect does in the same mode. +assign pwr_oe3 = tag_modulation & ~lf_weak_load; // base antenna load = 33 Ohms +assign pwr_oe4 = tag_modulation & lf_weak_load; // 10k Ohms // Debug Output ADC clock assign debug = adc_clk; diff --git a/fpga/lo_edge_detect.v b/fpga/lo_edge_detect.v index c29fdccb3..e06cbda02 100644 --- a/fpga/lo_edge_detect.v +++ b/fpga/lo_edge_detect.v @@ -32,6 +32,10 @@ module lo_edge_detect( input cross_lo, input lf_field, input lf_ed_toggle_mode, + input lf_weak_load, + input lf_ed_hold_tracker, + input lf_ed_sensitive, + input lf_ed_slope, input [7:0] lf_ed_threshold, input ssp_dout, @@ -52,15 +56,78 @@ wire reader_modulation = !ssp_dout & lf_field & pck_divclk; // No logic, straight through. assign pwr_oe1 = 1'b0; // not used in LF mode -assign pwr_oe3 = 1'b0; // base antenna load = 33 Ohms -// when modulating, add another 33 Ohms and 10k Ohms in parallel: -assign pwr_oe2 = tag_modulation; + +// Modulate on the same leg the working LF tag simulator uses. +// +// This used to hold pwr_oe3 off and modulate on pwr_oe2 and pwr_oe4 instead, +// which is not what lo_adc.v does - and lo_adc.v is the path behind the LF tag +// simulation that is known to swing a reader's ADC rail to rail from this coil: +// +// lo_adc.v oe2 = 0, oe3 = mod & ~weak, oe4 = mod & weak +// lo_edge_detect.v oe2 = mod & ~weak, oe3 = 0, oe4 = mod +// +// Measured against a genuine Paxton reader with a Proxmark simulating on top of +// it: the reader beeps at a continuous coil load toggle, so it can see this +// antenna modulating, and our Hitag 2 answer is emitted perfectly - 1184 samples +// a frame, no bails, the turnaround matching a genuine fob's 227 T0 to the +// carrier period - yet the reader never advances past START_AUTH. Detectable +// but not decodable is what too shallow a load looks like on a short burst. +// +// The earlier note here claimed both legs together take our own envelope from +// ~148 counts to 0. That figure was withdrawn as unsound - it assumed a DOUT +// toggle in a mode where it was not reaching the coil - and in any case what +// matters is the perturbation at the READER's antenna, not at ours. +// Modulation depth, measured against a genuine Paxton reader. +// +// Three load configurations were tried, judged both by how many of the reader's +// START_AUTH polls this simulator could still hear after its own answer, and by +// whether the reader ever advanced past START_AUTH: +// +// oe2 + oe4 96 polls seen of 218 reader does not advance +// oe3 alone 218 polls seen of 218 reader does not advance +// oe2 + oe3 + oe4 103 polls seen of 218 reader does not advance +// +// So depth is not what the reader is rejecting - across a 2x range of load it +// behaves identically - but it matters a great deal to our own receive. A +// heavier load pins the min/max tracker this same module feeds and leaves the +// simulator deaf for a while after every answer, which loses half the reader's +// polls and would lose its follow up command too: a real reader's t_WAIT2 can be +// as short as 90 T0, and Paxton's measures about 269. +// +// oe3 alone is the lightest of the three, and the leg lo_adc.v drives - but it is +// too light to be HEARD: with it a Proxmark reader 1 cm away got nothing at all +// from this simulator, RXFAIL no_signal=127 and not one block read, where +// oe2 + oe4 reads and writes reliably. So the pair stays. +// +// That leaves our own post-answer deafness to solve the other way, by freezing +// the min/max tracker across our modulation rather than by modulating less - see +// lf_ed_hold_tracker below, which is what that input is for. +assign pwr_oe2 = tag_modulation & ~lf_weak_load; assign pwr_oe4 = tag_modulation; +assign pwr_oe3 = 1'b0; // base antenna load = 33 Ohms assign ssp_clk = cross_lo; assign pwr_lo = reader_modulation; assign pwr_hi = 1'b0; +// Hold the envelope follower across our own answer. +// +// Retriggerable: every carrier period in which we are modulating reloads the +// counter, so the follower stays held for the whole frame and is released a +// short time after the last transition. pck0 is 24 MHz, so 8192 counts is +// about 340 us - longer than a 128 us half bit, short enough to be listening +// again well inside the reader's t_WAIT2. +reg [12:0] hold_cnt = 0; +always @(posedge pck0) +begin + if (tag_modulation) + hold_cnt <= 13'h1FFF; + else if (hold_cnt != 0) + hold_cnt <= hold_cnt - 1; +end + +wire tracker_freeze = lf_ed_hold_tracker & (hold_cnt != 0); + // filter the ADC values wire data_rdy; wire [7:0] adc_filtered; @@ -78,10 +145,19 @@ wire [7:0] high_threshold, highz_threshold, lowz_threshold, low_threshold; wire [7:0] max, min; wire edge_state, edge_toggle; +// Measured: feeding the detector the unfiltered adc_d instead of adc_filtered +// was tried, on the grounds that lp20khz_1MSa_iir_filter cuts right at the 20 kHz +// a 6 T0 reader gap sits on and rounds it. It produced an edge storm - 188043 +// edges and not one decoded frame - so the filter stays. + lf_edge_detect lf_ed( .clk (pck0), .adc_d (adc_filtered), .lf_ed_threshold (lf_ed_threshold), + .freeze (tracker_freeze), + .sensitive (lf_ed_sensitive), + .slope_mode (lf_ed_slope), + .data_rdy (data_rdy), .max (max), .min (min), .high_threshold (high_threshold), diff --git a/fpga/min_max_tracker.v b/fpga/min_max_tracker.v index 2aaab66bb..c504fc571 100644 --- a/fpga/min_max_tracker.v +++ b/fpga/min_max_tracker.v @@ -27,6 +27,7 @@ module min_max_tracker( input clk, input [7:0] adc_d, input [7:0] threshold, + input freeze, output [7:0] min, output [7:0] max ); @@ -37,7 +38,14 @@ reg [7:0] cur_min_val = 255; reg [7:0] cur_max_val = 0; reg [1:0] state = 0; +// `freeze` holds every register still. A tag simulator's own load modulation +// is far deeper than the reader's, so letting it into this follower drags min and +// max to the extremes and the slicing levels derived from them no longer bracket +// the reader's much shallower signal - measured on a Proxmark simulating Hitag 2, +// that left the receiver deaf for ~1200 T0 after every answer. Holding the +// follower across our own transmission keeps it converged on the reader. always @(posedge clk) +if (!freeze) begin case (state) 0: // initialize diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index f2b6c03bf..45edec322 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -483,8 +483,11 @@ typedef struct { // CMD_LF_HITAGS_SIMULATE / CMD_LF_HITAGU_SIMULATE payload typedef struct { uint8_t tag_mem_supplied; - uint8_t rfu; + uint8_t flags; // bit0: invert load modulation polarity uint16_t threshold; + uint16_t twait; // tag response delay in T0, 0 = firmware default + uint8_t sof; // SOF bits in the tag answer, 0 = firmware default (5) + uint8_t duty; // carrier periods loaded per half bit, 0 = firmware default (16) uint8_t data[]; } PACKED hitag_sim_t; diff --git a/tools/pm3_online_tests.sh b/tools/pm3_online_tests.sh index 4de3797f9..780903cf2 100755 --- a/tools/pm3_online_tests.sh +++ b/tools/pm3_online_tests.sh @@ -14,6 +14,7 @@ TESTMFHIDENCODE=false TESTICLASSREADER=false TESTSMARTCARD=false TESTICLASSEMU=false +TESTHITAG2=false NEED_MF_HID_ENCODE_WIPE=false TESTMANUAL=false @@ -23,7 +24,7 @@ while (( "$#" )); do case "$1" in -h|--help) echo """ -Usage: $0 [--pm3bin /path/to/pm3] [--pm3port /dev/tty...] [desfire_value|hid_wiegand|mf_hid_encode|iclass_emu|iclass_reader] +Usage: $0 [--pm3bin /path/to/pm3] [--pm3port /dev/tty...] [desfire_value|hid_wiegand|mf_hid_encode|iclass_emu|iclass_reader|hitag2] --pm3bin ...: Specify path to pm3 binary to test --pm3port ...: Specify serial port for client/proxmark3 --manual ...: Pause after successful online LF HID clone/read checks for external reader verification @@ -33,6 +34,7 @@ Usage: $0 [--pm3bin /path/to/pm3] [--pm3port /dev/tty...] [desfire_value|hid_wie iclass_emu: Test iCLASS emulator memory load/write/read flows iclass_reader: Load iCLASS HID credentials into emulator memory for external reader verification smartcard: Test the RDV4 SIM module and an ISO 7816 contact card + hitag2: Test Hitag 2 against a genuine card and a genuine reader You must specify a test target - no default 'all' for online tests """ exit 0 @@ -89,6 +91,11 @@ Usage: $0 [--pm3bin /path/to/pm3] [--pm3port /dev/tty...] [desfire_value|hid_wie TESTICLASSEMU=true shift ;; + hitag2) + TESTALL=false + TESTHITAG2=true + shift + ;; -*|--*=) # unsupported flags echo "Error: Unsupported flag $1" >&2 exit 1 @@ -102,6 +109,8 @@ done # set positional arguments in their proper place eval set -- "$PARAMS" +HITAG2_DUMP="${HITAG2_DUMP:-traces/lf-hitag-CE129911-dump.bin}" + C_RED='\033[0;31m' C_GREEN='\033[0;32m' C_YELLOW='\033[0;33m' @@ -348,12 +357,27 @@ function CheckMfHidEncodeCleanup() { function WaitForEnter() { echo "" echo "$1" - echo "Press Enter when ready, or Ctrl-C to abort." - if [ -r /dev/tty ]; then + + # Only prompt when there is really a terminal to prompt on. + # + # `[ -r /dev/tty ]` is not that test: the node can exist and be readable by + # mode bits while the process has no controlling terminal, and the redirect + # then fails with "No such device or address" and the run carries on with the + # rig unconfirmed. Opening it is the only reliable check. + if [ -n "${PM3_ONLINE_NOPROMPT:-}" ]; then + echo "PM3_ONLINE_NOPROMPT set - assuming the rig is ready." + return + fi + + if (exec < /dev/tty) 2>/dev/null; then + echo "Press Enter when ready, or Ctrl-C to abort." stty sane < /dev/tty 2>/dev/null || true IFS= read -r < /dev/tty + elif [ -t 0 ]; then + echo "Press Enter when ready, or Ctrl-C to abort." + IFS= read -r else - read -r + echo "No terminal to prompt on - assuming the rig is ready." fi } @@ -372,7 +396,7 @@ if command -v git >/dev/null && git rev-parse --is-inside-work-tree >/dev/null 2 fi # Check that user specified a test -if [ "$TESTDESFIREVALUE" = false ] && [ "$TESTHIDWIEGAND" = false ] && [ "$TESTMFHIDENCODE" = false ] && [ "$TESTICLASSEMU" = false ] && [ "$TESTICLASSREADER" = false ] && [ "$TESTSMARTCARD" = false ]; then +if [ "$TESTDESFIREVALUE" = false ] && [ "$TESTHIDWIEGAND" = false ] && [ "$TESTMFHIDENCODE" = false ] && [ "$TESTICLASSEMU" = false ] && [ "$TESTICLASSREADER" = false ] && [ "$TESTSMARTCARD" = false ] && [ "$TESTHITAG2" = false ]; then echo "Error: You must specify a test target. Use -h for help." exit 1 fi @@ -447,6 +471,50 @@ while true; do if ! CheckExecute "hf 15 uid sim resets emu state" "timeout 15 $PM3CMD -c 'hf 15 sim -u E011223344556677 -t 100; hf 15 eview' 2>&1 | LC_ALL=C tr -cd '\11\12\15\40-\176' | tr '\n' ' '" "UID.*E0 11 22 33 44 55 66 77.*4 bytes / blocks x 64 blocks"; then break; fi fi + # Hitag 2, against a genuine card and a genuine reader. + # + # The card is a password mode Hitag 2 (configuration byte 0x06). Its UID and + # password are read from the card itself rather than hardcoded, so the tests + # work with whatever fob is on the bench; only the ones that need a known + # password use HITAG2_KEY, which defaults to the Paxton fob this was developed + # against and can be overridden from the environment. + if $TESTHITAG2; then + echo -e "\n${C_BLUE}Testing Hitag 2 with a genuine card and reader${C_NC} ${PM3BIN:=./pm3}" + if ! CheckFileExist "pm3 exists" "$PM3BIN"; then break; fi + PM3CMD="$PM3BIN" + if [ -n "${PM3PORT:-}" ]; then + echo "Using PM3 port: $PM3PORT" + PM3CMD="$PM3CMD -p $PM3PORT" + fi + HITAG2_KEY="${HITAG2_KEY:-BDF5E846}" + + WaitForEnter "PLACE THE GENUINE HITAG 2 CARD ON THE PM3 LF ANTENNA" + + # Reading the card: identification, then a full password mode dump. The + # config byte has to come back as a Hitag 2 in password mode, and every one + # of the eight pages has to be present - a partial dump is the failure this + # is here to catch, since one lost frame used to end the read early. + if ! CheckExecute "lf hitag info genuine card" "$PM3CMD -c 'lf hitag info' 2>&1 | LC_ALL=C tr -cd '\11\12\15\40-\176' | tr '\n' ' '" "UID.*Password mode.*Hitag 2"; then break; fi + if ! CheckExecute "lf hitag read genuine card" "$PM3CMD -c 'lf hitag read -2 --pwd -k $HITAG2_KEY' 2>&1 | LC_ALL=C tr -cd '\11\12\15\40-\176' | tr '\n' ' '" "0/0x00.*1/0x01.*2/0x02.*3/0x03.*4/0x04.*5/0x05.*6/0x06.*7/0x07"; then break; fi + + # Writing: put a known value in page 4 and read it back. Page 4 is the + # first user page, so this does not touch the UID, the key or the config. + if ! CheckExecute "lf hitag wrbl genuine card" "$PM3CMD -c 'lf hitag wrbl -2 -k $HITAG2_KEY -p 4 -d 11223344' 2>&1" "Write \( ok \)"; then break; fi + if ! CheckExecute "lf hitag write readback" "$PM3CMD -c 'lf hitag read -2 --pwd -k $HITAG2_KEY' 2>&1 | LC_ALL=C tr -cd '\11\12\15\40-\176' | tr '\n' ' '" "4/0x04 \| 11 22 33 44"; then break; fi + + # Sniffing a genuine exchange. Both directions have to appear: the reader's + # START_AUTH and password, and the tag's answers. A capture with reader + # frames but no tag frames is the defect this catches - the tag side decoder + # used to fabricate rows with no card present and miss real ones. + WaitForEnter "PUT THE PM3 BETWEEN THE GENUINE CARD AND THE GENUINE READER, THEN PRESS ENTER. PRESS ENTER AGAIN IN THE CLIENT TO STOP THE SNIFF" + if ! CheckExecute "lf hitag sniff genuine pair" "$PM3CMD -c 'lf hitag sniff; lf hitag list' 2>&1 | LC_ALL=C tr -cd '\11\12\15\40-\176' | tr '\n' ' '" "Rdr.*START AUTH.*Tag.*32:"; then break; fi + + # Simulating to a genuine reader. Only the operator can confirm the reader + # actually accepted it, so this asks - the client cannot see the beep. + WaitForEnter "REMOVE THE CARD, PRESENT THE PM3 TO THE GENUINE READER. THE SIM RUNS FOR 20s - LISTEN FOR THE READER TO BEEP, THEN PRESS ENTER" + if ! CheckExecute "lf hitag sim to reader" "timeout 30 $PM3CMD -c 'lf hitag eload -f $HITAG2_DUMP -2; lf hitag sim -2' 2>&1 | LC_ALL=C tr -cd '\11\12\15\40-\176' | tr '\n' ' '" "Starting Hitag 2 simulation"; then break; fi + WaitForEnter "DID THE READER BEEP / ACCEPT THE SIMULATED CARD? PRESS ENTER IF YES, CTRL-C IF NO" + fi if $TESTICLASSREADER; then echo -e "\n${C_BLUE}Testing iCLASS reader verification${C_NC} ${PM3BIN:=./pm3}" if ! CheckFileExist "pm3 exists" "$PM3BIN"; then break; fi