everhack Stuff I've been messing with, or just thinking about.

21Oct/112

RFID reader, part 5 – 1’s and 0’s, but what do they mean?

100000001000000001000110001100111011

 

0000000000000000

 

100011 001100111011000000 1000000000100 11000110011101100000001000000000100011000110011101100000001000000000

100011000110011101100000001000000000100011000110011101100000001000000000100011000110011101100000001000000000

10001100 01100111 01100000 00100000 00001000 11000110 01110110 00000010 00000000 10001100 01100111 01100000 00100000 0000

100011000110011101100000001000000000100011000110011101100000001000000000100011000110011101100000001000000000

100011000110011101100000001000000000100011000110011101100000001000000000100011000110011101100000001000000000

100011000110011101100000001000000000100011000110011101100000001000000000100011000110011101100000001000000000

100011000110011101100000001000000000100011000110011101100000001000000000100011000110011101100000001000000000

100011000110011101100000001000000000100011000110011101100000001000000000100011000110011101100000001000000000

100011000110011 0110000000100000000 1000110001 00111011000000 1000000000100011000110011101100000001000000001

00011000110011 0110000000100000000 1000110011 00111011000000 10000000001 0011000110011 0110000000100000000

100011000100111 011000000010000000001000110011 0011101100000001000000000100011000110011101100000001000000000

100011000100111 01100000001000000000100011000110011101100000001000000000100011000110011101100000001000000000

 

 

1000110001100111011000000010000000001000110001100111011000000010000000001000110001100111011000000010000000001000110001100111011000000010000000001000110001100111011000000010000000001000110001100111011000000010000000001000110001100111011000000010000000001000110001100111011000000010000000001000100011001110110000000100000000010001100011001110110000000100000000100110001100111011000000100000000010001100011001111100000001000000001000110001101110110000001000000000100010001100111011000000010000000001000110001100111011000000010000000001000110001100111011000000010000000001000110001100111011000000010000000001000110001100111011000000010000000001000110001100111011000000010000000001000110001100111011000000010000000001000110001100111011000000010000000001

This is what my reader is writing to the serial port now.

As before, the analog comparator is connected between the analog threshold voltage and the antenna signal.

The input capture interrupt function now toggles the LED and debug pins, and writes a 0 or 1 to the serial port, if the time between the last falling and rising edge from the analog comparator output occurred in one of two ranges of time. i.e, 250-1100 ticks right now for a "short", and 1101-3499 ticks for a "long".

Based on my previous reading I think I have to actually be timing how long since the last rising edge* - the catch is that the "high part" of the signal is actually constantly toggling at 250khz (every rising and falling analog comparator edge), so I have to be able to ignore the very short-duration low periods to properly time the "high part". Maybe if I just check the low period duration and don't reset the timer if it's too short, effectively filtering out the higher frequency component of the signal.

I've had a great time trying to view the signal on my analog scope. I connected one probe to the raw, rectified, a/c coupled antenna signal,  and the other probe to the debug pin on the Teensy.

Using the coarse and fine timebase controls on the scope, triggering on the debug pin, I can zoom out far enough to see the entire signal from the card. Since the signal is constantly repeating, I can get a static and unique "image" of each card's bitstream.

Playing with the potentiometer on the threshold voltage, I discovered that the ideal threshold voltage is directly related to how far away the card is. The further the card, the lower the threshold voltage.

The "depth of field" of the "best" threshold value is surprisingly low as well. Holding the card at a constant distance from the reader, I turn the knob back and forth, watching as the bits in the "bit picture" on the scope eerily flicker in and out of view, locked horizontally, but flickering more and less depending on the error rate.

Sorry, I thought I took a cellphone picture of it but I must have not hit "save" before closing the phone. I hate when I do that.

The best, most rock-solid signal is obtained (not surprisingly) when the card is laying right on the wood of the reader coil. At the best threshold setting, it reads the card only up to about a half inch from the wood.

However, by re-tuning the threshold voltage for various card-to-reader distances, I can manage to successfully lock onto the signal from up to maybe 4 inches away.

Clearly, a dynamic threshold voltage tuner seems like a worthwhile upgrade for maximum read-range flexibility.

Something else interesting that I noticed, the cards are nearly "one-sided." That is, when I flip the card over, I can only barely see the signal, probably not well enough to actually read it. My work badge is a different type of HID card and doesn't seem to have that behavior. I'll have to see if the reader on the hackerspace door does the same thing.

Back to the bits. I was really eager to see what my serial bitstream looked like, if it was repeating, the length, and so on.

Opening the log file in my text editor, I played with trying to line up sections of the text to find a repeating pattern, and its length.

Sure enough, I discovered one on each of my two hackerspace cards! But, oddly enough, the number of bits doesn't seem to match up with the expected number.

I've realized that I don't really know what encoding is being used.

From Scanlime's blog, I read that "... Cesar Fernandez described the HID card format ... The 45-bit code"... ; but in my text file, the two visually identical cards appear to give slightly different-length repeating bitstreams. (36 & 38 bits)

00000000 10001100011010000100100000001
00000000010001100011010000100100000001
00000000 10001100011010000100100000001
00000000010001100011010000100100000001
00000000 1000110001101000 100100000001
00000000 10001100011010000100100000001
0000000001000110001101000 100100000001
00000000 10001100011010000100100000001
0000000001000110001101000 100100000001
0000000001000110001101000 100100000001
00000000010001100011010000100100000001
00000000 1000110001101000 100100000001
00000000010001100011010000100100000001

