mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2026-10-05 20:57:28 +00:00
ReaderHitag() and WriterHitag() double-replied on the abort path: when a new command arrives mid-loop, data_available() sets checked = -1 and breaks, then the out: block calls reply_ng(PM3_ESOFT) *and* falls through to a second reply_ng(PM3_SUCCESS/EFAILED) — two NG responses for one command. USB tolerates the stray frame, but over the BLE/FPC bridge the extra unsolicited response desyncs the pipeline and the device appears to stop responding until reconnect (reproducible with `lf hitag dump --pwd` on empty air, then any following command over BLE). Gate the final reply_ng behind an else so each command yields exactly one response on every path: abort -> PM3_ESOFT, otherwise -> PM3_SUCCESS/EFAILED. Signed-off-by: Niel Nielsen <nieldk@gmail.com>
4604 lines
199 KiB
C
4604 lines
199 KiB
C
//-----------------------------------------------------------------------------
|
|
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// See LICENSE.txt for the text of the license.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "hitag2.h"
|
|
#include "hitag2/hitag2_crypto.h"
|
|
#include "string.h"
|
|
#include "proxmark3_arm.h"
|
|
#include "cmd.h"
|
|
#include "BigBuf.h"
|
|
#include "fpga_loader.h"
|
|
#include "fpga_apis.h"
|
|
#include "ticks_apis.h"
|
|
#include "dbprint.h"
|
|
#include "util.h"
|
|
#include "lfadc.h"
|
|
#include "hitag_common.h"
|
|
#include "lfsampling.h"
|
|
#include "lfdemod.h"
|
|
#include "commonutil.h"
|
|
#include "appmain.h"
|
|
#include "protocols.h"
|
|
|
|
#define test_bit(data, i) (*(data + (i/8)) >> (7-(i % 8))) & 1
|
|
#define set_bit(data, i) *(data + (i/8)) |= (1 << (7-(i % 8)))
|
|
#define clear_bit(data, i) *(data + (i/8)) &= ~(1 << (7-(i % 8)))
|
|
#define flip_bit(data, i) *(data + (i/8)) ^= (1 << (7-(i % 8)))
|
|
|
|
// Successful crypto auth
|
|
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;
|
|
static bool bPwd;
|
|
static bool bSuccessful;
|
|
|
|
/*
|
|
Password Mode : 0x06 - 0000 0110
|
|
Crypto Mode : 0x0E - 0000 1110
|
|
Public Mode A : 0x02 - 0000 0010
|
|
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,
|
|
};
|
|
|
|
// 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,
|
|
WRITE_STATE_PROG
|
|
} writestate;
|
|
|
|
// ToDo: define a meaningful maximum size for auth_table. The bigger this is, the lower will be the available memory for traces.
|
|
// Historically it used to be FREE_BUFFER_SIZE, which was 2744.
|
|
#define AUTH_TABLE_LENGTH 2744
|
|
static uint8_t *auth_table;
|
|
static size_t auth_table_pos = 0;
|
|
static size_t auth_table_len = AUTH_TABLE_LENGTH;
|
|
|
|
static uint8_t password[4];
|
|
static uint8_t NrAr[8];
|
|
static uint8_t key[8];
|
|
static uint8_t writedata[4];
|
|
static uint8_t logdata_0[4], logdata_1[4];
|
|
static uint8_t nonce[4];
|
|
static uint8_t key_no;
|
|
static uint64_t cipher_state;
|
|
|
|
static int16_t blocknr;
|
|
static uint32_t byte_value = 0;
|
|
|
|
static void hitag2_reset(void) {
|
|
tag.state = TAG_STATE_RESET;
|
|
tag.crypto_active = 0;
|
|
}
|
|
|
|
static void hitag2_init(void) {
|
|
hitag2_reset();
|
|
}
|
|
|
|
// The input-capture timer (StartInputCapture, see common_arm/ticks) runs at
|
|
// TIMER_CLOCK3 = MCK/32 = 1.5 MHz. Hitag units (T0) have a duration of 8 us
|
|
// (1/125000 s, the carrier period), so T0 = 1.5 MHz / 125 kHz = 12 counter ticks.
|
|
#ifndef HITAG_T0
|
|
#define HITAG_T0 12
|
|
#endif
|
|
|
|
#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 */
|
|
#define HITAG_T_WAIT_MAX 300 /* bit more than HITAG_T_WAIT_1 + HITAG_T_WAIT_2 */
|
|
#define HITAG_T_PROG 614
|
|
#define HITAG_T_WAIT_POWERUP 313 /* transponder internal powerup time is 312.5 */
|
|
#define HITAG_T_WAIT_START_AUTH_MAX 232 /* transponder waiting time to receive the START_AUTH command is 232.5, then it enters public mode */
|
|
|
|
#define HITAG_T_TAG_ONE_HALF_PERIOD 10
|
|
#define HITAG_T_TAG_TWO_HALF_PERIOD 25
|
|
#define HITAG_T_TAG_THREE_HALF_PERIOD 41
|
|
#define HITAG_T_TAG_FOUR_HALF_PERIOD 57
|
|
|
|
#define HITAG_T_TAG_HALF_PERIOD 16
|
|
#define HITAG_T_TAG_FULL_PERIOD 32
|
|
|
|
#define HITAG_T_TAG_CAPTURE_ONE_HALF 13
|
|
#define HITAG_T_TAG_CAPTURE_TWO_HALF 25
|
|
#define HITAG_T_TAG_CAPTURE_THREE_HALF 41
|
|
#define HITAG_T_TAG_CAPTURE_FOUR_HALF 57
|
|
|
|
#define HT2_MAX_NRSZ ((8 * HITAG_FRAME_LEN + 5) * 2)
|
|
|
|
|
|
// sim
|
|
static void hitag2_handle_reader_command(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen) {
|
|
uint8_t rx_air[HITAG_FRAME_LEN];
|
|
|
|
// Copy the (original) received frame how it is send over the air
|
|
memcpy(rx_air, rx, nbytes(rxlen));
|
|
|
|
if (tag.crypto_active) {
|
|
ht2_hitag2_cipher_transcrypt(&(tag.cs), rx, rxlen / 8, rxlen % 8);
|
|
}
|
|
|
|
// 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
|
|
case 5: {
|
|
// Always send over the air in the clear plaintext mode
|
|
if (rx_air[0] != HITAG2_START_AUTH) {
|
|
// 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;
|
|
}
|
|
break;
|
|
|
|
// Read/Write command: ..xx x..y yy with yyy == ~xxx, xxx is sector number
|
|
case 10: {
|
|
uint16_t sector = (~(((rx[0] << 2) & 0x04) | ((rx[1] >> 6) & 0x03)) & 0x07);
|
|
|
|
// Verify complement of sector index
|
|
if (sector != ((rx[0] >> 3) & 0x07)) {
|
|
DBG DbpString("Transmission error (read/write)");
|
|
return;
|
|
}
|
|
|
|
switch (rx[0] & 0xC6) {
|
|
// Read command: 11xx x00y
|
|
case HITAG2_READ_PAGE: {
|
|
memcpy(tx, tag.sectors[sector], 4);
|
|
*txlen = 32;
|
|
break;
|
|
}
|
|
// Inverted Read command: 01xx x10y
|
|
case HITAG2_READ_PAGE_INVERTED: {
|
|
for (size_t i = 0; i < 4; i++) {
|
|
tx[i] = tag.sectors[sector][i] ^ 0xff;
|
|
}
|
|
*txlen = 32;
|
|
break;
|
|
}
|
|
// Write command: 10xx x01y
|
|
case HITAG2_WRITE_PAGE: {
|
|
// Prepare write, acknowledge by repeating command
|
|
memcpy(tx, rx, nbytes(rxlen));
|
|
*txlen = rxlen;
|
|
tag.active_sector = sector;
|
|
tag.state = TAG_STATE_WRITING;
|
|
break;
|
|
}
|
|
// Unknown command
|
|
default: {
|
|
DBG Dbprintf("Unknown command: %02x %02x", rx[0], rx[1]);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
// Writing data or Reader password
|
|
case 32: {
|
|
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.
|
|
//
|
|
// 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;
|
|
}
|
|
*txlen = 32;
|
|
memcpy(tx, tag.sectors[3], 4);
|
|
}
|
|
}
|
|
break;
|
|
|
|
// 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);
|
|
auth_table_len += 8;
|
|
}
|
|
|
|
// Reset the cipher state
|
|
ht2_hitag2_cipher_reset(&tag, rx);
|
|
|
|
// Check if the authentication was correct
|
|
if (!ht2_hitag2_cipher_authenticate(&(tag.cs), rx + 4)) {
|
|
// The reader failed to authenticate, do nothing
|
|
DBG Dbprintf("auth: %02x%02x%02x%02x%02x%02x%02x%02x Failed!", rx[0], rx[1], rx[2], rx[3], rx[4], rx[5], rx[6], rx[7]);
|
|
return;
|
|
}
|
|
// Activate encryption algorithm for all further communication
|
|
tag.crypto_active = 1;
|
|
|
|
// Use the tag password as response
|
|
memcpy(tx, tag.sectors[3], 4);
|
|
*txlen = 32;
|
|
}
|
|
break;
|
|
}
|
|
|
|
// LogTraceBits(rx, rxlen, 0, 0, false);
|
|
// LogTraceBits(tx, txlen, 0, 0, true);
|
|
|
|
if (tag.crypto_active) {
|
|
ht2_hitag2_cipher_transcrypt(&(tag.cs), tx, *txlen / 8, *txlen % 8);
|
|
}
|
|
}
|
|
|
|
// reader/writer
|
|
// returns how long it took
|
|
static uint32_t hitag2_reader_send_bit(int bit) {
|
|
// Binary pulse length modulation (BPLM) is used to encode the data stream
|
|
// This means that a transmission of a one takes longer than that of a zero
|
|
|
|
// Enable modulation, which means, drop the field
|
|
lf_modulation(true);
|
|
|
|
// Wait for 4-10 times the carrier period
|
|
lf_wait_periods(HITAG_T_LOW); // wait for 4-10 times the carrier period
|
|
uint32_t wait = HITAG_T_LOW;
|
|
|
|
// Disable modulation, just activates the field again
|
|
lf_modulation(false);
|
|
|
|
if (bit == 0) {
|
|
// Zero bit: |_-|
|
|
lf_wait_periods(HITAG_T_0 - HITAG_T_LOW); // wait for 18-22 times the carrier period
|
|
wait += HITAG_T_0 - HITAG_T_LOW;
|
|
} else {
|
|
// One bit: |_--|
|
|
lf_wait_periods(HITAG_T_1 - HITAG_T_LOW); // wait for 26-32 times the carrier period
|
|
wait += HITAG_T_1 - HITAG_T_LOW;
|
|
}
|
|
|
|
return wait;
|
|
}
|
|
|
|
// reader / writer commands
|
|
// frame_len is in number of bits?
|
|
static uint32_t hitag2_reader_send_frame(const uint8_t *frame, size_t frame_len) {
|
|
WDT_HIT();
|
|
|
|
uint32_t wait = 0;
|
|
// Send the content of the frame
|
|
for (size_t i = 0; i < frame_len; i++) {
|
|
wait += hitag2_reader_send_bit((frame[i / 8] >> (7 - (i % 8))) & 1);
|
|
}
|
|
|
|
// Send EOF
|
|
// Enable modulation, which means, drop the field
|
|
lf_modulation(true);
|
|
|
|
// Wait for 4-10 times the carrier period
|
|
lf_wait_periods(HITAG_T_LOW);
|
|
wait += HITAG_T_LOW;
|
|
|
|
// Disable modulation, just activates the field again
|
|
lf_modulation(false);
|
|
|
|
// t_stop, high field for stop condition (> 36)
|
|
lf_wait_periods(HITAG_T_STOP);
|
|
wait += HITAG_T_STOP;
|
|
WDT_HIT();
|
|
return wait;
|
|
}
|
|
|
|
// reader / writer commands
|
|
// frame_len is in number of bits?
|
|
static uint32_t hitag2_reader_send_framebits(const uint8_t *frame, size_t frame_len) {
|
|
|
|
WDT_HIT();
|
|
|
|
uint32_t wait = 0;
|
|
// Send the content of the frame
|
|
for (size_t i = 0; i < frame_len; i++) {
|
|
wait += hitag2_reader_send_bit(frame[i]);
|
|
}
|
|
|
|
// Send EOF
|
|
// Enable modulation, which means, drop the field
|
|
// set GPIO_SSC_DOUT to HIGH
|
|
lf_modulation(true);
|
|
|
|
// Wait for 4-10 times the carrier period
|
|
lf_wait_periods(HITAG_T_LOW);
|
|
wait += HITAG_T_LOW;
|
|
|
|
// Disable modulation, just activates the field again
|
|
// set GPIO_SSC_DOUT to LOW
|
|
lf_modulation(false);
|
|
|
|
// t_stop, high field for stop condition (> 36)
|
|
lf_wait_periods(HITAG_T_STOP);
|
|
wait += HITAG_T_STOP;
|
|
|
|
WDT_HIT();
|
|
return wait;
|
|
}
|
|
|
|
static uint8_t hitag_crc(uint8_t *data, size_t n) {
|
|
uint8_t crc = 0xFF;
|
|
for (size_t i = 0; i < ((n + 7) / 8); i++) {
|
|
crc ^= *(data + i);
|
|
uint8_t bit = n < (8 * (i + 1)) ? (n % 8) : 8;
|
|
while (bit--) {
|
|
if (crc & 0x80) {
|
|
crc <<= 1;
|
|
crc ^= 0x1D;
|
|
} else {
|
|
crc <<= 1;
|
|
}
|
|
}
|
|
}
|
|
return crc;
|
|
}
|
|
|
|
/*
|
|
void fix_ac_decoding(uint8_t *input, size_t len) {
|
|
// Reader routine tries to decode AC data after Manchester decoding
|
|
// AC has double the bitrate, extract data from bit-pairs
|
|
uint8_t temp[len / 16];
|
|
memset(temp, 0, sizeof(temp));
|
|
|
|
for (size_t i = 1; i < len; i += 2) {
|
|
if (test_bit(input, i) && test_bit(input, (i + 1))) {
|
|
set_bit(temp, (i / 2));
|
|
}
|
|
}
|
|
memcpy(input, temp, sizeof(temp));
|
|
}
|
|
*/
|
|
|
|
|
|
// looks at number of received bits.
|
|
// 0 = collision?
|
|
// 32 = good response
|
|
static bool hitag1_plain(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen, bool hitag_s) {
|
|
*txlen = 0;
|
|
switch (rxlen) {
|
|
case 0: {
|
|
// retry waking up card
|
|
/*tx[0] = 0xb0; // Rev 3.0*/
|
|
tx[0] = HITAG1_SET_CC; // Rev 2.0
|
|
*txlen = 5;
|
|
|
|
if (bCollision == false) {
|
|
blocknr--;
|
|
}
|
|
|
|
if (blocknr < 0) {
|
|
blocknr = 0;
|
|
}
|
|
|
|
if (hitag_s == false) {
|
|
if (blocknr > 1 && blocknr < 31) {
|
|
blocknr = 31;
|
|
}
|
|
}
|
|
bCollision = true;
|
|
return true;
|
|
}
|
|
case 32: {
|
|
uint8_t crc;
|
|
if (bCollision) {
|
|
// Select card by serial from response
|
|
tx[0] = HITAG1_SELECT | rx[0] >> 5;
|
|
tx[1] = rx[0] << 3 | rx[1] >> 5;
|
|
tx[2] = rx[1] << 3 | rx[2] >> 5;
|
|
tx[3] = rx[2] << 3 | rx[3] >> 5;
|
|
tx[4] = rx[3] << 3;
|
|
crc = hitag_crc(tx, 37);
|
|
tx[4] |= crc >> 5;
|
|
tx[5] = crc << 3;
|
|
*txlen = 45;
|
|
bCollision = false;
|
|
} else {
|
|
memcpy(tag.sectors[blocknr], rx, 4);
|
|
blocknr++;
|
|
|
|
if (hitag_s == false) {
|
|
if (blocknr > 1 && blocknr < 31) {
|
|
blocknr = 31;
|
|
}
|
|
}
|
|
|
|
if (blocknr > 63) {
|
|
DbpString("Read successful!");
|
|
*txlen = 0;
|
|
bSuccessful = true;
|
|
return false;
|
|
}
|
|
// read next page of card until done
|
|
Dbprintf("Reading page %02u", blocknr);
|
|
tx[0] = HITAG1_RDPPAGE | blocknr >> 4; // RDPPAGE
|
|
tx[1] = blocknr << 4;
|
|
crc = hitag_crc(tx, 12);
|
|
tx[1] |= crc >> 4;
|
|
tx[2] = crc << 4;
|
|
*txlen = 20;
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
Dbprintf("Unknown frame length: %d", rxlen);
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static bool hitag1_authenticate(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen) {
|
|
uint8_t crc;
|
|
*txlen = 0;
|
|
switch (rxlen) {
|
|
case 0: {
|
|
// retry waking up card
|
|
/*tx[0] = 0xb0; // Rev 3.0*/
|
|
tx[0] = HITAG1_SELECT; // Rev 2.0
|
|
*txlen = 5;
|
|
|
|
if (bCrypto && byte_value <= 0xff) {
|
|
// to retry
|
|
bCrypto = false;
|
|
}
|
|
|
|
if (bCollision == false) {
|
|
blocknr--;
|
|
}
|
|
|
|
if (blocknr < 0) {
|
|
blocknr = 0;
|
|
}
|
|
|
|
bCollision = true;
|
|
// will receive 32-bit UID
|
|
break;
|
|
}
|
|
case 2: {
|
|
if (bAuthenticating) {
|
|
// received Auth init ACK, send nonce
|
|
// TODO Roel, bit-manipulation goes here
|
|
/*nonce[0] = 0x2d;*/
|
|
/*nonce[1] = 0x74;*/
|
|
/*nonce[2] = 0x80;*/
|
|
/*nonce[3] = 0xa5;*/
|
|
nonce[0] = byte_value;
|
|
byte_value++;
|
|
/*set_bit(nonce,flipped_bit);*/
|
|
memcpy(tx, nonce, 4);
|
|
*txlen = 32;
|
|
// will receive 32 bit encrypted Logdata
|
|
} else if (bCrypto) {
|
|
// authed, start reading
|
|
tx[0] = HITAG1_RDCPAGE | blocknr >> 4; // RDCPAGE
|
|
tx[1] = blocknr << 4;
|
|
crc = hitag_crc(tx, 12);
|
|
tx[1] |= crc >> 4;
|
|
tx[2] = crc << 4;
|
|
*txlen = 20;
|
|
// will receive 32-bit encrypted page
|
|
}
|
|
break;
|
|
}
|
|
case 32: {
|
|
if (bCollision) {
|
|
// Select card by serial from response
|
|
tx[0] = HITAG1_SELECT | rx[0] >> 5;
|
|
tx[1] = rx[0] << 3 | rx[1] >> 5;
|
|
tx[2] = rx[1] << 3 | rx[2] >> 5;
|
|
tx[3] = rx[2] << 3 | rx[3] >> 5;
|
|
tx[4] = rx[3] << 3;
|
|
crc = hitag_crc(tx, 37);
|
|
tx[4] |= crc >> 5;
|
|
tx[5] = crc << 3;
|
|
*txlen = 45;
|
|
bCollision = false;
|
|
bSelecting = true;
|
|
// will receive 32-bit configuration page
|
|
} else if (bSelecting) {
|
|
// Initiate auth
|
|
tx[0] = HITAG1_WRCPAGE | (key_no); // WRCPAGE
|
|
tx[1] = blocknr << 4;
|
|
crc = hitag_crc(tx, 12);
|
|
tx[1] |= crc >> 4;
|
|
tx[2] = crc << 4;
|
|
*txlen = 20;
|
|
bSelecting = false;
|
|
bAuthenticating = true;
|
|
// will receive 2-bit ACK
|
|
} else if (bAuthenticating) {
|
|
// received 32-bit logdata 0
|
|
// TODO decrypt logdata 0, verify against logdata_0
|
|
memcpy(tag.sectors[0], rx, 4);
|
|
memcpy(tag.sectors[1], tx, 4);
|
|
Dbprintf("%02x%02x%02x%02x %02x%02x%02x%02x", rx[0], rx[1], rx[2], rx[3], tx[0], tx[1], tx[2], tx[3]);
|
|
// TODO replace with secret data stream
|
|
// TODO encrypt logdata_1
|
|
memcpy(tx, logdata_1, 4);
|
|
*txlen = 32;
|
|
bAuthenticating = false;
|
|
bCrypto = true;
|
|
// will receive 2-bit ACK
|
|
} else if (bCrypto) {
|
|
// received 32-bit encrypted page
|
|
// TODO decrypt rx
|
|
memcpy(tag.sectors[blocknr], rx, 4);
|
|
blocknr++;
|
|
if (blocknr > 63) {
|
|
DbpString("Read successful!");
|
|
bSuccessful = true;
|
|
return false;
|
|
}
|
|
|
|
// TEST
|
|
Dbprintf("Successfully authenticated with logdata:");
|
|
Dbhexdump(4, logdata_1, false);
|
|
bSuccessful = true;
|
|
return false;
|
|
/*
|
|
// read next page of card until done
|
|
tx[0] = HITAG1_RDCPAGE | blocknr >> 4; // RDCPAGE
|
|
tx[1] = blocknr << 4;
|
|
crc = hitag_crc(tx, 12);
|
|
tx[1] |= crc >> 4;
|
|
tx[2] = crc << 4;
|
|
*txlen = 20;
|
|
*/
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
Dbprintf("Unknown frame length: %d", rxlen);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Hitag 2 operations
|
|
//-----------------------------------------------------------------------------
|
|
|
|
static bool hitag2_write_page(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen) {
|
|
switch (writestate) {
|
|
case WRITE_STATE_START: {
|
|
*txlen = 10;
|
|
tx[0] = HITAG2_WRITE_PAGE | (blocknr << 3) | ((blocknr ^ 7) >> 2);
|
|
tx[1] = ((blocknr ^ 7) << 6);
|
|
writestate = WRITE_STATE_PAGENUM_WRITTEN;
|
|
break;
|
|
}
|
|
case WRITE_STATE_PAGENUM_WRITTEN: {
|
|
// Check if page number was received correctly
|
|
if ((rxlen == 10)
|
|
&& (rx[0] == (HITAG2_WRITE_PAGE | (blocknr << 3) | ((blocknr ^ 7) >> 2)))
|
|
&& (rx[1] == (((blocknr & 0x3) ^ 0x3) << 6))) {
|
|
|
|
*txlen = 32;
|
|
memset(tx, 0, HITAG_FRAME_LEN);
|
|
memcpy(tx, writedata, 4);
|
|
writestate = WRITE_STATE_PROG;
|
|
} else {
|
|
Dbprintf("hitag2_write_page: Page number was not received correctly: rxlen %d rx %02x%02x%02x%02x"
|
|
, rxlen
|
|
, rx[0], rx[1], rx[2], rx[3]
|
|
);
|
|
bSuccessful = false;
|
|
return false;
|
|
}
|
|
break;
|
|
}
|
|
case WRITE_STATE_PROG: {
|
|
if (rxlen == 0) {
|
|
bSuccessful = true;
|
|
} else {
|
|
bSuccessful = false;
|
|
Dbprintf("hitag2_write_page: unexpected rx data (%d) after page write", rxlen);
|
|
}
|
|
return false;
|
|
}
|
|
default: {
|
|
Dbprintf("hitag2_write_page: Unknown state " _RED_("%d"), writestate);
|
|
bSuccessful = false;
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static bool hitag2_password(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen, bool write) {
|
|
// Reset the transmission frame length
|
|
*txlen = 0;
|
|
|
|
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;
|
|
}
|
|
|
|
} else {
|
|
// Try to find out which command was send by selecting on length (in bits)
|
|
switch (rxlen) {
|
|
// No answer, try to resurrect
|
|
case 0: {
|
|
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;
|
|
}
|
|
*txlen = 5;
|
|
memcpy(tx, "\xC0", nbytes(*txlen));
|
|
break;
|
|
}
|
|
|
|
// Received UID, tag password
|
|
case 32: {
|
|
// stage 1, got UID
|
|
if (bPwd == false) {
|
|
bPwd = true;
|
|
bAuthenticating = true;
|
|
memcpy(tx, password, 4);
|
|
*txlen = 32;
|
|
} else {
|
|
// stage 2, got config byte+password TAG, discard as will read later
|
|
if (bAuthenticating) {
|
|
bAuthenticating = false;
|
|
|
|
if (write) {
|
|
|
|
if (!hitag2_write_page(rx, rxlen, tx, txlen)) {
|
|
return false;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
// stage 2+, got data block
|
|
else {
|
|
memcpy(tag.sectors[blocknr], rx, 4);
|
|
blocknr++;
|
|
pwd_retries = 0;
|
|
}
|
|
|
|
if (blocknr > 7) {
|
|
bSuccessful = true;
|
|
return false;
|
|
}
|
|
|
|
*txlen = 10;
|
|
tx[0] = HITAG2_READ_PAGE | (blocknr << 3) | ((blocknr ^ 7) >> 2);
|
|
tx[1] = ((blocknr ^ 7) << 6);
|
|
}
|
|
break;
|
|
}
|
|
// Unexpected response
|
|
default: {
|
|
DBG Dbprintf("Unknown frame length: " _RED_("%d"), rxlen);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool hitag2_crypto(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen, bool write) {
|
|
// Reset the transmission frame length
|
|
*txlen = 0;
|
|
|
|
if (bCrypto) {
|
|
ht2_hitag2_cipher_transcrypt(&cipher_state, rx, rxlen / 8, rxlen % 8);
|
|
}
|
|
|
|
if (bCrypto && (bAuthenticating == false) && write) {
|
|
|
|
SpinDelay(2);
|
|
if (hitag2_write_page(rx, rxlen, tx, txlen) == false) {
|
|
return false;
|
|
}
|
|
|
|
} else {
|
|
|
|
// Try to find out which command was send by selecting on length (in bits)
|
|
switch (rxlen) {
|
|
// No answer, try to resurrect
|
|
case 0: {
|
|
// Stop if there is no answer while we are in crypto mode (after sending NrAr)
|
|
if (bCrypto) {
|
|
// Failed during authentication
|
|
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);
|
|
} else if (blocknr == 2) {
|
|
// Write the high part of the key in memory
|
|
tag.sectors[2][0] = 0x00;
|
|
tag.sectors[2][1] = 0x00;
|
|
tag.sectors[2][2] = key[0];
|
|
tag.sectors[2][3] = key[1];
|
|
} else {
|
|
// Just put zero's in the memory (of the unreadable block)
|
|
memset(tag.sectors[blocknr], 0x00, 4);
|
|
}
|
|
blocknr++;
|
|
bCrypto = false;
|
|
}
|
|
} else {
|
|
*txlen = 5;
|
|
memcpy(tx, "\xc0", nbytes(*txlen));
|
|
}
|
|
break;
|
|
}
|
|
// Received UID, crypto tag answer
|
|
case 32: {
|
|
// stage 1, got UID
|
|
if (bCrypto == false) {
|
|
|
|
uint64_t ui64key = key[0] |
|
|
((uint64_t)key[1]) << 8 |
|
|
((uint64_t)key[2]) << 16 |
|
|
((uint64_t)key[3]) << 24 |
|
|
((uint64_t)key[4]) << 32 |
|
|
((uint64_t)key[5]) << 40;
|
|
|
|
uint32_t ui32uid = MemLeToUint4byte(rx);
|
|
|
|
DBG Dbprintf("hitag2_crypto: key array ");
|
|
DBG Dbhexdump(6, key, false);
|
|
DBG Dbprintf("hitag2_crypto: key=0x%x%x uid=0x%x"
|
|
, (uint32_t)((REV64(ui64key)) >> 32)
|
|
, (uint32_t)((REV64(ui64key)) & 0xffffffff)
|
|
, REV32(ui32uid)
|
|
);
|
|
|
|
cipher_state = ht2_hitag2_init(REV64(ui64key), REV32(ui32uid), 0);
|
|
|
|
// PRN 00 00 00 00
|
|
memset(tx, 0x00, 4);
|
|
// Secret data FF FF FF FF
|
|
memset(tx + 4, 0xff, 4);
|
|
ht2_hitag2_cipher_transcrypt(&cipher_state, tx + 4, 4, 0);
|
|
*txlen = 64;
|
|
bCrypto = true;
|
|
bAuthenticating = true;
|
|
} else {
|
|
|
|
// stage 2, got config byte+password TAG, discard as will read later
|
|
if (bAuthenticating) {
|
|
|
|
bAuthenticating = false;
|
|
|
|
if (write) {
|
|
if (hitag2_write_page(rx, rxlen, tx, txlen) == false) {
|
|
return false;
|
|
}
|
|
break;
|
|
}
|
|
|
|
} else { // stage 2+, got data block
|
|
|
|
// Store the received block
|
|
memcpy(tag.sectors[blocknr], rx, 4);
|
|
blocknr++;
|
|
crypto_retries = 0;
|
|
}
|
|
|
|
if (blocknr > 7) {
|
|
DBG DbpString("Read successful!");
|
|
bSuccessful = true;
|
|
return false;
|
|
} else {
|
|
*txlen = 10;
|
|
tx[0] = HITAG2_READ_PAGE | (blocknr << 3) | ((blocknr ^ 7) >> 2);
|
|
tx[1] = ((blocknr ^ 7) << 6);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
DBG Dbprintf("Unknown frame length: " _RED_("%d"), rxlen);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// try to avoid double encryption calls
|
|
if (bCrypto && bAuthenticating == false) {
|
|
ht2_hitag2_cipher_transcrypt(&cipher_state, tx, *txlen / 8, *txlen % 8);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool hitag2_authenticate(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen, bool write) {
|
|
// Reset the transmission frame length
|
|
*txlen = 0;
|
|
|
|
// Try to find out which command was send by selecting on length (in bits)
|
|
switch (rxlen) {
|
|
case 0: {
|
|
// No answer, try to resurrect
|
|
// Stop if there is no answer while we are in crypto mode (after sending NrAr)
|
|
if (bCrypto) {
|
|
DBG DbpString("No answer after sending NrAr!");
|
|
return false;
|
|
} else {
|
|
|
|
// Failed during authentication
|
|
if (bAuthenticating) {
|
|
DBG DbpString("Authentication - failed!");
|
|
return false;
|
|
}
|
|
|
|
DBG DbpString("Authenticating - send 0xC0");
|
|
*txlen = 5;
|
|
memcpy(tx, "\xC0", nbytes(*txlen));
|
|
}
|
|
break;
|
|
}
|
|
case 32: {
|
|
// Received UID or crypto tag answer
|
|
if (bCrypto == false) {
|
|
*txlen = 64;
|
|
memcpy(tx, NrAr, sizeof(NrAr));
|
|
bCrypto = true;
|
|
bAuthenticating = true;
|
|
DBG DbpString("Authenticating sending NrAr");
|
|
} else {
|
|
DBG DbpString("Authentication successful!");
|
|
|
|
// stage 2, got config byte+password TAG, discard as will read later
|
|
if (bAuthenticating) {
|
|
|
|
bAuthenticating = false;
|
|
|
|
if (write) {
|
|
if (hitag2_write_page(rx, rxlen, tx, txlen) == false) {
|
|
return false;
|
|
}
|
|
break;
|
|
}
|
|
|
|
} else { // stage 2+, got data block
|
|
|
|
// Store the received block
|
|
memcpy(tag.sectors[blocknr], rx, 4);
|
|
blocknr++;
|
|
}
|
|
|
|
if (blocknr > 7) {
|
|
DBG DbpString("Read successful!");
|
|
bSuccessful = true;
|
|
return false;
|
|
} else {
|
|
|
|
DBG Dbprintf("Sending read block %u", blocknr);
|
|
|
|
*txlen = 10;
|
|
tx[0] = HITAG2_READ_PAGE | (blocknr << 3) | ((blocknr ^ 7) >> 2);
|
|
tx[1] = ((blocknr ^ 7) << 6);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
DBG Dbprintf("Unknown frame length: " _RED_("%d"), rxlen);
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static bool hitag2_test_auth_attempts(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen) {
|
|
|
|
// Reset the transmission frame length
|
|
*txlen = 0;
|
|
|
|
// Try to find out which command was send by selecting on length (in bits)
|
|
switch (rxlen) {
|
|
// No answer, try to resurrect
|
|
case 0: {
|
|
// Stop if there is no answer while we are in crypto mode (after sending NrAr)
|
|
if (bCrypto) {
|
|
Dbprintf("auth: %02x%02x%02x%02x%02x%02x%02x%02x Failed, removed entry!", NrAr[0], NrAr[1], NrAr[2], NrAr[3], NrAr[4], NrAr[5], NrAr[6], NrAr[7]);
|
|
|
|
// Removing failed entry from authentications table
|
|
memcpy(auth_table + auth_table_pos, auth_table + auth_table_pos + 8, 8);
|
|
auth_table_len -= 8;
|
|
|
|
// Return if we reached the end of the authentications table
|
|
bCrypto = false;
|
|
if (auth_table_pos == auth_table_len) {
|
|
return false;
|
|
}
|
|
|
|
// Copy the next authentication attempt in row (at the same position, b/c we removed last failed entry)
|
|
memcpy(NrAr, auth_table + auth_table_pos, 8);
|
|
}
|
|
*txlen = 5;
|
|
memcpy(tx, "\xc0", nbytes(*txlen));
|
|
break;
|
|
}
|
|
// Received UID, crypto tag answer, or read block response
|
|
case 32: {
|
|
if (bCrypto == false) {
|
|
*txlen = 64;
|
|
memcpy(tx, NrAr, 8);
|
|
bCrypto = true;
|
|
} else {
|
|
Dbprintf("auth: %02x%02x%02x%02x%02x%02x%02x%02x ( " _GREEN_("ok") " )", NrAr[0], NrAr[1], NrAr[2], NrAr[3], NrAr[4], NrAr[5], NrAr[6], NrAr[7]);
|
|
bCrypto = false;
|
|
if ((auth_table_pos + 8) == auth_table_len) {
|
|
return false;
|
|
}
|
|
auth_table_pos += 8;
|
|
memcpy(NrAr, auth_table + auth_table_pos, 8);
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
Dbprintf("Unknown frame length: " _RED_("%d"), rxlen);
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Hitag 2 Sniffing
|
|
void hitag_sniff(void) {
|
|
|
|
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
|
|
|
|
BigBuf_free();
|
|
BigBuf_Clear_ext(false);
|
|
set_tracing(true);
|
|
|
|
// Set up eavesdropping mode, frequency divisor which will drive the FPGA
|
|
// and analog mux selection.
|
|
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_TOGGLE_MODE);
|
|
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_125); // 125Khz
|
|
SetAdcMuxFor(ADC_MUXSEL_LOPKD);
|
|
}
|
|
|
|
|
|
// T0 18-22 fc (total time ZERO)
|
|
// T1 26-32 fc (total time ONE)
|
|
// Tstop 36 > fc (high field stop limit)
|
|
// Tlow 4-10 fc (reader field low time)
|
|
// 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);
|
|
|
|
// 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);
|
|
|
|
/*
|
|
lf_init(LF_ADC_SNIFF, LF_ADC_WAV_REVERSED, ledcontrol);
|
|
|
|
// no logging of the raw signal
|
|
g_logging = true;
|
|
uint32_t total_count = 0;
|
|
|
|
uint8_t rx[HITAG_FRAME_BIT_COUNT * 2];
|
|
|
|
while (BUTTON_PRESS() == false) {
|
|
|
|
lf_reset_counter();
|
|
|
|
WDT_HIT();
|
|
|
|
size_t periods = 0;
|
|
uint16_t rxlen = 0;
|
|
memset(rx, 0x00, sizeof(rx));
|
|
|
|
// Use the current modulation state as starting point
|
|
uint8_t mod_state = lf_get_reader_modulation();
|
|
|
|
while (rxlen < sizeof(rx)) {
|
|
periods = lf_count_edge_periods(64);
|
|
// 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 __|)
|
|
rx[rxlen++] = mod_state;
|
|
if (rxlen < sizeof(rx)) {
|
|
rx[rxlen++] = mod_state;
|
|
}
|
|
// toggle tag modulation state
|
|
mod_state ^= 1;
|
|
|
|
} else if (periods > 0 && periods < 24) {
|
|
// Detected one bit and a modulation switch
|
|
// NRZ modulation: (1 => -|) or (0 _|)
|
|
rx[rxlen++] = mod_state;
|
|
mod_state ^= 1;
|
|
} else {
|
|
mod_state ^= 1;
|
|
// The function lf_count_edge_periods() returns > 64 periods, this is not a valid number periods
|
|
Dbprintf("Detected unexpected period count... " _YELLOW_("%zu"), periods);
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
if (rxlen < 10) {
|
|
continue;
|
|
}
|
|
|
|
// tag sends 11111 + uid,
|
|
bool got_tag = (memcmp(rx, "\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00", 10) == 0);
|
|
|
|
Dbprintf("periods... %zu rxlen... %u", periods, rxlen);
|
|
Dbhexdump(rxlen, rx, false);
|
|
|
|
if (got_tag) {
|
|
|
|
bool bad_man = false;
|
|
uint16_t bitnum = 0;
|
|
// mqnchester decode
|
|
for (uint16_t i = 0; i < rxlen; i += 2) {
|
|
|
|
if (rx[i] == 1 && (rx[i + 1] == 0)) {
|
|
rx[bitnum++] = 0;
|
|
} else if ((rx[i] == 0) && rx[i + 1] == 1) {
|
|
rx[bitnum++] = 1;
|
|
} else {
|
|
bad_man = true;
|
|
break;
|
|
}
|
|
}
|
|
// Dbprintf(_YELLOW_("TAG") " rxlen... %u bitnum... %u", rxlen, bitnum);
|
|
if (bad_man) {
|
|
Dbprintf("bad manchester ( bitnum %u )", bitnum);
|
|
continue;;
|
|
}
|
|
|
|
if (bitnum < 5) {
|
|
DbpString("too few bits");
|
|
continue;
|
|
}
|
|
|
|
// Pack the response into a byte array,
|
|
// and skip header 11111 (start at idx 5)
|
|
rxlen = 0;
|
|
|
|
for (uint16_t i = 5; i < bitnum; i++) {
|
|
uint8_t b = rx[i];
|
|
rx[rxlen >> 3] |= b << (7 - (rxlen % 8));
|
|
rxlen++;
|
|
}
|
|
|
|
// skip spurious bit
|
|
if (rxlen % 8 == 1) {
|
|
rxlen--;
|
|
}
|
|
|
|
// nothing to log
|
|
if (rxlen == 0) {
|
|
if (ledcontrol) LED_A_INV();
|
|
continue;
|
|
}
|
|
|
|
LogTraceBits(rx, rxlen, 0, periods, false);
|
|
total_count += nbytes(rxlen);
|
|
|
|
} else {
|
|
|
|
// nothing to log
|
|
if (rxlen < 3) {
|
|
if (ledcontrol) LED_A_INV();
|
|
continue;
|
|
}
|
|
|
|
uint16_t n = 0;
|
|
for (uint16_t i = 0; i < rxlen; i++) {
|
|
uint8_t b = rx[i];
|
|
rx[n >> 3] |= b << (7 - (n % 8));
|
|
n++;
|
|
}
|
|
|
|
// decode reader comms
|
|
LogTraceBits(rx, n, 0, periods, true);
|
|
total_count += nbytes(n);
|
|
}
|
|
if (ledcontrol) LED_A_INV();
|
|
}
|
|
|
|
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();
|
|
|
|
// 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();
|
|
|
|
// 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
|
|
uint8_t rx[HITAG_FRAME_LEN + 1] = {0};
|
|
size_t rxlen = 0;
|
|
|
|
auth_table_len = 0;
|
|
auth_table_pos = 0;
|
|
|
|
auth_table = (uint8_t *)BigBuf_calloc(AUTH_TABLE_LENGTH);
|
|
|
|
// Only for debug, if we want to see the edge timing of the captured frames
|
|
uint8_t edges[100];
|
|
uint8_t e_count = 0;
|
|
|
|
// 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.
|
|
//
|
|
// 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();
|
|
|
|
// Rising edge: RA holds the falling->rising sub-period (the reader's tlow).
|
|
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) {
|
|
// Switch from tag to reader capture
|
|
if (ledcontrol) LED_C_OFF();
|
|
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 (frame_start == 0) {
|
|
frame_start = TIMESTAMP;
|
|
}
|
|
|
|
if (ledcontrol) {
|
|
if (reader_frame) LED_B_ON();
|
|
else LED_C_ON();
|
|
}
|
|
|
|
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.
|
|
//
|
|
// 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, frame_start, TIMESTAMP, reader_frame);
|
|
|
|
// 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 ((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
|
|
//
|
|
// 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++;
|
|
}
|
|
}
|
|
|
|
if (ledcontrol) {
|
|
LED_B_OFF();
|
|
LED_C_OFF();
|
|
}
|
|
|
|
// 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);
|
|
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_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(uint8_t threshold, uint16_t twait, uint8_t flags, uint8_t sof, uint8_t duty, bool ledcontrol) {
|
|
|
|
hitag_tag_set_mod_polarity((flags & 1) != 0);
|
|
hitag_tag_set_mod_duty(duty);
|
|
s_no_alternation = ((flags & 2) != 0);
|
|
s_alt_phase = false;
|
|
|
|
// 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 <pm3 - paxton>, 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 <pm3 - pm3>, 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();
|
|
|
|
uint8_t rx[HITAG_FRAME_LEN] = {0};
|
|
uint8_t tx[HITAG_FRAME_LEN] = {0};
|
|
|
|
auth_table_len = 0;
|
|
auth_table_pos = 0;
|
|
// auth_table = BigBuf_calloc(AUTH_TABLE_LENGTH);
|
|
|
|
DbpString("Starting Hitag 2 simulation");
|
|
|
|
// 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;
|
|
// 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++) {
|
|
block <<= 8;
|
|
block |= tag.sectors[i][j];
|
|
}
|
|
Dbprintf("| %d | %08x |", i, block);
|
|
}
|
|
|
|
// SIMULATE
|
|
//
|
|
// 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;
|
|
|
|
// 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);
|
|
DBG 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;
|
|
DBG Dbprintf("Edge detect threshold auto-tuned to %u", tuned);
|
|
}
|
|
|
|
// 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_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.
|
|
DBG 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);
|
|
}
|
|
|
|
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);
|
|
|
|
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;
|
|
|
|
d_loops++;
|
|
WDT_HIT();
|
|
|
|
// 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;
|
|
}
|
|
|
|
|
|
|
|
// 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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
} else {
|
|
// 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];
|
|
}
|
|
if (threshold == 0) {
|
|
FpgaSendCommand(FPGA_CMD_SET_EDGE_DETECT_THRESHOLD, active_threshold);
|
|
}
|
|
post_hold:
|
|
;
|
|
}
|
|
|
|
// 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;
|
|
|
|
// 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 (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++;
|
|
}
|
|
}
|
|
|
|
if (tx_pending) {
|
|
LogTraceBits(tx_pending_buf, tx_pending_len, tx_pending_start, tx_pending_end, false);
|
|
tx_pending = false;
|
|
}
|
|
|
|
// 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, 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)
|
|
// 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)) {
|
|
|
|
const uint32_t meas_t0 = TIMESTAMP;
|
|
|
|
// 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.
|
|
|
|
// 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 <pm3 - paxton> 112, 168..196 (14 samples), one 216
|
|
// rig B <pm3 - pm3> 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);
|
|
}
|
|
|
|
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();
|
|
}
|
|
|
|
memset(rx, 0x00, sizeof(rx));
|
|
|
|
if (ledcontrol) LED_B_OFF();
|
|
}
|
|
|
|
// Carry the timer overflow, it is 0 whenever a frame was received
|
|
overflow += (GetLoEdgeCaptureCount() / T0);
|
|
ResetLoEdgeCapture();
|
|
}
|
|
|
|
DBG Dbprintf("LISTEN blocks=%u adc_valid=%u flags=%u", d_listen5, s_adc_valid, flags);
|
|
|
|
if (s_adc_valid) {
|
|
DBG 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]);
|
|
}
|
|
}
|
|
|
|
DBG 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_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;
|
|
|
|
uint8_t rx[HITAG_FRAME_LEN] = {0};
|
|
size_t rxlen = 0;
|
|
uint8_t txbuf[HITAG_FRAME_LEN] = {0};
|
|
uint8_t *tx = txbuf;
|
|
size_t txlen = 0;
|
|
|
|
int t_wait_1 = 204;
|
|
int t_wait_1_guard = 8;
|
|
int t_wait_2 = 128;
|
|
size_t tag_size = 48;
|
|
bool bStop = false;
|
|
|
|
|
|
// Reset the return status
|
|
bSuccessful = false;
|
|
bCrypto = false;
|
|
|
|
// Clean up trace and prepare it for storing frames
|
|
set_tracing(true);
|
|
clear_trace();
|
|
|
|
// Check configuration
|
|
switch (payload->cmd) {
|
|
case HT1F_PLAIN: {
|
|
DBG Dbprintf("Read public blocks in plain mode");
|
|
// this part will be unreadable
|
|
memset(tag.sectors + 2, 0x0, 30);
|
|
blocknr = 0;
|
|
break;
|
|
}
|
|
case HT1F_AUTHENTICATE: {
|
|
DBG Dbprintf("Read all blocks in authed mode");
|
|
|
|
memcpy(nonce, payload->nonce, 4);
|
|
memcpy(key, payload->key, 4);
|
|
memcpy(logdata_0, payload->logdata_0, 4);
|
|
memcpy(logdata_1, payload->logdata_1, 4);
|
|
|
|
// TEST
|
|
memset(nonce, 0x0, 4);
|
|
memset(logdata_1, 0x00, 4);
|
|
|
|
byte_value = 0;
|
|
key_no = payload->key_no;
|
|
|
|
DBG Dbprintf("Authenticating using key #%u :", key_no);
|
|
DBG Dbhexdump(4, key, false);
|
|
DBG DbpString("Nonce:");
|
|
DBG Dbhexdump(4, nonce, false);
|
|
DBG DbpString("Logdata_0:");
|
|
DBG Dbhexdump(4, logdata_0, false);
|
|
DBG DbpString("Logdata_1:");
|
|
DBG Dbhexdump(4, logdata_1, false);
|
|
blocknr = 0;
|
|
break;
|
|
}
|
|
case HT2F_PASSWORD: {
|
|
DBG Dbprintf("List identifier in password mode");
|
|
if (memcmp(payload->pwd, "\x00\x00\x00\x00", 4) == 0) {
|
|
memcpy(password, tag.sectors[1], sizeof(password));
|
|
} else {
|
|
memcpy(password, payload->pwd, sizeof(password));
|
|
}
|
|
blocknr = 0;
|
|
bPwd = false;
|
|
bAuthenticating = false;
|
|
pwd_retries = 0;
|
|
crypto_retries = 0;
|
|
break;
|
|
}
|
|
case HT2F_AUTHENTICATE: {
|
|
DBG DbpString("Authenticating using NrAr pair:");
|
|
memcpy(NrAr, payload->NrAr, 8);
|
|
DBG Dbhexdump(8, NrAr, false);
|
|
// We can't read block 0, 1, 2..
|
|
blocknr = 3;
|
|
bCrypto = false;
|
|
bPwd = false;
|
|
bAuthenticating = false;
|
|
break;
|
|
}
|
|
case HT2F_CRYPTO: {
|
|
DBG DbpString("Authenticating using key:");
|
|
memcpy(key, payload->key, 6); //HACK; 4 or 6?? I read both in the code.
|
|
DBG Dbhexdump(6, key, false);
|
|
DBG DbpString("Nonce:");
|
|
DBG Dbhexdump(4, nonce, false);
|
|
memcpy(nonce, payload->data, 4);
|
|
blocknr = 0;
|
|
bCrypto = false;
|
|
bAuthenticating = false;
|
|
crypto_retries = 0;
|
|
break;
|
|
}
|
|
case HT2F_TEST_AUTH_ATTEMPTS: {
|
|
DBG Dbprintf("Testing " _YELLOW_("%d") " authentication attempts", (auth_table_len / 8));
|
|
auth_table_pos = 0;
|
|
memcpy(NrAr, auth_table, 8);
|
|
bCrypto = false;
|
|
break;
|
|
}
|
|
default: {
|
|
DBG Dbprintf("Error, unknown function: " _RED_("%d"), payload->cmd);
|
|
set_tracing(false);
|
|
reply_ng(CMD_LF_HITAG_READER, PM3_ESOFT, NULL, 0);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (ledcontrol) LED_D_ON();
|
|
|
|
// hitag 2 state machine?
|
|
hitag2_init();
|
|
|
|
// Tag specific configuration settings (sof, timings, etc.)
|
|
// TODO HTS
|
|
/* if (payload->cmd <= HTS_LAST_CMD) {
|
|
// hitag S settings
|
|
t_wait_1 = 204;
|
|
t_wait_2 = 128;
|
|
flipped_bit = 0;
|
|
tag_size = 8;
|
|
DBG DbpString("Configured for " _YELLOW_("Hitag S") " reader");
|
|
} else */
|
|
if (payload->cmd <= HT1_LAST_CMD) {
|
|
// hitag 1 settings
|
|
t_wait_1 = 204;
|
|
t_wait_2 = 128;
|
|
tag_size = 256;
|
|
DBG DbpString("Configured for " _YELLOW_("Hitag 1") " reader");
|
|
} else if (payload->cmd <= HT2_LAST_CMD) {
|
|
// hitag 2 settings
|
|
t_wait_1 = HITAG_T_WAIT_1_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);
|
|
|
|
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;
|
|
size_t nrzs = 0;
|
|
int16_t checked = 0;
|
|
uint32_t signal_size = 10000;
|
|
|
|
while (bStop == false && BUTTON_PRESS() == false) {
|
|
|
|
// use malloc
|
|
initSampleBufferEx(&signal_size, true);
|
|
|
|
WDT_HIT();
|
|
|
|
// 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;
|
|
}
|
|
|
|
// By default reset the transmission buffer
|
|
tx = txbuf;
|
|
switch (payload->cmd) {
|
|
case HT1F_PLAIN: {
|
|
bStop = !hitag1_plain(rx, rxlen, tx, &txlen, false);
|
|
break;
|
|
}
|
|
case HT1F_AUTHENTICATE: {
|
|
bStop = !hitag1_authenticate(rx, rxlen, tx, &txlen);
|
|
break;
|
|
}
|
|
case HT2F_PASSWORD: {
|
|
bStop = !hitag2_password(rx, rxlen, tx, &txlen, false);
|
|
break;
|
|
}
|
|
case HT2F_AUTHENTICATE: {
|
|
bStop = !hitag2_authenticate(rx, rxlen, tx, &txlen, false);
|
|
break;
|
|
}
|
|
case HT2F_CRYPTO: {
|
|
bStop = !hitag2_crypto(rx, rxlen, tx, &txlen, false);
|
|
break;
|
|
}
|
|
case HT2F_TEST_AUTH_ATTEMPTS: {
|
|
bStop = !hitag2_test_auth_attempts(rx, rxlen, tx, &txlen);
|
|
break;
|
|
}
|
|
default: {
|
|
DBG Dbprintf("Error, unknown function: " _RED_("%d"), payload->cmd);
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
if (bStop) {
|
|
break;
|
|
}
|
|
|
|
if (turn_on) {
|
|
// Wait 50ms with field off to be sure the transponder gets reset
|
|
SpinDelay(50);
|
|
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);
|
|
turn_on = false;
|
|
// Wait with field on to be in "Wait for START_AUTH" timeframe
|
|
lf_wait_periods(HITAG_T_WAIT_POWERUP + HITAG_T_WAIT_START_AUTH_MAX / 4);
|
|
command_start += HITAG_T_WAIT_POWERUP + HITAG_T_WAIT_START_AUTH_MAX / 4;
|
|
} else {
|
|
// Wait for t_wait_2 carrier periods after the last tag bit before transmitting,
|
|
lf_wait_periods(t_wait_2);
|
|
command_start += t_wait_2;
|
|
}
|
|
|
|
// Transmit the reader frame
|
|
command_duration = hitag2_reader_send_frame(tx, txlen);
|
|
response_start = command_start + command_duration;
|
|
|
|
// Let the antenna and ADC values settle
|
|
// 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;
|
|
|
|
// 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;
|
|
}
|
|
|
|
ht2_normalise_head((uint8_t *)nrz_samples, &nrzs);
|
|
|
|
|
|
// 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.
|
|
|
|
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) {
|
|
DBG 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]);
|
|
}
|
|
}
|
|
// 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;
|
|
}
|
|
|
|
|
|
// 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);
|
|
|
|
// 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?
|
|
// 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);
|
|
|
|
StopTimestamp();
|
|
lf_finalize(ledcontrol);
|
|
|
|
// release allocated memory from BigBuff.
|
|
BigBuf_free();
|
|
|
|
// Exactly one NG response per command. On the abort path (checked == -1,
|
|
// a new command arrived while the reader loop was still running) send only
|
|
// the abort reply - falling through to a second reply_ng left the transport
|
|
// with a stray unsolicited frame, which the higher-latency BLE/FPC bridge
|
|
// desyncs on (USB tolerates it).
|
|
if (checked == -1) {
|
|
reply_ng(CMD_LF_HITAG_READER, PM3_ESOFT, NULL, 0);
|
|
} else {
|
|
reply_ng(CMD_LF_HITAG_READER
|
|
, (bSuccessful) ? PM3_SUCCESS : PM3_EFAILED
|
|
, (uint8_t *)tag.sectors
|
|
, tag_size
|
|
);
|
|
}
|
|
|
|
}
|
|
|
|
void WriterHitag(const lf_hitag_data_t *payload, bool ledcontrol) {
|
|
// 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] = {0};
|
|
size_t rxlen = 0;
|
|
|
|
uint8_t txbuf[HITAG_FRAME_LEN];
|
|
uint8_t *tx = txbuf;
|
|
size_t txlen = 0;
|
|
|
|
int t_wait_1 = 204;
|
|
int t_wait_1_guard = 8;
|
|
int t_wait_2 = 128;
|
|
size_t tag_size = 48;
|
|
|
|
bool bStop = false;
|
|
|
|
// Raw demodulation/decoding by sampling edge periods
|
|
|
|
// iceman: Hitag2 is filled with static global vars.
|
|
// these following are globals status indicator :-|
|
|
// Reset the return status
|
|
bSuccessful = false;
|
|
|
|
writestate = WRITE_STATE_START;
|
|
blocknr = 0;
|
|
|
|
// Clean up trace and prepare it for storing frames
|
|
set_tracing(true);
|
|
clear_trace();
|
|
|
|
// Check configuration
|
|
switch (payload->cmd) {
|
|
case HT2F_CRYPTO: {
|
|
DBG DbpString("Authenticating using key:");
|
|
memcpy(key, payload->key, 6); //HACK; 4 or 6?? I read both in the code.
|
|
memcpy(writedata, payload->data, 4);
|
|
Dbhexdump(6, key, false);
|
|
blocknr = payload->page;
|
|
bCrypto = false;
|
|
bAuthenticating = false;
|
|
break;
|
|
}
|
|
case HT2F_PASSWORD: {
|
|
DBG DbpString("Authenticating using password:");
|
|
if (memcmp(payload->pwd, "\x00\x00\x00\x00", 4) == 0) {
|
|
memcpy(password, tag.sectors[1], sizeof(password));
|
|
} else {
|
|
memcpy(password, payload->pwd, sizeof(password));
|
|
}
|
|
memcpy(writedata, payload->data, 4);
|
|
DBG Dbhexdump(4, password, false);
|
|
blocknr = payload->page;
|
|
bPwd = false;
|
|
bAuthenticating = false;
|
|
break;
|
|
}
|
|
default: {
|
|
DBG Dbprintf("Error, unknown function: " _RED_("%d"), payload->cmd);
|
|
reply_ng(CMD_LF_HITAG2_WRITE, PM3_ESOFT, NULL, 0);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (ledcontrol) LED_D_ON();
|
|
|
|
hitag2_init();
|
|
|
|
// 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.)
|
|
// TODO HTS
|
|
/* if (payload->cmd <= HTS_LAST_CMD) {
|
|
// hitag S settings
|
|
t_wait_1 = 204;
|
|
t_wait_2 = 128;
|
|
//tag_size = 256;
|
|
flipped_bit = 0;
|
|
tag_size = 8;
|
|
DBG DbpString("Configured for " _YELLOW_("Hitag S") " writer");
|
|
} else
|
|
*/
|
|
if (payload->cmd <= HT1_LAST_CMD) {
|
|
// hitag 1 settings
|
|
t_wait_1 = 204;
|
|
t_wait_2 = 128;
|
|
tag_size = 256;
|
|
DBG DbpString("Configured for " _YELLOW_("Hitag 1") " writer");
|
|
} else if (payload->cmd <= HT2_LAST_CMD) {
|
|
// hitag 2 settings
|
|
t_wait_1 = HITAG_T_WAIT_1_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");
|
|
}
|
|
|
|
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;
|
|
int16_t checked = 0;
|
|
uint32_t signal_size = 10000;
|
|
bool turn_on = true;
|
|
|
|
while (bStop == false && BUTTON_PRESS() == false) {
|
|
|
|
// use malloc
|
|
initSampleBufferEx(&signal_size, true);
|
|
|
|
// 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;
|
|
}
|
|
|
|
WDT_HIT();
|
|
|
|
// By default reset the transmission buffer
|
|
tx = txbuf;
|
|
|
|
switch (payload->cmd) {
|
|
case HT2F_CRYPTO: {
|
|
bStop = !hitag2_crypto(rx, rxlen, tx, &txlen, true);
|
|
break;
|
|
}
|
|
case HT2F_PASSWORD: {
|
|
bStop = !hitag2_password(rx, rxlen, tx, &txlen, true);
|
|
break;
|
|
}
|
|
default: {
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
if (bStop) {
|
|
break;
|
|
}
|
|
|
|
if (turn_on) {
|
|
// Wait 50ms with field off to be sure the transponder gets reset
|
|
SpinDelay(50);
|
|
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);
|
|
turn_on = false;
|
|
// Wait with field on to be in "Wait for START_AUTH" timeframe
|
|
lf_wait_periods(HITAG_T_WAIT_POWERUP + HITAG_T_WAIT_START_AUTH_MAX / 4);
|
|
command_start += HITAG_T_WAIT_POWERUP + HITAG_T_WAIT_START_AUTH_MAX / 4;
|
|
} else {
|
|
// Wait for t_wait_2 carrier periods after the last tag bit before transmitting,
|
|
lf_wait_periods(t_wait_2);
|
|
command_start += t_wait_2;
|
|
}
|
|
|
|
// Transmit the reader frame
|
|
command_duration = hitag2_reader_send_frame(tx, txlen);
|
|
|
|
// 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);
|
|
StopTimestamp();
|
|
lf_finalize(ledcontrol);
|
|
BigBuf_free();
|
|
return;
|
|
}
|
|
|
|
response_start = command_start + command_duration;
|
|
|
|
// Let the antenna and ADC values settle
|
|
// 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;
|
|
|
|
// 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
|
|
// still use the same memory space)
|
|
LogTraceBits(tx, txlen, command_start, command_start + command_duration, true);
|
|
|
|
// Reset values for receiving frames
|
|
memset(rx, 0x00, sizeof(rx));
|
|
rxlen = 0;
|
|
|
|
// If there is no response, just repeat the loop
|
|
if (got_answer == false) {
|
|
d_noans++;
|
|
continue;
|
|
}
|
|
|
|
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 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];
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
|
|
// 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:
|
|
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.
|
|
BigBuf_free();
|
|
|
|
// Exactly one NG response per command. On the abort path (checked == -1,
|
|
// a new command arrived while the reader loop was still running) send only
|
|
// the abort reply - falling through to a second reply_ng left the transport
|
|
// with a stray unsolicited frame, which the higher-latency BLE/FPC bridge
|
|
// desyncs on (USB tolerates it).
|
|
if (checked == -1) {
|
|
reply_ng(CMD_LF_HITAG2_WRITE, PM3_ESOFT, NULL, 0);
|
|
} else {
|
|
reply_ng(CMD_LF_HITAG2_WRITE
|
|
, (bSuccessful) ? PM3_SUCCESS : PM3_EFAILED
|
|
, (uint8_t *)tag.sectors
|
|
, tag_size
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
static void ht2_send(bool turn_on, uint32_t *cmd_start
|
|
, uint32_t *cmd_duration, uint32_t *resp_start
|
|
, uint8_t *tx, size_t txlen, bool send_bits) {
|
|
|
|
// Tag specific configuration settings (sof, timings, etc.) HITAG2 Settings
|
|
#define T_WAIT_1_GUARD 7
|
|
|
|
if (turn_on) {
|
|
// Wait 50ms with field off to be sure the transponder gets reset
|
|
SpinDelay(50);
|
|
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);
|
|
|
|
// Wait with field on to be in "Wait for START_AUTH" timeframe
|
|
lf_wait_periods(HITAG_T_WAIT_POWERUP + HITAG_T_WAIT_START_AUTH_MAX / 4);
|
|
*cmd_start += HITAG_T_WAIT_POWERUP + HITAG_T_WAIT_START_AUTH_MAX / 4;
|
|
|
|
} else {
|
|
// Wait for t_wait_2 carrier periods after the last tag bit before transmitting,
|
|
lf_wait_periods(HITAG_T_WAIT_2_MIN + HITAG_T_WAIT_2_MIN);
|
|
*cmd_start += (HITAG_T_WAIT_2_MIN + HITAG_T_WAIT_2_MIN);
|
|
}
|
|
|
|
// Transmit the reader frame
|
|
if (send_bits) {
|
|
*cmd_duration = hitag2_reader_send_framebits(tx, txlen);
|
|
} else {
|
|
*cmd_duration = hitag2_reader_send_frame(tx, txlen);
|
|
}
|
|
|
|
*resp_start = (*cmd_start + *cmd_duration);
|
|
|
|
*resp_start += (HITAG_T_WAIT_1_MIN - T_WAIT_1_GUARD);
|
|
// Let the antenna and ADC values settle
|
|
// And find the position where edge sampling should start
|
|
lf_wait_periods(HITAG_T_WAIT_1_MIN - T_WAIT_1_GUARD);
|
|
}
|
|
|
|
static bool ht2_receive(uint32_t *resp_start, uint32_t *resp_duration, uint8_t *nrz_samples, size_t *samples) {
|
|
|
|
// 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();
|
|
|
|
// Raw demodulation/decoding by sampling edge periods
|
|
|
|
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);
|
|
|
|
// 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;
|
|
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);
|
|
resp_duration = resp_start;
|
|
|
|
} else {
|
|
// Register the number of periods that have passed
|
|
resp_start += periods;
|
|
resp_duration = resp_start;
|
|
}
|
|
|
|
// 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
|
|
detected_tag_modulation = true;
|
|
|
|
} else {
|
|
// The function lf_count_edge_periods() returns 0 when a time-out occurs
|
|
if (periods == 0) {
|
|
break;
|
|
}
|
|
}
|
|
// 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 __|)
|
|
nrz_samples[nrzs++] = tag_modulation;
|
|
|
|
if (nrzs < HT2_MAX_NRSZ) {
|
|
nrz_samples[nrzs++] = tag_modulation;
|
|
}
|
|
|
|
resp_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;
|
|
|
|
resp_duration += periods;
|
|
|
|
tag_modulation ^= 1;
|
|
|
|
} else {
|
|
// The function lf_count_edge_periods() returns > 64 periods, this is not a valid number periods
|
|
break;
|
|
}
|
|
}
|
|
|
|
// 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 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;
|
|
}
|
|
|
|
// 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;
|
|
|
|
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) {
|
|
|
|
if (nrzs < 5) {
|
|
return false;
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|
|
const size_t remaining = nrzs - start;
|
|
|
|
// 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;
|
|
}
|
|
|
|
// 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[len >> 3] |= bit << (7 - (len % 8));
|
|
len++;
|
|
}
|
|
|
|
// 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) {
|
|
|
|
g_logging = false;
|
|
|
|
// keep field up indicates there are more traffic to be done.
|
|
if (keep_field_up == false) {
|
|
clear_trace();
|
|
}
|
|
|
|
// hitag 2 state machine?
|
|
hitag2_init();
|
|
|
|
// init as reader
|
|
lf_init(LF_ADC_READER, LF_ADC_WAV_REVERSED, true);
|
|
|
|
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
|
|
|
uint8_t rx[HITAG_FRAME_LEN] = {0};
|
|
size_t rxlen = 0; // In number of bits
|
|
|
|
uint8_t nrz_samples[HT2_MAX_NRSZ];
|
|
|
|
uint8_t attempt_count = 3;
|
|
|
|
int res = PM3_EFAILED;
|
|
bool turn_on = true;
|
|
|
|
while (attempt_count && BUTTON_PRESS() == false) {
|
|
|
|
attempt_count--;
|
|
|
|
WDT_HIT();
|
|
|
|
uint32_t command_start = 0, command_duration = 0;
|
|
uint32_t response_start = 0, response_duration = 0;
|
|
|
|
// start AUTH command
|
|
size_t txlen = 5;
|
|
uint8_t tx[] = {HITAG2_START_AUTH};
|
|
|
|
// Transmit as reader
|
|
ht2_send(turn_on, &command_start, &command_duration, &response_start, tx, txlen, false);
|
|
|
|
turn_on = false;
|
|
|
|
// Reset the number of NRZ samples and use edge detection to detect them
|
|
size_t nrzs = 0;
|
|
|
|
// receive raw samples
|
|
if (ht2_receive(&response_start, &response_duration, nrz_samples, &nrzs) == false) {
|
|
continue;
|
|
}
|
|
|
|
// Store the transmit frame ( TX ), 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);
|
|
|
|
// decode raw samples from Manchester Encoded to bits
|
|
manrawdecode(nrz_samples, &nrzs, true, 0);
|
|
|
|
// pack bits to bytes
|
|
if (ht2_packbits(nrz_samples, nrzs, rx, &rxlen) == false) {
|
|
continue;
|
|
}
|
|
|
|
// log Receive data
|
|
LogTraceBits(rx, rxlen, response_start, response_start + response_duration, false);
|
|
|
|
if (rxlen != 32) {
|
|
continue;
|
|
}
|
|
|
|
// Store received UID
|
|
memcpy(tag.sectors[0], rx, 4);
|
|
if (uid) {
|
|
memcpy(uid, rx, 4);
|
|
}
|
|
res = PM3_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
if (keep_field_up == false) {
|
|
lf_finalize(false);
|
|
BigBuf_free_keep_EM();
|
|
}
|
|
|
|
if (send_answer) {
|
|
reply_ng(CMD_LF_HITAG_READER, res, (uint8_t *)tag.sectors, 4);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
// This function assumes you have called hitag2_read_uid before to turn on the field :)
|
|
// tx = expects bin arrays 0,1 i
|
|
// txlen = number of bits to send
|
|
// rx = return bin arrys
|
|
// rxlen = number of bits returned
|
|
int ht2_tx_rx(uint8_t *tx, size_t txlen, uint8_t *rx, size_t *rxlen, bool ledcontrol, bool keep_field_up) {
|
|
|
|
int res = PM3_EFAILED;
|
|
size_t nrzs = 0;
|
|
uint8_t samples[HT2_MAX_NRSZ] = {0};
|
|
|
|
uint32_t command_start = 0, command_duration = 0;
|
|
uint32_t response_start = 0, response_duration = 0;
|
|
|
|
// Transmit as reader
|
|
ht2_send(false, &command_start, &command_duration, &response_start, tx, txlen, true);
|
|
|
|
// receive raw samples
|
|
if (ht2_receive(&response_start, &response_duration, samples, &nrzs) == false) {
|
|
goto out;
|
|
}
|
|
|
|
ht2_normalise_head(samples, &nrzs);
|
|
|
|
// decode raw samples from Manchester Encoded to bits
|
|
if (manrawdecode(samples, &nrzs, true, 0)) {
|
|
goto out;
|
|
}
|
|
|
|
// pack bits to bytes
|
|
if (rx && (ht2_packbits(samples, nrzs, rx, rxlen) == false)) {
|
|
goto out;
|
|
}
|
|
|
|
res = PM3_SUCCESS;
|
|
|
|
out:
|
|
if (keep_field_up == false) {
|
|
lf_finalize(false);
|
|
}
|
|
return res;
|
|
}
|