Instantly share code, notes, and snippets.
-
Star
(0)
0
You must be signed in to star a gist -
Fork
(0)
0
You must be signed in to fork a gist
-
Save bosb/ce82dc6569ee16fccdfe4dbd8d8dac93 to your computer and use it in GitHub Desktop.
tag bins
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//----------------------------------------------------------------------------- | |
// This code is licensed to you under the terms of the GNU GPL, version 2 or, | |
// at your option, any later version. See the LICENSE.txt file for the text of | |
// the license. | |
//----------------------------------------------------------------------------- | |
// HitagS emulation (preliminary test version) | |
// | |
// (c) 2016 Oguzhan Cicek, Hendrik Schwartke, Ralf Spenneberg | |
// <info@os-s.de> | |
//----------------------------------------------------------------------------- | |
// Some code was copied from Hitag2.c | |
//----------------------------------------------------------------------------- | |
#include "hitagS.h" | |
#include "proxmark3_arm.h" | |
#include "cmd.h" | |
#include "BigBuf.h" | |
#include "fpgaloader.h" | |
#include "ticks.h" | |
#include "dbprint.h" | |
#include "util.h" | |
#include "string.h" | |
#include "commonutil.h" | |
#include "hitag2_crypto.h" | |
#define CRC_PRESET 0xFF | |
#define CRC_POLYNOM 0x1D | |
static bool bQuiet; | |
static bool bSuccessful; | |
static struct hitagS_tag tag; | |
static uint8_t page_to_be_written = 0; | |
static int block_data_left = 0; | |
typedef enum modulation { | |
AC2K = 0, | |
AC4K, | |
MC4K, | |
MC8K | |
} MOD; | |
static MOD m = AC2K; // used modulation | |
static uint32_t temp_uid; | |
static int temp2 = 0; | |
static int sof_bits; // number of start-of-frame bits | |
static uint8_t pwdh0, pwdl0, pwdl1; // password bytes | |
static uint32_t rnd = 0x74124485; // randomnumber | |
static int nochmal = 0; | |
static uint8_t tx2[10]; | |
size_t blocknr; | |
bool end = false; | |
//#define SENDBIT_TEST | |
#define ht2bs_4a(a,b,c,d) (~(((a|b)&c)^(a|d)^b)) | |
#define ht2bs_4b(a,b,c,d) (~(((d|c)&(a^b))^(d|a|b))) | |
#define ht2bs_5c(a,b,c,d,e) (~((((((c^e)|d)&a)^b)&(c^b))^(((d^e)|a)&((d^b)|c)))) | |
// 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 | |
#ifndef T0 | |
#define T0 192 | |
#endif | |
#define HITAG_FRAME_LEN 20 | |
#define HITAG_T_STOP 36 /* T_EOF should be > 36 */ | |
#define HITAG_T_LOW 8 /* T_LOW should be 4..10 */ | |
#define HITAG_T_0_MIN 15 /* T[0] should be 18..22 */ | |
#define HITAG_T_1_MIN 25 /* T[1] should be 26..30 */ | |
//#define HITAG_T_EOF 40 /* T_EOF should be > 36 */ | |
#define HITAG_T_EOF 80 /* T_EOF should be > 36 */ | |
#define HITAG_T_WAIT_1 200 /* T_wresp should be 199..206 */ | |
#define HITAG_T_WAIT_2 90 /* T_wresp should be 199..206 */ | |
#define HITAG_T_WAIT_MAX 300 /* bit more than HITAG_T_WAIT_1 + HITAG_T_WAIT_2 */ | |
#define HITAG_T_TAG_ONE_HALF_PERIOD 10 | |
#define HITAG_T_TAG_TWO_HALF_PERIOD 25 | |
#define HITAG_T_TAG_THREE_HALF_PERIOD 41 | |
#define HITAG_T_TAG_FOUR_HALF_PERIOD 57 | |
#define HITAG_T_TAG_HALF_PERIOD 16 | |
#define HITAG_T_TAG_FULL_PERIOD 32 | |
#define HITAG_T_TAG_CAPTURE_ONE_HALF 13 | |
#define HITAG_T_TAG_CAPTURE_TWO_HALF 25 | |
#define HITAG_T_TAG_CAPTURE_THREE_HALF 41 | |
#define HITAG_T_TAG_CAPTURE_FOUR_HALF 57 | |
#define DEBUG 1 | |
/* | |
* Implementation of the crc8 calculation from Hitag S | |
* from http://www.proxmark.org/files/Documents/125%20kHz%20-%20Hitag/HitagS.V11.pdf | |
*/ | |
void calc_crc(unsigned char *crc, unsigned char data, unsigned char Bitcount) { | |
*crc ^= data; // crc = crc (exor) data | |
do { | |
if (*crc & 0x80) { // if (MSB-CRC == 1) | |
*crc <<= 1; // CRC = CRC Bit-shift left | |
*crc ^= CRC_POLYNOM; // CRC = CRC (exor) CRC_POLYNOM | |
} else { | |
*crc <<= 1; // CRC = CRC Bit-shift left | |
} | |
} while (--Bitcount); | |
} | |
static void hitag_send_bit(int bit) { | |
LED_A_ON(); | |
// Reset clock for the next bit | |
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; | |
switch (m) { | |
case AC2K: | |
if (bit == 0) { | |
// AC Coding --__ | |
HIGH(GPIO_SSC_DOUT); | |
while (AT91C_BASE_TC0->TC_CV < T0 * 32) {}; | |
LOW(GPIO_SSC_DOUT); | |
while (AT91C_BASE_TC0->TC_CV < T0 * 64) {}; | |
} else { | |
// AC coding -_-_ | |
HIGH(GPIO_SSC_DOUT); | |
while (AT91C_BASE_TC0->TC_CV < T0 * 16) {}; | |
LOW(GPIO_SSC_DOUT); | |
while (AT91C_BASE_TC0->TC_CV < T0 * 32) {}; | |
HIGH(GPIO_SSC_DOUT); | |
while (AT91C_BASE_TC0->TC_CV < T0 * 48) {}; | |
LOW(GPIO_SSC_DOUT); | |
while (AT91C_BASE_TC0->TC_CV < T0 * 64) {}; | |
} | |
LED_A_OFF(); | |
break; | |
case AC4K: | |
if (bit == 0) { | |
// AC Coding --__ | |
HIGH(GPIO_SSC_DOUT); | |
while (AT91C_BASE_TC0->TC_CV < T0 * HITAG_T_TAG_HALF_PERIOD) {}; | |
LOW(GPIO_SSC_DOUT); | |
while (AT91C_BASE_TC0->TC_CV < T0 * HITAG_T_TAG_FULL_PERIOD) {}; | |
} else { | |
// AC coding -_-_ | |
HIGH(GPIO_SSC_DOUT); | |
while (AT91C_BASE_TC0->TC_CV < T0 * 8) {}; | |
LOW(GPIO_SSC_DOUT); | |
while (AT91C_BASE_TC0->TC_CV < T0 * 16) {}; | |
HIGH(GPIO_SSC_DOUT); | |
while (AT91C_BASE_TC0->TC_CV < T0 * 24) {}; | |
LOW(GPIO_SSC_DOUT); | |
while (AT91C_BASE_TC0->TC_CV < T0 * 32) {}; | |
} | |
LED_A_OFF(); | |
break; | |
case MC4K: | |
if (bit == 0) { | |
// Manchester: Unloaded, then loaded |__--| | |
LOW(GPIO_SSC_DOUT); | |
while (AT91C_BASE_TC0->TC_CV < T0 * 16) {}; | |
HIGH(GPIO_SSC_DOUT); | |
while (AT91C_BASE_TC0->TC_CV < T0 * 32) {}; | |
} else { | |
// Manchester: Loaded, then unloaded |--__| | |
HIGH(GPIO_SSC_DOUT); | |
while (AT91C_BASE_TC0->TC_CV < T0 * 16) {}; | |
LOW(GPIO_SSC_DOUT); | |
while (AT91C_BASE_TC0->TC_CV < T0 * 32) {}; | |
} | |
LED_A_OFF(); | |
break; | |
case MC8K: | |
if (bit == 0) { | |
// Manchester: Unloaded, then loaded |__--| | |
LOW(GPIO_SSC_DOUT); | |
while (AT91C_BASE_TC0->TC_CV < T0 * 8) {}; | |
HIGH(GPIO_SSC_DOUT); | |
while (AT91C_BASE_TC0->TC_CV < T0 * 16) {}; | |
} else { | |
// Manchester: Loaded, then unloaded |--__| | |
HIGH(GPIO_SSC_DOUT); | |
while (AT91C_BASE_TC0->TC_CV < T0 * 8) {}; | |
LOW(GPIO_SSC_DOUT); | |
while (AT91C_BASE_TC0->TC_CV < T0 * 16) {}; | |
} | |
LED_A_OFF(); | |
break; | |
default: | |
break; | |
} | |
} | |
static void hitag_send_frame(const uint8_t *frame, size_t frame_len) { | |
// SOF - send start of frame | |
for (size_t i = 0; i < sof_bits; i++) { | |
hitag_send_bit(1); | |
} | |
// Send the content of the frame | |
for (size_t i = 0; i < frame_len; i++) { | |
hitag_send_bit((frame[i / 8] >> (7 - (i % 8))) & 1); | |
} | |
LOW(GPIO_SSC_DOUT); | |
} | |
static void hitag_reader_send_bit(int bit) { | |
LED_A_ON(); | |
// Reset clock for the next bit | |
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 | |
HIGH(GPIO_SSC_DOUT); | |
#ifdef SENDBIT_TEST | |
// Wait for 4-10 times the carrier period | |
while (AT91C_BASE_TC0->TC_CV < T0 * 6) {}; | |
LOW(GPIO_SSC_DOUT); | |
if (bit == 0) { | |
// Zero bit: |_-| | |
while (AT91C_BASE_TC0->TC_CV < T0 * 11) {}; | |
} else { | |
// One bit: |_--| | |
while (AT91C_BASE_TC0->TC_CV < T0 * 14) {}; | |
} | |
#else | |
// Wait for 4-10 times the carrier period | |
while (AT91C_BASE_TC0->TC_CV < T0 * 6) {}; | |
LOW(GPIO_SSC_DOUT); | |
if (bit == 0) { | |
// Zero bit: |_-| | |
while (AT91C_BASE_TC0->TC_CV < T0 * 22) {}; | |
} else { | |
// One bit: |_--| | |
while (AT91C_BASE_TC0->TC_CV < T0 * 28) {}; | |
} | |
#endif | |
LED_A_OFF(); | |
} | |
static void hitag_reader_send_frame(const uint8_t *frame, size_t frame_len) { | |
//if (frame_len > 0) | |
//Dbprintf("hitag_reader_send_frame: %i - 0x%02x 0x%02x",frame_len,frame[0],frame[1]); | |
// Send the content of the frame | |
for (size_t i = 0; i < frame_len; i++) { | |
// if (frame[0] == 0xf8) { | |
//Dbprintf("BIT: %d",(frame[i / 8] >> (7 - (i % 8))) & 1); | |
// } | |
hitag_reader_send_bit((frame[i / 8] >> (7 - (i % 8))) & 1); | |
} | |
// send EOF | |
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; | |
HIGH(GPIO_SSC_DOUT); | |
// Wait for 4-10 times the carrier period | |
while (AT91C_BASE_TC0->TC_CV < T0 * 6) {}; | |
LOW(GPIO_SSC_DOUT); | |
} | |
/* | |
* to check if the right uid was selected | |
*/ | |
static int check_select(uint8_t *rx, uint32_t uid) { | |
unsigned char resp[48]; | |
uint32_t ans = 0x0; | |
for (int i = 0; i < 48; i++) | |
resp[i] = (rx[i / 8] >> (7 - (i % 8))) & 0x1; | |
for (int i = 0; i < 32; i++) | |
ans += resp[5 + i] << (31 - i); | |
temp_uid = ans; | |
if (ans == tag.uid) | |
return 1; | |
return 0; | |
} | |
/* | |
* handles all commands from a reader | |
*/ | |
static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen, | |
uint8_t *tx, size_t *txlen) { | |
uint8_t rx_air[HITAG_FRAME_LEN]; | |
uint64_t state; | |
unsigned char crc; | |
// Copy the (original) received frame how it is send over the air | |
memcpy(rx_air, rx, nbytes(rxlen)); | |
// Reset the transmission frame length | |
*txlen = 0; | |
// Try to find out which command was send by selecting on length (in bits) | |
switch (rxlen) { | |
case 5: { | |
//UID request with a selected response protocol mode | |
tag.pstate = HT_READY; | |
tag.tstate = HT_NO_OP; | |
if ((rx[0] & 0xf0) == 0x30) { | |
tag.mode = HT_STANDARD; | |
sof_bits = 1; | |
m = AC2K; | |
} | |
if ((rx[0] & 0xf0) == 0xc0) { | |
tag.mode = HT_ADVANCED; | |
sof_bits = 3; | |
m = AC2K; | |
} | |
if ((rx[0] & 0xf0) == 0xd0) { | |
tag.mode = HT_FAST_ADVANCED; | |
sof_bits = 3; | |
m = AC4K; | |
} | |
//send uid as a response | |
*txlen = 32; | |
for (int i = 0; i < 4; i++) | |
tx[i] = (tag.uid >> (24 - (i * 8))) & 0xff; | |
} | |
break; | |
case 45: { | |
//select command from reader received | |
if (check_select(rx, tag.uid) == 1) { | |
//if the right tag was selected | |
*txlen = 32; | |
switch (tag.mode) { | |
case HT_STANDARD: | |
sof_bits = 1; | |
m = MC4K; | |
break; | |
case HT_ADVANCED: | |
sof_bits = 6; | |
m = MC4K; | |
break; | |
case HT_FAST_ADVANCED: | |
sof_bits = 6; | |
m = MC8K; | |
break; | |
default: | |
break; | |
} | |
//send configuration | |
for (int i = 0; i < 4; i++) | |
tx[i] = (tag.pages[0][1] >> (i * 8)) & 0xff; | |
tx[3] = 0xff; | |
if (tag.mode != HT_STANDARD) { | |
*txlen = 40; | |
crc = CRC_PRESET; | |
for (int i = 0; i < 4; i++) | |
calc_crc(&crc, tx[i], 8); | |
tx[4] = crc; | |
} | |
} | |
} | |
break; | |
case 64: { | |
//challenge message received | |
Dbprintf("Challenge for UID: %X", temp_uid); | |
temp2++; | |
*txlen = 32; | |
state = _hitag2_init(REV64(tag.key), | |
REV32(tag.pages[0][0]), | |
REV32(((rx[3] << 24) + (rx[2] << 16) + (rx[1] << 8) + rx[0])) | |
); | |
Dbprintf(",{0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X}", | |
rx[0], rx[1], rx[2], rx[3], rx[4], rx[5], rx[6], rx[7]); | |
switch (tag.mode) { | |
case HT_STANDARD: | |
sof_bits = 1; | |
m = MC4K; | |
break; | |
case HT_ADVANCED: | |
sof_bits = 6; | |
m = MC4K; | |
break; | |
case HT_FAST_ADVANCED: | |
sof_bits = 6; | |
m = MC8K; | |
break; | |
default: | |
break; | |
} | |
for (int i = 0; i < 4; i++) | |
_hitag2_byte(&state); | |
//send con2, pwdh0, pwdl0, pwdl1 encrypted as a response | |
tx[0] = _hitag2_byte(&state) ^ ((tag.pages[0][1] >> 16) & 0xff); | |
tx[1] = _hitag2_byte(&state) ^ tag.pwdh0; | |
tx[2] = _hitag2_byte(&state) ^ tag.pwdl0; | |
tx[3] = _hitag2_byte(&state) ^ tag.pwdl1; | |
if (tag.mode != HT_STANDARD) { | |
//add crc8 | |
*txlen = 40; | |
crc = CRC_PRESET; | |
calc_crc(&crc, ((tag.pages[0][1] >> 16) & 0xff), 8); | |
calc_crc(&crc, tag.pwdh0, 8); | |
calc_crc(&crc, tag.pwdl0, 8); | |
calc_crc(&crc, tag.pwdl1, 8); | |
tx[4] = (crc ^ _hitag2_byte(&state)); | |
} | |
/* | |
* some readers do not allow to authenticate multiple times in a row with the same tag. | |
* use this to change the uid between authentications. | |
if (temp2 % 2 == 0) { | |
tag.uid = 0x11223344; | |
tag.pages[0][0] = 0x44332211; | |
} else { | |
tag.uid = 0x55667788; | |
tag.pages[0][0] = 0x88776655; | |
} | |
*/ | |
} | |
case 40: | |
//data received to be written | |
if (tag.tstate == HT_WRITING_PAGE_DATA) { | |
tag.tstate = HT_NO_OP; | |
tag.pages[page_to_be_written / 4][page_to_be_written % 4] = (rx[0] | |
<< 0) + (rx[1] << 8) + (rx[2] << 16) + (rx[3] << 24); | |
//send ack | |
*txlen = 2; | |
tx[0] = 0x40; | |
page_to_be_written = 0; | |
switch (tag.mode) { | |
case HT_STANDARD: | |
sof_bits = 1; | |
m = MC4K; | |
break; | |
case HT_ADVANCED: | |
sof_bits = 6; | |
m = MC4K; | |
break; | |
case HT_FAST_ADVANCED: | |
sof_bits = 6; | |
m = MC8K; | |
break; | |
default: | |
break; | |
} | |
} else if (tag.tstate == HT_WRITING_BLOCK_DATA) { | |
tag.pages[page_to_be_written / 4][page_to_be_written % 4] = (rx[0] | |
<< 24) + (rx[1] << 16) + (rx[2] << 8) + rx[3]; | |
//send ack | |
*txlen = 2; | |
tx[0] = 0x40; | |
switch (tag.mode) { | |
case HT_STANDARD: | |
sof_bits = 1; | |
m = MC4K; | |
break; | |
case HT_ADVANCED: | |
sof_bits = 6; | |
m = MC4K; | |
break; | |
case HT_FAST_ADVANCED: | |
sof_bits = 6; | |
m = MC8K; | |
break; | |
default: | |
break; | |
} | |
page_to_be_written++; | |
block_data_left--; | |
if (block_data_left == 0) { | |
tag.tstate = HT_NO_OP; | |
page_to_be_written = 0; | |
} | |
} | |
break; | |
case 20: { | |
//write page, write block, read page or read block command received | |
if ((rx[0] & 0xf0) == 0xc0) { //read page | |
//send page data | |
uint8_t page = ((rx[0] & 0x0f) * 16) + ((rx[1] & 0xf0) / 16); | |
*txlen = 32; | |
tx[0] = (tag.pages[page / 4][page % 4]) & 0xff; | |
tx[1] = (tag.pages[page / 4][page % 4] >> 8) & 0xff; | |
tx[2] = (tag.pages[page / 4][page % 4] >> 16) & 0xff; | |
tx[3] = (tag.pages[page / 4][page % 4] >> 24) & 0xff; | |
if (tag.LKP && page == 1) | |
tx[3] = 0xff; | |
switch (tag.mode) { | |
case HT_STANDARD: | |
sof_bits = 1; | |
m = MC4K; | |
break; | |
case HT_ADVANCED: | |
sof_bits = 6; | |
m = MC4K; | |
break; | |
case HT_FAST_ADVANCED: | |
sof_bits = 6; | |
m = MC8K; | |
break; | |
default: | |
break; | |
} | |
if (tag.mode != HT_STANDARD) { | |
//add crc8 | |
*txlen = 40; | |
crc = CRC_PRESET; | |
for (int i = 0; i < 4; i++) | |
calc_crc(&crc, tx[i], 8); | |
tx[4] = crc; | |
} | |
if (tag.LKP && (page == 2 || page == 3)) { | |
//if reader asks for key or password and the LKP-mark is set do not respond | |
sof_bits = 0; | |
*txlen = 0; | |
} | |
} else if ((rx[0] & 0xf0) == 0xd0) { //read block | |
uint8_t page = ((rx[0] & 0x0f) * 16) + ((rx[1] & 0xf0) / 16); | |
*txlen = 32 * 4; | |
//send page,...,page+3 data | |
for (int i = 0; i < 4; i++) { | |
tx[0 + i * 4] = (tag.pages[page / 4][page % 4]) & 0xff; | |
tx[1 + i * 4] = (tag.pages[page / 4][page % 4] >> 8) & 0xff; | |
tx[2 + i * 4] = (tag.pages[page / 4][page % 4] >> 16) & 0xff; | |
tx[3 + i * 4] = (tag.pages[page / 4][page % 4] >> 24) & 0xff; | |
page++; | |
} | |
switch (tag.mode) { | |
case HT_STANDARD: | |
sof_bits = 1; | |
m = MC4K; | |
break; | |
case HT_ADVANCED: | |
sof_bits = 6; | |
m = MC4K; | |
break; | |
case HT_FAST_ADVANCED: | |
sof_bits = 6; | |
m = MC8K; | |
break; | |
default: | |
break; | |
} | |
if (tag.mode != HT_STANDARD) { | |
//add crc8 | |
*txlen = 32 * 4 + 8; | |
crc = CRC_PRESET; | |
for (int i = 0; i < 16; i++) | |
calc_crc(&crc, tx[i], 8); | |
tx[16] = crc; | |
} | |
if ((page - 4) % 4 != 0 || (tag.LKP && (page - 4) == 0)) { | |
sof_bits = 0; | |
*txlen = 0; | |
} | |
} else if ((rx[0] & 0xf0) == 0x80) { //write page | |
uint8_t page = ((rx[0] & 0x0f) * 16) + ((rx[1] & 0xf0) / 16); | |
switch (tag.mode) { | |
case HT_STANDARD: | |
sof_bits = 1; | |
m = MC4K; | |
break; | |
case HT_ADVANCED: | |
sof_bits = 6; | |
m = MC4K; | |
break; | |
case HT_FAST_ADVANCED: | |
sof_bits = 6; | |
m = MC8K; | |
break; | |
default: | |
break; | |
} | |
if ((tag.LCON && page == 1) | |
|| (tag.LKP && (page == 2 || page == 3))) { | |
//deny | |
*txlen = 0; | |
} else { | |
//allow | |
*txlen = 2; | |
tx[0] = 0x40; | |
page_to_be_written = page; | |
tag.tstate = HT_WRITING_PAGE_DATA; | |
} | |
} else if ((rx[0] & 0xf0) == 0x90) { //write block | |
uint8_t page = ((rx[0] & 0x0f) * 6) + ((rx[1] & 0xf0) / 16); | |
switch (tag.mode) { | |
case HT_STANDARD: | |
sof_bits = 1; | |
m = MC4K; | |
break; | |
case HT_ADVANCED: | |
sof_bits = 6; | |
m = MC4K; | |
break; | |
case HT_FAST_ADVANCED: | |
sof_bits = 6; | |
m = MC8K; | |
break; | |
default: | |
break; | |
} | |
if (page % 4 != 0 || page == 0) { | |
//deny | |
*txlen = 0; | |
} else { | |
//allow | |
*txlen = 2; | |
tx[0] = 0x40; | |
page_to_be_written = page; | |
block_data_left = 4; | |
tag.tstate = HT_WRITING_BLOCK_DATA; | |
} | |
} | |
} | |
break; | |
default: | |
break; | |
} | |
} | |
/* | |
* to autenticate to a tag with the given key or challenge | |
*/ | |
static int hitagS_handle_tag_auth(hitag_function htf, uint64_t key, uint64_t NrAr, uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen) { | |
uint8_t rx_air[HITAG_FRAME_LEN]; | |
int response_bit[200]; | |
unsigned char mask = 1; | |
unsigned char uid[32]; | |
unsigned char crc; | |
uint64_t state; | |
uint8_t auth_ks[4]; | |
uint8_t conf_pages[3]; | |
memcpy(rx_air, rx, nbytes(rxlen)); | |
*txlen = 0; | |
Dbprintf("hitagS_handle_tag_auth: %i", rxlen); | |
if (nochmal == 3) { | |
Dbprintf("NOCHMAL"); | |
*txlen = 45; | |
for (int i = 0; i < 6; i++) | |
tx[i] = tx2[i]; | |
tag.pstate = HT_INIT; | |
nochmal = 0; | |
} else if (tag.pstate == HT_READY && rxlen >= 67) { | |
//received uid | |
if (end == true) { | |
Dbprintf("authentication failed!"); | |
return -1; | |
} | |
int z = 0; | |
for (int i = 0; i < 10; i++) { | |
for (int j = 0; j < 8; j++) { | |
response_bit[z] = 0; | |
if ((rx[i] & ((mask << 7) >> j)) != 0) | |
response_bit[z] = 1; | |
z++; | |
} | |
} | |
uint16_t k = 0; | |
for (int i = 5; i < z; i += 2) { | |
uid[k] = response_bit[i]; | |
k++; | |
if (k > 31) | |
break; | |
} | |
uint8_t uid1 = (uid[0] << 7) | |
| (uid[1] << 6) | |
| (uid[2] << 5) | |
| (uid[3] << 4) | |
| (uid[4] << 3) | |
| (uid[5] << 2) | |
| (uid[6] << 1) | |
| uid[7]; | |
uint8_t uid2 = (uid[8] << 7) | |
| (uid[9] << 6) | |
| (uid[10] << 5) | |
| (uid[11] << 4) | |
| (uid[12] << 3) | |
| (uid[13] << 2) | |
| (uid[14] << 1) | |
| uid[15]; | |
uint8_t uid3 = (uid[16] << 7) | |
| (uid[17] << 6) | |
| (uid[18] << 5) | |
| (uid[19] << 4) | |
| (uid[20] << 3) | |
| (uid[21] << 2) | |
| (uid[22] << 1) | |
| uid[23]; | |
uint8_t uid4 = (uid[24] << 7) | |
| (uid[25] << 6) | |
| (uid[26] << 5) | |
| (uid[27] << 4) | |
| (uid[28] << 3) | |
| (uid[29] << 2) | |
| (uid[30] << 1) | |
| uid[31]; | |
if (DEBUG) | |
Dbprintf("UID: %02X %02X %02X %02X", uid1, uid2, uid3, uid4); | |
tag.uid = (uid4 << 24 | uid3 << 16 | uid2 << 8 | uid1); | |
//select uid | |
*txlen = 45; | |
crc = CRC_PRESET; | |
calc_crc(&crc, 0x00, 5); | |
calc_crc(&crc, uid1, 8); | |
calc_crc(&crc, uid2, 8); | |
calc_crc(&crc, uid3, 8); | |
calc_crc(&crc, uid4, 8); | |
for (int i = 0; i < 100; i++) { | |
response_bit[i] = 0; | |
} | |
for (int i = 0; i < 5; i++) { | |
response_bit[i] = 0; | |
} | |
{ | |
int i = 5; | |
for (; i < 37; i++) { | |
response_bit[i] = uid[i - 5]; | |
} | |
for (int j = 0; j < 8; j++) { | |
response_bit[i] = 0; | |
if ((crc & ((mask << 7) >> j)) != 0) | |
response_bit[i] = 1; | |
i++; | |
} | |
} | |
k = 0; | |
for (int i = 0; i < 6; i++) { | |
tx[i] = (response_bit[k] << 7) | |
| (response_bit[k + 1] << 6) | |
| (response_bit[k + 2] << 5) | |
| (response_bit[k + 3] << 4) | |
| (response_bit[k + 4] << 3) | |
| (response_bit[k + 5] << 2) | |
| (response_bit[k + 6] << 1) | |
| response_bit[k + 7]; | |
k += 8; | |
} | |
for (int i = 0; i < 6; i++) | |
tx2[i] = tx[i]; | |
nochmal = 1; | |
tag.pstate = HT_INIT; | |
} else if (tag.pstate == HT_INIT && rxlen < 40) { | |
*txlen = 45; | |
for (int i = 0; i < 6; i++) | |
tx[i] = tx2[i]; | |
} else if (tag.pstate == HT_INIT && rxlen == 63) { | |
// received configuration after select command | |
unsigned char uid[63]; | |
int z = 0; | |
for (int i = 0; i < 7; i++) { | |
for (int j = 0; j < 8; j++) { | |
uid[z] = 0; | |
if ((rx[i] & ((mask << 7) >> j)) != 0) | |
uid[z] = 1; | |
z++; | |
} | |
} | |
uint8_t uid1 = (uid[0] << 7) | |
| (uid[1] << 6) | |
| (uid[2] << 5) | |
| (uid[3] << 4) | |
| (uid[4] << 3) | |
| (uid[5] << 2) | |
| (uid[6] << 1) | |
| uid[7]; | |
uint8_t uid2 = (uid[8] << 7) | |
| (uid[9] << 6) | |
| (uid[10] << 5) | |
| (uid[11] << 4) | |
| (uid[12] << 3) | |
| (uid[13] << 2) | |
| (uid[14] << 1) | |
| uid[15]; | |
uint8_t uid3 = (uid[16] << 7) | |
| (uid[17] << 6) | |
| (uid[18] << 5) | |
| (uid[19] << 4) | |
| (uid[20] << 3) | |
| (uid[21] << 2) | |
| (uid[22] << 1) | |
| uid[23]; | |
uint8_t uid4 = (uid[24] << 7) | |
| (uid[25] << 6) | |
| (uid[26] << 5) | |
| (uid[27] << 4) | |
| (uid[28] << 3) | |
| (uid[29] << 2) | |
| (uid[30] << 1) | |
| uid[31]; | |
uint8_t uid5 = (uid[32] << 7) | |
| (uid[33] << 6) | |
| (uid[34] << 5) | |
| (uid[35] << 4) | |
| (uid[36] << 3) | |
| (uid[37] << 2) | |
| (uid[38] << 1) | |
| uid[39]; | |
uint8_t uid6 = (uid[40] << 7) | |
| (uid[41] << 6) | |
| (uid[42] << 5) | |
| (uid[43] << 4) | |
| (uid[44] << 3) | |
| (uid[45] << 2) | |
| (uid[46] << 1) | |
| uid[47]; | |
uint8_t uid7 = (uid[48] << 7) | |
| (uid[49] << 6) | |
| (uid[50] << 5) | |
| (uid[51] << 4) | |
| (uid[52] << 3) | |
| (uid[53] << 2) | |
| (uid[54] << 1) | |
| uid[55]; | |
Dbprintf("xxx: %02X %02X %02X %02X %02X %02X %02X", uid1, uid2, uid3, uid4, uid5, uid6, uid7); | |
} else if (tag.pstate == HT_INIT && rxlen == 44) { | |
// received configuration after select command | |
int z = 0; | |
for (int i = 0; i < 6; i++) { | |
for (int j = 0; j < 8; j++) { | |
response_bit[z] = 0; | |
if ((rx[i] & ((mask << 7) >> j)) != 0) | |
response_bit[z] = 1; | |
z++; | |
} | |
} | |
conf_pages[0] = ((response_bit[4] << 7) | (response_bit[5] << 6) | |
| (response_bit[6] << 5) | (response_bit[7] << 4) | |
| (response_bit[8] << 3) | (response_bit[9] << 2) | |
| (response_bit[10] << 1) | response_bit[11]); | |
//check wich memorysize this tag has | |
if (response_bit[10] == 0 && response_bit[11] == 0) | |
tag.max_page = 32 / 32; | |
if (response_bit[10] == 0 && response_bit[11] == 1) | |
tag.max_page = 256 / 32; | |
if (response_bit[10] == 1 && response_bit[11] == 0) | |
tag.max_page = 2048 / 32; | |
conf_pages[1] = ((response_bit[12] << 7) | (response_bit[13] << 6) | |
| (response_bit[14] << 5) | (response_bit[15] << 4) | |
| (response_bit[16] << 3) | (response_bit[17] << 2) | |
| (response_bit[18] << 1) | response_bit[19]); | |
tag.auth = response_bit[12]; | |
tag.TTFC = response_bit[13]; | |
//tag.TTFDR in response_bit[14] and response_bit[15] | |
//tag.TTFM in response_bit[16] and response_bit[17] | |
tag.LCON = response_bit[18]; | |
tag.LKP = response_bit[19]; | |
conf_pages[2] = ((response_bit[20] << 7) | (response_bit[21] << 6) | |
| (response_bit[22] << 5) | (response_bit[23] << 4) | |
| (response_bit[24] << 3) | (response_bit[25] << 2) | |
| (response_bit[26] << 1) | response_bit[27]); | |
tag.LCK7 = response_bit[20]; | |
tag.LCK6 = response_bit[21]; | |
tag.LCK5 = response_bit[22]; | |
tag.LCK4 = response_bit[23]; | |
tag.LCK3 = response_bit[24]; | |
tag.LCK2 = response_bit[25]; | |
tag.LCK1 = response_bit[26]; | |
tag.LCK0 = response_bit[27]; | |
if (DEBUG) | |
Dbprintf("conf0: %02X conf1: %02X conf2: %02X", conf_pages[0], conf_pages[1], conf_pages[2]); | |
if (tag.auth == 1) { | |
//if the tag is in authentication mode try the key or challenge | |
*txlen = 64; | |
if (end != true) { | |
if (htf == 02 || htf == 04) { //RHTS_KEY //WHTS_KEY | |
state = _hitag2_init(REV64(key), REV32(tag.uid), REV32(rnd)); | |
for (int i = 0; i < 4; i++) { | |
auth_ks[i] = _hitag2_byte(&state) ^ 0xff; | |
} | |
*txlen = 64; | |
tx[0] = rnd & 0xff; | |
tx[1] = (rnd >> 8) & 0xff; | |
tx[2] = (rnd >> 16) & 0xff; | |
tx[3] = (rnd >> 24) & 0xff; | |
tx[4] = auth_ks[0]; | |
tx[5] = auth_ks[1]; | |
tx[6] = auth_ks[2]; | |
tx[7] = auth_ks[3]; | |
if (DEBUG) | |
Dbprintf("%02X %02X %02X %02X %02X %02X %02X %02X", tx[0], | |
tx[1], tx[2], tx[3], tx[4], tx[5], tx[6], tx[7]); | |
} else if (htf == 01 || htf == 03) { //RHTS_CHALLENGE //WHTS_CHALLENGE | |
for (int i = 0; i < 8; i++) | |
tx[i] = ((NrAr >> (56 - (i * 8))) & 0xff); | |
} | |
end = true; | |
tag.pstate = HT_AUTHENTICATE; | |
} else { | |
Dbprintf("authentication failed!"); | |
return -1; | |
} | |
} else if (tag.auth == 0) { | |
tag.pstate = HT_SELECTED; | |
} | |
} else if (tag.pstate == HT_AUTHENTICATE && rxlen == 44) { | |
//encrypted con2,password received. | |
crc = CRC_PRESET; | |
calc_crc(&crc, 0x80, 1); | |
calc_crc(&crc, ((rx[0] & 0x0f) * 16 + ((rx[1] & 0xf0) / 16)), 8); | |
calc_crc(&crc, ((rx[1] & 0x0f) * 16 + ((rx[2] & 0xf0) / 16)), 8); | |
calc_crc(&crc, ((rx[2] & 0x0f) * 16 + ((rx[3] & 0xf0) / 16)), 8); | |
calc_crc(&crc, ((rx[3] & 0x0f) * 16 + ((rx[4] & 0xf0) / 16)), 8); | |
if (DEBUG) { | |
Dbprintf("UID:::%X", tag.uid); | |
Dbprintf("RND:::%X", rnd); | |
} | |
//decrypt password | |
pwdh0 = 0; | |
pwdl0 = 0; | |
pwdl1 = 0; | |
if (htf == 02 || htf == 04) { //RHTS_KEY //WHTS_KEY | |
{ | |
state = _hitag2_init(REV64(key), REV32(tag.uid), REV32(rnd)); | |
for (int i = 0; i < 5; i++) | |
_hitag2_byte(&state); | |
pwdh0 = ((rx[1] & 0x0f) * 16 + ((rx[2] & 0xf0) / 16)) ^ _hitag2_byte(&state); | |
pwdl0 = ((rx[2] & 0x0f) * 16 + ((rx[3] & 0xf0) / 16)) ^ _hitag2_byte(&state); | |
pwdl1 = ((rx[3] & 0x0f) * 16 + ((rx[4] & 0xf0) / 16)) ^ _hitag2_byte(&state); | |
} | |
if (DEBUG) | |
Dbprintf("pwdh0 %02X pwdl0 %02X pwdl1 %02X", pwdh0, pwdl0, pwdl1); | |
//Dbprintf("%X %02X", rnd, ((rx[4] & 0x0f) * 16) + ((rx[5] & 0xf0) / 16)); | |
//rnd += 1; | |
} | |
tag.pstate = HT_SELECTED; //tag is now ready for read/write commands | |
} | |
return 0; | |
} | |
/* | |
* Emulates a Hitag S Tag with the given data from the .hts file | |
*/ | |
void SimulateHitagSTag(bool tag_mem_supplied, uint8_t *data) { | |
StopTicks(); | |
// int frame_count = 0; | |
int response = 0, overflow = 0; | |
int i, j; | |
uint8_t rx[HITAG_FRAME_LEN]; | |
size_t rxlen = 0; | |
bQuiet = false; | |
uint8_t txbuf[HITAG_FRAME_LEN]; | |
uint8_t *tx = txbuf; | |
size_t txlen = 0; | |
// Reset the received frame, frame count and timing info | |
memset(rx, 0x00, sizeof(rx)); | |
// free eventually allocated BigBuf memory | |
BigBuf_free(); | |
BigBuf_Clear_ext(false); | |
// Clean up trace and prepare it for storing frames | |
set_tracing(true); | |
clear_trace(); | |
DbpString("Starting HitagS simulation"); | |
LED_D_ON(); | |
tag.pstate = HT_READY; | |
tag.tstate = HT_NO_OP; | |
for (i = 0; i < 16; i++) | |
for (j = 0; j < 4; j++) | |
tag.pages[i][j] = 0x0; | |
// read tag data into memory | |
if (tag_mem_supplied) { | |
DbpString("Loading hitagS memory..."); | |
memcpy((uint8_t *)tag.pages, data, 4 * 64); | |
} | |
tag.uid = (uint32_t)tag.pages[0]; | |
tag.key = (intptr_t)tag.pages[3]; | |
tag.key <<= 16; | |
tag.key += ((tag.pages[2][0]) << 8) + tag.pages[2][1]; | |
tag.pwdl0 = tag.pages[2][3]; | |
tag.pwdl1 = tag.pages[2][2]; | |
tag.pwdh0 = tag.pages[1][0]; | |
//con0 | |
tag.max_page = 64; | |
if ((tag.pages[1][3] & 0x2) == 0 && (tag.pages[1][3] & 0x1) == 1) | |
tag.max_page = 8; | |
if ((tag.pages[1][3] & 0x2) == 0 && (tag.pages[1][3] & 0x1) == 0) | |
tag.max_page = 0; | |
//con1 | |
tag.auth = 0; | |
if ((tag.pages[1][2] & 0x80) == 0x80) | |
tag.auth = 1; | |
tag.LCON = 0; | |
if ((tag.pages[1][2] & 0x2) == 0x02) | |
tag.LCON = 1; | |
tag.LKP = 0; | |
if ((tag.pages[1][2] & 0x1) == 0x01) | |
tag.LKP = 1; | |
//con2 | |
//0=read write 1=read only | |
tag.LCK7 = 0; | |
if ((tag.pages[1][1] & 0x80) == 0x80) | |
tag.LCK7 = 1; | |
tag.LCK6 = 0; | |
if ((tag.pages[1][1] & 0x40) == 0x040) | |
tag.LCK6 = 1; | |
tag.LCK5 = 0; | |
if ((tag.pages[1][1] & 0x20) == 0x20) | |
tag.LCK5 = 1; | |
tag.LCK4 = 0; | |
if ((tag.pages[1][1] & 0x10) == 0x10) | |
tag.LCK4 = 1; | |
tag.LCK3 = 0; | |
if ((tag.pages[1][1] & 0x8) == 0x08) | |
tag.LCK3 = 1; | |
tag.LCK2 = 0; | |
if ((tag.pages[1][1] & 0x4) == 0x04) | |
tag.LCK2 = 1; | |
tag.LCK1 = 0; | |
if ((tag.pages[1][1] & 0x2) == 0x02) | |
tag.LCK1 = 1; | |
tag.LCK0 = 0; | |
if ((tag.pages[1][1] & 0x1) == 0x01) | |
tag.LCK0 = 1; | |
// Set up simulator mode, frequency divisor which will drive the FPGA | |
// and analog mux selection. | |
FpgaDownloadAndGo(FPGA_BITSTREAM_LF); | |
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); | |
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125kHz | |
SetAdcMuxFor(GPIO_MUXSEL_LOPKD); | |
// 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 | |
// TIMER_CLOCK1, used to capture edges of the tag frames | |
AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1); | |
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 rising edge of TIOA. | |
AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | |
| AT91C_TC_ETRGEDG_RISING | AT91C_TC_ABETRG | AT91C_TC_LDRA_RISING; | |
// Enable and reset counter | |
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 | |
while (!BUTTON_PRESS() && !data_available()) { | |
WDT_HIT(); | |
// Receive frame, watch for at most T0*EOF periods | |
while (AT91C_BASE_TC1->TC_CV < T0 * HITAG_T_EOF) { | |
// 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) + overflow; | |
overflow = 0; | |
// Reset timer every frame, we have to capture the last edge for timing | |
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; | |
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 | |
} | |
} | |
} | |
// Check if frame was captured | |
if (rxlen > 0) { | |
// frame_count++; | |
LogTrace(rx, nbytes(rxlen), response, 0, NULL, true); | |
// Disable timer 1 with external trigger to avoid triggers during our own modulation | |
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; | |
// Process the incoming frame (rx) and prepare the outgoing frame (tx) | |
hitagS_handle_reader_command(rx, rxlen, tx, &txlen); | |
// Wait for HITAG_T_WAIT_1 carrier periods after the last reader bit, | |
// not that since the clock counts since the rising edge, but T_Wait1 is | |
// with respect to the falling edge, we need to wait actually (T_Wait1 - T_Low) | |
// periods. The gap time T_Low varies (4..10). All timer values are in | |
// terms of T0 units | |
while (AT91C_BASE_TC0->TC_CV < T0 * (HITAG_T_WAIT_1 - HITAG_T_LOW)) {}; | |
// Send and store the tag answer (if there is any) | |
if (txlen > 0) { | |
// Transmit the tag frame | |
hitag_send_frame(tx, txlen); | |
LogTrace(tx, nbytes(txlen), 0, 0, NULL, false); | |
} | |
// Reset the received frame and response timing info | |
memset(rx, 0x00, sizeof(rx)); | |
response = 0; | |
// Enable and reset external trigger in timer for capturing future frames | |
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; | |
LED_B_OFF(); | |
} | |
// Reset the frame length | |
rxlen = 0; | |
// Save the timer overflow, will be 0 when frame was received | |
overflow += (AT91C_BASE_TC1->TC_CV / T0); | |
// 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; | |
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; | |
// release allocated memory from BigBuff. | |
BigBuf_free(); | |
StartTicks(); | |
DbpString("Sim Stopped"); | |
} | |
/* | |
* Authenticates to the Tag with the given key or challenge. | |
* If the key was given the password will be decrypted. | |
* Reads every page of a hitag S transpoder. | |
*/ | |
void ReadHitagS(hitag_function htf, hitag_data *htd) { | |
StopTicks(); | |
int i, j, z, k; | |
// int frame_count = 0; | |
int response = 0; | |
int response_bit[200]; | |
uint8_t rx[HITAG_FRAME_LEN]; | |
size_t rxlen = 0; | |
uint8_t txbuf[HITAG_FRAME_LEN]; | |
uint8_t *tx = txbuf; | |
size_t txlen = 0; | |
int lastbit = 1; | |
int reset_sof = 1; | |
int t_wait = HITAG_T_WAIT_MAX; | |
bool bStop = false; | |
int sendNum = 0; | |
unsigned char mask = 1; | |
unsigned char crc; | |
unsigned char pageData[32]; | |
page_to_be_written = 0; | |
//read given key/challenge | |
uint8_t NrAr_[8]; | |
uint64_t key = 0; | |
uint64_t NrAr = 0; | |
uint8_t key_[6]; | |
switch (htf) { | |
case RHTSF_CHALLENGE: { | |
DbpString("Authenticating using nr,ar pair:"); | |
memcpy(NrAr_, htd->auth.NrAr, 8); | |
Dbhexdump(8, NrAr_, false); | |
NrAr = NrAr_[7] | ((uint64_t)NrAr_[6]) << 8 | ((uint64_t)NrAr_[5]) << 16 | ((uint64_t)NrAr_[4]) << 24 | ((uint64_t)NrAr_[3]) << 32 | | |
((uint64_t)NrAr_[2]) << 40 | ((uint64_t)NrAr_[1]) << 48 | ((uint64_t)NrAr_[0]) << 56; | |
break; | |
} | |
case RHTSF_KEY: { | |
DbpString("Authenticating using key:"); | |
memcpy(key_, htd->crypto.key, 6); | |
Dbhexdump(6, key_, false); | |
key = key_[5] | ((uint64_t)key_[4]) << 8 | ((uint64_t)key_[3]) << 16 | ((uint64_t)key_[2]) << 24 | ((uint64_t)key_[1]) << 32 | ((uint64_t)key_[0]) << 40; | |
break; | |
} | |
default: { | |
Dbprintf("Error , unknown function: %d", htf); | |
return; | |
} | |
} | |
FpgaDownloadAndGo(FPGA_BITSTREAM_LF); | |
// Reset the return status | |
bSuccessful = false; | |
// Clean up trace and prepare it for storing frames | |
set_tracing(true); | |
clear_trace(); | |
bQuiet = false; | |
LED_D_ON(); | |
// Set fpga in edge detect with reader field, we can modulate as reader now | |
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_READER_FIELD); | |
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //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); | |
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, defaul 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 | |
// Reset the received frame, frame count and timing info | |
t_wait = 200; | |
while (!bStop && !BUTTON_PRESS() && !data_available()) { | |
WDT_HIT(); | |
// Check if frame was captured and store it | |
if (rxlen > 0) { | |
// frame_count++; | |
LogTrace(rx, nbytes(rxlen), response, 0, NULL, false); | |
} | |
// By default reset the transmission buffer | |
tx = txbuf; | |
txlen = 0; | |
if (rxlen == 0 && tag.pstate != HT_INIT && tag.pstate != HT_SELECTED) { | |
//start authentication | |
txlen = 5; | |
memcpy(tx, "\xC0", nbytes(txlen)); | |
tag.pstate = HT_READY; | |
tag.tstate = HT_NO_OP; | |
} else if (tag.pstate != HT_SELECTED) { | |
if (hitagS_handle_tag_auth(htf, key, NrAr, rx, rxlen, tx, &txlen) == -1) | |
bStop = !false; | |
} | |
if (tag.pstate == HT_SELECTED && ((tag.tstate == HT_NO_OP && rxlen > 0) || (tag.tstate == HT_READING_PAGE && rxlen == 0))) { | |
//send read request | |
tag.tstate = HT_READING_PAGE; | |
txlen = 20; | |
crc = CRC_PRESET; | |
tx[0] = 0xc0 + (sendNum / 16); | |
calc_crc(&crc, tx[0], 8); | |
calc_crc(&crc, 0x00 + ((sendNum % 16) * 16), 4); | |
tx[1] = 0x00 + ((sendNum % 16) * 16) + (crc / 16); | |
tx[2] = 0x00 + (crc % 16) * 16; | |
} else if (tag.pstate == HT_SELECTED | |
&& tag.tstate == HT_READING_PAGE | |
&& rxlen > 0) { | |
//save received data | |
z = 0; | |
for (i = 0; i < 5; i++) { | |
for (j = 0; j < 8; j++) { | |
response_bit[z] = 0; | |
if ((rx[i] & ((mask << 7) >> j)) != 0) | |
response_bit[z] = 1; | |
z++; | |
} | |
} | |
k = 0; | |
for (i = 4; i < 36; i++) { | |
pageData[k] = response_bit[i]; | |
k++; | |
} | |
for (i = 0; i < 4; i++) | |
tag.pages[sendNum][i] = 0x0; | |
for (i = 0; i < 4; i++) { | |
tag.pages[sendNum][i] += ((pageData[i * 8] << 7) | |
| (pageData[1 + (i * 8)] << 6) | |
| (pageData[2 + (i * 8)] << 5) | |
| (pageData[3 + (i * 8)] << 4) | |
| (pageData[4 + (i * 8)] << 3) | |
| (pageData[5 + (i * 8)] << 2) | |
| (pageData[6 + (i * 8)] << 1) | |
| pageData[7 + (i * 8)]); | |
} | |
if (tag.auth && tag.LKP && sendNum == 1) { | |
Dbprintf("Page[%2d]: %02X %02X %02X %02X", sendNum, pwdh0, | |
(tag.pages[sendNum][2]) & 0xff, | |
(tag.pages[sendNum][1]) & 0xff, | |
tag.pages[sendNum][0] & 0xff); | |
} else { | |
Dbprintf("Page[%2d]: %02X %02X %02X %02X", sendNum, | |
(tag.pages[sendNum][3]) & 0xff, | |
(tag.pages[sendNum][2]) & 0xff, | |
(tag.pages[sendNum][1]) & 0xff, | |
tag.pages[sendNum][0] & 0xff); | |
} | |
sendNum++; | |
//display key and password if possible | |
if (sendNum == 2 && tag.auth == 1 && tag.LKP) { | |
if (htf == RHTSF_KEY) { | |
Dbprintf("Page[ 2]: %02X %02X %02X %02X", | |
(uint8_t)(key >> 8) & 0xff, | |
(uint8_t) key & 0xff, | |
pwdl1, | |
pwdl0 | |
); | |
Dbprintf("Page[ 3]: %02X %02X %02X %02X", | |
(uint8_t)(key >> 40) & 0xff, | |
(uint8_t)(key >> 32) & 0xff, | |
(uint8_t)(key >> 24) & 0xff, | |
(uint8_t)(key >> 16) & 0xff | |
); | |
} else { | |
//if the authentication is done with a challenge the key and password are unknown | |
Dbprintf("Page[ 2]: __ __ __ __"); | |
Dbprintf("Page[ 3]: __ __ __ __"); | |
} | |
sendNum = 4; | |
} | |
txlen = 20; | |
crc = CRC_PRESET; | |
tx[0] = 0xc0 + (sendNum / 16); | |
calc_crc(&crc, tx[0], 8); | |
calc_crc(&crc, 0x00 + ((sendNum % 16) * 16), 4); | |
tx[1] = 0x00 + ((sendNum % 16) * 16) + (crc / 16); | |
tx[2] = 0x00 + (crc % 16) * 16; | |
if (sendNum >= tag.max_page) { | |
bStop = !false; | |
} | |
} | |
// Send and store the reader command | |
// Disable timer 1 with external trigger to avoid triggers during our own modulation | |
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 occured 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 | |
hitag_reader_send_frame(tx, txlen); | |
// Enable and reset external trigger in timer for capturing future frames | |
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; | |
// Add transmitted frame to total count | |
if (txlen > 0) { | |
// frame_count++; | |
LogTrace(tx, nbytes(txlen), HITAG_T_WAIT_2, 0, NULL, true); | |
} | |
// Reset values for receiving frames | |
memset(rx, 0x00, sizeof(rx)); | |
rxlen = 0; | |
lastbit = 1; | |
bool bSkip = true; | |
int tag_sof = reset_sof; | |
response = 0; | |
// Receive frame, watch for at most T0*EOF periods | |
while (AT91C_BASE_TC1->TC_CV < T0 * HITAG_T_WAIT_MAX) { | |
// Check if falling edge in tag 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); | |
// Reset timer every frame, we have to capture the last edge for timing | |
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; | |
LED_B_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 | |
} | |
} | |
// 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; | |
} | |
} | |
} | |
end = false; | |
LEDsoff(); | |
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); | |
set_tracing(false); | |
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; | |
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; | |
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); | |
StartTicks(); | |
reply_old(CMD_ACK, bSuccessful, 0, 0, 0, 0); | |
} | |
/* | |
* Authenticates to the Tag with the given Key or Challenge. | |
* Writes the given 32Bit data into page_ | |
*/ | |
void WritePageHitagS(hitag_function htf, hitag_data *htd, int page) { | |
StopTicks(); | |
// int frame_count = 0; | |
int response = 0; | |
uint8_t rx[HITAG_FRAME_LEN]; | |
size_t rxlen = 0; | |
uint8_t txbuf[HITAG_FRAME_LEN]; | |
uint8_t *tx = txbuf; | |
size_t txlen = 0; | |
int lastbit; | |
int reset_sof; | |
int t_wait = HITAG_T_WAIT_MAX; | |
bool bStop; | |
unsigned char crc; | |
uint8_t data[4] = {0, 0, 0, 0}; | |
FpgaDownloadAndGo(FPGA_BITSTREAM_LF); | |
bSuccessful = false; | |
// Clean up trace and prepare it for storing frames | |
set_tracing(true); | |
clear_trace(); | |
//read given key/challenge, the page and the data | |
uint8_t NrAr_[8]; | |
uint64_t key = 0; | |
uint64_t NrAr = 0; | |
uint8_t key_[6]; | |
switch (htf) { | |
case WHTSF_CHALLENGE: { | |
memcpy(data, htd->auth.data, 4); | |
DbpString("Authenticating using nr,ar pair:"); | |
memcpy(NrAr_, htd->auth.NrAr, 8); | |
Dbhexdump(8, NrAr_, false); | |
NrAr = NrAr_[7] | ((uint64_t)NrAr_[6]) << 8 | ((uint64_t)NrAr_[5]) << 16 | ((uint64_t)NrAr_[4]) << 24 | ((uint64_t)NrAr_[3]) << 32 | | |
((uint64_t)NrAr_[2]) << 40 | ((uint64_t)NrAr_[1]) << 48 | ((uint64_t)NrAr_[0]) << 56; | |
break; | |
} | |
case WHTSF_KEY: { | |
memcpy(data, htd->crypto.data, 4); | |
DbpString("Authenticating using key:"); | |
memcpy(key_, htd->crypto.key, 6); | |
Dbhexdump(6, key_, false); | |
key = key_[5] | ((uint64_t)key_[4]) << 8 | ((uint64_t)key_[3]) << 16 | ((uint64_t)key_[2]) << 24 | ((uint64_t)key_[1]) << 32 | ((uint64_t)key_[0]) << 40; | |
break; | |
} | |
default: { | |
Dbprintf("Error , unknown function: %d", htf); | |
return; | |
} | |
} | |
Dbprintf("Page: %d", page); | |
Dbprintf("DATA: %02X %02X %02X %02X", data[0], data[1], data[2], data[3]); | |
tag.pstate = HT_READY; | |
tag.tstate = HT_NO_OP; | |
LED_D_ON(); | |
// 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; | |
// Set fpga in edge detect with reader field, we can modulate as reader now | |
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_READER_FIELD); | |
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125kHz | |
SetAdcMuxFor(GPIO_MUXSEL_LOPKD); | |
// 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); | |
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; | |
// Capture mode, defaul 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; | |
while (AT91C_BASE_TC0->TC_CV > 0); | |
// Reset the received frame, frame count and timing info | |
lastbit = 1; | |
bStop = false; | |
reset_sof = 1; | |
t_wait = 200; | |
while (!bStop && !BUTTON_PRESS() && !data_available()) { | |
WDT_HIT(); | |
// Check if frame was captured and store it | |
if (rxlen > 0) { | |
// frame_count++; | |
LogTrace(rx, nbytes(rxlen), response, 0, NULL, false); | |
} | |
//check for valid input | |
if (page == 0) { | |
Dbprintf( | |
"usage: lf hitag writer [03 | 04] [CHALLENGE | KEY] [page] [byte0] [byte1] [byte2] [byte3]"); | |
bStop = !false; | |
} | |
// By default reset the transmission buffer | |
tx = txbuf; | |
txlen = 0; | |
if (rxlen == 0 && tag.tstate == HT_WRITING_PAGE_ACK) { | |
//no write access on this page | |
Dbprintf("no write access on page %d", page); | |
bStop = !false; | |
} else if (rxlen == 0 && tag.tstate != HT_WRITING_PAGE_DATA) { | |
//start the authetication | |
txlen = 5; | |
memcpy(tx, "\xc0", nbytes(txlen)); | |
tag.pstate = HT_READY; | |
tag.tstate = HT_NO_OP; | |
} else if (tag.pstate != HT_SELECTED) { | |
//try to authenticate with the given key or challenge | |
if (hitagS_handle_tag_auth(htf, key, NrAr, rx, rxlen, tx, &txlen) == -1) | |
bStop = !false; | |
} | |
if (tag.pstate == HT_SELECTED && tag.tstate == HT_NO_OP && rxlen > 0) { | |
//check if the given page exists | |
if (page > tag.max_page) { | |
Dbprintf("page number too big"); | |
bStop = !false; | |
} | |
//ask Tag for write permission | |
tag.tstate = HT_WRITING_PAGE_ACK; | |
txlen = 20; | |
crc = CRC_PRESET; | |
tx[0] = 0x90 + (page / 16); | |
calc_crc(&crc, tx[0], 8); | |
calc_crc(&crc, 0x00 + ((page % 16) * 16), 4); | |
tx[1] = 0x00 + ((page % 16) * 16) + (crc / 16); | |
tx[2] = 0x00 + (crc % 16) * 16; | |
} else if (tag.pstate == HT_SELECTED && tag.tstate == HT_WRITING_PAGE_ACK | |
&& rxlen == 6 && rx[0] == 0xf4) { | |
//ACK recieved to write the page. send data | |
tag.tstate = HT_WRITING_PAGE_DATA; | |
txlen = 40; | |
crc = CRC_PRESET; | |
calc_crc(&crc, data[3], 8); | |
calc_crc(&crc, data[2], 8); | |
calc_crc(&crc, data[1], 8); | |
calc_crc(&crc, data[0], 8); | |
tx[0] = data[3]; | |
tx[1] = data[2]; | |
tx[2] = data[1]; | |
tx[3] = data[0]; | |
tx[4] = crc; | |
} else if (tag.pstate == HT_SELECTED && tag.tstate == HT_WRITING_PAGE_DATA | |
&& rxlen == 6 && rx[0] == 0xf4) { | |
//received ACK | |
Dbprintf("Successful!"); | |
bStop = !false; | |
} | |
// Send and store the reader command | |
// Disable timer 1 with external trigger to avoid triggers during our own modulation | |
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 occured 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 | |
hitag_reader_send_frame(tx, txlen); | |
// Enable and reset external trigger in timer for capturing future frames | |
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; | |
// Add transmitted frame to total count | |
if (txlen > 0) { | |
// frame_count++; | |
LogTrace(tx, nbytes(txlen), HITAG_T_WAIT_2, 0, NULL, true); | |
} | |
// Reset values for receiving frames | |
memset(rx, 0x00, sizeof(rx)); | |
rxlen = 0; | |
lastbit = 1; | |
bool bSkip = true; | |
int tag_sof = reset_sof; | |
response = 0; | |
uint32_t errorCount = 0; | |
// Receive frame, watch for at most T0*EOF periods | |
while (AT91C_BASE_TC1->TC_CV < T0 * HITAG_T_WAIT_MAX) { | |
// Check if falling edge in tag 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); | |
// Reset timer every frame, we have to capture the last edge for timing | |
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; | |
LED_B_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 | |
errorCount++; | |
} | |
} | |
// 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; | |
} | |
} | |
} | |
end = false; | |
LEDsoff(); | |
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); | |
set_tracing(false); | |
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; | |
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; | |
StartTicks(); | |
reply_old(CMD_ACK, bSuccessful, 0, 0, 0, 0); | |
} | |
/* | |
* Tries to authenticate to a Hitag S Transponder with the given challenges from a .cc file. | |
* Displays all Challenges that failed. | |
* When collecting Challenges to break the key it is possible that some data | |
* is not received correctly due to Antenna problems. This function | |
* detects these challenges. | |
*/ | |
void check_challenges(bool file_given, uint8_t *data) { | |
int i, j, z, k; | |
// int frame_count = 0; | |
int response = 0; | |
uint8_t uid_byte[4]; | |
uint8_t rx[HITAG_FRAME_LEN]; | |
uint8_t unlocker[60][8]; | |
int u1 = 0; | |
size_t rxlen = 0; | |
uint8_t txbuf[HITAG_FRAME_LEN]; | |
int t_wait = HITAG_T_WAIT_MAX; | |
int lastbit, reset_sof, STATE = 0;; | |
bool bStop; | |
int response_bit[200]; | |
unsigned char mask = 1; | |
unsigned char uid[32]; | |
unsigned char crc; | |
FpgaDownloadAndGo(FPGA_BITSTREAM_LF); | |
// Reset the return status | |
bSuccessful = false; | |
// Clean up trace and prepare it for storing frames | |
set_tracing(true); | |
clear_trace(); | |
bQuiet = false; | |
LED_D_ON(); | |
// 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; | |
// Set fpga in edge detect with reader field, we can modulate as reader now | |
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_READER_FIELD); | |
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125kHz | |
SetAdcMuxFor(GPIO_MUXSEL_LOPKD); | |
// 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); | |
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, defaul 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; | |
while (AT91C_BASE_TC0->TC_CV > 0) {}; | |
// Reset the received frame, frame count and timing info | |
lastbit = 1; | |
bStop = false; | |
reset_sof = 1; | |
t_wait = 200; | |
if (file_given) { | |
DbpString("Loading challenges..."); | |
memcpy((uint8_t *)unlocker, data, 60 * 8); | |
} | |
while (file_given && !bStop && !BUTTON_PRESS()) { | |
// Watchdog hit | |
WDT_HIT(); | |
// Check if frame was captured and store it | |
if (rxlen > 0) { | |
// frame_count++; | |
LogTrace(rx, nbytes(rxlen), response, 0, NULL, false); | |
} | |
uint8_t *tx = txbuf; | |
size_t txlen = 0; | |
if (rxlen == 0) { | |
if (STATE == 2) | |
// challenge failed | |
Dbprintf("Challenge failed: %02X %02X %02X %02X %02X %02X %02X %02X", | |
unlocker[u1 - 1][0], unlocker[u1 - 1][1], | |
unlocker[u1 - 1][2], unlocker[u1 - 1][3], | |
unlocker[u1 - 1][4], unlocker[u1 - 1][5], | |
unlocker[u1 - 1][6], unlocker[u1 - 1][7]); | |
STATE = 0; | |
txlen = 5; | |
//start new authentication | |
memcpy(tx, "\xC0", nbytes(txlen)); | |
} else if (rxlen >= 67 && STATE == 0) { | |
//received uid | |
z = 0; | |
for (i = 0; i < 10; i++) { | |
for (j = 0; j < 8; j++) { | |
response_bit[z] = 0; | |
if ((rx[i] & ((mask << 7) >> j)) != 0) | |
response_bit[z] = 1; | |
z++; | |
} | |
} | |
k = 0; | |
for (i = 5; i < z; i += 2) { | |
uid[k] = response_bit[i]; | |
k++; | |
if (k > 31) | |
break; | |
} | |
uid_byte[0] = (uid[0] << 7) | (uid[1] << 6) | (uid[2] << 5) | |
| (uid[3] << 4) | (uid[4] << 3) | (uid[5] << 2) | |
| (uid[6] << 1) | uid[7]; | |
uid_byte[1] = (uid[8] << 7) | (uid[9] << 6) | (uid[10] << 5) | |
| (uid[11] << 4) | (uid[12] << 3) | (uid[13] << 2) | |
| (uid[14] << 1) | uid[15]; | |
uid_byte[2] = (uid[16] << 7) | (uid[17] << 6) | (uid[18] << 5) | |
| (uid[19] << 4) | (uid[20] << 3) | (uid[21] << 2) | |
| (uid[22] << 1) | uid[23]; | |
uid_byte[3] = (uid[24] << 7) | (uid[25] << 6) | (uid[26] << 5) | |
| (uid[27] << 4) | (uid[28] << 3) | (uid[29] << 2) | |
| (uid[30] << 1) | uid[31]; | |
//Dbhexdump(10, rx, rxlen); | |
STATE = 1; | |
txlen = 45; | |
crc = CRC_PRESET; | |
calc_crc(&crc, 0x00, 5); | |
calc_crc(&crc, uid_byte[0], 8); | |
calc_crc(&crc, uid_byte[1], 8); | |
calc_crc(&crc, uid_byte[2], 8); | |
calc_crc(&crc, uid_byte[3], 8); | |
for (i = 0; i < 100; i++) { | |
response_bit[i] = 0; | |
} | |
for (i = 0; i < 5; i++) { | |
response_bit[i] = 0; | |
} | |
for (i = 5; i < 37; i++) { | |
response_bit[i] = uid[i - 5]; | |
} | |
for (j = 0; j < 8; j++) { | |
response_bit[i] = 0; | |
if ((crc & ((mask << 7) >> j)) != 0) | |
response_bit[i] = 1; | |
i++; | |
} | |
k = 0; | |
for (i = 0; i < 6; i++) { | |
tx[i] = (response_bit[k] << 7) | (response_bit[k + 1] << 6) | |
| (response_bit[k + 2] << 5) | |
| (response_bit[k + 3] << 4) | |
| (response_bit[k + 4] << 3) | |
| (response_bit[k + 5] << 2) | |
| (response_bit[k + 6] << 1) | response_bit[k + 7]; | |
k += 8; | |
} | |
} else if (STATE == 1 && rxlen == 44) { | |
//received configuration | |
STATE = 2; | |
z = 0; | |
for (i = 0; i < 6; i++) { | |
for (j = 0; j < 8; j++) { | |
response_bit[z] = 0; | |
if ((rx[i] & ((mask << 7) >> j)) != 0) | |
response_bit[z] = 1; | |
z++; | |
} | |
} | |
txlen = 64; | |
if (u1 >= ARRAYLEN(unlocker)) | |
bStop = !false; | |
for (i = 0; i < 8; i++) | |
tx[i] = unlocker[u1][i]; | |
u1++; | |
} else if (STATE == 2 && rxlen >= 44) { | |
STATE = 0; | |
} | |
// Send and store the reader command | |
// Disable timer 1 with external trigger to avoid triggers during our own modulation | |
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 occured 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 | |
hitag_reader_send_frame(tx, txlen); | |
// Enable and reset external trigger in timer for capturing future frames | |
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; | |
// Add transmitted frame to total count | |
if (txlen > 0) { | |
// frame_count++; | |
LogTrace(tx, nbytes(txlen), HITAG_T_WAIT_2, 0, NULL, true); | |
} | |
// Reset values for receiving frames | |
memset(rx, 0x00, sizeof(rx)); | |
rxlen = 0; | |
lastbit = 1; | |
bool bSkip = true; | |
int tag_sof = reset_sof; | |
response = 0; | |
// Receive frame, watch for at most T0*EOF periods | |
while (AT91C_BASE_TC1->TC_CV < T0 * HITAG_T_WAIT_MAX) { | |
// Check if falling edge in tag 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); | |
// Reset timer every frame, we have to capture the last edge for timing | |
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; | |
LED_B_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 | |
} | |
} | |
// 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; | |
} | |
} | |
} | |
LEDsoff(); | |
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); | |
set_tracing(false); | |
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; | |
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; | |
StartTicks(); | |
reply_old(CMD_ACK, bSuccessful, 0, 0, 0, 0); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment