From: iceman1001 <iceman@iuse.se>
Date: Mon, 22 Dec 2014 14:14:05 +0000 (+0100)
Subject: added the changes from PM3 master.
X-Git-Url: https://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/commitdiff_plain/3bc3598e880b68870cfcc55fbdda443d77395809?ds=sidebyside

added the changes from PM3 master.
added some code for the AWID26
---

diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c
index d8edc209..269a00c5 100644
--- a/armsrc/iso14443a.c
+++ b/armsrc/iso14443a.c
@@ -1715,6 +1715,10 @@ int ReaderReceive(uint8_t *receivedAnswer, uint8_t *parity)
  * fills the uid pointer unless NULL
  * fills resp_data unless NULL */
 int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, uint32_t* cuid_ptr) {
+
+	iso14a_set_timeout(10500); // 10ms default  10*105 = 
+	
+	//uint8_t deselect[]   = {0xc2};  //DESELECT
 	//uint8_t halt[]       = { 0x50, 0x00, 0x57, 0xCD };  // HALT
 	uint8_t wupa[]       = { 0x52 };  // WAKE-UP
 	//uint8_t reqa[]       = { 0x26 };  // REQUEST A
@@ -1731,8 +1735,8 @@ int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, u
 	int len;
 	
 	// test for the SKYLANDERS TOY.
-	//ReaderTransmit(halt,sizeof(halt), NULL);
-	//len = ReaderReceive(resp, resp_par);
+	// ReaderTransmit(deselect,sizeof(deselect), NULL);
+	// len = ReaderReceive(resp, resp_par);
 	
 	// Broadcast for a card, WUPA (0x52) will force response from all cards in the field
 	ReaderTransmitBitsPar(wupa,7,0, NULL);
@@ -1836,7 +1840,7 @@ int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, u
     p_hi14a_card->sak = sak;
     p_hi14a_card->ats_len = 0;
   }
-
+  
 	if( (sak & 0x20) == 0) {
 		return 2; // non iso14443a compliant tag
 	}
@@ -1845,8 +1849,13 @@ int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, u
 	AppendCrc14443a(rats, 2);
 	ReaderTransmit(rats, sizeof(rats), NULL);
 
+	
 	len = ReaderReceive(resp, resp_par);
