RFID Spoofer

Posted on August 5, 2013

0


Here is a little work I have done for my Master thesis: An RFID spoofer with my arduino.

An RFID spoofer is a device pretending to be a particular transponder with specific characteristics and values. To imitate it, the device needs to use the same modulation, coding and frequency in order to be able to communicate with the reader from the same application the impersonated transponder is suppose to work in.

An RFID spoofer can be composed of a single resistor and an 8-PIN microcontroller which makes it simple to build although not very versatile. Other more complex solutions are possible: adding a coil instead of the resistor — for a wider range —, a key panel and using a more developed microcontroller for editing on the fly the data, the encoding or the modulation.

The spoofer can either constantly broadcast information (e.g. its unique ID) when powered or it can work in a more logical way, by interpreting the RFID reader commands and providing the data required.

The RFID spoofer built for this dissertation is based on the “[arduino / pic] spoofer rfid” project (SkyWodd n.d.) that simulates the communication of an EM4100 RFID transponder working at 125kHz. The device needs to work on the same frequency (125kHz), modulation (PSK) and encoding (Manchester) to communicate with the reader, using the proper protocol.

Frequency

a circuit can resonate with a certain frequency depending on the inductance of the coil and the capacitance of the capacitor. The resonant frequency of an LC circuit is

ω = √(1/LC)

Where ω is the angular frequency in radians per second, L is the inductance in henries and C the capacitance in farads. In order to have the frequency in hertz (cycles per second), ω need to be devided by 2π (2π radians being 1 cycle):

f = ω/2π = 1/(2π √(LC))

For this spoofer, a coil with an inductance of 860μH has been used together with 3 capacitors in parallel with an equivalent capacitance of 1.883ηF (1.52ηF + 0.33ηF + 0.033ηF).

antenna

This LC circuit does not resonate exactly at 125kHz but at 125.068kHz:

f = 1/(2π √(860 x 10^-6) x (1.883 x 10^-9)) = 125.068kHz

This 68Hz difference is not that significant since the reader actually sweeps a range of the frequency from a minimum and a maximum at equal distance from the main frequency i.e. 125kHz in this case.

Modulation

The EM4100 protocol uses PSK modulation to transmit information. A 1N4148 diode bridge is plugged on the LC circuit and an Arduino output pin in order to manipulate the inducted signal: when the Arduino pin is LOW, this corrects the induced signal, which is a “1” logic for the reader. When the pin is HIGH, the diode bridge is inert and does not alter the signal and is therefore a “0” logic.

module

The EM4100 protocol uses 64, 32 or 16 cycles for the synchronisation between the reader and the transponder. One cycle last 8μs:

125kHz = 125 x 10^3 cycles / 1 second → 1/(125 x 10^3) = 8 x 10^-6 second per cycle

In this project, the clock period lasts 64 cycles, which means in seconds:

64 x (8 10^-6) = 512μs

The protocol uses the Manchester encoding that representing a value by a transition during the clock period. Therefore, for each value of the line code, during a half clock period (256 ), the Arduino pin will be HIGH or LOW then LOW or HIGH for another half clock period.

void spoofnow() {
  for(int i = 0; i < 64; i++) {
    send_manchester(0, spoofed_card[i]); delayMicroseconds(256);
    send_manchester(1, spoofed_card[i]);
    delayMicroseconds(256); 
  }
}

Encoding

The Manchester encoding represents the “1” logic with a negative transition and the “0” logic with a positive transition. A negative transition means half a period of the clock, the signal is HIGH, the other half, the signal is LOW.

void send_manchester(int clock_half, int signal) {
  // XOR the clock and the signal
  int man_encoded = clock_half ^ signal;

  if(man_encoded) { 
    digitalWrite(coil_pin, LOW);
  } else {
    digitalWrite(coil_pin, HIGH);
  }
}

EM4100 protocol

The EM4100 has a special data format for sending its unique ID (Priority 1 Design 2007). First, it starts with 9bit header of logic 1 followed by an 8bit version number (D00-07), then the 32 bits of the unique ID (D08-39) and finally it ends with a 4bit column parity and 1 stop bit (S0) represented by a 0 logic. The 9 bits are used to automatically synchronise the clock signal with the reader. Each group of 4 bits is actually followed by an even parity bit (P0-9).

