mirror of
https://github.com/Proxmark/proxmark3.git
synced 2025-08-24 15:05:29 -07:00
EM4x50 simulation (Not complete yet)
Add EM4x50 simulation (Not complete yet)
This commit is contained in:
parent
b324b02f88
commit
b85208d66b
7 changed files with 756 additions and 2 deletions
|
@ -15,7 +15,7 @@ APP_CFLAGS = -DWITH_ISO14443a_StandAlone -DWITH_LF -DWITH_ISO15693 -DWITH_ISO144
|
||||||
#-DWITH_LCD
|
#-DWITH_LCD
|
||||||
|
|
||||||
#SRC_LCD = fonts.c LCD.c
|
#SRC_LCD = fonts.c LCD.c
|
||||||
SRC_LF = lfops.c hitag2.c hitagS.c lfsampling.c pcf7931.c lfdemod.c protocols.c
|
SRC_LF = lfops.c hitag2.c hitagS.c em4x50.c lfsampling.c pcf7931.c lfdemod.c protocols.c
|
||||||
SRC_ISO15693 = iso15693.c iso15693tools.c
|
SRC_ISO15693 = iso15693.c iso15693tools.c
|
||||||
SRC_ISO14443a = epa.c iso14443a.c mifareutil.c mifarecmd.c mifaresniff.c
|
SRC_ISO14443a = epa.c iso14443a.c mifareutil.c mifarecmd.c mifaresniff.c
|
||||||
SRC_ISO14443b = iso14443b.c
|
SRC_ISO14443b = iso14443b.c
|
||||||
|
|
|
@ -1005,6 +1005,9 @@ void UsbPacketReceived(uint8_t *packet, int len)
|
||||||
case CMD_VIKING_CLONE_TAG:
|
case CMD_VIKING_CLONE_TAG:
|
||||||
CopyVikingtoT55xx(c->arg[0], c->arg[1], c->arg[2]);
|
CopyVikingtoT55xx(c->arg[0], c->arg[1], c->arg[2]);
|
||||||
break;
|
break;
|
||||||
|
case CMD_SIMULATE_EM4x50: // Simulate EM4x50 tag, args = memory content
|
||||||
|
SimulateEM4x50Tag((bool)c->arg[0], (byte_t*)c->d.asBytes);
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef WITH_HITAG
|
#ifdef WITH_HITAG
|
||||||
|
|
|
@ -175,6 +175,9 @@ void iClass_Dump(uint8_t blockno, uint8_t numblks);
|
||||||
void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t *data);
|
void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t *data);
|
||||||
void iClass_ReadCheck(uint8_t blockNo, uint8_t keyType);
|
void iClass_ReadCheck(uint8_t blockNo, uint8_t keyType);
|
||||||
|
|
||||||
|
// em4x50
|
||||||
|
void SimulateEM4x50Tag(bool tag_mem_supplied, byte_t* data);
|
||||||
|
|
||||||
// hitag2.h
|
// hitag2.h
|
||||||
void SnoopHitag(uint32_t type);
|
void SnoopHitag(uint32_t type);
|
||||||
void SimulateHitagTag(bool tag_mem_supplied, byte_t* data);
|
void SimulateHitagTag(bool tag_mem_supplied, byte_t* data);
|
||||||
|
|
708
armsrc/em4x50.c
Normal file
708
armsrc/em4x50.c
Normal file
|
@ -0,0 +1,708 @@
|
||||||
|
#include "proxmark3.h"
|
||||||
|
#include "apps.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "string.h"
|
||||||
|
|
||||||
|
#define EM4x50_PASSWORD 0
|
||||||
|
#define EM4x50_PROTECTION 1
|
||||||
|
#define EM4x50_CONTROL 2
|
||||||
|
#define EM4x50_SERIAL 32
|
||||||
|
#define EM4x50_DEVICE_ID 33
|
||||||
|
|
||||||
|
#define EM4x50_FIRST_WORD_READ_BYTE 0
|
||||||
|
#define EM4x50_LAST_WORD_READ_BYTE 1
|
||||||
|
#define EM4x50_FIRST_WORD_READ_PROTECTED_BYTE 0
|
||||||
|
#define EM4x50_LAST_WORD_READ_PROTECTED_BYTE 1
|
||||||
|
#define EM4x50_FIRST_WORD_WRITE_INHIBITED_BYTE 2
|
||||||
|
#define EM4x50_LAST_WORD_WRITE_INHIBITED_BYTE 3
|
||||||
|
#define EM4X50_PASSWORD_CHECK_BIT 16
|
||||||
|
#define EM4X50_READ_AFTER_WRITE 17
|
||||||
|
|
||||||
|
// Sam7s has several timers, we will use the source TIMER_CLOCK1 (aka AT91C_TC_CLKS_TIMER_DIV1_CLOCK)
|
||||||
|
// TIMER_CLOCK1 = MCK/2, MCK is running at 48 MHz, Timer is running at 48/2 = 24 MHz
|
||||||
|
// Hitag units (T0) have duration of 8 microseconds (us), which is 1/125000 per second (carrier)
|
||||||
|
// T0 = TIMER_CLOCK1 / 125000 = 192
|
||||||
|
#define T0 192
|
||||||
|
|
||||||
|
#define EM4x50_T_HALF_PERIOD 32
|
||||||
|
#define EM4x50_T_FULL_PERIOD 64
|
||||||
|
|
||||||
|
#define EM4x50_COMMAND_NONE 0xFF
|
||||||
|
#define EM4x50_COMMAND_BREAK 0x00
|
||||||
|
#define EM4x50_COMMAND_LOGIN 0x01
|
||||||
|
#define EM4x50_COMMAND_WRITE_PASSWORD 0x11
|
||||||
|
#define EM4x50_COMMAND_WRITE 0x12
|
||||||
|
#define EM4x50_COMMAND_SELECTIVE_READ 0x0A
|
||||||
|
#define EM4x50_COMMAND_RESET 0x80
|
||||||
|
|
||||||
|
#define EM4X50_T_PROCESSING_PAUSE 64
|
||||||
|
#define EM4X50_T_INIT 2112
|
||||||
|
#define EM4X50_T_WRITE_ACCESS 64
|
||||||
|
#define EM4X50_T_EEPROM_WRITE 3200
|
||||||
|
|
||||||
|
#define EM4X50_WAITING_FOR_DATA 0
|
||||||
|
#define EM4X50_WAITING_FOR_BYTE_PARITY 1
|
||||||
|
#define EM4X50_WAITING_FOR_CULOMN_PARITY 2
|
||||||
|
#define EM4X50_WAITING_FOR_0 3
|
||||||
|
|
||||||
|
#define EM4X50_STATE_READ 0
|
||||||
|
#define EM4X50_STATE_SELECTIVE_READ 1
|
||||||
|
|
||||||
|
// 1. Login command arguments are
|
||||||
|
// a. current password (32 bit password + 4 bit byte parity + 8 bit culommn parity + 0)
|
||||||
|
// 2. Write password arguments are
|
||||||
|
// a. new password (32 bit password + 4 bit byte parity + 8 bit culommn parity + 0)
|
||||||
|
// b. current password (32 bit password + 4 bit byte parity + 8 bit culommn parity + 0)
|
||||||
|
// 3. Write arguments are
|
||||||
|
// a. address (2 0s + 6 bit address + 1 bit parity)
|
||||||
|
// b. data (32 bit data + 4 bit byte parity + 8 bit culommn parity + 0)
|
||||||
|
// 4. Selective read arguments are
|
||||||
|
// a. First address (2 0s + 6 bit address + 1 bit parity)
|
||||||
|
// b. Last address (2 0s + 6 bit address + 1 bit parity)
|
||||||
|
// 5. Reset command has not arguments
|
||||||
|
|
||||||
|
struct em4x50_tag
|
||||||
|
{
|
||||||
|
int state;
|
||||||
|
int first_word;
|
||||||
|
int last_word;
|
||||||
|
byte_t data[34][4];
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct em4x50_tag tag = {
|
||||||
|
.state = EM4X50_STATE_READ,
|
||||||
|
.first_word = 0x20,
|
||||||
|
.last_word = 0x21,
|
||||||
|
.data = {
|
||||||
|
[0] = { 0x00, 0x00, 0x00, 0x00 }, // PASSWORD
|
||||||
|
[1] = { 0x00, 0x1F, 0x00, 0x00 }, // PROTECTION WORD
|
||||||
|
[2] = { 0x20, 0x20, 0x00, 0x00 }, // CONTROL WORD
|
||||||
|
[3] = { 0x01, 0x02, 0x03, 0x04 }, // User
|
||||||
|
[4] = { 0x05, 0x06, 0x07, 0x08 }, // User
|
||||||
|
[5] = { 0x09, 0x0A, 0x0B, 0x0C }, // User
|
||||||
|
[6] = { 0x0D, 0x0E, 0x0F, 0x00 }, // User
|
||||||
|
[7] = { 0x11, 0x12, 0x13, 0x14 }, // User
|
||||||
|
[8] = { 0x15, 0x16, 0x17, 0x18 }, // User
|
||||||
|
[9] = { 0x19, 0x1A, 0x1B, 0x1C }, // User
|
||||||
|
[10] = { 0x1D, 0x1E, 0x1F, 0x10 }, // User
|
||||||
|
[11] = { 0x21, 0x22, 0x23, 0x24 }, // User
|
||||||
|
[12] = { 0x25, 0x26, 0x27, 0x28 }, // User
|
||||||
|
[13] = { 0x29, 0x2A, 0x2B, 0x2C }, // User
|
||||||
|
[14] = { 0x2D, 0x2E, 0x2F, 0x20 }, // User
|
||||||
|
[15] = { 0x31, 0x32, 0x33, 0x34 }, // User
|
||||||
|
[16] = { 0x35, 0x36, 0x37, 0x38 }, // User
|
||||||
|
[17] = { 0x39, 0x3A, 0x3B, 0x3C }, // User
|
||||||
|
[18] = { 0x3D, 0x3E, 0x3F, 0x30 }, // User
|
||||||
|
[19] = { 0x41, 0x42, 0x43, 0x44 }, // User
|
||||||
|
[20] = { 0x45, 0x46, 0x47, 0x48 }, // User
|
||||||
|
[21] = { 0x49, 0x4A, 0x4B, 0x4C }, // User
|
||||||
|
[22] = { 0x4D, 0x4E, 0x4F, 0x40 }, // User
|
||||||
|
[23] = { 0x51, 0x52, 0x53, 0x54 }, // User
|
||||||
|
[24] = { 0x55, 0x56, 0x57, 0x58 }, // User
|
||||||
|
[25] = { 0x59, 0x5A, 0x5B, 0x5C }, // User
|
||||||
|
[26] = { 0x5D, 0x5E, 0x5F, 0x50 }, // User
|
||||||
|
[27] = { 0x61, 0x62, 0x63, 0x64 }, // User
|
||||||
|
[28] = { 0x65, 0x66, 0x67, 0x68 }, // User
|
||||||
|
[29] = { 0x69, 0x6A, 0x6B, 0x6C }, // User
|
||||||
|
[30] = { 0x6D, 0x6E, 0x6F, 0x60 }, // User
|
||||||
|
[31] = { 0x71, 0x72, 0x73, 0x74 }, // User
|
||||||
|
[32] = { 0x11, 0x22, 0x33, 0x44 }, // Serial number
|
||||||
|
[33] = { 0x55, 0x66, 0x77, 0x88 } // Device id
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static void em4x50_init()
|
||||||
|
{
|
||||||
|
tag.state = EM4X50_STATE_READ;
|
||||||
|
tag.first_word = tag.data[EM4x50_CONTROL][EM4x50_FIRST_WORD_READ_BYTE];
|
||||||
|
tag.last_word = tag.data[EM4x50_CONTROL][EM4x50_LAST_WORD_READ_BYTE];
|
||||||
|
}
|
||||||
|
|
||||||
|
static int em4x50_receive_bit()
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void em4x50_send_bit(int bit)
|
||||||
|
{
|
||||||
|
// Reset clock for the next bit
|
||||||
|
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
|
||||||
|
|
||||||
|
// Fixed modulation
|
||||||
|
if (bit == 0)
|
||||||
|
{
|
||||||
|
// Manchester: Unloaded, then loaded |__--|
|
||||||
|
LOW(GPIO_SSC_DOUT);
|
||||||
|
while (AT91C_BASE_TC0->TC_CV < T0*EM4x50_T_HALF_PERIOD);
|
||||||
|
HIGH(GPIO_SSC_DOUT);
|
||||||
|
while (AT91C_BASE_TC0->TC_CV < T0*EM4x50_T_FULL_PERIOD);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Manchester: Loaded, then unloaded |--__|
|
||||||
|
HIGH(GPIO_SSC_DOUT);
|
||||||
|
while (AT91C_BASE_TC0->TC_CV < T0*EM4x50_T_HALF_PERIOD);
|
||||||
|
LOW(GPIO_SSC_DOUT);
|
||||||
|
while (AT91C_BASE_TC0->TC_CV < T0*EM4x50_T_FULL_PERIOD);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void em4x50_send_byte(byte_t byte)
|
||||||
|
{
|
||||||
|
int mask = 0x80;
|
||||||
|
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
if ((byte & mask) == 0)
|
||||||
|
{
|
||||||
|
em4x50_send_bit(0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
em4x50_send_bit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
mask >>= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void em4x50_send_byte_with_parity(byte_t byte)
|
||||||
|
{
|
||||||
|
int parity = 0;
|
||||||
|
int mask = 0x80;
|
||||||
|
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
if ((byte & mask) == 0)
|
||||||
|
{
|
||||||
|
em4x50_send_bit(0);
|
||||||
|
parity ^= 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
em4x50_send_bit(1);
|
||||||
|
parity ^= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
mask >>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
em4x50_send_bit(parity);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void em4x50_send_word(int index)
|
||||||
|
{
|
||||||
|
int parity = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
em4x50_send_byte_with_parity(tag.data[index][i]);
|
||||||
|
|
||||||
|
parity ^= tag.data[index][i];
|
||||||
|
}
|
||||||
|
|
||||||
|
em4x50_send_byte(parity);
|
||||||
|
em4x50_send_bit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int em4x50_listen_one_bit(int *time, int *timestamp)
|
||||||
|
{
|
||||||
|
int bit = 1;
|
||||||
|
|
||||||
|
// 32 RF periods - high
|
||||||
|
*time += T0*EM4x50_T_HALF_PERIOD;
|
||||||
|
HIGH(GPIO_SSC_DOUT);
|
||||||
|
while (AT91C_BASE_TC0->TC_CV < *time);
|
||||||
|
|
||||||
|
// 32 RF periods - low
|
||||||
|
*time += T0*EM4x50_T_HALF_PERIOD;
|
||||||
|
LOW(GPIO_SSC_DOUT);
|
||||||
|
while (AT91C_BASE_TC0->TC_CV < *time);
|
||||||
|
|
||||||
|
return bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int em4x50_listen()
|
||||||
|
{
|
||||||
|
int period = 0;
|
||||||
|
int first_bit = 1;
|
||||||
|
int second_bit = 1;
|
||||||
|
int data_bit;
|
||||||
|
int parity_bit;
|
||||||
|
int command = EM4x50_COMMAND_BREAK;
|
||||||
|
bool command_is_valid = false;
|
||||||
|
int parity = 0;
|
||||||
|
int zero_falling_edge_time[2] = { -1, -1 };
|
||||||
|
int data_falling_edge_time[9] = { -1, -1, -1, -1, -1, -1, -1, -1, -1 };
|
||||||
|
|
||||||
|
// Reset clocks
|
||||||
|
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
|
||||||
|
|
||||||
|
// The listen window is composed of
|
||||||
|
// 32 RF periods - high
|
||||||
|
// 32 RF periods - low
|
||||||
|
// 128 RF periods - high
|
||||||
|
// 64 RF periods - low
|
||||||
|
// 64 RF periods - high
|
||||||
|
|
||||||
|
first_bit = em4x50_listen_one_bit(&period, &zero_falling_edge_time[0]);
|
||||||
|
if (first_bit == 0)
|
||||||
|
{
|
||||||
|
second_bit = em4x50_listen_one_bit(&period, &zero_falling_edge_time[1]);
|
||||||
|
if (second_bit == 0)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
data_bit = em4x50_listen_one_bit(&period, &data_falling_edge_time[i]);
|
||||||
|
command |= (data_bit << (7 - i));
|
||||||
|
parity ^= data_bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
parity_bit = em4x50_listen_one_bit(&period, &data_falling_edge_time[8]);
|
||||||
|
if (parity_bit == parity)
|
||||||
|
{
|
||||||
|
command_is_valid = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 128 RF periods - high
|
||||||
|
period += T0 * 2 * EM4x50_T_FULL_PERIOD;
|
||||||
|
HIGH(GPIO_SSC_DOUT);
|
||||||
|
while (AT91C_BASE_TC0->TC_CV < period);
|
||||||
|
|
||||||
|
// 64 RF periods - low
|
||||||
|
period += T0 * EM4x50_T_FULL_PERIOD;
|
||||||
|
LOW(GPIO_SSC_DOUT);
|
||||||
|
while (AT91C_BASE_TC0->TC_CV < period);
|
||||||
|
|
||||||
|
// 64 RF periods - high
|
||||||
|
period += T0 * EM4x50_T_FULL_PERIOD;
|
||||||
|
HIGH(GPIO_SSC_DOUT);
|
||||||
|
while (AT91C_BASE_TC0->TC_CV < period);
|
||||||
|
|
||||||
|
command = EM4x50_COMMAND_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (second_bit == 0)
|
||||||
|
{
|
||||||
|
if ((command_is_valid == false) || (command == EM4x50_COMMAND_NONE))
|
||||||
|
{
|
||||||
|
command = EM4x50_COMMAND_BREAK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void em4x50_send_ack()
|
||||||
|
{
|
||||||
|
int period;
|
||||||
|
|
||||||
|
// Reset clock
|
||||||
|
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
|
||||||
|
|
||||||
|
period = T0*EM4x50_T_HALF_PERIOD;
|
||||||
|
HIGH(GPIO_SSC_DOUT);
|
||||||
|
while (AT91C_BASE_TC0->TC_CV < period);
|
||||||
|
|
||||||
|
period += T0*EM4x50_T_HALF_PERIOD;
|
||||||
|
LOW(GPIO_SSC_DOUT);
|
||||||
|
while (AT91C_BASE_TC0->TC_CV < period);
|
||||||
|
|
||||||
|
period += T0 * 3 * EM4x50_T_HALF_PERIOD;
|
||||||
|
HIGH(GPIO_SSC_DOUT);
|
||||||
|
while (AT91C_BASE_TC0->TC_CV < period);
|
||||||
|
|
||||||
|
period += T0 * EM4x50_T_HALF_PERIOD;
|
||||||
|
LOW(GPIO_SSC_DOUT);
|
||||||
|
while (AT91C_BASE_TC0->TC_CV < period);
|
||||||
|
|
||||||
|
period += T0 * 3 * EM4x50_T_HALF_PERIOD;
|
||||||
|
HIGH(GPIO_SSC_DOUT);
|
||||||
|
while (AT91C_BASE_TC0->TC_CV < period);
|
||||||
|
|
||||||
|
period += T0 * EM4x50_T_HALF_PERIOD;
|
||||||
|
LOW(GPIO_SSC_DOUT);
|
||||||
|
while (AT91C_BASE_TC0->TC_CV < period);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void em4x50_send_nack()
|
||||||
|
{
|
||||||
|
int period;
|
||||||
|
|
||||||
|
// Reset clock
|
||||||
|
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
|
||||||
|
|
||||||
|
period = T0*EM4x50_T_HALF_PERIOD;
|
||||||
|
HIGH(GPIO_SSC_DOUT);
|
||||||
|
while (AT91C_BASE_TC0->TC_CV < period);
|
||||||
|
|
||||||
|
period += T0*EM4x50_T_HALF_PERIOD;
|
||||||
|
LOW(GPIO_SSC_DOUT);
|
||||||
|
while (AT91C_BASE_TC0->TC_CV < period);
|
||||||
|
|
||||||
|
period += T0 * 3 * EM4x50_T_HALF_PERIOD;
|
||||||
|
HIGH(GPIO_SSC_DOUT);
|
||||||
|
while (AT91C_BASE_TC0->TC_CV < period);
|
||||||
|
|
||||||
|
period += T0 * EM4x50_T_HALF_PERIOD;
|
||||||
|
LOW(GPIO_SSC_DOUT);
|
||||||
|
while (AT91C_BASE_TC0->TC_CV < period);
|
||||||
|
|
||||||
|
period += T0 * 3 * EM4x50_T_HALF_PERIOD;
|
||||||
|
HIGH(GPIO_SSC_DOUT);
|
||||||
|
while (AT91C_BASE_TC0->TC_CV < period);
|
||||||
|
|
||||||
|
period += T0 * EM4x50_T_HALF_PERIOD;
|
||||||
|
LOW(GPIO_SSC_DOUT);
|
||||||
|
while (AT91C_BASE_TC0->TC_CV < period);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void em4x50_handle_login_command()
|
||||||
|
{
|
||||||
|
bool done = false;
|
||||||
|
bool success = true;
|
||||||
|
int state = EM4X50_WAITING_FOR_DATA;
|
||||||
|
int in_state_bits = 0;
|
||||||
|
int data_bits = 0;
|
||||||
|
int password = 0;
|
||||||
|
int byte_parity = 0;
|
||||||
|
byte_t password_culomn_parity = 0;
|
||||||
|
byte_t culomn_parity = 0;
|
||||||
|
|
||||||
|
while ((success == true) && (done == false))
|
||||||
|
{
|
||||||
|
int bit = em4x50_receive_bit();
|
||||||
|
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case EM4X50_WAITING_FOR_DATA:
|
||||||
|
{
|
||||||
|
password <<= 1;
|
||||||
|
password |= bit;
|
||||||
|
byte_parity ^= bit;
|
||||||
|
in_state_bits++;
|
||||||
|
if (in_state_bits == 8)
|
||||||
|
{
|
||||||
|
password_culomn_parity ^= (byte_t)password;
|
||||||
|
|
||||||
|
data_bits += in_state_bits;
|
||||||
|
in_state_bits = 0;
|
||||||
|
|
||||||
|
state = EM4X50_WAITING_FOR_BYTE_PARITY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EM4X50_WAITING_FOR_BYTE_PARITY:
|
||||||
|
{
|
||||||
|
if (byte_parity == bit)
|
||||||
|
{
|
||||||
|
byte_parity = 0;
|
||||||
|
|
||||||
|
if (data_bits == 32)
|
||||||
|
{
|
||||||
|
state = EM4X50_WAITING_FOR_CULOMN_PARITY;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
state = EM4X50_WAITING_FOR_DATA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EM4X50_WAITING_FOR_CULOMN_PARITY:
|
||||||
|
{
|
||||||
|
culomn_parity <<= 1;
|
||||||
|
culomn_parity |= bit;
|
||||||
|
in_state_bits++;
|
||||||
|
if (in_state_bits == 8)
|
||||||
|
{
|
||||||
|
if (culomn_parity == password_culomn_parity)
|
||||||
|
{
|
||||||
|
state = EM4X50_WAITING_FOR_0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EM4X50_WAITING_FOR_0:
|
||||||
|
{
|
||||||
|
if (bit == 0)
|
||||||
|
{
|
||||||
|
done = true;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (success == false)
|
||||||
|
{
|
||||||
|
em4x50_send_nack();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
em4x50_send_ack();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for processing pause time
|
||||||
|
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
|
||||||
|
while (AT91C_BASE_TC0->TC_CV < EM4X50_T_PROCESSING_PAUSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void em4x50_handle_write_password_command()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void em4x50_handle_write_command()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void em4x50_handle_selective_read_command()
|
||||||
|
{
|
||||||
|
bool done = false;
|
||||||
|
bool success = true;
|
||||||
|
int state = EM4X50_WAITING_FOR_DATA;
|
||||||
|
int in_state_bits = 0;
|
||||||
|
byte_t first_address = 0;
|
||||||
|
byte_t last_address = 0;
|
||||||
|
byte_t *p_address = &first_address;
|
||||||
|
int byte_parity = 0;
|
||||||
|
|
||||||
|
while ((success == true) && (done == false))
|
||||||
|
{
|
||||||
|
int bit = em4x50_receive_bit();
|
||||||
|
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case EM4X50_WAITING_FOR_DATA:
|
||||||
|
{
|
||||||
|
(*p_address) <<= 1;
|
||||||
|
(*p_address) |= bit;
|
||||||
|
byte_parity ^= bit;
|
||||||
|
in_state_bits++;
|
||||||
|
if (in_state_bits == 8)
|
||||||
|
{
|
||||||
|
in_state_bits = 0;
|
||||||
|
|
||||||
|
state = EM4X50_WAITING_FOR_BYTE_PARITY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EM4X50_WAITING_FOR_BYTE_PARITY:
|
||||||
|
{
|
||||||
|
if (byte_parity == bit)
|
||||||
|
{
|
||||||
|
if (p_address == &first_address)
|
||||||
|
{
|
||||||
|
p_address = &last_address;
|
||||||
|
byte_parity = 0;
|
||||||
|
|
||||||
|
state = EM4X50_WAITING_FOR_DATA;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
done = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (success == false)
|
||||||
|
{
|
||||||
|
em4x50_send_nack();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
em4x50_send_ack();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for processing pause time
|
||||||
|
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
|
||||||
|
while (AT91C_BASE_TC0->TC_CV < EM4X50_T_PROCESSING_PAUSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void em4x50_handle_reset_command()
|
||||||
|
{
|
||||||
|
// Wait for processing pause time
|
||||||
|
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
|
||||||
|
while (AT91C_BASE_TC0->TC_CV < EM4X50_T_PROCESSING_PAUSE);
|
||||||
|
|
||||||
|
em4x50_init();
|
||||||
|
|
||||||
|
em4x50_send_ack();
|
||||||
|
|
||||||
|
// Wait for init time
|
||||||
|
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
|
||||||
|
while (AT91C_BASE_TC0->TC_CV < EM4X50_T_INIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimulateEM4x50Tag(bool tag_mem_supplied, byte_t* data)
|
||||||
|
{
|
||||||
|
int command;
|
||||||
|
|
||||||
|
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
|
||||||
|
|
||||||
|
// Clean up trace and prepare it for storing frames
|
||||||
|
set_tracing(TRUE);
|
||||||
|
clear_trace();
|
||||||
|
|
||||||
|
DbpString("Starting EM4x50 simulation");
|
||||||
|
LED_D_ON();
|
||||||
|
|
||||||
|
if (tag_mem_supplied)
|
||||||
|
{
|
||||||
|
DbpString("Loading EM4x50 memory...");
|
||||||
|
memcpy((byte_t*)tag.data, data, sizeof(tag.data));
|
||||||
|
em4x50_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
Dbprintf("Read mode %d -> %d", tag.first_word, tag.last_word);
|
||||||
|
|
||||||
|
// Set up simulator mode, frequency divisor which will drive the FPGA
|
||||||
|
// and analog mux selection.
|
||||||
|
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_READER_FIELD);
|
||||||
|
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
|
||||||
|
SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
|
||||||
|
RELAY_OFF();
|
||||||
|
|
||||||
|
// Configure output pin that is connected to the FPGA (for modulating)
|
||||||
|
AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT;
|
||||||
|
AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT;
|
||||||
|
|
||||||
|
// Disable modulation at default, which means release resistance
|
||||||
|
LOW(GPIO_SSC_DOUT);
|
||||||
|
|
||||||
|
// Enable Peripheral Clock for TIMER_CLOCK0, used to measure exact timing before answering
|
||||||
|
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0);
|
||||||
|
|
||||||
|
// Enable Peripheral Clock for TIMER_CLOCK1, used to capture edges of the reader frames
|
||||||
|
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1);
|
||||||
|
AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME;
|
||||||
|
|
||||||
|
// Enable timer
|
||||||
|
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
|
||||||
|
|
||||||
|
// Disable timer during configuration
|
||||||
|
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
|
||||||
|
// Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger,
|
||||||
|
// external trigger falling edge, load RA on falling edge of TIOA.
|
||||||
|
AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_ETRGEDG_FALLING | AT91C_TC_ABETRG | AT91C_TC_LDRA_FALLING;
|
||||||
|
|
||||||
|
while (!BUTTON_PRESS())
|
||||||
|
{
|
||||||
|
// Watchdog hit
|
||||||
|
WDT_HIT();
|
||||||
|
|
||||||
|
// The structure for each frame is
|
||||||
|
// LISTEN_WINDOW LISTEN_WINDOW FIRST_WORD LISTEN_WINDOW SECOND_WORD ...... LISTEN_WINDOW LAST_WORD
|
||||||
|
// i.e. it starts with a listen windows and then pairs of (listen window, data word).
|
||||||
|
// In read mode the range of transmitteed words is defined by the control register.
|
||||||
|
// During the listen window the transceiver can send commands to the em4x50 . The em4x50 will stop the frame transmission
|
||||||
|
// and will perform the command.
|
||||||
|
|
||||||
|
// Start a frame with a listen window.
|
||||||
|
command = em4x50_listen();
|
||||||
|
|
||||||
|
// If no command was received during the listen window, continue with the frame transmission.
|
||||||
|
if (command == EM4x50_COMMAND_NONE)
|
||||||
|
{
|
||||||
|
// Loop thought the [first_word..last_word] and transmit pairs of (listen window, data word).
|
||||||
|
for (int i = tag.first_word; i <= tag.last_word; i++)
|
||||||
|
{
|
||||||
|
// // Start a pair with a listen window.
|
||||||
|
command = em4x50_listen();
|
||||||
|
|
||||||
|
// If no command was received during the listen window, continue with the data word transmission.
|
||||||
|
if (command == EM4x50_COMMAND_NONE)
|
||||||
|
{
|
||||||
|
em4x50_send_word(i);
|
||||||
|
}
|
||||||
|
// If a command was received during the listen window, break the frame transmission.
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The transceiver can send a selective mode command and provide the first and last word to be transmitted. The em4x50 will send
|
||||||
|
// those words in the follwoing frame once and will return to read mode.
|
||||||
|
// If the current frame was transmitted in selective read state then the em4x50 should return to read mode.
|
||||||
|
if (tag.state == EM4X50_STATE_SELECTIVE_READ)
|
||||||
|
{
|
||||||
|
// Set the state to read mode.
|
||||||
|
tag.state = EM4X50_STATE_READ;
|
||||||
|
|
||||||
|
// Set the transmitted words range according to the control register.
|
||||||
|
tag.first_word = tag.data[EM4x50_CONTROL][EM4x50_FIRST_WORD_READ_BYTE];
|
||||||
|
tag.last_word = tag.data[EM4x50_CONTROL][EM4x50_LAST_WORD_READ_BYTE];
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a command was received during the frame
|
||||||
|
if (command != EM4x50_COMMAND_NONE)
|
||||||
|
{
|
||||||
|
switch (command)
|
||||||
|
{
|
||||||
|
case EM4x50_COMMAND_BREAK:
|
||||||
|
{
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EM4x50_COMMAND_LOGIN:
|
||||||
|
{
|
||||||
|
// Handle login command.
|
||||||
|
em4x50_handle_login_command();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EM4x50_COMMAND_WRITE_PASSWORD:
|
||||||
|
{
|
||||||
|
// Handle write password command.
|
||||||
|
em4x50_handle_write_password_command();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EM4x50_COMMAND_WRITE:
|
||||||
|
{
|
||||||
|
// Handle write command.
|
||||||
|
em4x50_handle_write_command();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EM4x50_COMMAND_SELECTIVE_READ:
|
||||||
|
{
|
||||||
|
// Handle selective command.
|
||||||
|
em4x50_handle_selective_read_command();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EM4x50_COMMAND_RESET:
|
||||||
|
{
|
||||||
|
// Handle reset command.
|
||||||
|
em4x50_handle_reset_command();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LED_D_OFF();
|
||||||
|
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
|
||||||
|
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||||
|
|
||||||
|
DbpString("Sim Stopped");
|
||||||
|
}
|
|
@ -498,6 +498,44 @@ int CmdEM4x50Read(const char *Cmd)
|
||||||
return EM4x50Read(Cmd, true);
|
return EM4x50Read(Cmd, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int CmdEM4x50Sim(const char *Cmd)
|
||||||
|
{
|
||||||
|
UsbCommand c = { CMD_SIMULATE_EM4x50 };
|
||||||
|
char filename[FILE_PATH_SIZE] = { 0x00 };
|
||||||
|
FILE* pf;
|
||||||
|
bool tag_mem_supplied;
|
||||||
|
int len = strlen(Cmd);
|
||||||
|
if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE;
|
||||||
|
memcpy(filename, Cmd, len);
|
||||||
|
|
||||||
|
if (strlen(filename) > 0)
|
||||||
|
{
|
||||||
|
if ((pf = fopen(filename, "rb+")) == NULL)
|
||||||
|
{
|
||||||
|
PrintAndLog("Error: Could not open file [%s]", filename);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
tag_mem_supplied = true;
|
||||||
|
if (fread(c.d.asBytes, 136, 1, pf) == 0)
|
||||||
|
{
|
||||||
|
PrintAndLog("Error: File reading error");
|
||||||
|
fclose(pf);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
fclose(pf);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tag_mem_supplied = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Does the tag comes with memory
|
||||||
|
c.arg[0] = (uint32_t)tag_mem_supplied;
|
||||||
|
|
||||||
|
SendCommand(&c);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int CmdReadWord(const char *Cmd)
|
int CmdReadWord(const char *Cmd)
|
||||||
{
|
{
|
||||||
int Word = -1; //default to invalid word
|
int Word = -1; //default to invalid word
|
||||||
|
@ -604,6 +642,7 @@ static command_t CommandTable[] =
|
||||||
{"em410xspoof", CmdEM410xWatchnSpoof, 0, "['h'] --- Watches for EM410x 125/134 kHz tags, and replays them. (option 'h' for 134)" },
|
{"em410xspoof", CmdEM410xWatchnSpoof, 0, "['h'] --- Watches for EM410x 125/134 kHz tags, and replays them. (option 'h' for 134)" },
|
||||||
{"em410xwrite", CmdEM410xWrite, 0, "<UID> <'0' T5555> <'1' T55x7> [clock rate] -- Write EM410x UID to T5555(Q5) or T55x7 tag, optionally setting clock rate"},
|
{"em410xwrite", CmdEM410xWrite, 0, "<UID> <'0' T5555> <'1' T55x7> [clock rate] -- Write EM410x UID to T5555(Q5) or T55x7 tag, optionally setting clock rate"},
|
||||||
{"em4x50read", CmdEM4x50Read, 1, "Extract data from EM4x50 tag"},
|
{"em4x50read", CmdEM4x50Read, 1, "Extract data from EM4x50 tag"},
|
||||||
|
{"em4x50sim", CmdEM4x50Sim, 0, "Simulates an EM4x50 tag"},
|
||||||
{"readword", CmdReadWord, 1, "<Word> -- Read EM4xxx word data"},
|
{"readword", CmdReadWord, 1, "<Word> -- Read EM4xxx word data"},
|
||||||
{"readwordPWD", CmdReadWordPWD, 1, "<Word> <Password> -- Read EM4xxx word data in password mode"},
|
{"readwordPWD", CmdReadWordPWD, 1, "<Word> <Password> -- Read EM4xxx word data in password mode"},
|
||||||
{"writeword", CmdWriteWord, 1, "<Data> <Word> -- Write EM4xxx word data"},
|
{"writeword", CmdWriteWord, 1, "<Data> <Word> -- Write EM4xxx word data"},
|
||||||
|
|
|
@ -87,6 +87,7 @@ typedef struct {
|
||||||
#define CMD_AWID_DEMOD_FSK 0x0221
|
#define CMD_AWID_DEMOD_FSK 0x0221
|
||||||
#define CMD_VIKING_CLONE_TAG 0x0223
|
#define CMD_VIKING_CLONE_TAG 0x0223
|
||||||
#define CMD_T55XX_WAKEUP 0x0224
|
#define CMD_T55XX_WAKEUP 0x0224
|
||||||
|
#define CMD_SIMULATE_EM4x50 0x0225
|
||||||
|
|
||||||
/* CMD_SET_ADC_MUX: ext1 is 0 for lopkd, 1 for loraw, 2 for hipkd, 3 for hiraw */
|
/* CMD_SET_ADC_MUX: ext1 is 0 for lopkd, 1 for loraw, 2 for hipkd, 3 for hiraw */
|
||||||
|
|
||||||
|
|
|
@ -101,7 +101,7 @@ typedef struct{
|
||||||
#define CMD_AWID_DEMOD_FSK 0x0221
|
#define CMD_AWID_DEMOD_FSK 0x0221
|
||||||
#define CMD_VIKING_CLONE_TAG 0x0223
|
#define CMD_VIKING_CLONE_TAG 0x0223
|
||||||
#define CMD_T55XX_WAKEUP 0x0224
|
#define CMD_T55XX_WAKEUP 0x0224
|
||||||
|
#define CMD_SIMULATE_EM4x50 0x0225
|
||||||
|
|
||||||
/* CMD_SET_ADC_MUX: ext1 is 0 for lopkd, 1 for loraw, 2 for hipkd, 3 for hiraw */
|
/* CMD_SET_ADC_MUX: ext1 is 0 for lopkd, 1 for loraw, 2 for hipkd, 3 for hiraw */
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue