mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-19 21:03:48 -07:00
hitag signal refactoring
This commit is contained in:
parent
d956e8c2a3
commit
89bae75c55
7 changed files with 523 additions and 340 deletions
|
@ -23,7 +23,7 @@ APP_CFLAGS = $(PLATFORM_DEFS) \
|
||||||
-DON_DEVICE \
|
-DON_DEVICE \
|
||||||
-fno-strict-aliasing -ffunction-sections -fdata-sections
|
-fno-strict-aliasing -ffunction-sections -fdata-sections
|
||||||
|
|
||||||
SRC_LF = lfops.c lfsampling.c pcf7931.c lfdemod.c
|
SRC_LF = lfops.c lfsampling.c pcf7931.c lfdemod.c lfadc.c
|
||||||
SRC_ISO15693 = iso15693.c iso15693tools.c
|
SRC_ISO15693 = iso15693.c iso15693tools.c
|
||||||
SRC_ISO14443a = iso14443a.c mifareutil.c mifarecmd.c epa.c mifaresim.c
|
SRC_ISO14443a = iso14443a.c mifareutil.c mifarecmd.c epa.c mifaresim.c
|
||||||
#UNUSED: mifaresniff.c desfire_crypto.c
|
#UNUSED: mifaresniff.c desfire_crypto.c
|
||||||
|
|
805
armsrc/hitag2.c
805
armsrc/hitag2.c
|
@ -17,6 +17,7 @@
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Piwi, 2019
|
// Piwi, 2019
|
||||||
// Iceman, 2019
|
// Iceman, 2019
|
||||||
|
// Anon, 2019
|
||||||
|
|
||||||
#include "hitag2.h"
|
#include "hitag2.h"
|
||||||
#include "hitag2_crypto.h"
|
#include "hitag2_crypto.h"
|
||||||
|
@ -28,12 +29,18 @@
|
||||||
#include "ticks.h"
|
#include "ticks.h"
|
||||||
#include "dbprint.h"
|
#include "dbprint.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "lfadc.h"
|
||||||
|
#include "lfsampling.h"
|
||||||
|
#include "lfdemod.h"
|
||||||
|
#include "commonutil.h"
|
||||||
|
|
||||||
// Successful crypto auth
|
// Successful crypto auth
|
||||||
static bool bCrypto;
|
static bool bCrypto;
|
||||||
// Is in auth stage
|
// Is in auth stage
|
||||||
static bool bAuthenticating;
|
static bool bAuthenticating;
|
||||||
// Successful password auth
|
// Successful password auth
|
||||||
|
bool bSelecting;
|
||||||
|
bool bCollision;
|
||||||
static bool bPwd;
|
static bool bPwd;
|
||||||
static bool bSuccessful;
|
static bool bSuccessful;
|
||||||
|
|
||||||
|
@ -52,6 +59,7 @@ static struct hitag2_tag tag = {
|
||||||
[9] = { 0x00, 0x00, 0x00, 0x00}, // RSK High
|
[9] = { 0x00, 0x00, 0x00, 0x00}, // RSK High
|
||||||
[10] = { 0x00, 0x00, 0x00, 0x00}, // RCF
|
[10] = { 0x00, 0x00, 0x00, 0x00}, // RCF
|
||||||
[11] = { 0x00, 0x00, 0x00, 0x00}, // SYNC
|
[11] = { 0x00, 0x00, 0x00, 0x00}, // SYNC
|
||||||
|
// up to index 15 reserved for HITAG1/HITAGS public data
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -73,6 +81,9 @@ static uint8_t password[4];
|
||||||
static uint8_t NrAr[8];
|
static uint8_t NrAr[8];
|
||||||
static uint8_t key[8];
|
static uint8_t key[8];
|
||||||
static uint8_t writedata[4];
|
static uint8_t writedata[4];
|
||||||
|
uint8_t logdata_0[4], logdata_1[4];
|
||||||
|
uint8_t nonce[4];
|
||||||
|
bool key_no;
|
||||||
static uint64_t cipher_state;
|
static uint64_t cipher_state;
|
||||||
|
|
||||||
static int hitag2_reset(void) {
|
static int hitag2_reset(void) {
|
||||||
|
@ -288,29 +299,26 @@ static void hitag2_handle_reader_command(uint8_t *rx, const size_t rxlen, uint8_
|
||||||
// sim
|
// sim
|
||||||
static void hitag_reader_send_bit(int bit) {
|
static void hitag_reader_send_bit(int bit) {
|
||||||
LED_A_ON();
|
LED_A_ON();
|
||||||
// Reset clock for the next bit
|
// Binary pulse length modulation (BPLM) is used to encode the data stream
|
||||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
|
|
||||||
|
|
||||||
// Binary puls 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
|
// This means that a transmission of a one takes longer than that of a zero
|
||||||
|
|
||||||
// Enable modulation, which means, drop the field
|
// Enable modulation, which means, drop the field
|
||||||
HIGH(GPIO_SSC_DOUT);
|
lf_modulation(true);
|
||||||
|
|
||||||
// Wait for 4-10 times the carrier period
|
// Wait for 4-10 times the carrier period
|
||||||
while (AT91C_BASE_TC0->TC_CV < T0 * 6) {};
|
lf_wait_periods(8); // wait for 4-10 times the carrier period
|
||||||
|
|
||||||
// Disable modulation, just activates the field again
|
// Disable modulation, just activates the field again
|
||||||
LOW(GPIO_SSC_DOUT);
|
lf_modulation(false);
|
||||||
|
|
||||||
if (bit == 0) {
|
if (bit == 0) {
|
||||||
// Zero bit: |_-|
|
// Zero bit: |_-|
|
||||||
while (AT91C_BASE_TC0->TC_CV < T0 * 22) {};
|
lf_wait_periods(12); // wait for 18-22 times the carrier period
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// One bit: |_--|
|
// One bit: |_--|
|
||||||
while (AT91C_BASE_TC0->TC_CV < T0 * 28) {};
|
lf_wait_periods(22); // wait for 26-32 times the carrier period
|
||||||
}
|
}
|
||||||
|
/*lf_wait_periods(10);*/
|
||||||
LED_A_OFF();
|
LED_A_OFF();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -320,18 +328,243 @@ static void hitag_reader_send_frame(const uint8_t *frame, size_t frame_len) {
|
||||||
for (size_t i = 0; i < frame_len; i++) {
|
for (size_t i = 0; i < frame_len; i++) {
|
||||||
hitag_reader_send_bit((frame[i / 8] >> (7 - (i % 8))) & 1);
|
hitag_reader_send_bit((frame[i / 8] >> (7 - (i % 8))) & 1);
|
||||||
}
|
}
|
||||||
// Send EOF
|
// Enable modulation, which means, drop the field
|
||||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
|
lf_modulation(true);
|
||||||
// Enable modulation, which means, drop the field
|
|
||||||
HIGH(GPIO_SSC_DOUT);
|
|
||||||
// Wait for 4-10 times the carrier period
|
// Wait for 4-10 times the carrier period
|
||||||
while (AT91C_BASE_TC0->TC_CV < T0 * 6) {};
|
lf_wait_periods(8);
|
||||||
// Disable modulation, just activates the field again
|
// Disable modulation, just activates the field again
|
||||||
LOW(GPIO_SSC_DOUT);
|
lf_modulation(false);
|
||||||
|
|
||||||
|
// t_stop, high field for stop condition (> 36)
|
||||||
|
lf_wait_periods(28);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t blocknr;
|
size_t blocknr;
|
||||||
|
|
||||||
|
uint8_t hitag_crc(uint8_t *data, size_t length){
|
||||||
|
uint8_t crc = 0xff;
|
||||||
|
unsigned int byte, bit;
|
||||||
|
for(byte=0; byte<((length+7)/8); byte++){
|
||||||
|
crc ^= *(data + byte);
|
||||||
|
bit = length < (8*(byte+1)) ? (length % 8) : 8;
|
||||||
|
while(bit--){
|
||||||
|
if(crc & 0x80){
|
||||||
|
crc<<=1;
|
||||||
|
crc ^= 0x1d;
|
||||||
|
} else {
|
||||||
|
crc<<=1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
#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)))
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hitag_plain(uint8_t* rx, const size_t rxlen, uint8_t* tx, size_t* txlen, bool hitag_s) {
|
||||||
|
uint8_t crc;
|
||||||
|
*txlen = 0;
|
||||||
|
switch (rxlen) {
|
||||||
|
case 0: {
|
||||||
|
// retry waking up card
|
||||||
|
/*tx[0] = 0xb0; // Rev 3.0*/
|
||||||
|
tx[0] = 0x30; // Rev 2.0
|
||||||
|
*txlen = 5;
|
||||||
|
if(!bCollision) blocknr--;
|
||||||
|
if(blocknr < 0) {
|
||||||
|
blocknr = 0;
|
||||||
|
}
|
||||||
|
if(!hitag_s){
|
||||||
|
if (blocknr > 1 && blocknr < 31) {
|
||||||
|
blocknr=31;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bCollision = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case 32: {
|
||||||
|
if(bCollision){
|
||||||
|
// Select card by serial from response
|
||||||
|
tx[0] = 0x00 | 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){
|
||||||
|
if (blocknr > 1 && blocknr < 31) {
|
||||||
|
blocknr=31;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (blocknr > 63) {
|
||||||
|
DbpString("Read succesful!");
|
||||||
|
*txlen = 0;
|
||||||
|
bSuccessful = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// read next page of card until done
|
||||||
|
Dbprintf("Reading page %02u", blocknr);
|
||||||
|
tx[0] = 0xc0 | 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("Uknown frame length: %d",rxlen);
|
||||||
|
return false;
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t flipped_bit = 0;
|
||||||
|
|
||||||
|
uint32_t byte_value = 0;
|
||||||
|
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] = 0x30; // Rev 2.0
|
||||||
|
*txlen = 5;
|
||||||
|
if (bCrypto && byte_value <= 0xff){
|
||||||
|
// to retry
|
||||||
|
bCrypto = false;
|
||||||
|
}
|
||||||
|
if(!bCollision) 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] = 0xe0 | 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] = 0x00 | 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] = 0xa0 | key_no >> 4; // 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 succesful!");
|
||||||
|
bSuccessful = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TEST
|
||||||
|
Dbprintf("Succesfully authenticated with logdata:");
|
||||||
|
Dbhexdump(4,logdata_1,false);
|
||||||
|
bSuccessful = true;
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// read next page of card until done
|
||||||
|
tx[0] = 0xe0 | 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("Uknown frame length: %d",rxlen);
|
||||||
|
return false;
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Hitag2 operations
|
// Hitag2 operations
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
@ -686,9 +919,11 @@ static bool hitag2_read_uid(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t
|
||||||
// Store the received block
|
// Store the received block
|
||||||
memcpy(tag.sectors[blocknr], rx, 4);
|
memcpy(tag.sectors[blocknr], rx, 4);
|
||||||
blocknr++;
|
blocknr++;
|
||||||
|
|
||||||
|
Dbhexdump(4, rx, false);
|
||||||
}
|
}
|
||||||
if (blocknr > 0) {
|
if (blocknr > 0) {
|
||||||
// DbpString("Read successful!");
|
DbpString("Read successful!");
|
||||||
bSuccessful = true;
|
bSuccessful = true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -705,21 +940,11 @@ static bool hitag2_read_uid(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hitag2 Sniffing
|
// Hitag2 Sniffing
|
||||||
void SniffHitag(void) {
|
void SniffHitag(uint32_t type) {
|
||||||
|
|
||||||
|
LEDsoff();
|
||||||
StopTicks();
|
StopTicks();
|
||||||
|
|
||||||
// int frame_count;
|
|
||||||
int response;
|
|
||||||
int overflow;
|
|
||||||
bool rising_edge;
|
|
||||||
bool reader_frame;
|
|
||||||
int lastbit;
|
|
||||||
bool bSkip;
|
|
||||||
int tag_sof;
|
|
||||||
uint8_t rx[HITAG_FRAME_LEN];
|
|
||||||
size_t rxlen = 0;
|
|
||||||
|
|
||||||
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
|
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
|
||||||
BigBuf_free();
|
BigBuf_free();
|
||||||
BigBuf_Clear_ext(false);
|
BigBuf_Clear_ext(false);
|
||||||
|
@ -735,143 +960,41 @@ void SniffHitag(void) {
|
||||||
DbpString("Starting Hitag2 sniffing");
|
DbpString("Starting Hitag2 sniffing");
|
||||||
LED_D_ON();
|
LED_D_ON();
|
||||||
|
|
||||||
// Set up eavesdropping mode, frequency divisor which will drive the FPGA
|
lf_init(false);
|
||||||
// and analog mux selection.
|
logging = false;
|
||||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_TOGGLE_MODE);
|
|
||||||
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_125);
|
|
||||||
SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
|
|
||||||
|
|
||||||
// Configure output pin that is connected to the FPGA (for modulating)
|
size_t periods = 0;
|
||||||
AT91C_BASE_PIOA->PIO_OER |= GPIO_SSC_DOUT;
|
uint8_t periods_bytes[4];
|
||||||
AT91C_BASE_PIOA->PIO_PER |= GPIO_SSC_DOUT;
|
|
||||||
|
|
||||||
// Disable modulation, we are going to eavesdrop, not modulate ;)
|
/*bool waiting_for_first_edge = true;*/
|
||||||
LOW(GPIO_SSC_DOUT);
|
LED_C_ON();
|
||||||
|
|
||||||
// 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;
|
|
||||||
|
|
||||||
// Disable timer during configuration
|
|
||||||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
|
|
||||||
|
|
||||||
// TC1: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger,
|
|
||||||
// external trigger rising edge, load RA on rising edge of TIOA.
|
|
||||||
AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_ETRGEDG_BOTH | AT91C_TC_ABETRG | AT91C_TC_LDRA_BOTH;
|
|
||||||
|
|
||||||
// Enable and reset counter
|
|
||||||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
|
|
||||||
|
|
||||||
// synchronized startup procedure
|
|
||||||
while (AT91C_BASE_TC1->TC_CV > 0) {}; // wait until TC1 returned to zero
|
|
||||||
|
|
||||||
// Reset the received frame, frame count and timing info
|
|
||||||
memset(rx, 0x00, sizeof(rx));
|
|
||||||
// frame_count = 0;
|
|
||||||
response = 0;
|
|
||||||
overflow = 0;
|
|
||||||
reader_frame = false;
|
|
||||||
lastbit = 1;
|
|
||||||
bSkip = true;
|
|
||||||
tag_sof = 4;
|
|
||||||
|
|
||||||
while (!BUTTON_PRESS() && !data_available()) {
|
while (!BUTTON_PRESS() && !data_available()) {
|
||||||
// Watchdog hit
|
|
||||||
WDT_HIT();
|
WDT_HIT();
|
||||||
|
|
||||||
// Receive frame, watch for at most T0*EOF periods
|
// Receive frame, watch for at most T0*EOF periods
|
||||||
while (AT91C_BASE_TC1->TC_CV < T0 * HITAG_T_EOF) {
|
lf_reset_counter();
|
||||||
// Check if rising edge in modulation is detected
|
|
||||||
if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) {
|
|
||||||
// Retrieve the new timing values
|
|
||||||
int ra = (AT91C_BASE_TC1->TC_RA / T0);
|
|
||||||
|
|
||||||
// Find out if we are dealing with a rising or falling edge
|
// Wait "infinite" for reader modulation
|
||||||
rising_edge = (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME) > 0;
|
periods = lf_detect_gap(20000);
|
||||||
|
|
||||||
// Shorter periods will only happen with reader frames
|
// Test if we detected the first reader modulation edge
|
||||||
if (!reader_frame && rising_edge && ra < HITAG_T_TAG_CAPTURE_ONE_HALF) {
|
if (periods != 0) {
|
||||||
// Switch from tag to reader capture
|
if (logging == false) {
|
||||||
LED_C_OFF();
|
logging = true;
|
||||||
reader_frame = true;
|
LED_D_ON();
|
||||||
memset(rx, 0x00, sizeof(rx));
|
|
||||||
rxlen = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only handle if reader frame and rising edge, or tag frame and falling edge
|
|
||||||
if (reader_frame != rising_edge) {
|
|
||||||
overflow += ra;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the buffered timing values of earlier captured edges which were skipped
|
|
||||||
ra += overflow;
|
|
||||||
overflow = 0;
|
|
||||||
|
|
||||||
if (reader_frame) {
|
|
||||||
LED_B_ON();
|
|
||||||
// Capture reader frame
|
|
||||||
if (ra >= HITAG_T_STOP) {
|
|
||||||
if (rxlen != 0) {
|
|
||||||
//DbpString("wierd0?");
|
|
||||||
}
|
|
||||||
// Capture the T0 periods that have passed since last communication or field drop (reset)
|
|
||||||
response = (ra - HITAG_T_LOW);
|
|
||||||
} else if (ra >= HITAG_T_1_MIN) {
|
|
||||||
// '1' bit
|
|
||||||
rx[rxlen / 8] |= 1 << (7 - (rxlen % 8));
|
|
||||||
rxlen++;
|
|
||||||
} else if (ra >= HITAG_T_0_MIN) {
|
|
||||||
// '0' bit
|
|
||||||
rx[rxlen / 8] |= 0 << (7 - (rxlen % 8));
|
|
||||||
rxlen++;
|
|
||||||
} else {
|
|
||||||
// Ignore wierd value, is to small to mean anything
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LED_C_ON();
|
|
||||||
// Capture tag frame (manchester decoding using only falling edges)
|
|
||||||
if (ra >= HITAG_T_EOF) {
|
|
||||||
if (rxlen != 0) {
|
|
||||||
//DbpString("wierd1?");
|
|
||||||
}
|
|
||||||
// Capture the T0 periods that have passed since last communication or field drop (reset)
|
|
||||||
// We always recieve a 'one' first, which has the falling edge after a half period |-_|
|
|
||||||
response = ra - HITAG_T_TAG_HALF_PERIOD;
|
|
||||||
} else if (ra >= 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 (ra >= 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) {
|
|
||||||
rx[rxlen / 8] |= 1 << (7 - (rxlen % 8));
|
|
||||||
rxlen++;
|
|
||||||
}
|
|
||||||
lastbit = !lastbit;
|
|
||||||
bSkip = !bSkip;
|
|
||||||
} else if (ra >= 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++;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Ignore wierd value, is to small to mean anything
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*lf_count_edge_periods(10000);*/
|
||||||
|
while ((periods = lf_detect_gap(64)) != 0){
|
||||||
|
num_to_bytes(periods, 4, periods_bytes);
|
||||||
|
LogTrace(periods_bytes, 4, 0, 0, NULL, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
// Check if frame was captured
|
// Check if frame was captured
|
||||||
if (rxlen > 0) {
|
if (rxlen > 0) {
|
||||||
// frame_count++;
|
// frame_count++;
|
||||||
|
@ -885,38 +1008,14 @@ void SniffHitag(void) {
|
||||||
auth_table_len += 8;
|
auth_table_len += 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
// Reset the received frame and response timing info
|
|
||||||
memset(rx, 0x00, sizeof(rx));
|
|
||||||
response = 0;
|
|
||||||
reader_frame = false;
|
|
||||||
lastbit = 1;
|
|
||||||
bSkip = true;
|
|
||||||
tag_sof = 4;
|
|
||||||
overflow = 0;
|
|
||||||
|
|
||||||
LED_B_OFF();
|
|
||||||
LED_C_OFF();
|
|
||||||
} else {
|
|
||||||
// Save the timer overflow, will be 0 when frame was received
|
|
||||||
overflow += (AT91C_BASE_TC1->TC_CV / T0);
|
|
||||||
}
|
|
||||||
// Reset the frame length
|
|
||||||
rxlen = 0;
|
|
||||||
// Reset the timer to restart while-loop that receives frames
|
|
||||||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG;
|
|
||||||
}
|
}
|
||||||
LEDsoff();
|
|
||||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
|
||||||
set_tracing(false);
|
|
||||||
|
|
||||||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
|
lf_finalize();
|
||||||
|
|
||||||
// release allocated memory from BigBuff.
|
|
||||||
BigBuf_free();
|
|
||||||
StartTicks();
|
StartTicks();
|
||||||
|
|
||||||
DbpString("Hitag2 sniffing end, use `lf hitag list` for annotations");
|
DbpString("Hitag2 sniffing finish. Use `lf hitag list` for annotations");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hitag2 simulation
|
// Hitag2 simulation
|
||||||
|
@ -1098,24 +1197,61 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
|
||||||
|
|
||||||
StopTicks();
|
StopTicks();
|
||||||
|
|
||||||
// int frame_count = 0;
|
int frame_count = 0;
|
||||||
int response = 0;
|
int response;
|
||||||
uint8_t rx[HITAG_FRAME_LEN];
|
uint8_t rx[HITAG_FRAME_LEN];
|
||||||
size_t rxlen = 0;
|
size_t rxlen = 0;
|
||||||
uint8_t txbuf[HITAG_FRAME_LEN];
|
uint8_t txbuf[HITAG_FRAME_LEN];
|
||||||
uint8_t *tx = txbuf;
|
uint8_t *tx = txbuf;
|
||||||
size_t txlen = 0;
|
size_t txlen = 0;
|
||||||
int lastbit = 1;
|
int t_wait_1;
|
||||||
bool bSkip;
|
int t_wait_2;
|
||||||
int reset_sof;
|
size_t tag_size;
|
||||||
int tag_sof;
|
bool bStop = false;
|
||||||
int t_wait = HITAG_T_WAIT_MAX;
|
|
||||||
bool bStop = false;
|
|
||||||
|
|
||||||
|
// Raw demodulation/decoding by sampling edge periods
|
||||||
|
size_t periods = 0;
|
||||||
|
|
||||||
|
// Reset the return status
|
||||||
bSuccessful = false;
|
bSuccessful = false;
|
||||||
|
bCrypto = false;
|
||||||
|
|
||||||
|
// Clean up trace and prepare it for storing frames
|
||||||
|
set_tracing(true);
|
||||||
|
clear_trace();
|
||||||
|
|
||||||
|
DbpString("Starting Hitag reader family");
|
||||||
|
|
||||||
// Check configuration
|
// Check configuration
|
||||||
switch (htf) {
|
switch (htf) {
|
||||||
|
case RHT1F_PLAIN: {
|
||||||
|
Dbprintf("Read public blocks in plain mode");
|
||||||
|
// this part will be unreadable
|
||||||
|
memset(tag.sectors+2, 0x0, 30);
|
||||||
|
blocknr = 0;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case RHT1F_AUTHENTICATE: {
|
||||||
|
Dbprintf("Read all blocks in authed mode");
|
||||||
|
memcpy(nonce, htd->ht1auth.nonce, 4);
|
||||||
|
memcpy(key, htd->ht1auth.key, 4);
|
||||||
|
memcpy(logdata_0, htd->ht1auth.logdata_0, 4);
|
||||||
|
memcpy(logdata_1, htd->ht1auth.logdata_1, 4);
|
||||||
|
// TEST
|
||||||
|
memset(nonce, 0x0, 4);
|
||||||
|
memset(logdata_1, 0x00, 4);
|
||||||
|
byte_value = 0;
|
||||||
|
key_no = htd->ht1auth.key_no;
|
||||||
|
Dbprintf("Authenticating using key #%d:", key_no);
|
||||||
|
Dbhexdump(4, key, false);
|
||||||
|
DbpString("Nonce:");
|
||||||
|
Dbhexdump(4, nonce, false);
|
||||||
|
DbpString("Logdata_0:");
|
||||||
|
Dbhexdump(4, logdata_0, false);
|
||||||
|
DbpString("Logdata_1:");
|
||||||
|
Dbhexdump(4, logdata_1, false);
|
||||||
|
blocknr = 0;
|
||||||
|
} break;
|
||||||
case RHT2F_PASSWORD: {
|
case RHT2F_PASSWORD: {
|
||||||
Dbprintf("List identifier in password mode");
|
Dbprintf("List identifier in password mode");
|
||||||
memcpy(password, htd->pwd.password, 4);
|
memcpy(password, htd->pwd.password, 4);
|
||||||
|
@ -1136,6 +1272,9 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
|
||||||
DbpString("Authenticating using key:");
|
DbpString("Authenticating using key:");
|
||||||
memcpy(key, htd->crypto.key, 6); //HACK; 4 or 6?? I read both in the code.
|
memcpy(key, htd->crypto.key, 6); //HACK; 4 or 6?? I read both in the code.
|
||||||
Dbhexdump(6, key, false);
|
Dbhexdump(6, key, false);
|
||||||
|
DbpString("Nonce:");
|
||||||
|
Dbhexdump(4,nonce,false);
|
||||||
|
memcpy(nonce,htd->crypto.data,4);
|
||||||
blocknr = 0;
|
blocknr = 0;
|
||||||
bCrypto = false;
|
bCrypto = false;
|
||||||
bAuthenticating = false;
|
bAuthenticating = false;
|
||||||
|
@ -1162,71 +1301,45 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
|
|
||||||
BigBuf_free();
|
|
||||||
clear_trace();
|
|
||||||
set_tracing(true);
|
|
||||||
|
|
||||||
LED_D_ON();
|
LED_D_ON();
|
||||||
hitag2_init();
|
hitag2_init();
|
||||||
|
|
||||||
|
// init as reader
|
||||||
|
lf_init(true);
|
||||||
|
|
||||||
// Set fpga in edge detect with reader field, we can modulate as reader now
|
uint8_t attempt_count = 0;
|
||||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_READER_FIELD);
|
|
||||||
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_125); //125kHz
|
|
||||||
SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
|
|
||||||
|
|
||||||
// Configure output and enable 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 enable the field
|
|
||||||
LOW(GPIO_SSC_DOUT);
|
|
||||||
|
|
||||||
// Enable Peripheral Clock for
|
|
||||||
// TIMER_CLOCK0, used to measure exact timing before answering
|
|
||||||
// TIMER_CLOCK1, used to capture edges of the tag frames
|
|
||||||
AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1);
|
|
||||||
|
|
||||||
// PIO_A - BSR
|
|
||||||
AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME;
|
|
||||||
|
|
||||||
// Disable timer during configuration
|
|
||||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
|
|
||||||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
|
|
||||||
|
|
||||||
// TC0: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), no triggers
|
|
||||||
AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK;
|
|
||||||
|
|
||||||
// TC1: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger,
|
|
||||||
// external trigger rising 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;
|
|
||||||
|
|
||||||
// Enable and reset counters
|
|
||||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
|
|
||||||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
|
|
||||||
|
|
||||||
// synchronized startup procedure
|
|
||||||
while (AT91C_BASE_TC0->TC_CV > 0) {}; // wait until TC0 returned to zero
|
|
||||||
|
|
||||||
// Tag specific configuration settings (sof, timings, etc.)
|
// Tag specific configuration settings (sof, timings, etc.)
|
||||||
if (htf < 10) {
|
if (htf < 10){
|
||||||
// hitagS settings
|
// hitagS settings
|
||||||
reset_sof = 1;
|
t_wait_1 = 204;
|
||||||
t_wait = 200;
|
t_wait_2 = 128;
|
||||||
|
/*tag_size = 256;*/
|
||||||
|
flipped_bit = 0;
|
||||||
|
tag_size = 8;
|
||||||
|
DbpString("Configured for hitagS reader");
|
||||||
} else if (htf < 20) {
|
} else if (htf < 20) {
|
||||||
// hitag1 settings
|
// hitag1 settings
|
||||||
reset_sof = 1;
|
t_wait_1 = 204;
|
||||||
t_wait = 200;
|
t_wait_2 = 128;
|
||||||
|
tag_size = 256;
|
||||||
|
flipped_bit = 0;
|
||||||
|
DbpString("Configured for hitag1 reader");
|
||||||
} else if (htf < 30) {
|
} else if (htf < 30) {
|
||||||
// hitag2 settings
|
// hitag2 settings
|
||||||
reset_sof = 4;
|
t_wait_1 = 206;
|
||||||
t_wait = HITAG_T_WAIT_2;
|
t_wait_2 = 90;
|
||||||
|
tag_size = 48;
|
||||||
|
DbpString("Configured for hitag2 reader");
|
||||||
} else {
|
} else {
|
||||||
Dbprintf("Error, unknown hitag reader type: %d", htf);
|
Dbprintf("Error, unknown hitag reader type: %d", htf);
|
||||||
goto out;
|
return;
|
||||||
}
|
}
|
||||||
uint8_t attempt_count = 0;
|
|
||||||
|
uint8_t tag_modulation;
|
||||||
|
size_t max_nrzs = 8 * HITAG_FRAME_LEN + 5;
|
||||||
|
uint8_t nrz_samples[max_nrzs];
|
||||||
|
size_t nrzs = 0;
|
||||||
|
|
||||||
while (!bStop && !BUTTON_PRESS() && !data_available()) {
|
while (!bStop && !BUTTON_PRESS() && !data_available()) {
|
||||||
|
|
||||||
|
@ -1234,13 +1347,23 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
|
||||||
|
|
||||||
// Check if frame was captured and store it
|
// Check if frame was captured and store it
|
||||||
if (rxlen > 0) {
|
if (rxlen > 0) {
|
||||||
// frame_count++;
|
frame_count++;
|
||||||
|
response++;
|
||||||
LogTrace(rx, nbytes(rxlen), response, response, NULL, false);
|
LogTrace(rx, nbytes(rxlen), response, response, NULL, false);
|
||||||
|
//Dbhexdump(nbytes(rxlen), rx, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// By default reset the transmission buffer
|
// By default reset the transmission buffer
|
||||||
tx = txbuf;
|
tx = txbuf;
|
||||||
switch (htf) {
|
switch (htf) {
|
||||||
|
case RHT1F_PLAIN: {
|
||||||
|
bStop = !hitag_plain(rx, rxlen, tx, &txlen, false);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case RHT1F_AUTHENTICATE: {
|
||||||
|
bStop = !hitag1_authenticate(rx, rxlen, tx, &txlen);
|
||||||
|
} break;
|
||||||
|
|
||||||
case RHT2F_PASSWORD: {
|
case RHT2F_PASSWORD: {
|
||||||
bStop = !hitag2_password(rx, rxlen, tx, &txlen, false);
|
bStop = !hitag2_password(rx, rxlen, tx, &txlen, false);
|
||||||
break;
|
break;
|
||||||
|
@ -1271,113 +1394,153 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send and store the reader command
|
// Wait for t_wait_2 carrier periods after the last tag bit before transmitting,
|
||||||
// Disable timer 1 with external trigger to avoid triggers during our own modulation
|
lf_wait_periods(t_wait_2);
|
||||||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
|
|
||||||
|
|
||||||
// Wait for HITAG_T_WAIT_2 carrier periods after the last tag bit before transmitting,
|
|
||||||
// Since the clock counts since the last falling edge, a 'one' means that the
|
|
||||||
// falling edge occurred halfway the period. with respect to this falling edge,
|
|
||||||
// we need to wait (T_Wait2 + half_tag_period) when the last was a 'one'.
|
|
||||||
// All timer values are in terms of T0 units
|
|
||||||
while (AT91C_BASE_TC0->TC_CV < T0 * (t_wait + (HITAG_T_TAG_HALF_PERIOD * lastbit)));
|
|
||||||
|
|
||||||
// Transmit the reader frame
|
// Transmit the reader frame
|
||||||
hitag_reader_send_frame(tx, txlen);
|
hitag_reader_send_frame(tx, txlen);
|
||||||
|
|
||||||
// Enable and reset external trigger in timer for capturing future frames
|
// Let the antenna and ADC values settle
|
||||||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
|
// And find the position where edge sampling should start
|
||||||
|
lf_wait_periods(t_wait_1 - 64);
|
||||||
|
|
||||||
// Add transmitted frame to total count
|
// Reset the response time (in number of periods)
|
||||||
|
response = 0;
|
||||||
|
|
||||||
|
// Keep administration of the first edge detection
|
||||||
|
bool waiting_for_first_edge = true;
|
||||||
|
|
||||||
|
// Did we detected any modulaiton at all
|
||||||
|
bool detected_tag_modulation = false;
|
||||||
|
|
||||||
|
// Use the current modulation state as starting point
|
||||||
|
tag_modulation = lf_get_tag_modulation();
|
||||||
|
|
||||||
|
// Reset the number of NRZ samples and use edge detection to detect them
|
||||||
|
nrzs = 0;
|
||||||
|
while (nrzs < max_nrzs) {
|
||||||
|
// Get the timing of the next edge in number of wave periods
|
||||||
|
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;
|
||||||
|
// Register the number of periods that have passed
|
||||||
|
response = t_wait_1-64 + periods;
|
||||||
|
// Indicate that we have dealt with the first edge
|
||||||
|
waiting_for_first_edge = false;
|
||||||
|
// 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) {
|
||||||
|
Dbprintf("Detected timeout after [%d] nrz samples",nrzs);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 __|)
|
||||||
|
nrz_samples[nrzs++] = tag_modulation;
|
||||||
|
nrz_samples[nrzs++] = tag_modulation;
|
||||||
|
// 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;
|
||||||
|
tag_modulation ^= 1;
|
||||||
|
} else {
|
||||||
|
tag_modulation ^= 1;
|
||||||
|
// The function lf_count_edge_periods() returns > 64 periods, this is not a valid number periods
|
||||||
|
Dbprintf("Detected unexpected period count: %d", periods);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
if (txlen > 0) {
|
if (txlen > 0) {
|
||||||
// frame_count++;
|
frame_count++;
|
||||||
LogTrace(tx, nbytes(txlen), HITAG_T_WAIT_2, HITAG_T_WAIT_2, NULL, true);
|
LogTrace(tx, nbytes(txlen), HITAG_T_WAIT_2, HITAG_T_WAIT_2, NULL, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset values for receiving frames
|
// Reset values for receiving frames
|
||||||
memset(rx, 0x00, sizeof(rx));
|
memset(rx, 0x00, sizeof(rx));
|
||||||
rxlen = 0;
|
rxlen = 0;
|
||||||
lastbit = 1;
|
|
||||||
bSkip = true;
|
|
||||||
tag_sof = reset_sof;
|
|
||||||
response = 0;
|
|
||||||
uint32_t errorCount = 0;
|
|
||||||
|
|
||||||
// Receive frame, watch for at most T0*EOF periods
|
// If there is no response, just repeat the loop
|
||||||
while (AT91C_BASE_TC1->TC_CV < T0 * HITAG_T_WAIT_MAX) {
|
if (!detected_tag_modulation) continue;
|
||||||
|
|
||||||
// Check if falling edge in tag modulation is detected
|
// Make sure we always have an even number of samples. This fixes the problem
|
||||||
if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) {
|
// of ending the manchester decoding with a zero. See the example below where
|
||||||
// Retrieve the new timing values
|
// the '|' character is end of modulation
|
||||||
int ra = (AT91C_BASE_TC1->TC_RA / T0);
|
// 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 ((nrzs % 2) != 0) {
|
||||||
|
nrz_samples[nrzs++] = tag_modulation;
|
||||||
|
}
|
||||||
|
|
||||||
// Reset timer every frame, we have to capture the last edge for timing
|
LED_B_ON();
|
||||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
|
|
||||||
|
|
||||||
LED_B_ON();
|
// decode bitstream
|
||||||
|
manrawdecode((uint8_t*)nrz_samples, &nrzs, true, 0);
|
||||||
|
|
||||||
// Capture tag frame (manchester decoding using only falling edges)
|
// decode frame
|
||||||
if (ra >= HITAG_T_EOF) {
|
|
||||||
// Capture the T0 periods that have passed since last communication or field drop (reset)
|
// Verify if the header consists of five consecutive ones
|
||||||
// We always recieve a 'one' first, which has the falling edge after a half period |-_|
|
if (nrzs < 5) {
|
||||||
response = ra - HITAG_T_TAG_HALF_PERIOD;
|
Dbprintf("Detected unexpected number of manchester decoded samples [%d]",nrzs);
|
||||||
} else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) {
|
break;
|
||||||
// Manchester coding example |-_|_-|-_| (101)
|
} else {
|
||||||
rx[rxlen / 8] |= 0 << (7 - (rxlen % 8));
|
for (size_t i = 0; i < 5; i++){
|
||||||
rxlen++;
|
if (nrz_samples[i] != 1) {
|
||||||
rx[rxlen / 8] |= 1 << (7 - (rxlen % 8));
|
Dbprintf("Detected incorrect header, the bit [%d] is zero instead of one",i);
|
||||||
rxlen++;
|
|
||||||
} else if (ra >= 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) {
|
|
||||||
rx[rxlen / 8] |= 1 << (7 - (rxlen % 8));
|
|
||||||
rxlen++;
|
|
||||||
}
|
|
||||||
lastbit = !lastbit;
|
|
||||||
bSkip = !bSkip;
|
|
||||||
} else if (ra >= 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++;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
errorCount++;
|
|
||||||
// Ignore wierd value, is to small to mean anything
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//if we saw over 100 wierd values break it probably isn't hitag...
|
|
||||||
if (errorCount > 100) break;
|
|
||||||
// We can break this loop if we received the last bit from a frame
|
|
||||||
if (AT91C_BASE_TC1->TC_CV > T0 * HITAG_T_EOF) {
|
|
||||||
if (rxlen > 0) break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// Pack the response into a byte array
|
||||||
|
for (size_t i = 5; i < 37; i++){
|
||||||
|
uint8_t bit = nrz_samples[i];
|
||||||
|
rx[rxlen / 8] |= bit << (7 - (rxlen % 8));
|
||||||
|
rxlen++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if frame was captured and store it
|
||||||
|
if (rxlen > 0) {
|
||||||
|
frame_count++;
|
||||||
|
if (bCollision){
|
||||||
|
// AC decoding hack
|
||||||
|
fix_ac_decoding(rx, 64);
|
||||||
|
rxlen = 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogTrace(rx, rxlen, response, 0, NULL, false);
|
||||||
|
//Dbhexdump(rxlen, rx, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
LEDsoff();
|
lf_finalize();
|
||||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
Dbprintf("frame received: %u", frame_count);
|
||||||
set_tracing(false);
|
|
||||||
|
|
||||||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
|
|
||||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
|
|
||||||
|
|
||||||
// release allocated memory from BigBuff.
|
// release allocated memory from BigBuff.
|
||||||
BigBuf_free();
|
BigBuf_free();
|
||||||
StartTicks();
|
StartTicks();
|
||||||
|
|
||||||
if (bSuccessful)
|
if (bSuccessful)
|
||||||
reply_old(CMD_ACK, bSuccessful, 0, 0, (uint8_t *)tag.sectors, 48);
|
reply_old(CMD_ACK, bSuccessful, 0, 0, (uint8_t *)tag.sectors, tag_size);
|
||||||
else
|
else
|
||||||
reply_old(CMD_ACK, bSuccessful, 0, 0, 0, 0);
|
reply_mix(CMD_ACK, bSuccessful, 0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriterHitag(hitag_function htf, hitag_data *htd, int page) {
|
void WriterHitag(hitag_function htf, hitag_data *htd, int page) {
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "hitag.h"
|
#include "hitag.h"
|
||||||
|
|
||||||
void SniffHitag(void);
|
void SniffHitag(uint32_t type);
|
||||||
void SimulateHitagTag(bool tag_mem_supplied, uint8_t *data);
|
void SimulateHitagTag(bool tag_mem_supplied, uint8_t *data);
|
||||||
void ReaderHitag(hitag_function htf, hitag_data *htd);
|
void ReaderHitag(hitag_function htf, hitag_data *htd);
|
||||||
void WriterHitag(hitag_function htf, hitag_data *htd, int page);
|
void WriterHitag(hitag_function htf, hitag_data *htd, int page);
|
||||||
|
|
|
@ -168,7 +168,9 @@ void lf_init(bool reader) {
|
||||||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
|
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
|
||||||
|
|
||||||
// Prepare data trace
|
// Prepare data trace
|
||||||
if (logging) initSampleBuffer(NULL);
|
uint32_t bufsize = 20000;
|
||||||
|
|
||||||
|
if (logging) initSampleBuffer(&bufsize);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -106,17 +106,23 @@ sampling_t samples = {0, 0, 0, 0};
|
||||||
|
|
||||||
void initSampleBuffer(uint32_t *sample_size) {
|
void initSampleBuffer(uint32_t *sample_size) {
|
||||||
|
|
||||||
|
BigBuf_free();
|
||||||
|
BigBuf_Clear_ext(false);
|
||||||
|
|
||||||
if (sample_size == NULL || *sample_size == 0) {
|
if (sample_size == NULL || *sample_size == 0) {
|
||||||
*sample_size = BigBuf_max_traceLen();
|
*sample_size = BigBuf_max_traceLen();
|
||||||
|
|
||||||
|
data.buffer = BigBuf_get_addr();
|
||||||
|
|
||||||
|
memset(data.buffer, 0, *sample_size);
|
||||||
} else {
|
} else {
|
||||||
*sample_size = MIN(*sample_size, BigBuf_max_traceLen());
|
*sample_size = MIN(*sample_size, BigBuf_max_traceLen());
|
||||||
|
|
||||||
|
data.buffer = BigBuf_malloc(*sample_size);
|
||||||
|
|
||||||
|
memset(data.buffer, 0, *sample_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// use a bitstream to handle the output
|
|
||||||
data.buffer = BigBuf_get_addr();
|
|
||||||
|
|
||||||
memset(data.buffer, 0, *sample_size);
|
|
||||||
|
|
||||||
//
|
//
|
||||||
samples.dec_counter = 0;
|
samples.dec_counter = 0;
|
||||||
samples.sum = 0;
|
samples.sum = 0;
|
||||||
|
|
|
@ -485,8 +485,9 @@ static int CmdLFHitagInfo(const char *Cmd) {
|
||||||
if (getHitagUid(&uid) == false)
|
if (getHitagUid(&uid) == false)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, "UID: %08X", uid);
|
PrintAndLogEx(SUCCESS, "UID: " _YELLOW_("%08X"), uid);
|
||||||
|
|
||||||
|
return PM3_SUCCESS;
|
||||||
// how to detemine Hitag types?
|
// how to detemine Hitag types?
|
||||||
// read block3, get configuration byte.
|
// read block3, get configuration byte.
|
||||||
PrintAndLogEx(FAILED, _RED_("TODO: This is a hardcoded example!"));
|
PrintAndLogEx(FAILED, _RED_("TODO: This is a hardcoded example!"));
|
||||||
|
@ -497,7 +498,7 @@ static int CmdLFHitagInfo(const char *Cmd) {
|
||||||
//printHitagConfiguration( 0x02 );
|
//printHitagConfiguration( 0x02 );
|
||||||
//printHitagConfiguration( 0x00 );
|
//printHitagConfiguration( 0x00 );
|
||||||
//printHitagConfiguration( 0x04 );
|
//printHitagConfiguration( 0x04 );
|
||||||
return 0;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: iceman
|
// TODO: iceman
|
||||||
|
@ -564,7 +565,7 @@ static int CmdLFHitagReader(const char *Cmd) {
|
||||||
|
|
||||||
uint32_t id = bytes_to_num(resp.data.asBytes, 4);
|
uint32_t id = bytes_to_num(resp.data.asBytes, 4);
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, "Valid Hitag2 tag found - UID: %08x", id);
|
PrintAndLogEx(SUCCESS, "Valid Hitag2 tag found - UID: " _YELLOW_("%08x"), id);
|
||||||
if (htf != RHT2F_UID_ONLY) {
|
if (htf != RHT2F_UID_ONLY) {
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, "Dumping tag memory...");
|
PrintAndLogEx(SUCCESS, "Dumping tag memory...");
|
||||||
|
|
|
@ -21,6 +21,8 @@ typedef enum {
|
||||||
RHTSF_KEY = 02,
|
RHTSF_KEY = 02,
|
||||||
WHTSF_CHALLENGE = 03,
|
WHTSF_CHALLENGE = 03,
|
||||||
WHTSF_KEY = 04,
|
WHTSF_KEY = 04,
|
||||||
|
RHT1F_PLAIN = 11,
|
||||||
|
RHT1F_AUTHENTICATE = 12,
|
||||||
RHT2F_PASSWORD = 21,
|
RHT2F_PASSWORD = 21,
|
||||||
RHT2F_AUTHENTICATE = 22,
|
RHT2F_AUTHENTICATE = 22,
|
||||||
RHT2F_CRYPTO = 23,
|
RHT2F_CRYPTO = 23,
|
||||||
|
@ -44,8 +46,17 @@ typedef struct {
|
||||||
uint8_t data[4];
|
uint8_t data[4];
|
||||||
} PACKED rht2d_crypto;
|
} PACKED rht2d_crypto;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool key_no;
|
||||||
|
uint8_t logdata_0[4];
|
||||||
|
uint8_t logdata_1[4];
|
||||||
|
uint8_t nonce[4];
|
||||||
|
uint8_t key[4];
|
||||||
|
} PACKED rht1d_authenticate;
|
||||||
|
|
||||||
typedef union {
|
typedef union {
|
||||||
rht2d_password pwd;
|
rht2d_password pwd;
|
||||||
|
rht1d_authenticate ht1auth;
|
||||||
rht2d_authenticate auth;
|
rht2d_authenticate auth;
|
||||||
rht2d_crypto crypto;
|
rht2d_crypto crypto;
|
||||||
} hitag_data;
|
} hitag_data;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue