Louis Yi, Mary Ruthven, Kevin O'Toole, & Jay Patterson
We made an Radio Frequency ID (RFID) card reader and, while attempting to create a long-range spoofer, created an jammer which overcomes card's signals.
The reader uses filtering circuitry following a 125kHz driven resonator to produce the returned FSK signal from the HID brand RFID proximity cards used around Olin college. Reading was initially performed by capturing data with an oscilloscope and then processing in MATLAB, but was eventually implemented on an FPGA using Verilog.
Reading the cards provided the binary data we attempted to reproduce with the RFID spoofer. Trying several transmission hardware designs and many encoding methods failed to yield a successful RFID activation. We discovered while testing that sending similar signals at high amplitudes blocked real RFID cards, effectively jamming them and locking the door.
RFID systems are currently and increasingly a part of our lives. We use them at school, at work, and on the roads for fare collection in systems like the Northeast's E-ZPass. Frighteningly, many online papers and our own experiments show, they're not very secure. Personal data stored on such cards is available to anyone nearby with a suitable, inexpensive RFID reader.
We were curious about the technology involved and whether we could implement a full RFID system. Also, Eric really wanted an RFID gun, which we are disappointed to say we couldn't deliver.
The RFID protocol of communication is a nesting of three different encodings: Backscattering of a carrier frequency, Frequency Shift Keying, and Manchester encoding.
The RFID reader outputs a constant 125kHz signal to all nearby tags, amplifying the signal when it detects any reflected signal. Since an RFID tag is passive, it needs to send back a signal without drawing any power itself. Using the sent signal as both a power source and a clock, the RFID tag flips a transistor in a predefined sequence (a black box described in the Frequency Shift Keying section) to send a sequence of HIGH and LOW values through the backscattered signal back to the reader.
Diagram of backscattering transmission of ON and OFF signals.
On top of this encoding, HIGH and LOW signals are determined by the frequency of the backscattered ONs and OFFs. In Frequency Shift Keying, which is used by Olin’s Prox Cards, switching from ON to OFF at a rate of 12.5kHz (period every 10 cycles of the carrier frequency) denotes a LOW signal, and switching from ON to OFF at a rate of 15.6kHz (period every 8 cycles of the carrier frequency) denotes a HIGH signal. Thus the HIGH and LOW digital signals are encoded by
The advantages of this encoding is that it is computationally simpler and less susceptible to noise than traditional pulse-amplitude modulated signals. Because only takes two frequencies to send a message, proper filtering can ensure the system is only susceptible to white noise around those two frequencies. Additionally, no channel equalization or phase calibration is needed, since the decoding method simply calculates the distance between peaks, and determines if it is closer to 12.5kHz or 15.6kHz. The HIGH and LOW frequencies are switched between according to a predetermined signal, a black box determined by the Manchester encoding of the tag’s data.
On top of this encoding, 1s and 0s are encoded and decoded from the highs and lows using Manchester Encoding. Manchester Encoding simply encodes a 1 as (HIGH, LOW) and a 0 as (LOW, HIGH).
\\
Diagram of a decoding of a Manchester-Encoded sequence of HIGH and LOW signals.
The advantage of Manchester encoding is a huge improvement in the accuracy of readers and writers that are out of phase, and signals that stay high or low for extended periods of time. Manchester encoding guarantees that there is a flip from high to low in the center of each bit transmitted, so it is trivial to determine the phase of the writer’s signal. It is also impossible to be half a bit off, because a random sequence will include consecutive HIGHs or LOWs if the phase is half a period off. Manchester Encoding also prevents timing errors in long strings of 1s or 0s by making it trivial to count the number of bits in a long string of (LOW, HIGH)s.
Circuit used to decode the rfid tag modulated with a 125KHz down to a digital signal to be processed.
Photos of comparator'd traces
Our first implementation of the RFID reader was to take an analog signal and measure the peaks in order to find the signal was at 15KHz or 12.5KHz. We then graphed those differences representing different frequencies with as either a 'one' bit or a 'zero' bit. Finally we manually pieced multiple graphs together and then also manually decoded the graphs. decoded.pdf
Manchester Encoding from Louis' prox card processed by the matlab code.
Manchester Encoding from arduino spoofer emulating Louis' prox also processed by the matlab code.
As seen from the two graphs above, both Louis' prox card and the spoofer resulted in similar outputs from the matlab code. This verified that our spoofer was outputting correctly.
Clean signal from RFID tag which clearly demonstrates FSK and manchester encoding of the tag information. Close up of RFID tag signal. Messy signal from RFID spoofer. We haven't been able to determine the source of the noise in the signal. Close up of spoofer signal.
RFID reader signal after comparator. This signal was processed by the FPGA into the RFID card data.
We tested our code in MATLAB before we implemented it in Verilog. We designed our MATLAB code with Verilog in mind. We designed our MATLAB code so that was a loop and updated the extracted code with each cycle of the code. We also avoided division and multiplication which helped make the transition to Verilog easy.
In our code, we attempted to correct errors by correcting single bit errors. We checked that the value of one of a bit's neighbors was the same as the bit we were checking. If it wasn't then we changed the value of that bit.
We made a 125kHz square wave with the FPGA and used it to drive our reader circuit. The FPGA could not supply enough current for the circuit, so we added a buffer before the coil. We did not accomplish the goal of getting a FPGA RFID reader to work, because we did not but the Verilog we developed on the FPGA. If we were to pursue this project then we would have to put the Verilog on the FPGA and figure out what the counting threshold is for the two different frequency waves.
All of the code is saved in RFID exploration code folder.
We tried three different driving methods for the RFID spoofer: a bipolar transistor, a pair of FETs, and a rectifying full-bridge followed by a loading FET. All three methods modulated the signal quite successfully, but failed when tested on a commercial HID prox reader.
Circuits for the three different driving methods.
The Signal was sent by an Arduino using port manipulation to keep delays low and precise. Note that one side of each resonating coil and capacitor is grounded.
// Coil control pin int coil_pin = 8; void setup() { digitalWrite(coil_pin, LOW); DDRB = B00000001; // set pin 8 OUTPUT PORTB = B00000000; // set Pin 8 Low, port manipulation } void set_pin_manchester(int clock_half, int signal) {\ // encoded and send data int man_encoded = clock_half ^ signal; // xor if(man_encoded == 1) { send_1(); } else { send_0(); } } int data_to_spoof[45] = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0}; // insert binary card data here //int i = 33; void loop() { // start sequence // send_0(); send_0(); send_0(); send_0(); send_1(); send_1(); send_1(); // data payload // for(int i = 0; i < 45; i++) { set_pin_manchester(0, data_to_spoof[i]); set_pin_manchester(1, data_to_spoof[i]); } } int one = 40; // microsecond delay to send 12.5kHz int zero = 32; // microsecond delay to send 15kHz void send_1() { // send six periods of 12.5kHz signal PORTB = B00000000; delayMicroseconds(one); PORTB = B00000001; delayMicroseconds(one); PORTB = B00000000; delayMicroseconds(one); PORTB = B00000001; delayMicroseconds(one); PORTB = B00000000; delayMicroseconds(one); PORTB = B00000001; delayMicroseconds(one); PORTB = B00000000; delayMicroseconds(one); PORTB = B00000001; delayMicroseconds(one); PORTB = B00000000; delayMicroseconds(one); PORTB = B00000001; delayMicroseconds(one); } void send_0() { // send six periods of 15kHz signal PORTB = B00000000; delayMicroseconds(zero); PORTB = B00000001; delayMicroseconds(zero); PORTB = B00000000; delayMicroseconds(zero); PORTB = B00000001; delayMicroseconds(zero); PORTB = B00000000; delayMicroseconds(zero); PORTB = B00000001; delayMicroseconds(zero); PORTB = B00000000; delayMicroseconds(zero); PORTB = B00000001; delayMicroseconds(zero); PORTB = B00000000; delayMicroseconds(zero); PORTB = B00000001; delayMicroseconds(zero); PORTB = B00000000; delayMicroseconds(zero); PORTB = B00000001; delayMicroseconds(zero); }
- Working with undocumented black boxes is difficult, you need to know what's going on inside.
Our efforts were focused on recording the data from an RFID card and then reproducing it with separate harware. Instead of this two stage process, we could have tried to simply amplify the RFID card by reading it with one coil, amplifying the signal and directing the amplified signal toward a prox card reader. This solution may have resolved our issues with properly reproducing the prox signal and allowed us to focus simply on extending the prox card's range. This approach effectively makes a passive system into an active one.
The algorithms we used to process data were not as efficient and clean as they could have been. Instead of simply edge-triggering to determine the location of a peak, we could have found the center of each pulse which may have yielded cleaner and more consistent results.
Because the input signal to the comparator was noisy, there were regular incorrect pulses that the software had to be resilient to. A Schmitt trigger (a comparator with hysteresis) could have cleaned up the signal and simplified the software.
As far as creating an RFID reader went, our workplan was accurate. The circuit involved was not terribly difficult, and once we understood the protocol and what we were supposed to see at each stage it wasn't difficult to debug.
We started on the transmitter ahead of schedule and tried to make it work in many different ways. Unfortunately, interfacing with the HID prox readers on campus was not nearly as simple as we thought and we made little further progress. If we had not been interacting with a black box without any intermediate feedback beyond success or failure, this project would have been much more likely to succeed. We should have invested in a basic RFID reader that would tell us what the signal we were sending was being interpreted as. As it was, there was no feedback and we had no idea of whether we were getting closer or further away from success.
As we struggled getting the transmitter to work, we pivoted to pursue RFID reading near the end of the project. As such, we made some modification to the reader to digitize the output data signal and attempted to hook it up to an FPGA. We probably should have worked on the FPGA RFID reader more in parallel with the rest of the project, when we were struggling with the writer.
Overall, we effectively kept on or ahead of schedule, but experienced far more difficulties than we could have anticipated.