-	if(!len) return 0;
+	Dbprintf("RATS Reponse: %d", len);
+	if(!len) {
+		Dbprintf("RATS: %02x %02x %02x", resp[0], resp[1], resp[2]);
+		return 0;
+	}
 
 	if(p_hi14a_card) {
 		memcpy(p_hi14a_card->ats, resp, sizeof(p_hi14a_card->ats));
diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c
index 97d102be..bfa7bfbf 100644
--- a/client/cmdhf14a.c
+++ b/client/cmdhf14a.c
@@ -181,6 +181,11 @@ int CmdHF14AReader(const char *Cmd)
 	
 	if(select_status == 0) {
 		PrintAndLog("iso14443a card select failed");
+		// disconnect
+		c.arg[0] = 0;
+		c.arg[1] = 0;
+		c.arg[2] = 0;
+		SendCommand(&c);
 		return 0;
 	}
 
diff --git a/client/cmdhficlass.c b/client/cmdhficlass.c
index e033422a..75c6e2c9 100644
--- a/client/cmdhficlass.c
+++ b/client/cmdhficlass.c
@@ -43,7 +43,6 @@ int xorbits_8(uint8_t val)
 
 int CmdHFiClassList(const char *Cmd)
 {
-
 	bool ShowWaitCycles = false;
 	char param = param_getchar(Cmd, 0);
 
@@ -55,8 +54,11 @@ int CmdHFiClassList(const char *Cmd)
 		return 0;
 	}
 
-	uint8_t got[TRACE_BUFFER_SIZE];
-	GetFromBigBuf(got,sizeof(got),0);
+// for the time being. Need better Bigbuf handling.	
+#define TRACE_SIZE 3000	
+
+	uint8_t trace[TRACE_SIZE];
+	GetFromBigBuf(trace, TRACE_SIZE, 0);
 	WaitForResponse(CMD_ACK,NULL);
 
 	PrintAndLog("Recorded Activity");
@@ -64,155 +66,58 @@ int CmdHFiClassList(const char *Cmd)
 	PrintAndLog("Start = Start of Start Bit, End = End of last modulation. Src = Source of Transfer");
 	PrintAndLog("All times are in carrier periods (1/13.56Mhz)");
 	PrintAndLog("");
-	PrintAndLog("     Start |       End | Src | Data");
-	PrintAndLog("-----------|-----------|-----|--------");
-
-	int i;
-	uint32_t first_timestamp = 0;
+	PrintAndLog("     Start |       End | Src | Data (! denotes parity error)                                   | CRC ");
+	PrintAndLog("-----------|-----------|-----|-----------------------------------------------------------------------");
+
+	uint16_t tracepos = 0;
+	uint16_t duration;
+	uint16_t data_len;
+	uint16_t parity_len;
+	bool isResponse;
 	uint32_t timestamp;
-	bool tagToReader;
-	uint32_t parityBits;
-	uint8_t len;
-	uint8_t *frame;
-	uint32_t EndOfTransmissionTimestamp = 0;
+	uint32_t first_timestamp;
+	uint32_t EndOfTransmissionTimestamp;
+	
+	for (;;) {
 
+		if(tracepos >= TRACE_SIZE) {
+			break;
+		}
 
-	for( i=0; i < TRACE_BUFFER_SIZE;)
-	{
-		//First 32 bits contain
-		// isResponse (1 bit)
-		// timestamp (remaining)
-		//Then paritybits
-		//Then length
-		timestamp = *((uint32_t *)(got+i));
-		parityBits = *((uint32_t *)(got+i+4));
-		len = got[i+8];
-		frame = (got+i+9);
-		uint32_t next_timestamp = (*((uint32_t *)(got+i+9))) & 0x7fffffff;
-
-		tagToReader = timestamp & 0x80000000;
-		timestamp &= 0x7fffffff;
-
-		if(i==0) {
+		timestamp = *((uint32_t *)(trace + tracepos));
+		if(tracepos == 0) {
 			first_timestamp = timestamp;
 		}
 
-        // Break and stick with current result idf buffer was not completely full
-		if (frame[0] == 0x44 && frame[1] == 0x44 && frame[2] == 0x44 && frame[3] == 0x44) break;
-
-		char line[1000] = "";
-
-		if(len)//We have some data to display
-		{
-			int j,oddparity;
-
-			for(j = 0; j < len ; j++)
-			{
-				oddparity = 0x01 ^ xorbits_8(frame[j] & 0xFF);
-
-				if (tagToReader && (oddparity != ((parityBits >> (len - j - 1)) & 0x01))) {
-					sprintf(line+(j*4), "%02x!  ", frame[j]);
-				} else {
-					sprintf(line+(j*4), "%02x   ", frame[j]);
-				}
-			}
-		}else
-		{
-			if (ShowWaitCycles) {
-				sprintf(line, "fdt (Frame Delay Time): %d", (next_timestamp - timestamp));
-			}
+    // Break and stick with current result if buffer was not completely full
+		if (timestamp == 0x44444444) break; 
+
+		tracepos += 4;
+		duration = *((uint16_t *)(trace + tracepos));
+		tracepos += 2;
+		data_len = *((uint16_t *)(trace + tracepos));
+		tracepos += 2;
+		
+		if (data_len & 0x8000) {
+		  data_len &= 0x7fff;
+		  isResponse = true;
+		} else {
+		  isResponse = false;
 		}
 
-		char *crc = "";
-
-		if(len > 2)
-		{
-			uint8_t b1, b2;
-			if(!tagToReader && len == 4) {
-				// Rough guess that this is a command from the reader
-				// For iClass the command byte is not part of the CRC
-					ComputeCrc14443(CRC_ICLASS, &frame[1], len-3, &b1, &b2);
-			}
-			else {
-				  // For other data.. CRC might not be applicable (UPDATE commands etc.)
-				ComputeCrc14443(CRC_ICLASS, frame, len-2, &b1, &b2);
-			}
+		parity_len = (data_len-1)/8 + 1;
 
-			if (b1 != frame[len-2] || b2 != frame[len-1]) {
-				crc = (tagToReader & (len < 8)) ? "" : " !crc";
-			}
+		if (tracepos + data_len + parity_len >= TRACE_SIZE) {
+			break;
 		}
-
-		i += (len + 9);
-		EndOfTransmissionTimestamp = (*((uint32_t *)(got+i))) & 0x7fffffff;
-
-		// Not implemented for iclass on the ARM-side
-		//if (!ShowWaitCycles) i += 9;
-
-		PrintAndLog(" %9d | %9d | %s | %s %s",
-			(timestamp - first_timestamp),
-			(EndOfTransmissionTimestamp - first_timestamp),
-			(len?(tagToReader ? "Tag" : "Rdr"):"   "),
-			line, crc);
-	}
-	return 0;
-}
-
-int CmdHFiClassListOld(const char *Cmd)
-{
-  uint8_t got[1920];
-  GetFromBigBuf(got,sizeof(got),0);
-
-  PrintAndLog("recorded activity:");
-  PrintAndLog(" ETU     :rssi: who bytes");
-  PrintAndLog("---------+----+----+-----------");
-
-  int i = 0;
-  int prev = -1;
-
-  for (;;) {
-    if(i >= 1900) {
-      break;
-    }
-
-    bool isResponse;
-    int timestamp = *((uint32_t *)(got+i));
-    if (timestamp & 0x80000000) {
-      timestamp &= 0x7fffffff;
-      isResponse = 1;
-    } else {
-      isResponse = 0;
-    }
-
-
-    int metric = 0;
-
-    int parityBits = *((uint32_t *)(got+i+4));
-    // 4 bytes of additional information...
-    // maximum of 32 additional parity bit information
-    //
-    // TODO:
-    // at each quarter bit period we can send power level (16 levels)
-    // or each half bit period in 256 levels.
-
-
-    int len = got[i+8];
-
-    if (len > 100) {
-      break;
-    }
-    if (i + len >= 1900) {
-      break;
-    }
-
-    uint8_t *frame = (got+i+9);
-
-    // Break and stick with current result if buffer was not completely full
-    if (frame[0] == 0x44 && frame[1] == 0x44 && frame[3] == 0x44) { break; }
-
-    char line[1000] = "";
-    int j;
-    for (j = 0; j < len; j++) {
+		
+		uint8_t *frame = trace + tracepos;
+		tracepos += data_len;
+		uint8_t *parityBytes = trace + tracepos;
+		tracepos += parity_len;
+
+		char line[16][110];
+		for (int j = 0; j < data_len; j++) {
       int oddparity = 0x01;
       int k;
 
@@ -220,79 +125,68 @@ int CmdHFiClassListOld(const char *Cmd)
         oddparity ^= (((frame[j] & 0xFF) >> k) & 0x01);
       }
 
-      //if((parityBits >> (len - j - 1)) & 0x01) {
-      if (isResponse && (oddparity != ((parityBits >> (len - j - 1)) & 0x01))) {
-        sprintf(line+(j*4), "%02x!  ", frame[j]);
-      }
-      else {
-        sprintf(line+(j*4), "%02x   ", frame[j]);
-      }
-    }
+			uint8_t parityBits = parityBytes[j>>3];
+			if (isResponse && (oddparity != ((parityBits >> (7-(j&0x0007))) & 0x01))) {
+				sprintf(line[j/16]+((j%16)*4), "%02x! ", frame[j]);
+			} else {
+				sprintf(line[j/16]+((j%16)*4), "%02x  ", frame[j]);
+			}
 
-    char *crc;
-    crc = "";
-    if (len > 2) {
-      uint8_t b1, b2;
-      for (j = 0; j < (len - 1); j++) {
-        // gives problems... search for the reason..
-        /*if(frame[j] == 0xAA) {
-          switch(frame[j+1]) {
-            case 0x01:
-              crc = "[1] Two drops close after each other";
-            break;
-            case 0x02:
-              crc = "[2] Potential SOC with a drop in second half of bitperiod";
-              break;
-            case 0x03:
-              crc = "[3] Segment Z after segment X is not possible";
-              break;
-            case 0x04:
-              crc = "[4] Parity bit of a fully received byte was wrong";
-              break;
-            default:
-              crc = "[?] Unknown error";
-              break;
-          }
-          break;
-        }*/
-      }
+		}
 
-      if (strlen(crc)==0) {
-	if(!isResponse && len == 4) {
+		char *crc = ""; 
+		if (data_len > 2) {
+      uint8_t b1, b2;
+			if(!isResponse && data_len == 4 ) {
 		// Rough guess that this is a command from the reader
 		// For iClass the command byte is not part of the CRC
-	        ComputeCrc14443(CRC_ICLASS, &frame[1], len-3, &b1, &b2);
+				ComputeCrc14443(CRC_ICLASS, &frame[1], data_len-3, &b1, &b2);
+				if (b1 != frame[data_len-2] || b2 != frame[data_len-1]) {
+					crc = "!crc";
+				}
 	}
 	else {
 		// For other data.. CRC might not be applicable (UPDATE commands etc.)
-	        ComputeCrc14443(CRC_ICLASS, frame, len-2, &b1, &b2);
-	}
-	//printf("%1x %1x",(unsigned)b1,(unsigned)b2);
-        if (b1 != frame[len-2] || b2 != frame[len-1]) {
-          crc = (isResponse & (len < 8)) ? "" : " !crc";
-        } else {
-          crc = "";
-        }
-      }
-    } else {
-      crc = ""; // SHORT
-    }
-
-    char metricString[100];
-    if (isResponse) {
-      sprintf(metricString, "%3d", metric);
-    } else {
-      strcpy(metricString, "   ");
-    }
-
-    PrintAndLog(" +%7d: %s: %s %s %s",
-      (prev < 0 ? 0 : (timestamp - prev)),
-      metricString,
-      (isResponse ? "TAG" : "   "), line, crc);
+				ComputeCrc14443(CRC_ICLASS, frame, data_len-2, &b1, &b2);
+				if (b1 != frame[data_len-2] || b2 != frame[data_len-1]) {
+					crc = "!crc";
+				}
+			}
+		}
 
-    prev = timestamp;
-    i += (len + 9);
-  }
+		EndOfTransmissionTimestamp = timestamp + duration;
+		
+		int num_lines = (data_len - 1)/16 + 1;
+		for (int j = 0; j < num_lines; j++) {
+			if (j == 0) {
+				PrintAndLog(" %9d | %9d | %s | %-64s| %s",
+					(timestamp - first_timestamp),
+					(EndOfTransmissionTimestamp - first_timestamp),
+					(isResponse ? "Tag" : "Rdr"),
+					line[j], 
+					(j == num_lines-1)?crc:"");
+        } else {
+				PrintAndLog("           |           |     | %-64s| %s",
+					line[j], 
+					(j == num_lines-1)?crc:"");
+			}
+		}				
+
+		bool next_isResponse = *((uint16_t *)(trace + tracepos + 6)) & 0x8000;
+		
+		if (ShowWaitCycles && !isResponse && next_isResponse) {
+			uint32_t next_timestamp = *((uint32_t *)(trace + tracepos));
+			if (next_timestamp != 0x44444444) {
+				PrintAndLog(" %9d | %9d | %s | fdt (Frame Delay Time): %d",
+					(EndOfTransmissionTimestamp - first_timestamp),
+					(next_timestamp - first_timestamp),
+					"   ",
+					(next_timestamp - EndOfTransmissionTimestamp));
+			}
+		}
+			
+	}
+	
   return 0;
 }
 
diff --git a/client/cmdlf.c b/client/cmdlf.c
index 2f55cd22..faf95ccd 100644
--- a/client/cmdlf.c
+++ b/client/cmdlf.c
@@ -581,7 +581,7 @@ static command_t CommandTable[] =
   {"simman",      CmdLFSimManchester, 0, "<Clock> <Bitstream> [GAP] Simulate arbitrary Manchester LF tag"},
   {"snoop",       CmdLFSnoop,         0, "['l'|'h'|<divisor>] [trigger threshold]-- Snoop LF (l:125khz, h:134khz)"},
   
-  {"avid",        CmdLFAWID26,        1, "{ AWID26 tags }"},
+  {"awid26",        CmdLFAWID26,        1, "{ AWID26 tags }"},
   {"em4x",        CmdLFEM4X,          1, "{ EM4X tags }"},      
   {"hid",         CmdLFHID,           1, "{ HID tags }"},
   {"hitag",       CmdLFHitag,         1, "{ Hitag tags and transponders }"},
diff --git a/client/cmdlfawid26.c b/client/cmdlfawid26.c
index 63b35fdd..0e1fca8e 100644
--- a/client/cmdlfawid26.c
+++ b/client/cmdlfawid26.c
@@ -12,14 +12,14 @@
 #include <inttypes.h>
 #include "proxmark3.h"
 #include "ui.h"
-#include "graph.h"
+//#include "graph.h"
 #include "cmdmain.h"
 #include "cmdparser.h"
-#include "cmddata.h"
+//#include "cmddata.h"
 #include "cmdlf.h"
 #include "cmdlfawid26.h"
 #include "util.h"
-#include "data.h"
+//#include "data.h"
 
 
 static int CmdHelp(const char *Cmd);
@@ -29,11 +29,10 @@ int CmdClone(const char *Cmd)
 	char cmdp = param_getchar(Cmd, 0);
 
 	if (strlen(Cmd) < 1 || cmdp == 'h' || cmdp == 'H') {
-		PrintAndLog("Usage:  lf awid26 write  []");
+		PrintAndLog("Usage:  lf awid26 clone  <facility> <id>");
 		PrintAndLog("     [], ");
 		PrintAndLog("");
-		PrintAndLog("     sample: lf awid26 write 26 2233");
-		PrintAndLog("           : lf awid26 write 26 15 2233");
+		PrintAndLog("     sample: lf awid26 clone 15 2233");
 		return 0;
 	}
 
@@ -50,6 +49,108 @@ int CmdClone(const char *Cmd)
 	return 0;
 }
 
+
+// convert 96 bit AWID FSK data to 8 digit BCD UID
+bool awid26_hex_to_uid(unsigned char *response, unsigned char *awid26)
+{
+	// uint8_t i, tmp[96], tmp1[7];
+    // int site;
+    // int id;
+	
+    // if(!hextobinarray(tmp, awid26))
+        // return false;
+
+    // // data is in blocks of 4 bits - every 4th bit is parity, except the first
+    // // block which is all zeros
+    // for(i= 0 ; i < 4 ; ++i)
+        // if(tmp[i] != 0x00)
+            // return false;
+
+    // // discard 1st block
+    // memcpy(tmp, tmp + 4, 92);
+
+    // // check and strip parity on the rest
+    // for(i= 1 ; i < 23 ; ++i)
+        // if(tmp[(i * 4) - 1] != parity(tmp + (i - 1) * 4, ODD, 3))
+            // return false;
+        // else
+            // memcpy((tmp + (i - 1) * 3), tmp + (i - 1) * 4, 3);
+
+    // // discard the rest of the header - 1 more 3 bit block
+    // memcpy(tmp, tmp + 3, 66);
+
+    // // next 8 bits is data length - should be 26: 0x1A
+    // binarraytohex(tmp1, tmp, 8);
+    // if(strcmp(tmp1, "1A") != 0)
+        // return false;
+    // memcpy(tmp, tmp +8, 58);
+
+    // // standard wiegand parity check - even for 1st 12 bits, odd for 2nd 12
+    // if(tmp[0] != parity(tmp + 1, EVEN, 12))
+        // return false;
+    // if(tmp[25] != parity(tmp + 13, ODD, 12))
+        // return false;
+
+    // // convert to hex, ignoring parity bits
+    // if(!binarraytohex(tmp1, tmp + 1, 24))
+        // return false;
+
+    // // convert hex to site/id
+    // sscanf(tmp1,"%2X%4X", &site, &id);
+
+    // // final output 8 byte BCD
+    // sprintf(response,"%03d%05d", site, id);
+
+    return true;
+}
+
+// convert null-terminated BCD UID (8 digits) to 96 bit awid26 encoded binary array
+bool bcd_to_awid26_bin(unsigned char *awid26, unsigned char *bcd)
+{
+    // char i, p, tmp1[8], tmp2[26];
+    // int tmpint;
+
+    // if(strlen(bcd) != 8)
+        // return false;
+
+    // // convert BCD site code to HEX
+    // sscanf(bcd, "%03d", &tmpint);
+    // sprintf(tmp2, "%02x", tmpint);
+    // memcpy(tmp1, tmp2, 2);
+
+    // // convert BCD ID to HEX
+    // sscanf(bcd + 3, "%05d", &tmpint);;
+    // sprintf(tmp2, "%04x", tmpint);
+	
+    // // copy with trailing NULL
+    // memcpy(tmp1 + 2, tmp2, 5);
+
+    // // convert full HEX to binary, leaving room for parity prefix
+    // hextobinarray(tmp2 + 1, tmp1);
+    
+    // wiegand_add_parity(tmp2, tmp2 + 1, 24);
+
+    // memset(awid26, '\x0', 96);
+
+    // // magic 18 bit awid26 header (we will overwrite the last two bits)
+    // hextobinarray(awid26, "011D8");
+
+    // // copy to target leaving space for parity bits
+    // for(i= 0, p= 18 ; i < 26 ; ++i, ++p)
+    // {
+        // // skip target bit if this is a parity location
+        // if(!((p + 1) % 4))
+            // p += 1;
+        // awid26[p]= tmp2[i];
+    // }
+
+    // // add parity bits
+    // for(i= 1 ; i < 24 ; ++i)
+        // awid26[((i + 1) * 4) - 1]= parity(&awid26[i * 4], ODD, 3);
+
+    return false;
+}
+
 // int CmdReadTrace(const char *Cmd)
 // {
 
@@ -84,8 +185,8 @@ int CmdClone(const char *Cmd)
 
 static command_t CommandTable[] =
 {
-  {"help",   CmdHelp,        1, "This help"},
-  {"clone",  CmdClone,    0, "<facility> <id> -- clone to a t55xx tag"},
+  {"help",   CmdHelp,     1, "This help"},
+  {"clone",  CmdClone,    1, "<facility> <id> -- clone AWID26 to t55xx tag"},
   {NULL, NULL, 0, NULL}
 };
 
diff --git a/client/cmdlfawid26.h b/client/cmdlfawid26.h
index c0facf51..cb1cd9e2 100644
--- a/client/cmdlfawid26.h
+++ b/client/cmdlfawid26.h
@@ -13,4 +13,6 @@
 int CmdLFAWID26(const char *Cmd);
 
 int CmdClone(const char *Cmd);
+bool awid26_hex_to_uid(unsigned char *response, unsigned char *awid26);
+bool bcd_to_awid26_bin(unsigned char *awid26, unsigned char *bcd);
 #endif
diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c
index 78d90e7c..6ea9d2d3 100644
--- a/client/cmdlft55xx.c
+++ b/client/cmdlft55xx.c
@@ -468,6 +468,9 @@ uint32_t PackBits(uint8_t start, uint8_t len, uint8_t* bits){
 	
 	int i = start;
 	int j = len-1;
+	if (len > 32) {
+		return 0;
+	}
  	uint32_t tmp = 0;
 	for (; j >= 0; --j, ++i){
 		tmp	|= bits[i] << j;
diff --git a/client/util.c b/client/util.c
index 56c4998d..0418dd98 100644
--- a/client/util.c
+++ b/client/util.c
@@ -292,3 +292,102 @@ int param_getstr(const char *line, int paramnum, char * str)
 	
 	return en - bg + 1;
 }
+
+/*
+The following methods comes from Rfidler sourcecode.
+https://github.com/ApertureLabsLtd/RFIDler/blob/master/firmware/Pic32/RFIDler.X/src/
+*/
+
+// convert hex to sequence of 0/1 bit values
+// returns number of bits converted
+int hextobinarray(char *target, char *source)
+{
+    int length, i, count= 0;
+    char x;
+
+    length = strlen(source);
+    // process 4 bits (1 hex digit) at a time
+    while(length--)
+    {
+        x= *(source++);
+        // capitalize
+        if (x >= 'a' && x <= 'f')
+            x -= 32;
+        // convert to numeric value
+        if (x >= '0' && x <= '9')
+            x -= '0';
+        else if (x >= 'A' && x <= 'F')
+            x -= 'A' - 10;
+        else
+            return 0;
+        // output
+        for(i= 0 ; i < 4 ; ++i, ++count)
+            *(target++)= (x >> (3 - i)) & 1;
+    }
+    
+    return count;
+}
+
+// convert hex to human readable binary string
+int hextobinstring(char *target, char *source)
+{
+    int length;
+
+    if(!(length= hextobinarray(target, source)))
+        return 0;
+    binarraytobinstring(target, target, length);
+    return length;
+}
+
+// convert binary array of 0x00/0x01 values to hex (safe to do in place as target will always be shorter than source)
+// return number of bits converted
+int binarraytohex(char *target, char *source, int length)
+{
+    unsigned char i, x;
+    int j = length;
+
+    if(j % 4)
+        return 0;
+
+    while(j)
+    {
+        for(i= x= 0 ; i < 4 ; ++i)
+            x +=  ( source[i] << (3 - i));
+        sprintf(target,"%X", x);
+        ++target;
+        source += 4;
+        j -= 4;
+    }
+    return length;
+}
+
+// convert binary array to human readable binary
+void binarraytobinstring(char *target, char *source,  int length)
+{
+    int i;
+
+    for(i= 0 ; i < length ; ++i)
+        *(target++)= *(source++) + '0';
+    *target= '\0';
+}
+
+// return parity bit required to match type
+uint8_t parity( char *bits, uint8_t type, int length)
+{
+    int x;
+
+    for(x= 0 ; length > 0 ; --length)
+        x += bits[length - 1];
+    x %= 2;
+
+    return x ^ type;
+}
+
+// add HID parity to binary array: EVEN prefix for 1st half of ID, ODD suffix for 2nd half
+void wiegand_add_parity(char *target, char *source, char length)
+{
+    *(target++)= parity(source, EVEN, length / 2);
+    memcpy(target, source, length);
+    target += length;
+    *(target)= parity(source + length / 2, ODD, length / 2);
+}
diff --git a/client/util.h b/client/util.h
index 54562a07..10bafba9 100644
--- a/client/util.h
+++ b/client/util.h
@@ -23,6 +23,10 @@
 #ifndef MAX
 # define MAX(a, b) (((a) > (b)) ? (a) : (b))
 #endif
+#define TRUE                        1
+#define FALSE                       0
+#define EVEN                        0
+#define ODD                         1
 
 int ukbhit(void);
 
@@ -48,4 +52,10 @@ uint64_t param_get64ex(const char *line, int paramnum, int deflt, int base);
 int param_gethex(const char *line, int paramnum, uint8_t * data, int hexcnt);
 int param_getstr(const char *line, int paramnum, char * str);
 
+ int hextobinarray( char *target,  char *source);
+ int hextobinstring( char *target,  char *source);
+ int binarraytohex( char *target,  char *source,  int length);
+void binarraytobinstring(char *target,  char *source,  int length);
+uint8_t parity( char *string, uint8_t type,  int length);
+void wiegand_add_parity(char *target, char *source, char length);