EM4100 protocol

This means a transponder with version number 06 and a unique ID 00CAFE42 will send the following data:

111111111 0000 0 0110 0 0000 0 0000 0 1100 0 1010 0 1111 0 1110 1 0100 1 0010 1 0111 0

Summary

Here is a summary of how the RFID spoofer works:

  1. The user enters the unique ID to spoof
  2. The RFID spoofer generates the data to be sent in the proper format
  3. The data is encoded in Manchester
  4. The line code is outputted on the Arduino pin connected to the 125kHz antennamodule

Regarding the output, the antenna will rectify the induced signal (the electromagnetic field) which will be interpreted by the reader by as a 1 or a 0.

Reader

In order to test the efficiency of the RFID spoofer, a reader needs to be developped. For this dissertation, the Parallax serial Read/Write RFID module (#28140) has been used together with an Arduino.

To read the unique ID of an EM4100 transponder, the Arduino has to send the command 0x0F:

// Command to read EM4100
#define RFID_READ 0x0F

void loop() {
  // Send the command to the Parallax RFID antenna to read EM4100 transponder 
  mySerial.print("!RW");
  mySerial.print(RFID_READ, BYTE);

  // The output of the command is a 12bytes response with // 1 byte header (0x0A)
  // 10 bytes ID
  // 1 byte footer (0x0D)
  for(int i = 0; i < 12; i++) {
    val[i] = mySerial.read();
  }
}

The output of this command is a header (1 bit) + ID (10 bits) + footer (1 bit).

Source codes

Here are the source code for both the spoofer and the reader.

EM4100 RFID reader Arduino sketch

// Define the Arduino PIN 
#define coil_pin 12

// ID to spoof
char data[10] = {'0', '6', '0', '0', 'C', 'A', 'F', 'E', '4', '2'};

int spoofed_card[64];

void setup() { 
  Serial.begin(9600); 
  pinMode(coil_pin, OUTPUT); 
  digitalWrite(coil_pin, LOW); 
  build_content();
}

void loop() {

  delay(500);
  Serial.println("Ready for spoofing");

  for(int h = 0; h < 50; h++) 
    spoofnow();

  Serial.println("Spoof done"); 
}

// Function that build the transponder's content 
void build_content() {

  // iterator for the ID wanted 
  int data_iterator = 0;

  // hex value of the ID 
  int raw_data;
  int i;

  // the 9 first bit are 1 logic (a+9) 
  for (i = 0; i < 9; i++) {
    spoofed_card[i] = 1; 
  }

  // the 5th bit is for parity. Calculated at the end 
  // This loop writes each hex in bit
  for (int a = 0; a < 10; a++) {
    raw_data = HexToDec(data[data_iterator]);
    spoofed_card[(a*5)+9] = bitRead(raw_data, 3); 
    spoofed_card[(a*5)+10] = bitRead(raw_data, 2); 
    spoofed_card[(a*5)+11] = bitRead(raw_data, 1); 
    spoofed_card[(a*5)+12] = bitRead(raw_data, 0);
    data_iterator++; 
  }

  int bit_set = 0;

  // CRC ROW
  for(int r = 0; r < 10; r++) {
    // Calculate number of 1 per row 
    for(i = 0; i < 4; i++) {
      if(spoofed_card[(r*5)+i+9]) { 
        bit_set++;
      } 
    }

    // If number of 1 is even, parity = 1 else 0
    if((bit_set % 2) != 0) { 
      spoofed_card[(5*r)+4+9] = 1;
    } else { 
      spoofed_card[(5*r)+4+9] = 0;
    }

    bit_set = 0; 
  }

  // CRC COLUMN
  bit_set = 0;

  for(int c = 0; c < 4; c++) {

    // Calculate number of 1 per column 
    for(i = 0; i < 10; i++) {

      if(spoofed_card[c+(i*5)+9]) { 
        bit_set++;
      }
    }

    // If number of 1 is even, parity = 1 else 0 
    if((bit_set % 2) != 0) {
      spoofed_card[50+9+c] = 1; 
    } else {
      spoofed_card[50+9+c] = 0; 
    }

    bit_set = 0; 
  }

  // Last bit = stop bit = 0
  spoofed_card[63] = 0; 
}

// Function that converts Hexadecimal in Decimal
int HexToDec(char hexa) {

  if(hexa == '0') 
    return 0;

  if(hexa == '1') 
    return 1;

  if(hexa == '2') 
    return 2;

  if(hexa == '3') 
    return 3;

  if(hexa == '4') 
    return 4;

  if(hexa == '5') 
    return 5;

  if(hexa == '6') 
    return 6;

  if(hexa == '7') 
    return 7;

  if(hexa == '8') 
    return 8;

  if(hexa == '9') 
    return 9;

  if(hexa == 'A') 
    return 10;

  if(hexa == 'B') 
    return 11;

  if(hexa == 'C') 
    return 12;

  if(hexa == 'D') 
    return 13;

  if(hexa == 'E') 
    return 14;

  if(hexa == 'F') 
    return 15;
}

void spoofnow() {
  for(int i = 0; i < 64; i++) {
    send_manchester(0, spoofed_card[i]); 
    delayMicroseconds(256);
    send_manchester(1, spoofed_card[i]);
    delayMicroseconds(256); 
  }
}

void send_manchester(int clock_half, int signal) {
  // XOR the clock and the signal
  int man_encoded = clock_half ^ signal;

  if(man_encoded) { 
    digitalWrite(coil_pin, LOW);
  } else {
    digitalWrite(coil_pin, HIGH);
  }
}

Reader

#include <NewSoftSerial.h>

// Command to read EM4100 
#define RFID_READ 0x0F

// Pin IN and OUT on Arduino 
#define txPin 12
#define rxPin 13

// Creating serial object to communicate with the Parallax RFID antenna 
NewSoftSerial mySerial(rxPin, txPin);

// variable that will contain the ID of the RFID tag 
int val[12];

void setup() {

  // Output to computer at 9600 baud 
  Serial.begin(9600);

  // Parallax RFID antenna working at 9600 bauds 
  mySerial.begin(9600);

  // Setup the Arduino PIN to work with the parallax RFID antenna 
  pinMode(txPin, OUTPUT);
  pinMode(rxPin, INPUT);

  // Little trick to don't use a breadboard, the Vcc is an output Arduino pin set to HIGH
  pinMode(11, OUTPUT); digitalWrite(11, HIGH);

  // Setup done
  Serial.println("PROGRAM INITIALISED");
}

void loop() {

  // Send the command to the Parallax RFID antenna to read EM4100 transponder 
  mySerial.print("!RW");
  mySerial.print(RFID_READ, BYTE);

  // The output of the command is a 12bytes response with 
  // 1 byte header (0x0A)
  // 10 bytes ID
  // 1 byte footer (0x0D)

  for(int i = 0; i < 12; i++) { 
    val[i] = mySerial.read();
  }

  // If 1st byte = 0x0A and last byte = 0x0D, this means the response is a RFID tag ID
  if(val[0] == 10 && val[11] == 13) { 

    Serial.print("ID: ");

    for(int j = 1; j <= 10; j++) {
      Serial.print(InToChar(val[j])); 
    }

    Serial.println("");
  }

  delay(750); 
}

// Function that convert Integer in Char 
char InToChar(int hexa)
{
  if(hexa == 48) 
    return '0';

  if(hexa == 49) 
    return '1';

  if(hexa == 50) 
    return '2';

  if(hexa == 51) 
    return '3';

  if(hexa == 52) 
    return '4';

  if(hexa == 53) 
    return '5';

  if(hexa == 54) 
    return '6';

  if(hexa == 55) 
    return '7';

  if(hexa == 56) 
    return '8';

  if(hexa == 57) 
    return '9';

  if(hexa == 65) 
    return 'A';

  if(hexa == 66) 
    return 'B';

  if(hexa == 67) 
    return 'C';

  if(hexa == 68) 
    return 'D';

  if(hexa == 69) 
    return 'E';

  if(hexa == 70) 
    return 'F';
}
Advertisements