]> git.zerfleddert.de Git - proxmark3-svn/commitdiff
Experimental HitagS support
authorRalf Spenneberg <ralf@os-t.de>
Fri, 4 Mar 2016 16:28:05 +0000 (17:28 +0100)
committerRalf Spenneberg <ralf@os-t.de>
Fri, 4 Mar 2016 16:28:05 +0000 (17:28 +0100)
armsrc/Makefile
armsrc/appmain.c
armsrc/apps.h
armsrc/hitag2.c
armsrc/hitagS.c [new file with mode: 0644]
client/cmdlfhitag.c
client/hid-flasher/usb_cmd.h
include/hitag2.h
include/hitagS.h [new file with mode: 0644]
include/usb_cmd.h

index 69ea23006c54c4a8008880179bc8c9d67628a63c..0b540b8483aaa1a9ce7ce6e71d49019bd5337e82 100644 (file)
@@ -15,7 +15,7 @@ APP_CFLAGS    = -DWITH_ISO14443a_StandAlone -DWITH_LF -DWITH_ISO15693 -DWITH_ISO144
 #-DWITH_LCD
 
 #SRC_LCD = fonts.c LCD.c
-SRC_LF = lfops.c hitag2.c lfsampling.c pcf7931.c lfdemod.c protocols.c
+SRC_LF = lfops.c hitag2.c hitagS.c lfsampling.c pcf7931.c lfdemod.c protocols.c
 SRC_ISO15693 = iso15693.c iso15693tools.c
 SRC_ISO14443a = epa.c iso14443a.c mifareutil.c mifarecmd.c mifaresniff.c
 SRC_ISO14443b = iso14443b.c
index 782c57fab10aa4371ce60d3ae64424bf81975874..475b1c1b8e7e2a3e593d9dde365e70b5229a50a5 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "legicrf.h"
 #include <hitag2.h>
+#include <hitagS.h>
 #include "lfsampling.h"
 #include "BigBuf.h"
 #include "mifareutil.h"
@@ -1016,6 +1017,18 @@ void UsbPacketReceived(uint8_t *packet, int len)
                case CMD_READER_HITAG: // Reader for Hitag tags, args = type and function
                        ReaderHitag((hitag_function)c->arg[0],(hitag_data*)c->d.asBytes);
                        break;
+               case CMD_SIMULATE_HITAG_S:// Simulate Hitag s tag, args = memory content
+                       SimulateHitagSTag((bool)c->arg[0],(byte_t*)c->d.asBytes);
+                       break;
+               case CMD_TEST_HITAGS_TRACES:// Tests every challenge within the given file
+                       check_challenges((bool)c->arg[0],(byte_t*)c->d.asBytes);
+                       break;
+               case CMD_READ_HITAG_S://Reader for only Hitag S tags, args = key or challenge
+                       ReadHitagS((hitag_function)c->arg[0],(hitag_data*)c->d.asBytes);
+                       break;
+               case CMD_WR_HITAG_S://writer for Hitag tags args=data to write,page and key or challenge
+                       WritePageHitagS((hitag_function)c->arg[0],(hitag_data*)c->d.asBytes,c->arg[2]);
+                       break;
 #endif
 
 #ifdef WITH_ISO15693
index c8397c38cdf225cc1d810f8dc75916e653c428c4..4d4c80837ef72747387e699a98536fa4d3d7abaf 100644 (file)
@@ -16,6 +16,7 @@
 #include <stddef.h>
 #include "common.h"
 #include "hitag2.h"
+#include "hitagS.h"
 #include "mifare.h"
 #include "../common/crc32.h"
 #include "BigBuf.h"
@@ -179,6 +180,13 @@ void SnoopHitag(uint32_t type);
 void SimulateHitagTag(bool tag_mem_supplied, byte_t* data);
 void ReaderHitag(hitag_function htf, hitag_data* htd);
 
+//hitagS.h
+void SimulateHitagSTag(bool tag_mem_supplied, byte_t* data);
+void ReadHitagS(hitag_function htf, hitag_data* htd);
+void WritePageHitagS(hitag_function htf, hitag_data* htd,int page);
+void check_challenges(bool file_given, byte_t* data);
+
+
 // cmd.h
 bool cmd_receive(UsbCommand* cmd);
 bool cmd_send(uint32_t cmd, uint32_t arg0, uint32_t arg1, uint32_t arg2, void* data, size_t len);