Lining up the repeating rows, and adding spaces where there were missing bits, I realized that the errors nearly all occur in the same places in the signal, and so I must have a slight misalignment in my time window lengths between 0's and 1's. I'll probably have to increase the timer1 prescaler from /8 to /1 to increase the resolution my cycle counter, and create a bigger difference in values between "short" vs "long".

If the card is using around 4 "low antenna cycles" to mean short, and around 8 to mean long, I had expected that a /8 timer would give me plenty of resolution (1 timer tick per 8 16mhz clock cycles, 16 per 125khz antenna cycle, 64 timer ticks per "4 low antenna cycle" 0, and 128 ticks per 1.

However, in practice, my window sizes are currently set at 4 and 10 times larger than this, based on just experimentation and observation of the output. I think what this means is that the encoding is not quite what I'm picking up, and I'm actually reliably missing 9 or 10 bits of the true signal.

Here's my latest code.


#include <avr/interrupt.h>
#include <avr/io.h>

#define CARRIERPOS_PIN 10
#define CARRIERPOS_REG PORTC6
#define CARRIERNEG_PIN 9
#define CARRIERPOS_REG PORTC7

#define LED_PIN 11
#define LED_PORT PORTD
#define LED_REG PORTD6

// AIN0 = PB6 = detect
// ADC0 = PF0 = threshold

#define DEBUG_PORT PORTB
#define DEBUG_REG PORTB3

#define LED_ON() (LED_PORT |= _BV(LED_REG))
#define LED_OFF() (LED_PORT &= ~_BV(LED_REG))
#define TOGGLE_LED() (LED_PORT ^= _BV(LED_REG))

#define DEBUG_ON() (DEBUG_PORT |= _BV(DEBUG_REG))
#define DEBUG_OFF() (DEBUG_PORT &= ~_BV(DEBUG_REG))
#define TOGGLE_DEBUG() (PORTB ^= _BV(DEBUG_REG))

void initTimer4()
{
// pwm with dead time generator
TCCR4A = _BV(PWM4A) | _BV(COM4A0);
// no prescaler (CK/1)
TCCR4B = _BV(CS40);
// phase & frequency correct pwm
TCCR4D = _BV(WGM40);
TCCR4E = _BV(ENHC4);

//duty cycle for oscillator toggle
OCR4A = 64;
// 125k would be no prescaler, period = 128
OCR4C = 64;
}

void initTimer1()
{

TCCR1A = 0; // ctc mode 4
TCCR1B |= _BV(WGM12); // CTC mode 4
//TCCR1B &= ~_BV(ICNC1) | ~_BV(ICES1); // edge detect falling, disable noise canceler
TCCR1B &= ~_BV(ICES1);
TCCR1B |= _BV(ICNC1);

OCR1A = 255; // TOP // 64 is about 8 cycles
TCNT1 = 0;

TCCR1B = _BV(CS11); // PS = 1
}

void initAnalogComparator()
{

// AIN0 = PE6 = detect
// ADC0 = PF0 = threshold

// input capture timer1
//ACSR = _BV(ACIC);

// disable adc
ADCSRA &= ~_BV(ADEN);
// enable analog comparator mux
ADCSRB |= _BV(ACME);
// clear analog comparator interrupt flag
ACSR |= _BV(ACI);

ACSR &= ~_BV(ACIS1) & ~_BV(ACIS0) & ~_BV(ACBG);
// enable analog comparator input capture on output toggle, AIN0 connected to AC+
ACSR |= _BV(ACIC);

TIMSK1 |= _BV(ICIE1);

// ADC0 connected to AC- input
ADMUX &= ~_BV(MUX2) & ~_BV(MUX1) & ~_BV(MUX0);

// disable digital input buffer
DIDR1 |= _BV(AIN0D);

// input ddr regs, enable pull-up resistors
DDRE &= ~_BV(DDE6);
PINE &= ~_BV(PORTE6);
DDRF &= ~_BV(DDF0);
PINF &= ~_BV(PORTF0);
}

ISR(TIMER1_CAPT_vect)
{
uint16_t timer1val = ICR1;

if (bit_is_set(ACSR, ACO))
{
// change edge to descending
TCCR1B &= ~_BV(ICES1);
}
else
{
// long for 1, short for 0
if (timer1val > 1100 && timer1val 250)
{
LED_ON();
DEBUG_ON();
LED_OFF();
DEBUG_OFF();
Serial.print("0");
}
else
{
LED_OFF();
DEBUG_OFF();
}
// if the signal was below threshold for longer than 8 125khz cycles, it's a 1
// change edge to rising
TCCR1B |= _BV(ICES1);
}

// the pulse timer
TCNT1 = 0;
// clear the interrupt flag after changing edge
TIFR1 |= _BV(ICF1);

}

void setup()
{
cli();

initTimer4();
initTimer1();
initAnalogComparator();

// debug pin out / toggle on analog comparator isr & timer0
DDRB |= _BV(PORTB3) | _BV(PORTB7);
PINB |= _BV(PINB7) | _BV(PINB7);

// 125khz carrier oscillator pins 8&9, OC4A/~OC4A
pinMode(CARRIERPOS_PIN, OUTPUT);
pinMode(CARRIERNEG_PIN, OUTPUT);
// led
pinMode(LED_PIN, OUTPUT);
sei();

Serial.begin(57600);
}

void loop()
{
}

Comments (2) Trackbacks (0)
  1. is the goal to read and understand the data, read the data, or to copy the data? The later goals are easier than the former…

  2. Read and understand first. Then spoof.


Leave a comment

No trackbacks yet.