index 508157de9c9c2eb5e1f1e77cbfb14fa3b2e2ebc2..46432d835b284f06ff785dbe21f1cc5bc924e84e 100644 (file)
@@ -1148,7 +1148,7 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) {
       
                case RHT2F_CRYPTO: {
                        DbpString("Authenticating using key:");
-                       memcpy(key,htd->crypto.key,4);    //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);
                        blocknr = 0;
                        bQuiet = false;
diff --git a/armsrc/hitagS.c b/armsrc/hitagS.c
new file mode 100644 (file)
index 0000000..99565f1
--- /dev/null
@@ -0,0 +1,2147 @@
+//-----------------------------------------------------------------------------
+// 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 <stdio.h>
+#include <stdlib.h>
+#include "proxmark3.h"
+#include "apps.h"
+#include "util.h"
+#include "hitagS.h"
+#include "hitag2.h"
+#include "string.h"
+#include "BigBuf.h"
+
+#define CRC_PRESET 0xFF
+#define CRC_POLYNOM 0x1D
+
+#define u8                             uint8_t
+#define u32                            uint32_t
+#define u64                            uint64_t
+#define rev8(x)                        ((((x)>>7)&1)+((((x)>>6)&1)<<1)+((((x)>>5)&1)<<2)+((((x)>>4)&1)<<3)+((((x)>>3)&1)<<4)+((((x)>>2)&1)<<5)+((((x)>>1)&1)<<6)+(((x)&1)<<7))
+#define rev16(x)               (rev8 (x)+(rev8 (x>> 8)<< 8))
+#define rev32(x)               (rev16(x)+(rev16(x>>16)<<16))
+#define rev64(x)               (rev32(x)+(rev32(x>>32)<<32))
+#define bit(x,n)               (((x)>>(n))&1)
+#define bit32(x,n)             ((((x)[(n)>>5])>>((n)))&1)
+#define inv32(x,i,n)   ((x)[(i)>>5]^=((u32)(n))<<((i)&31))
+#define rotl64(x, n)   ((((u64)(x))<<((n)&63))+(((u64)(x))>>((0-(n))&63)))
+
+static bool bQuiet;
+static bool bSuccessful;
+static struct hitagS_tag tag;
+static byte_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 byte_t pwdh0, pwdl0, pwdl1;     //password bytes
+static uint32_t rnd = 0x74124485;      //randomnumber
+static int test = 0;
+size_t blocknr;
+bool end=false;
+
+// Single bit Hitag2 functions:
+#define i4(x,a,b,c,d)  ((u32)((((x)>>(a))&1)+(((x)>>(b))&1)*2+(((x)>>(c))&1)*4+(((x)>>(d))&1)*8))
+static const u32 ht2_f4a = 0x2C79;                     // 0010 1100 0111 1001
+static const u32 ht2_f4b = 0x6671;                     // 0110 0110 0111 0001
+static const u32 ht2_f5c = 0x7907287B;                 // 0111 1001 0000 0111 0010 1000 0111 1011
+#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))))
+#define uf20bs                         u32             
+
+static u32 f20(const u64 x) {
+       u32 i5;
+
+       i5 = ((ht2_f4a >> i4(x, 1, 2, 4, 5)) & 1) * 1
+                       + ((ht2_f4b >> i4(x, 7, 11, 13, 14)) & 1) * 2
+                       + ((ht2_f4b >> i4(x, 16, 20, 22, 25)) & 1) * 4
+                       + ((ht2_f4b >> i4(x, 27, 28, 30, 32)) & 1) * 8
+                       + ((ht2_f4a >> i4(x, 33, 42, 43, 45)) & 1) * 16;
+
+       return (ht2_f5c >> i5) & 1;
+}
+static u64 hitag2_round(u64 *state) {
+       u64 x = *state;
+
+       x = (x >> 1)
+                       + ((((x >> 0) ^ (x >> 2) ^ (x >> 3) ^ (x >> 6) ^ (x >> 7) ^ (x >> 8)
+                                       ^ (x >> 16) ^ (x >> 22) ^ (x >> 23) ^ (x >> 26) ^ (x >> 30)
+                                       ^ (x >> 41) ^ (x >> 42) ^ (x >> 43) ^ (x >> 46) ^ (x >> 47))
+                                       & 1) << 47);
+
+       *state = x;
+       return f20(x);
+}
+static u64 hitag2_init(const u64 key, const u32 serial, const u32 IV) {
+       u32 i;
+       u64 x = ((key & 0xFFFF) << 32) + serial;
+       for (i = 0; i < 32; i++) {
+               x >>= 1;
+               x += (u64) (f20(x) ^ (((IV >> i) ^ (key >> (i + 16))) & 1)) << 47;
+       }
+       return x;
+}
+static u32 hitag2_byte(u64 *x) {
+       u32 i, c;
+
+       for (i = 0, c = 0; i < 8; i++)
+               c += (u32) hitag2_round(x) << (i ^ 7);
+       return 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
+#define T0                                                     192
+
+#define SHORT_COIL()                                           LOW(GPIO_SSC_DOUT)
+#define OPEN_COIL()                                                    HIGH(GPIO_SSC_DOUT)
+
+#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 0
+
+/*
+ * 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 byte_t* frame, size_t frame_len) {
+// 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);
+       }
+// Drop the modulation
+       LOW(GPIO_SSC_DOUT);
+}
+
+static void hitag_reader_send_bit(int bit) {
+//Dbprintf("BIT: %d",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
+
+// Enable modulation, which means, drop the the field
+       HIGH(GPIO_SSC_DOUT);
+       if (test == 1) {
+               // Wait for 4-10 times the carrier period
+               while (AT91C_BASE_TC0->TC_CV < T0 * 6)
+                       ;
+               //      SpinDelayUs(8*8);
+
+               // Disable modulation, just activates the field again
+               LOW(GPIO_SSC_DOUT);
+
+               if (bit == 0) {
+                       // Zero bit: |_-|
+                       while (AT91C_BASE_TC0->TC_CV < T0 * 11)
+                               ;
+                       //              SpinDelayUs(16*8);
+               } else {
+                       // One bit: |_--|
+                       while (AT91C_BASE_TC0->TC_CV < T0 * 14)
+                               ;
+                       //              SpinDelayUs(22*8);
+               }
+       } else {
+               // Wait for 4-10 times the carrier period
+               while (AT91C_BASE_TC0->TC_CV < T0 * 6)
+                       ;
+               //      SpinDelayUs(8*8);
+
+               // Disable modulation, just activates the field again
+               LOW(GPIO_SSC_DOUT);
+
+               if (bit == 0) {
+                       // Zero bit: |_-|
+                       while (AT91C_BASE_TC0->TC_CV < T0 * 22)
+                               ;
+                       //              SpinDelayUs(16*8);
+               } else {
+                       // One bit: |_--|
+                       while (AT91C_BASE_TC0->TC_CV < T0 * 28)
+                               ;
+                       //              SpinDelayUs(22*8);
+               }
+       }
+
+       LED_A_OFF();
+}
+
+static void hitag_reader_send_frame(const byte_t* frame, size_t frame_len) {
+// 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;
+// Enable modulation, which means, drop the the field
+       HIGH(GPIO_SSC_DOUT);
+// Wait for 4-10 times the carrier period
+       while (AT91C_BASE_TC0->TC_CV < T0 * 6)
+               ;
+// Disable modulation, just activates the field again
+       LOW(GPIO_SSC_DOUT);
+}
+
+/*
+ * to check if the right uid was selected
+ */
+static int check_select(byte_t* rx, uint32_t uid) {
+       unsigned char resp[48];
+       int i;
+       uint32_t ans = 0x0;
+       for (i = 0; i < 48; i++)
+               resp[i] = (rx[i / 8] >> (7 - (i % 8))) & 0x1;
+       for (i = 0; i < 32; i++)
+               ans += resp[5 + i] << (31 - i);
+       /*if (rx[0] == 0x01 && rx[1] == 0x15 && rx[2] == 0xc1 && rx[3] == 0x14
+        && rx[4] == 0x65 && rx[5] == 0x38)
+        Dbprintf("got uid %X", ans);*/
+       temp_uid = ans;
+       if (ans == tag.uid)
+               return 1;
+       return 0;
+}
+
+/*
+ * handles all commands from a reader
+ */
+static void hitagS_handle_reader_command(byte_t* rx, const size_t rxlen,
+               byte_t* tx, size_t* txlen) {
+       byte_t rx_air[HITAG_FRAME_LEN];
+       byte_t page;
+       int i;
+       u64 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 = READY;
+               tag.tstate = NO_OP;
+               if ((rx[0] & 0xf0) == 0x30) {
+                       tag.mode = STANDARD;
+                       sof_bits = 1;
+                       m = AC2K;
+               }
+               if ((rx[0] & 0xf0) == 0xc0) {
+                       tag.mode = ADVANCED;
+                       sof_bits = 3;
+                       m = AC2K;
+               }
+
+               if ((rx[0] & 0xf0) == 0xd0) {
+                       tag.mode = FAST_ADVANCED;
+                       sof_bits = 3;
+                       m = AC4K;
+               }
+               //send uid as a response
+               *txlen = 32;
+               for (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 STANDARD:
+                               sof_bits = 1;
+                               m = MC4K;
+                               break;
+                       case ADVANCED:
+                               sof_bits = 6;
+                               m = MC4K;
+                               break;
+                       case FAST_ADVANCED:
+                               sof_bits = 6;
+                               m = MC8K;
+                               break;
+                       default:
+                               break;
+                       }
+
+                       //send configuration
+                       for (i = 0; i < 4; i++)
+                               tx[i] = (tag.pages[0][1] >> (i * 8)) & 0xff;
+                       tx[3] = 0xff;
+                       if (tag.mode != STANDARD) {
+                               *txlen = 40;
+                               crc = CRC_PRESET;
+                               for (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 STANDARD:
+                       sof_bits = 1;
+                       m = MC4K;
+                       break;
+               case ADVANCED:
+                       sof_bits = 6;
+                       m = MC4K;
+                       break;
+               case FAST_ADVANCED:
+                       sof_bits = 6;
+                       m = MC8K;
+                       break;
+               default:
+                       break;
+               }
+
+               for (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 != 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 == WRITING_PAGE_DATA) {
+                       tag.tstate = 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 STANDARD:
+                               sof_bits = 1;
+                               m = MC4K;
+                               break;
+                       case ADVANCED:
+                               sof_bits = 6;
+                               m = MC4K;
+                               break;
+                       case FAST_ADVANCED:
+                               sof_bits = 6;
+                               m = MC8K;
+                               break;
+                       default:
+                               break;
+                       }
+               } else if (tag.tstate == 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 STANDARD:
+                               sof_bits = 1;
+                               m = MC4K;
+                               break;
+                       case ADVANCED:
+                               sof_bits = 6;
+                               m = MC4K;
+                               break;
+                       case FAST_ADVANCED:
+                               sof_bits = 6;
+                               m = MC8K;
+                               break;
+                       default:
+                               break;
+                       }
+                       page_to_be_written++;
+                       block_data_left--;
+                       if (block_data_left == 0) {
+                               tag.tstate = 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
+                       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 STANDARD:
+                               sof_bits = 1;
+                               m = MC4K;
+                               break;
+                       case ADVANCED:
+                               sof_bits = 6;
+                               m = MC4K;
+                               break;
+                       case FAST_ADVANCED:
+                               sof_bits = 6;
+                               m = MC8K;
+                               break;
+                       default:
+                               break;
+                       }
+
+                       if (tag.mode != STANDARD) {
+                               //add crc8
+                               *txlen = 40;
+                               crc = CRC_PRESET;
+                               for (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
+                               {
+                       page = ((rx[0] & 0x0f) * 16) + ((rx[1] & 0xf0) / 16);
+                       *txlen = 32 * 4;
+                       //send page,...,page+3 data
+                       for (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 STANDARD:
+                               sof_bits = 1;
+                               m = MC4K;
+                               break;
+                       case ADVANCED:
+                               sof_bits = 6;
+                               m = MC4K;
+                               break;
+                       case FAST_ADVANCED:
+                               sof_bits = 6;
+                               m = MC8K;
+                               break;
+                       default:
+                               break;
+                       }
+
+                       if (tag.mode != STANDARD) {
+                               //add crc8
+                               *txlen = 32 * 4 + 8;
+                               crc = CRC_PRESET;
+                               for (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
+                               {
+                       page = ((rx[0] & 0x0f) * 16) + ((rx[1] & 0xf0) / 16);
+
+                       switch (tag.mode) {
+                       case STANDARD:
+                               sof_bits = 1;
+                               m = MC4K;
+                               break;
+                       case ADVANCED:
+                               sof_bits = 6;
+                               m = MC4K;
+                               break;
+                       case 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 = WRITING_PAGE_DATA;
+                       }
+
+               } else if ((rx[0] & 0xf0) == 0x90) //write block
+                               {
+                       page = ((rx[0] & 0x0f) * 6) + ((rx[1] & 0xf0) / 16);
+                       switch (tag.mode) {
+                       case STANDARD:
+                               sof_bits = 1;
+                               m = MC4K;
+                               break;
+                       case ADVANCED:
+                               sof_bits = 6;
+                               m = MC4K;
+                               break;
+                       case 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 = 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, byte_t* rx, const size_t rxlen, byte_t* tx,
+               size_t* txlen) {
+       byte_t rx_air[HITAG_FRAME_LEN];
+       int response_bit[200];
+       int i, j, z, k;
+       unsigned char mask = 1;
+       unsigned char uid[32];
+       byte_t uid1 = 0x00, uid2 = 0x00, uid3 = 0x00, uid4 = 0x00;
+       unsigned char crc;
+       u64 state;
+       byte_t auth_ks[4];
+       byte_t conf_pages[3];
+       memcpy(rx_air, rx, nbytes(rxlen));
+       *txlen = 0;
+
+       if (tag.pstate == READY && rxlen >= 67) {
+               //received uid
+               if(end==true) {
+                       Dbprintf("authentication failed!");
+                       return -1;
+               }
+               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;
+               }
+               uid1 = (uid[0] << 7) | (uid[1] << 6) | (uid[2] << 5) | (uid[3] << 4)
+                               | (uid[4] << 3) | (uid[5] << 2) | (uid[6] << 1) | uid[7];
+               uid2 = (uid[8] << 7) | (uid[9] << 6) | (uid[10] << 5) | (uid[11] << 4)
+                               | (uid[12] << 3) | (uid[13] << 2) | (uid[14] << 1) | uid[15];
+               uid3 = (uid[16] << 7) | (uid[17] << 6) | (uid[18] << 5) | (uid[19] << 4)
+                               | (uid[20] << 3) | (uid[21] << 2) | (uid[22] << 1) | uid[23];
+               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 (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;
+               }
+               tag.pstate = INIT;
+       } else if (tag.pstate == INIT && rxlen == 44) {
+               // received configuration after select command
+               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++;
+                       }
+               }
+               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 (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 (i = 0; i < 8; i++)
+                                               tx[i]=((NrAr>>(56-(i*8)))&0xff);
+                               }
+                               end=true;
+                               tag.pstate = AUTHENTICATE;
+                       } else {
+                               Dbprintf("authentication failed!");
+                               return -1;
+                       }
+               } else if (tag.auth == 0) {
+                       tag.pstate = SELECTED;
+               }
+               
+       } else if (tag.pstate == 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 (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 = 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, byte_t* data) {
+       int frame_count;
+       int response;
+       int overflow;
+       int i, j;
+       byte_t rx[HITAG_FRAME_LEN];
+       size_t rxlen = 0;
+//bool bQuitTraceFull = false;
+       bQuiet = false;
+       byte_t txbuf[HITAG_FRAME_LEN];
+       byte_t* tx = txbuf;
+       size_t txlen = 0;
+       BigBuf_free();
+
+// Clean up trace and prepare it for storing frames
+       set_tracing(TRUE);
+       clear_trace();
+
+       DbpString("Starting HitagS simulation");
+       LED_D_ON();
+
+       tag.pstate = READY;
+       tag.tstate = 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((byte_t*)tag.pages,data,4*64);
+       }
+       tag.uid=(uint32_t)tag.pages[0];
+       Dbprintf("Hitag S simulation started");
+       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)==1)
+               tag.auth=1;
+       tag.LCON=0;
+       if((tag.pages[1][2]&0x2)==1)
+               tag.LCON=1;
+       tag.LKP=0;
+       if((tag.pages[1][2]&0x1)==1)
+               tag.LKP=1;
+       //con2
+       //0=read write 1=read only
+       tag.LCK7=0;
+       if((tag.pages[1][1]&0x80)==1)
+               tag.LCK7=1;
+       tag.LCK6=0;
+       if((tag.pages[1][1]&0x40)==1)
+               tag.LCK6=1;
+       tag.LCK5=0;
+       if((tag.pages[1][1]&0x20)==1)
+               tag.LCK5=1;
+       tag.LCK4=0;
+       if((tag.pages[1][1]&0x10)==1)
+               tag.LCK4=1;
+       tag.LCK3=0;
+       if((tag.pages[1][1]&0x8)==1)
+               tag.LCK3=1;
+       tag.LCK2=0;
+       if((tag.pages[1][1]&0x4)==1)
+               tag.LCK2=1;
+       tag.LCK1=0;
+       if((tag.pages[1][1]&0x2)==1)
+               tag.LCK1=1;
+       tag.LCK0=0;
+       if((tag.pages[1][1]&0x1)==1)
+               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 | FPGA_LF_EDGE_DETECT_READER_FIELD);
+       FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
+       SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
+       RELAY_OFF();
+
+// Configure output pin that is connected to the FPGA (for modulating)
+       AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT;
+       AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT;
+
+// Disable modulation at default, which means release resistance
+       LOW(GPIO_SSC_DOUT);
+
+// Enable Peripheral Clock for TIMER_CLOCK0, used to measure exact timing before answering
+       AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0);
+
+// Enable Peripheral Clock for TIMER_CLOCK1, used to capture edges of the reader frames
+       AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1);
+       AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME;
+
+// Disable timer during configuration
+       AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
+
+// Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger,
+// external trigger 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;
+
+// Reset the received frame, frame count and timing info
+       memset(rx, 0x00, sizeof(rx));
+       frame_count = 0;
+       response = 0;
+       overflow = 0;
+
+// Enable and reset counter
+       AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
+
+       while (!BUTTON_PRESS()) {
+               // Watchdog hit
+               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++;
+                       if (!bQuiet) {
+                               if (!LogTraceHitag(rx, rxlen, response, 0, true)) {
+                                       DbpString("Trace full");
+                                       clear_trace();
+                               }
+                       }
+
+                       // 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);
+                               // Store the frame in the trace
+                               if (!bQuiet) {
+                                       if (!LogTraceHitag(tx, txlen, 0, 0, false)) {
+                                               DbpString("Trace full");
+                                               clear_trace();
+                                       }
+                               }
+                       }
+
+                       // 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;
+       }
+       LED_B_OFF();
+       LED_D_OFF();
+       AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
+       AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
+       FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+}
+
+/*
+ * 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) {
+       int i, j, z, k;
+       int frame_count;
+       int response_bit[200];
+       int response;
+       byte_t rx[HITAG_FRAME_LEN];
+       size_t rxlen = 0;
+       byte_t txbuf[HITAG_FRAME_LEN];
+       byte_t* tx = txbuf;
+       size_t txlen = 0;
+       int lastbit;
+       bool bSkip;
+       int reset_sof;
+       int tag_sof;
+       int t_wait = HITAG_T_WAIT_MAX;
+       bool bStop;
+       bool bQuitTraceFull = false;
+       int sendNum = 0;
+       unsigned char mask = 1;
+       unsigned char crc;
+       unsigned char pageData[32];
+       page_to_be_written = 0;
+       
+       //read given key/challenge
+       byte_t NrAr_[8];
+       uint64_t key=0;
+       uint64_t NrAr=0;
+       byte_t key_[6];
+       switch(htf) {
+               case 01: { //RHTS_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 02: { //RHTS_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;
+               } break;
+       }
+
+
+
+       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;
+       bQuitTraceFull = true;
+
+       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);
+
+// Set Frequency divisor which will drive the FPGA and analog mux selection
+       FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95);                                      //125Khz
+       SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
+       RELAY_OFF();
+
+// Disable modulation at default, which means enable the field
+       LOW(GPIO_SSC_DOUT);
+
+// Give it a bit of time for the resonant antenna to settle.
+       SpinDelay(30);
+
+// Enable Peripheral Clock for TIMER_CLOCK0, used to measure exact timing before answering
+       AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0);
+
+// Enable Peripheral Clock for TIMER_CLOCK1, used to capture edges of the tag 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;
+
+// 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;
+
+// Reset the received frame, frame count and timing info
+       frame_count = 0;
+       response = 0;
+       lastbit = 1;
+       bStop = false;
+
+       reset_sof = 1;
+       t_wait = 200;
+
+       while (!bStop && !BUTTON_PRESS()) {
+               // Watchdog hit
+               WDT_HIT();
+
+               // Check if frame was captured and store it
+               if (rxlen > 0) {
+                       frame_count++;
+                       if (!bQuiet) {
+                               if (!LogTraceHitag(rx, rxlen, response, 0, false)) {
+                                       DbpString("Trace full");
+                                       if (bQuitTraceFull) {
+                                               break;
+                                       } else {
+                                               bQuiet = true;
+                                       }
+                               }
+                       }
+               }
+
+               // By default reset the transmission buffer
+               tx = txbuf;
+               txlen = 0;
+
+               if (rxlen == 0) {
+                       //start authentication
+                       txlen = 5;
+                       memcpy(tx, "\xc0", nbytes(txlen));
+                       tag.pstate = READY;
+                       tag.tstate = NO_OP;
+               } else if (tag.pstate != SELECTED) {
+                       if (hitagS_handle_tag_auth(htf, key,NrAr,rx, rxlen, tx, &txlen) == -1)
+                               bStop = !false;
+               }
+               if (tag.pstate == SELECTED && tag.tstate == NO_OP && rxlen > 0) {
+                       //send read request
+                       tag.tstate = 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 == SELECTED && tag.tstate == 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 / 4][sendNum % 4] = 0x0;
+                       for (i = 0; i < 4; i++) {
+                               tag.pages[sendNum / 4][sendNum % 4] += ((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)])
+                                               << (i * 8);
+                       }
+                       if (tag.auth && tag.LKP && sendNum == 1) {
+                               Dbprintf("Page[%2d]: %02X %02X %02X %02X", sendNum, pwdh0,
+                                               (tag.pages[sendNum / 4][sendNum % 4] >> 16) & 0xff,
+                                               (tag.pages[sendNum / 4][sendNum % 4] >> 8) & 0xff,
+                                               tag.pages[sendNum / 4][sendNum % 4] & 0xff);
+                       } else {
+                               Dbprintf("Page[%2d]: %02X %02X %02X %02X", sendNum,
+                                               (tag.pages[sendNum / 4][sendNum % 4] >> 24) & 0xff,
+                                               (tag.pages[sendNum / 4][sendNum % 4] >> 16) & 0xff,
+                                               (tag.pages[sendNum / 4][sendNum % 4] >> 8) & 0xff,
+                                               tag.pages[sendNum / 4][sendNum % 4] & 0xff);
+                       }
+
+                       sendNum++;
+                       //display key and password if possible
+                       if (sendNum == 2 && tag.auth == 1 && tag.LKP) {
+                               if (htf == 02) { //RHTS_KEY
+                                       Dbprintf("Page[ 2]: %02X %02X %02X %02X",
+                                                       (byte_t)(key >> 8) & 0xff,
+                                                       (byte_t) key & 0xff, pwdl1, pwdl0);
+                                       Dbprintf("Page[ 3]: %02X %02X %02X %02X",
+                                                       (byte_t)(key >> 40) & 0xff,
+                                                       (byte_t)(key >> 32) & 0xff,
+                                                       (byte_t)(key >> 24) & 0xff,
+                                                       (byte_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]: __ __ __ __");
+                               }
+                       }
+
+                       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++;
+                       if (!bQuiet) {
+                               // Store the frame in the trace
+                               if (!LogTraceHitag(tx, txlen, HITAG_T_WAIT_2, 0, true)) {
+                                       if (bQuitTraceFull) {
+                                               DbpString("Trace full");
+                                               break;
+                                       } else {
+                                               bQuiet = true;
+                                       }
+                               }
+                       }
+               }
+
+               // Reset values for receiving frames
+               memset(rx, 0x00, sizeof(rx));
+               rxlen = 0;
+               lastbit = 1;
+               bSkip = true;
+               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;
+       LED_B_OFF();
+       LED_D_OFF();
+       AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
+       AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
+       FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+       cmd_send(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_) {
+       int frame_count;
+       int response;
+       byte_t rx[HITAG_FRAME_LEN];
+       size_t rxlen = 0;
+       byte_t txbuf[HITAG_FRAME_LEN];
+       byte_t* tx = txbuf;
+       size_t txlen = 0;
+       int lastbit;
+       bool bSkip;
+       int reset_sof;
+       int tag_sof;
+       int t_wait = HITAG_T_WAIT_MAX;
+       bool bStop;
+       bool bQuitTraceFull = false;
+       int page = page_;
+       unsigned char crc;
+       byte_t data[4]= {0,0,0,0};
+       
+       //read given key/challenge, the page and the data
+       byte_t NrAr_[8];
+       uint64_t key=0;
+       uint64_t NrAr=0;
+       byte_t key_[6];
+       switch(htf) {
+               case 03: { //WHTS_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 04: { //WHTS_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;
+               } break;
+       }
+
+       Dbprintf("Page: %d",page_);
+       Dbprintf("DATA: %02X %02X %02X %02X", data[0], data[1], data[2], data[3]);
+       FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
+// Reset the return status
+       bSuccessful = false;
+
+       tag.pstate = READY;
+       tag.tstate = NO_OP;
+
+// Clean up trace and prepare it for storing frames
+       set_tracing(TRUE);
+       clear_trace();
+
+       bQuiet = false;
+       bQuitTraceFull = true;
+
+       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);
+
+// Set Frequency divisor which will drive the FPGA and analog mux selection
+       FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
+       SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
+       RELAY_OFF();
+
+// Disable modulation at default, which means enable the field
+       LOW(GPIO_SSC_DOUT);
+
+// Give it a bit of time for the resonant antenna to settle.
+       SpinDelay(30);
+
+// Enable Peripheral Clock for TIMER_CLOCK0, used to measure exact timing before answering
+       AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0);
+
+// Enable Peripheral Clock for TIMER_CLOCK1, used to capture edges of the tag 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;
+
+// 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;
+
+// Reset the received frame, frame count and timing info
+       frame_count = 0;
+       response = 0;
+       lastbit = 1;
+       bStop = false;
+
+       reset_sof = 1;
+       t_wait = 200;
+
+       while (!bStop && !BUTTON_PRESS()) {
+               // Watchdog hit
+               WDT_HIT();
+
+               // Check if frame was captured and store it
+               if (rxlen > 0) {
+                       frame_count++;
+                       if (!bQuiet) {
+                               if (!LogTraceHitag(rx, rxlen, response, 0, false)) {
+                                       DbpString("Trace full");
+                                       if (bQuitTraceFull) {
+                                               break;
+                                       } else {
+                                               bQuiet = true;
+                                       }
+                               }
+                       }
+               }
+
+               //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 == 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 != WRITING_PAGE_DATA) {
+                       //start the authetication
+                       txlen = 5;
+                       memcpy(tx, "\xc0", nbytes(txlen));
+                       tag.pstate = READY;
+                       tag.tstate = NO_OP;
+               } else if (tag.pstate != 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 == SELECTED && tag.tstate == 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 = 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 == SELECTED && tag.tstate == WRITING_PAGE_ACK
+                               && rxlen == 6 && rx[0] == 0xf4) {
+                       //ACK recieved to write the page. send data
+                       tag.tstate = 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 == SELECTED && tag.tstate == 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++;
+                       if (!bQuiet) {
+                               // Store the frame in the trace
+                               if (!LogTraceHitag(tx, txlen, HITAG_T_WAIT_2, 0, true)) {
+                                       if (bQuitTraceFull) {
+                                               DbpString("Trace full");
+                                               break;
+                                       } else {
+                                               bQuiet = true;
+                                       }
+                               }
+                       }
+               }
+
+               // Reset values for receiving frames
+               memset(rx, 0x00, sizeof(rx));
+               rxlen = 0;
+               lastbit = 1;
+               bSkip = true;
+               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;
+       LED_B_OFF();
+       LED_D_OFF();
+       AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
+       AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
+       FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+       cmd_send(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, byte_t* data) {
+       int i, j, z, k;
+       byte_t uid_byte[4];
+       int frame_count;
+       int response;
+       byte_t rx[HITAG_FRAME_LEN];
+       byte_t unlocker[60][8];
+       int u1 = 0;
+       size_t rxlen = 0;
+       byte_t txbuf[HITAG_FRAME_LEN];
+       byte_t* tx = txbuf;
+       size_t txlen = 0;
+       int lastbit;
+       bool bSkip;
+       int reset_sof;
+       int tag_sof;
+       int t_wait = HITAG_T_WAIT_MAX;
+       int STATE = 0;
+       bool bStop;
+       bool bQuitTraceFull = false;
+       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;
+       bQuitTraceFull = true;
+
+       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);
+
+// Set Frequency divisor which will drive the FPGA and analog mux selection
+       FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95);                                      //125Khz
+       SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
+       RELAY_OFF();
+
+// Disable modulation at default, which means enable the field
+       LOW(GPIO_SSC_DOUT);
+
+// Give it a bit of time for the resonant antenna to settle.
+       SpinDelay(30);
+
+// Enable Peripheral Clock for TIMER_CLOCK0, used to measure exact timing before answering
+       AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0);
+
+// Enable Peripheral Clock for TIMER_CLOCK1, used to capture edges of the tag 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;
+
+// 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;
+
+// Reset the received frame, frame count and timing info
+       frame_count = 0;
+       response = 0;
+       lastbit = 1;
+       bStop = false;
+
+       reset_sof = 1;
+       t_wait = 200;
+
+       if (file_given) {
+               DbpString("Loading challenges...");
+               memcpy((byte_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++;
+                       if (!bQuiet) {
+                               if (!LogTraceHitag(rx, rxlen, response, 0, false)) {
+                                       DbpString("Trace full");
+                                       if (bQuitTraceFull) {
+                                               break;
+                                       } else {
+                                               bQuiet = true;
+                                       }
+                               }
+                       }
+               }
+
+               tx = txbuf;
+               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 >= (sizeof(unlocker) / sizeof(unlocker[0])))
+                               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++;
+                       if (!bQuiet) {
+                               // Store the frame in the trace
+                               if (!LogTraceHitag(tx, txlen, HITAG_T_WAIT_2, 0, true)) {
+                                       if (bQuitTraceFull) {
+                                               DbpString("Trace full");
+                                               break;
+                                       } else {
+                                               bQuiet = true;
+                                       }
+                               }
+                       }
+               }
+
+               // Reset values for receiving frames
+               memset(rx, 0x00, sizeof(rx));
+               rxlen = 0;
+               lastbit = 1;
+               bSkip = true;
+               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;
+                       }
+               }
+       }
+       LED_B_OFF();
+       LED_D_OFF();
+       AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
+       AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
+       FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+       cmd_send(CMD_ACK, bSuccessful, 0, 0, 0, 0);
+}
+
+
+
index fe5ba587617a502d9b8a0b2ee43dd82619c1e376..07247364c0751a498836871fca7fab1cf193994e 100644 (file)
@@ -18,6 +18,7 @@
 #include "common.h"
 #include "util.h"
 #include "hitag2.h"
+#include "hitagS.h"
 #include "sleep.h"
 #include "cmdmain.h"
 
@@ -190,14 +191,20 @@ int CmdLFHitagSim(const char *Cmd) {
 }
 
 int CmdLFHitagReader(const char *Cmd) {
-//  UsbCommand c = {CMD_READER_HITAG};
-       
-//     param_get32ex(Cmd,1,0,16);
        UsbCommand c = {CMD_READER_HITAG};//, {param_get32ex(Cmd,0,0,10),param_get32ex(Cmd,1,0,16),param_get32ex(Cmd,2,0,16),param_get32ex(Cmd,3,0,16)}};
        hitag_data* htd = (hitag_data*)c.d.asBytes;
        hitag_function htf = param_get32ex(Cmd,0,0,10);
        
        switch (htf) {
+               case 01: { //RHTSF_CHALLENGE
+                       c = (UsbCommand){ CMD_READ_HITAG_S };
+                       num_to_bytes(param_get32ex(Cmd,1,0,16),4,htd->auth.NrAr);
+                       num_to_bytes(param_get32ex(Cmd,2,0,16),4,htd->auth.NrAr+4);
+               } break;
+               case 02: { //RHTSF_KEY
+                       c = (UsbCommand){ CMD_READ_HITAG_S };
+                       num_to_bytes(param_get64ex(Cmd,1,0,16),6,htd->crypto.key);
+               } break;
                case RHT2F_PASSWORD: {
                        num_to_bytes(param_get32ex(Cmd,1,0,16),4,htd->pwd.password);
                } break;
@@ -216,6 +223,8 @@ int CmdLFHitagReader(const char *Cmd) {
                        PrintAndLog("Error: unkown reader function %d",htf);
                        PrintAndLog("Hitag reader functions");
                        PrintAndLog(" HitagS (0*)");
+                       PrintAndLog("  01 <nr> <ar> (Challenge) read all pages from a Hitag S tag");
+                       PrintAndLog("  02 <key> (set to 0 if no authentication is needed) read all pages from a Hitag S tag");
                        PrintAndLog(" Hitag1 (1*)");
                        PrintAndLog(" Hitag2 (2*)");
                        PrintAndLog("  21 <password> (password mode)");
@@ -257,14 +266,126 @@ int CmdLFHitagReader(const char *Cmd) {
   return 0;
 }
 
+
+int CmdLFHitagSimS(const char *Cmd) {
+       UsbCommand c = { CMD_SIMULATE_HITAG_S };
+       char filename[FILE_PATH_SIZE] = { 0x00 };
+       FILE* pf;
+       bool tag_mem_supplied;
+       int len = strlen(Cmd);
+       if (len > FILE_PATH_SIZE)
+               len = FILE_PATH_SIZE;
+       memcpy(filename, Cmd, len);
+
+       if (strlen(filename) > 0) {
+               if ((pf = fopen(filename, "rb+")) == NULL) {
+                       PrintAndLog("Error: Could not open file [%s]", filename);
+                       return 1;
+               }
+               tag_mem_supplied = true;
+               if (fread(c.d.asBytes, 4*64, 1, pf) == 0) {
+                       PrintAndLog("Error: File reading error");
+                       fclose(pf);
+                       return 1;
+               }
+               fclose(pf);
+       } else {
+               tag_mem_supplied = false;
+       }
+
+       // Does the tag comes with memory
+       c.arg[0] = (uint32_t) tag_mem_supplied;
+
+       SendCommand(&c);
+       return 0;
+}
+
+int CmdLFHitagCheckChallenges(const char *Cmd) {
+       UsbCommand c = { CMD_TEST_HITAGS_TRACES };
+       char filename[FILE_PATH_SIZE] = { 0x00 };
+       FILE* pf;
+       bool file_given;
+       int len = strlen(Cmd);
+       if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE;
+       memcpy(filename, Cmd, len);
+       
+       if (strlen(filename) > 0) {
+               if ((pf = fopen(filename,"rb+")) == NULL) {
+                       PrintAndLog("Error: Could not open file [%s]",filename);
+                       return 1;
+               }
+               file_given = true;
+               if (fread(c.d.asBytes,8*60,1,pf) == 0) {
+      PrintAndLog("Error: File reading error");
+      fclose(pf);
+                       return 1;
+        }
+               fclose(pf);
+       } else {
+               file_given = false;
+       }
+       
+       //file with all the challenges to try
+       c.arg[0] = (uint32_t)file_given;
+
+  SendCommand(&c);
+  return 0;
+}
+
+
+int CmdLFHitagWP(const char *Cmd) {
+       UsbCommand c = { CMD_WR_HITAG_S };
+       hitag_data* htd = (hitag_data*)c.d.asBytes;
+       hitag_function htf = param_get32ex(Cmd,0,0,10);
+       switch (htf) {
+               case 03: { //WHTSF_CHALLENGE
+                       num_to_bytes(param_get64ex(Cmd,1,0,16),8,htd->auth.NrAr);
+                       c.arg[2]= param_get32ex(Cmd, 2, 0, 10);
+                       num_to_bytes(param_get32ex(Cmd,3,0,16),4,htd->auth.data);
+               } break;
+               case 04: { //WHTSF_KEY
+                       num_to_bytes(param_get64ex(Cmd,1,0,16),6,htd->crypto.key);
+                       c.arg[2]= param_get32ex(Cmd, 2, 0, 10);
+                       num_to_bytes(param_get32ex(Cmd,3,0,16),4,htd->crypto.data);
+
+               } break;
+               default: {
+                       PrintAndLog("Error: unkown writer function %d",htf);
+                       PrintAndLog("Hitag writer functions");
+                       PrintAndLog(" HitagS (0*)");
+                       PrintAndLog("  03 <nr,ar> (Challenge) <page> <byte0...byte3> write page on a Hitag S tag");
+                       PrintAndLog("  04 <key> (set to 0 if no authentication is needed) <page> <byte0...byte3> write page on a Hitag S tag");
+                       PrintAndLog(" Hitag1 (1*)");
+                       PrintAndLog(" Hitag2 (2*)");
+                       return 1;
+               } break;
+       }
+       // Copy the hitag function into the first argument
+       c.arg[0] = htf;
+
+  // Send the command to the proxmark
+  SendCommand(&c);
+  
+  UsbCommand resp;
+  WaitForResponse(CMD_ACK,&resp);
+  
+  // Check the return status, stored in the first argument
+  if (resp.arg[0] == false) return 1;
+  return 0;
+}
+
+
 static command_t CommandTable[] = 
 {
-  {"help",    CmdHelp,           1, "This help"},
-  {"list",    CmdLFHitagList,    1, "<outfile> List Hitag trace history"},
-  {"reader",  CmdLFHitagReader,  1, "Act like a Hitag Reader"},
-  {"sim",     CmdLFHitagSim,     1, "<infile> Simulate Hitag transponder"},
-  {"snoop",   CmdLFHitagSnoop,   1, "Eavesdrop Hitag communication"},
-               {NULL, NULL, 0, NULL}
+  {"help",             CmdHelp,           1, "This help"},
+  {"list",             CmdLFHitagList,    1, "<outfile> List Hitag trace history"},
+  {"reader",           CmdLFHitagReader,  1, "Act like a Hitag Reader"},
+  {"sim",              CmdLFHitagSim,     1, "<infile> Simulate Hitag transponder"},
+  {"snoop",            CmdLFHitagSnoop,   1, "Eavesdrop Hitag communication"},
+  {"writer",                   CmdLFHitagWP,      1, "Act like a Hitag Writer" },
+  {"simS",             CmdLFHitagSimS,    1, "<hitagS.hts> Simulate HitagS transponder" }, 
+  {"checkChallenges",  CmdLFHitagCheckChallenges,   1, "<challenges.cc> test all challenges" }, {
+                               NULL,NULL, 0, NULL }
 };
 
 int CmdLFHitag(const char *Cmd)
index 46738181e4c04453cde39e6fa4c3d259163a5645..bdf18912b712ecd7ab2e626980e86647cb1c669e 100644 (file)
@@ -107,6 +107,12 @@ typedef struct {
 #define CMD_SIMULATE_HITAG                                                0x0371
 #define CMD_READER_HITAG                                                  0x0372
 
+#define CMD_SIMULATE_HITAG_S                                              0x0368
+#define CMD_TEST_HITAGS_TRACES                                           0x0367
+#define CMD_READ_HITAG_S                                                 0x0373
+#define CMD_WR_HITAG_S                                                   0x0375
+#define CMD_EMU_HITAG_S                                                          0x0376
+
 #define CMD_SIMULATE_TAG_ISO_14443B                                       0x0381
 #define CMD_SNOOP_ISO_14443B                                              0x0382
 #define CMD_SNOOP_ISO_14443a                                              0x0383
index ca15d81d2b6e959040c2920ef53382c92a8d6275..284b5ecbec822381066eede41cad710906d98cc0 100644 (file)
@@ -7,11 +7,17 @@
 //-----------------------------------------------------------------------------
 // Hitag2 type prototyping
 //-----------------------------------------------------------------------------
+// HitagS added 
+//-----------------------------------------------------------------------------
 
 #ifndef _HITAG2_H_
 #define _HITAG2_H_
 
 typedef enum {
+       RHTSF_CHALLENGE           = 01,
+       RHTSF_KEY                 = 02,
+       WHTSF_CHALLENGE           = 03,
+       WHTSF_KEY                 = 04,
        RHT2F_PASSWORD            = 21,
        RHT2F_AUTHENTICATE        = 22,
        RHT2F_CRYPTO              = 23,
@@ -24,10 +30,12 @@ typedef struct {
 
 typedef struct {
        byte_t NrAr[8];
+       byte_t data[4];
 } PACKED rht2d_authenticate;
 
 typedef struct {
-       byte_t key[4];
+       byte_t key[6];
+       byte_t data[4];
 } PACKED rht2d_crypto;
 
 typedef union {
diff --git a/include/hitagS.h b/include/hitagS.h
new file mode 100644 (file)
index 0000000..870efb8
--- /dev/null
@@ -0,0 +1,54 @@
+//-----------------------------------------------------------------------------
+// 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>
+//-----------------------------------------------------------------------------
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <hitag2.h>
+
+#ifndef _HITAGS_H_
+#define _HITAGS_H_
+
+typedef enum PROTO_STATE {READY=0,INIT,AUTHENTICATE,SELECTED,QUIET,TTF,FAIL} PSTATE;                           //protocol-state
+typedef enum TAG_STATE   {NO_OP=0,READING_PAGE,WRITING_PAGE_ACK,WRITING_PAGE_DATA,WRITING_BLOCK_DATA} TSATE;   //tag-state
+typedef enum SOF_TYPE    {STANDARD=0,ADVANCED,FAST_ADVANCED,ONE,NO_BITS} stype;                                        //number of start-of-frame bits
+
+struct hitagS_tag {
+       PSTATE pstate; //protocol-state
+       TSATE tstate;  //tag-state
+       uint32_t uid;
+       uint32_t pages[16][4];
+       uint64_t key;
+       byte_t pwdl0,pwdl1,pwdh0;
+       //con0
+       int max_page;
+       stype mode;
+       //con1
+       bool auth;  //0=Plain 1=Auth
+       bool TTFC;  //Transponder Talks first coding. 0=Manchester 1=Biphase
+       int TTFDR;  //data rate in TTF Mode
+       int TTFM;   //the number of pages that are sent to the RWD
+       bool LCON;  //0=con1/2 read write 1=con1 read only and con2 OTP
+       bool LKP;   //0=page2/3 read write 1=page2/3 read only in Plain mode and no access in authenticate mode
+       //con2
+       //0=read write 1=read only
+       bool LCK7; //page4/5
+       bool LCK6; //page6/7
+       bool LCK5; //page8-11
+       bool LCK4; //page12-15
+       bool LCK3; //page16-23
+       bool LCK2; //page24-31
+       bool LCK1; //page32-47
+       bool LCK0; //page48-63
+} ;
+
+#endif
index 38f8617a84c14c2c23e152c8b45b1742aa025738..8448b06a09284e61e8566dc4f1c2b8b069847517 100644 (file)
@@ -124,6 +124,13 @@ typedef struct{
 #define CMD_SIMULATE_HITAG                                                0x0371
 #define CMD_READER_HITAG                                                  0x0372
 
+#define CMD_SIMULATE_HITAG_S                                              0x0368
+#define CMD_TEST_HITAGS_TRACES                                           0x0367
+#define CMD_READ_HITAG_S                                                 0x0373
+#define CMD_WR_HITAG_S                                                   0x0375
+#define CMD_EMU_HITAG_S                                                          0x0376
+
+
 #define CMD_SIMULATE_TAG_ISO_14443B                                       0x0381
 #define CMD_SNOOP_ISO_14443B                                              0x0382
 #define CMD_SNOOP_ISO_14443a                                              0x0383
Impressum, Datenschutz