]> cvs.zerfleddert.de Git - proxmark3-svn/commitdiff
Redesign of lf hid card format handler as discussed with @marshmellow42
authorgrauerfuchs <42082416+grauerfuchs@users.noreply.github.com>
Mon, 27 Aug 2018 18:03:46 +0000 (14:03 -0400)
committergrauerfuchs <42082416+grauerfuchs@users.noreply.github.com>
Mon, 27 Aug 2018 18:03:46 +0000 (14:03 -0400)
The new handler accepts multiple formats of the same length.
Because of this, the existing pack/unpack commands are unsupported
and have been removed and replaced with 'lf hid encode' and 'lf hid decode'.
The decode command will test a packed Prox ID against all programmed
formats and return results for all matching formats.
The encode command takes the parameter of format name instead of
bit length (as per the old pack command). Additionally, an 'lf hid write'
command has been added as a single-command combination of encode and clone.

To support easier addition of new formats, a library for handling card
fields has been added. This will allow direct access to the card bits,
to linear fields, and to non-linear (jumping) fields in a single line
of code without having to resort to managing bit positions or masks
on the underlying data. A number of new formats have been added as working
examples of the new support functions.

client/Makefile
client/cmdlfhid.c
client/cmdlfhid.h
client/hidcardformats.c [new file with mode: 0644]
client/hidcardformats.h [new file with mode: 0644]
client/hidcardformatutils.c [new file with mode: 0644]
client/hidcardformatutils.h [new file with mode: 0644]

index c6ca1cf1f1bb040344e9ff5d383a705ba98d07c4..7c79b63b7053b554aefae2b2d246aedc46107365 100644 (file)
@@ -160,6 +160,8 @@ CMDSRCS =   $(SRC_SMARTCARD) \
                        cmdlfem4x.c \
                        cmdlffdx.c \
                        cmdlfgproxii.c \
+                       hidcardformatutils.c\
+                       hidcardformats.c\
                        cmdlfhid.c \
                        cmdlfhitag.c \
                        cmdlfio.c \
index 1a9c3477fa5b95166c1d5b6048763564ad884e3e..d8e151b95538bcd0104cf60c9d40fba9d51cf83b 100644 (file)
 #include "cmdparser.h"
 #include "cmddata.h"  //for g_debugMode, demodbuff cmds
 #include "lfdemod.h" // for HIDdemodFSK
-#include "parity.h" // for parity
+#include "hidcardformats.h"
+#include "hidcardformatutils.h"
 #include "util.h" // for param_get8,32,64
 
-static int CmdHelp(const char *Cmd);
-
-/**
- * Packs an HID ID from component parts.
- *
- * This only works with 26, 34, 35, 37, and 48 bit card IDs.
- *
- * Returns false on invalid inputs.
- */
-bool pack_hid(/* out */ uint32_t *hi2, /* out */ uint32_t *hi, /* out */ uint32_t *lo, /* in */ const hid_info *info) {
-  uint32_t higher = 0, high = 0, low = 0;
-
-  switch (info->fmtLen) {
-    case 26: // HID H10301
-      low |= (info->cardnum & 0xffff) << 1;
-      low |= (info->fc & 0xff) << 17;
-
-      if (info->parityValid) {
-        // Calculate parity
-        low |= oddparity32((low >> 1) & 0xfff) & 1;
-        low |= (evenparity32((low >> 13) & 0xfff) & 1) << 25;
-      }
-    break;
-
-  case 34: // H10306
-    low |= (info->cardnum & 0xffff) << 1;
-    low |= (info->fc & 0x7fff) << 17;
-    high |= (info->fc & 0x8000) >> 15;
-      
-    if (info->parityValid) {
-      // Calculate parity
-      high |= (evenparity32((high & 0x00000001) ^ (low & 0xFFFE0000)) & 1) << 1;
-      low |= (oddparity32(low & 0x0001FFFE) & 1);
-    }
-    break;
-
-  case 35: // (Corporate 1000 35-bit)
-    low |= (info->cardnum & 0xfffff) << 1;
-    low |= (info->fc & 0x7ff) << 21;
-    high |= (info->fc & 0x800) >> 11;
-
-    if (info->parityValid) {
-      // Calculate parity
-      high |= (evenparity32((high & 0x00000001) ^ (low & 0xB6DB6DB6)) & 1) << 1;
-      low |=  (oddparity32( (high & 0x00000003) ^ (low & 0x6DB6DB6C)) & 1);
-      high |= (oddparity32( (high & 0x00000003) ^ (low & 0xFFFFFFFF)) & 1) << 2;
-    }
-    break;
-
-  case 37: //H10304
-    low |= (info->cardnum & 0x7ffff) << 1;
-    low |= (info->fc & 0xfff) << 20;
-    high |= (info->fc & 0xf000) >> 12;
-
-    if (info->parityValid) {
-      // Calculate parity
-      high |= (evenparity32((high & 0x0000000F) ^ (low & 0xFFFC0000)) & 1) << 4;
-      low |= (oddparity32(low & 0x0007FFFE) & 1);
-    }
-    break;
-
-  case 48: // Corporate 1000 48-bit
-    low |= (info->cardnum & 0x7FFFFF) << 1;
-    low |= (info->fc & 0xff) << 24;
-    high |= (info->fc & 0x3FFF00) >> 8;
-
-    if (info->parityValid) {
-      // Calculate parity
-      high |= (evenparity32((high & 0x00001B6D) ^ (low & 0xB6DB6DB6)) & 1) << 14;
-      low |=  (oddparity32( (high & 0x000036DB) ^ (low & 0x6DB6DB6C)) & 1);
-      high |= (oddparity32( (high & 0x00007FFF) ^ (low & 0xFFFFFFFF)) & 1) << 15;
-    }
-    break;
-
-  default:
-    // Invalid / unsupported length
-    return false;
-  }
-  
-  // Set the format length bits
-  if (info->fmtLen < 37) {
-    // Bit 37 is always set
-    high |= 0x20;
-
-    // Set the bit corresponding to the length.
-    if (info->fmtLen < 32)
-      low |= 1 << info->fmtLen;
-    else 
-      high |= 1 << (info->fmtLen - 32);
-    
-  } else if (info->fmtLen > 37){
-    if (info->fmtLen < 64) 
-      high |= 1 << (info->fmtLen - 32);
-    else 
-      higher |= 1 << (info->fmtLen - 64);
-  }
-  // Return result only if successful.
-  *hi2 = higher;
-  *hi = high;
-  *lo = low;
-  return true;
-}
-
-/**
- * Unpacks an HID ID into its component parts.
- *
- * This only works with 26, 34, 35, 37, and 48 bit card IDs.
- *
- * Returns false on invalid inputs.
- */
-bool unpack_hid(hid_info *out, uint32_t hi2, uint32_t hi, uint32_t lo) {
-  memset(out, 0, sizeof(hid_info));
-  uint8_t fmtLen = 0;
-       
-  uint32_t hFmt; // for calculating card length
-  if ((hi2 & 0x000FFFFF) > 0) { // > 64 bits
-    hFmt = hi2 & 0x000FFFFF;
-    fmtLen = 64;
-  } else if ((hi & 0xFFFFFFC0) > 0) { // < 63-38 bits
-    hFmt = hi & 0xFFFFFFC0;
-    fmtLen = 32;
-  } else if ((hi & 0x00000020) == 0) { // 37 bits
-    hFmt = 0;
-    fmtLen = 37;
-  } else if ((hi & 0x0000001F) > 0){ // 36-32 bits
-    hFmt = hi & 0x0000001F;
-    fmtLen = 32;
-  } else { // <32 bits
-    hFmt = lo;
-    fmtLen = 0;
-  }
-
-  while (hFmt > 1) {
-    hFmt >>= 1;
-    fmtLen++;
-  }
-  out->fmtLen = fmtLen;
-  switch (out->fmtLen) {
-    case 26: // HID H10301
-      out->cardnum = (lo >> 1) & 0xFFFF;
-      out->fc = (lo >> 17) & 0xFF;
-
-      if (g_debugMode) {
-        PrintAndLog("oddparity : input=%x, calculated=%d, provided=%d",
-          (lo >> 1) & 0xFFF, oddparity32((lo >> 1) & 0xFFF), lo & 1);
-        PrintAndLog("evenparity: input=%x, calculated=%d, provided=%d",
-          (lo >> 13) & 0xFFF, evenparity32((lo >> 13) & 0xFFF) & 1, (lo >> 25) & 1);
-      }
-
-      out->parityValid =
-        (oddparity32((lo >> 1) & 0xFFF) == (lo & 1)) &&
-        ((evenparity32((lo >> 13) & 0xFFF) & 1) == ((lo >> 25) & 1));
-      break;
-
-    case 34: // HID H10306
-      out->cardnum = (lo >> 1) & 0xFFFF;
-      out->fc = ((hi & 1) << 15) | (lo >> 17);
-      out->parityValid =
-        ((evenparity32((hi & 0x00000001) ^ (lo & 0xFFFE0000)) & 1) == ((hi >> 1) & 1)) &&
-        ((oddparity32(lo & 0x0001FFFE) & 1) == ((lo & 1)));
-      break;
-
-    case 35: // HID Corporate 1000-35
-      out->cardnum = (lo >> 1) & 0xFFFFF;
-      out->fc = ((hi & 1) << 11) | (lo >> 21);
-      out->parityValid = 
-        (evenparity32((hi & 0x00000001) ^ (lo & 0xB6DB6DB6)) == ((hi >> 1) & 1)) &&
-        (oddparity32( (hi & 0x00000003) ^ (lo & 0x6DB6DB6C)) == ((lo >> 0) & 1)) &&
-        (oddparity32( (hi & 0x00000003) ^ (lo & 0xFFFFFFFF)) == ((hi >> 2) & 1));
-      if (g_debugMode) {
-        PrintAndLog("Parity check: calculated {%d, %d, %d}, provided {%d, %d, %d}",
-          evenparity32((hi & 0x00000001) ^ (lo & 0xB6DB6DB6)),
-          oddparity32( (hi & 0x00000003) ^ (lo & 0x6DB6DB6C)),
-          oddparity32( (hi & 0x00000003) ^ (lo & 0xFFFFFFFF)),
-          ((hi >> 1) & 1),
-          ((lo >> 0) & 1),
-          ((hi >> 2) & 1)
-        );
-      }
-      break;
-
-    case 37: // HID H10304
-      out->fmtLen = 37;
-      out->cardnum = (lo >> 1) & 0x7FFFF;
-      out->fc = ((hi & 0xF) << 12) | (lo >> 20);
-      out->parityValid =
-        (evenparity32((hi & 0x0000000F) ^ (lo & 0xFFFC0000)) == ((hi >> 4) & 1)) &&
-        (oddparity32( lo & 0x0007FFFE) == (lo & 1));
-      break;
-
-    case 48: // HID Corporate 1000-48
-      out->cardnum = (lo >> 1) & 0x7FFFFF;  //Start 24, 23 length
-      out->fc = ((hi & 0x3FFF) << 8 ) | (lo >> 24);  //Start 2, 22 length
-      out->parityValid = 
-        (evenparity32((hi & 0x00001B6D) ^ (lo & 0xB6DB6DB6)) == ((hi >> 14) & 1)) &&
-        (oddparity32( (hi & 0x000036DB) ^ (lo & 0x6DB6DB6C)) == ((lo >> 0) & 1)) &&
-        (oddparity32( (hi & 0x00007FFF) ^ (lo & 0xFFFFFFFF)) == ((hi >> 15) & 1));
-      if (g_debugMode) {
-        PrintAndLog("Parity check: calculated {%d, %d, %d}, provided {%d, %d, %d}",
-          evenparity32((hi & 0x00001B6D) ^ (lo & 0xB6DB6DB6)),
-          oddparity32( (hi & 0x000036DB) ^ (lo & 0x6DB6DB6C)),
-          oddparity32( (hi & 0x00007FFF) ^ (lo & 0xFFFFFFFF)),
-          ((hi >> 14) & 1),
-          ((lo >> 0) & 1),
-          ((hi >> 15) & 1)
-        );
-      }
-      break;
-
-    default:
-      return false;
-  }
-  return true;
-}
 
 /**
  * Converts a hex string to component "hi2", "hi" and "lo" 32-bit integers, one nibble
@@ -301,21 +88,18 @@ int CmdFSKdemodHID(const char *Cmd)
     return 0;
   }
   
-  hid_info card_info;
-  bool ret = unpack_hid(&card_info, (uint32_t)hi2, (uint32_t)hi, (uint32_t)lo);
-  
   if (hi2 != 0)
-    PrintAndLog("HID Prox TAG ID: %x%08x%08x (%d) - Format Len: %u bits - FC: %u - Card: %u",
-      (unsigned int) hi2, (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF,
-      card_info.fmtLen, card_info.fc, card_info.cardnum);
+    PrintAndLog("HID Prox TAG ID: %x%08x%08x",
+      (unsigned int) hi2, (unsigned int) hi, (unsigned int) lo
+    );
   else
-    PrintAndLog("HID Prox TAG ID: %x%08x (%d) - Format Len: %u bits - FC: %u - Card: %u",
-      (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF,
-      card_info.fmtLen, card_info.fc, card_info.cardnum);
+    PrintAndLog("HID Prox TAG ID: %x%08x",
+      (unsigned int) hi, (unsigned int) lo
+    );
+
+  hidproxmessage_t packed = initialize_proxmessage_object(hi2, hi, lo);
+  bool ret = HIDTryUnpack(&packed);
 
-  if (card_info.fmtLen == 26 || card_info.fmtLen == 35 || card_info.fmtLen == 48) {
-    PrintAndLog("Parity: %s", card_info.parityValid ? "valid" : "invalid");
-  }
   if (!ret) {
     PrintAndLog("Invalid or unsupported tag length.");
   }
@@ -370,7 +154,7 @@ int CmdHIDClone(const char *Cmd)
   }
 
   c.cmd = CMD_HID_CLONE_TAG;
-  c.arg[0] = hi2;
+  c.arg[0] = (hi2 & 0x000FFFFF);
   c.arg[1] = hi;
   c.arg[2] = lo;
 
@@ -378,73 +162,118 @@ int CmdHIDClone(const char *Cmd)
   return 0;
 }
 
-
-int CmdHIDPack(const char *Cmd) {
-  uint32_t hi2 = 0, hi = 0, lo = 0;
-  
+int CmdHIDDecode(const char *Cmd){
   if (strlen(Cmd)<3) {
-    PrintAndLog("Usage:  lf hid pack <length> <facility code (decimal)> <card number (decimal)>");
-    PrintAndLog("        sample: lf hid pack 26 123 4567");
+    PrintAndLog("Usage:  lf hid decode <id>");
+    PrintAndLog("        sample: lf hid decode 2006f623ae");
     return 0;
   }
-  uint8_t fmtLen = param_get8(Cmd, 0);
 
-  hid_info card_info;
-  card_info.fmtLen = fmtLen;
-  card_info.fc = param_get32ex(Cmd, 1, 0, 10);
-  card_info.cardnum = param_get64ex(Cmd, 2, 0, 10);
-  card_info.parityValid = true;
+  uint32_t top = 0, mid = 0, bot = 0;
+  hexstring_to_int96(&top, &mid, &bot, Cmd);
+  hidproxmessage_t packed = initialize_proxmessage_object(top, mid, bot);
+  HIDTryUnpack(&packed);
+  return 0;
+}
+int CmdHIDEncode(const char *Cmd) {
+  if (strlen(Cmd) == 0) {
+    PrintAndLog("Usage:  lf hid encode <format> <facility code (decimal)> <card number (decimal)>");
+    PrintAndLog("        sample: lf hid encode H10301 123 4567");
+    return 0;
+  }
+
+  int formatIndex = -1;
+  if (!strcmp(Cmd, "help") || !strcmp(Cmd, "h") || !strcmp(Cmd, "list") || !strcmp(Cmd, "?")){
+    HIDListFormats();
+    return 0;
+  } else {
+    char format[16];
+    memset(format, 0, sizeof(format));
+    param_getstr(Cmd, 0, format, sizeof(format));
+    formatIndex = HIDFindCardFormat(format);
+    if (formatIndex == -1) {
+      HIDListFormats();
+      return 0;
+    }
+  }
 
-  bool ret = pack_hid(&hi2, &hi, &lo, &card_info);
-  if (ret) {
-    if (hi2 != 0) {
-      PrintAndLog("HID Prox TAG ID: %x%08x%08x (%d) - Format Len: %u bits - FC: %u - Card: %u",
-        (unsigned int) hi2, (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF,
-        card_info.fmtLen, card_info.fc, card_info.cardnum);
+  hidproxcard_t card;
+  memset(&card, 0, sizeof(hidproxcard_t));
+  card.FacilityCode = param_get32ex(Cmd, 1, 0, 10);
+  card.CardNumber = param_get64ex(Cmd, 2, 0, 10);
+  card.ParitySupported = true; // Try to encode parity if supported.
+
+  hidproxmessage_t packed;
+  memset(&packed, 0, sizeof(hidproxmessage_t));
+  if (HIDPack(formatIndex, &card, &packed)){
+    if (packed.top != 0) {
+      PrintAndLog("HID Prox TAG ID: %x%08x%08x",
+        (unsigned int)packed.top, (unsigned int)packed.mid, (unsigned int)packed.bot);
     } else {
-      PrintAndLog("HID Prox TAG ID: %x%08x (%d) - Format Len: %u bits - FC: %u - Card: %u",
-        (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF,
-        card_info.fmtLen, card_info.fc, card_info.cardnum); 
+      PrintAndLog("HID Prox TAG ID: %x%08x",
+        (unsigned int)packed.mid, (unsigned int)packed.bot); 
     }
   } else {
-    PrintAndLog("Invalid or unsupported tag length.");
+    PrintAndLog("The provided data could not be encoded with the selected format.");
   }
   return 0;
 }
 
+int CmdHIDWrite(const char *Cmd) {
+  if (strlen(Cmd) == 0) {
+    PrintAndLog("Usage:  lf hid write <format> <facility code (decimal)> <card number (decimal)>");
+    PrintAndLog("        sample: lf hid write H10301 123 4567");
+    return 0;
+  }
 
-int CmdHIDUnpack(const char *Cmd)
-{
-  uint32_t hi2 = 0, hi = 0, lo = 0;
-  if (strlen(Cmd)<1) {
-    PrintAndLog("Usage:  lf hid unpack <ID>");
-    PrintAndLog("        sample: lf hid unpack 2006f623ae");
+  int formatIndex = -1;
+  if (!strcmp(Cmd, "help") || !strcmp(Cmd, "h") || !strcmp(Cmd, "list") || !strcmp(Cmd, "?")){
+    HIDListFormats();
     return 0;
+  } else {
+    char format[16];
+    memset(format, 0, sizeof(format));
+    param_getstr(Cmd, 0, format, sizeof(format));
+    formatIndex = HIDFindCardFormat(format);
+    if (formatIndex == -1) {
+      HIDListFormats();
+      return 0;
+    }
   }
 
-  hexstring_to_int96(&hi2, &hi, &lo, Cmd);
-       
-  hid_info card_info;
-  bool ret = unpack_hid(&card_info, hi2, hi, lo);
+  hidproxcard_t card;
+  memset(&card, 0, sizeof(hidproxcard_t));
+  card.FacilityCode = param_get32ex(Cmd, 1, 0, 10);
+  card.CardNumber = param_get64ex(Cmd, 2, 0, 10);
+  card.ParitySupported = true; // Try to encode parity if supported.
+
+  hidproxmessage_t packed;
+  memset(&packed, 0, sizeof(hidproxmessage_t));
+  if (HIDPack(formatIndex, &card, &packed)){
+    UsbCommand c;
+    if (packed.top != 0) {
+      PrintAndLog("HID Prox TAG ID: %x%08x%08x",
+        (unsigned int)packed.top, (unsigned int)packed.mid, (unsigned int)packed.bot);
+      c.d.asBytes[0] = 1;
+    } else {
+      PrintAndLog("HID Prox TAG ID: %x%08x",
+        (unsigned int)packed.mid, (unsigned int)packed.bot); 
+      c.d.asBytes[0] = 0;
+    }
+
+    c.cmd = CMD_HID_CLONE_TAG;
+    c.arg[0] = (packed.top & 0x000FFFFF);
+    c.arg[1] = packed.mid;
+    c.arg[2] = packed.bot;
+    SendCommand(&c);
 
-  if (hi2 != 0) {
-    PrintAndLog("HID Prox TAG ID: %x%08x%08x (%d) - Format Len: %u bits - FC: %u - Card: %u",
-      (unsigned int) hi2, (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF,
-      card_info.fmtLen, card_info.fc, card_info.cardnum);
   } else {
-    PrintAndLog("HID Prox TAG ID: %x%08x (%d) - Format Len: %u bits - FC: %u - Card: %u",
-      (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF,
-      card_info.fmtLen, card_info.fc, card_info.cardnum);
-  }
-  PrintAndLog("Parity: %s", card_info.parityValid ? "valid" : "invalid");
-  
-  if (!ret) {
-    PrintAndLog("Invalid or unsupported tag length.");
+    PrintAndLog("The provided data could not be encoded with the selected format.");
   }
   return 0;
 }
 
-
+static int CmdHelp(const char *Cmd); // define this now so the below won't error out.
 static command_t CommandTable[] = 
 {
   {"help",      CmdHelp,        1, "This help"},
@@ -452,8 +281,9 @@ static command_t CommandTable[] =
   {"read",      CmdHIDReadFSK,  0, "['1'] Realtime HID FSK Read from antenna (option '1' for one tag only)"},
   {"sim",       CmdHIDSim,      0, "<ID> -- HID tag simulator"},
   {"clone",     CmdHIDClone,    0, "<ID> -- Clone HID to T55x7 (tag must be in antenna)"},
-  {"pack",      CmdHIDPack,     1, "<len> <fc> <num> -- packs an HID ID from its length, facility code and card number"},
-  {"unpack",    CmdHIDUnpack,   1, "<ID> -- unpacks an HID ID to its length, facility code and card number"},
+  {"decode",    CmdHIDDecode,   1, "<ID> -- Try to decode an HID tag and show its contents"},
+  {"encode",    CmdHIDEncode,   1, "<format> <fc> <num> -- Encode an HID ID with the specified format, facility code and card number"},
+  {"write",     CmdHIDWrite,    0, "<format> <fc> <num> -- Encode and write to a T55x7 tag (tag must be in antenna)"},
   {NULL, NULL, 0, NULL}
 };
 
index 463be56f3bbb7fc144d6fe5c1b75546b81e050e3..ef907f671cc0398db6a8df13defd35f0caa5a939 100644 (file)
 #include <stdint.h>
 #include <stdbool.h>
 
-// Structure for unpacked HID Prox tags.
-typedef struct {
-  // Format length, in bits.
-  uint8_t fmtLen;
-
-  // Facility code.
-  uint32_t fc;
-
-  // Card number.
-  uint64_t cardnum;
-
-  // Parity validity.
-  //
-  // When used with pack_hid, this determines if we should calculate
-  // parity values for the ID.
-  //
-  // When used with unpack_hid, this indicates if we got valid parity
-  // values for the ID.
-  bool parityValid;
-} hid_info;
-
-bool pack_hid(/* out */ uint32_t *hi2, /* out */ uint32_t *hi, /* out */ uint32_t *lo, /* in */ const hid_info *info);
-bool unpack_hid(hid_info* out, uint32_t hi2, uint32_t hi, uint32_t lo);
-
-
 int CmdLFHID(const char *Cmd);
 int CmdFSKdemodHID(const char *Cmd);
 int CmdHIDReadDemod(const char *Cmd);
 int CmdHIDSim(const char *Cmd);
 int CmdHIDClone(const char *Cmd);
-int CmdHIDPack(const char *Cmd);
-int CmdHIDUnpack(const char *Cmd);
-
+int CmdHIDDecode(const char *Cmd);
+int CmdHIDEncode(const char *Cmd);
+int CmdHIDWrite(const char *Cmd);
 #endif
diff --git a/client/hidcardformats.c b/client/hidcardformats.c
new file mode 100644 (file)
index 0000000..379eb68
--- /dev/null
@@ -0,0 +1,512 @@
+//-----------------------------------------------------------------------------
+// Copyright (C) 2018 grauerfuchs
+//
+// 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.
+//-----------------------------------------------------------------------------
+// HID card format packing/unpacking routines
+//-----------------------------------------------------------------------------
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include "cmddata.h"
+#include "hidcardformats.h"
+#include "hidcardformatutils.h"
+#include "parity.h" // for parity
+#include "ui.h"
+
+bool Pack_H10301(/*in*/hidproxcard_t* card, /*out*/hidproxmessage_t* packed){
+  memset(packed, 0, sizeof(hidproxmessage_t));
+  if (card->FacilityCode > 0xFF) return false; // Can't encode FC.
+  if (card->CardNumber > 0xFFFF) return false; // Can't encode CN.
+  
+  packed->Length = 26; // Set number of bits
+  packed->bot |= (card->CardNumber & 0xFFFF) << 1;
+  packed->bot |= (card->FacilityCode & 0xFF) << 17;
+  if (card->ParitySupported){
+    packed->bot |= oddparity32((packed->bot >> 1) & 0xFFF) & 1;
+    packed->bot |= (evenparity32((packed->bot >> 13) & 0xFFF) & 1) << 25;
+  }
+  return add_HID_header(packed);
+}
+bool Unpack_H10301(/*in*/hidproxmessage_t* packed, /*out*/hidproxcard_t* card){
+  memset(card, 0, sizeof(hidproxcard_t));
+  if (packed->Length != 26) return false; // Wrong length? Stop here.
+  card->CardNumber = (packed->bot >> 1) & 0xFFFF;
+  card->FacilityCode = (packed->bot >> 17) & 0xFF;
+  card->ParitySupported = true;
+  card->ParityValid =
+    (oddparity32((packed->bot >> 1) & 0xFFF) == (packed->bot & 1)) &&
+    ((evenparity32((packed->bot >> 13) & 0xFFF) & 1) == ((packed->bot >> 25) & 1));
+  return true;
+}
+
+bool Pack_Tecom27(/*in*/hidproxcard_t* card, /*out*/hidproxmessage_t* packed){
+  memset(packed, 0, sizeof(hidproxmessage_t));
+  if (card->FacilityCode > 0x7FF) return false; // Can't encode FC.
+  if (card->CardNumber > 0xFFFF) return false; // Can't encode CN.
+  packed->Length = 27;
+  set_nonlinear_field(packed, card->FacilityCode, 10, (uint8_t[]){15, 19, 24, 23, 22, 18, 6, 10, 14, 3, 2});
+  set_nonlinear_field(packed, card->CardNumber, 16, (uint8_t[]){0, 1, 13, 12, 9, 26, 20, 16, 17, 21, 25, 7, 8, 11, 4, 5});
+  return add_HID_header(packed);
+}
+bool Unpack_Tecom27(/*in*/hidproxmessage_t* packed, /*out*/hidproxcard_t* card){
+  memset(card, 0, sizeof(hidproxcard_t));
+  if (packed->Length != 27) return false; // Wrong length? Stop here.
+  card->CardNumber = get_nonlinear_field(packed, 16, (uint8_t[]){0, 1, 13, 12, 9, 26, 20, 16, 17, 21, 25, 7, 8, 11, 4, 5});
+  card->FacilityCode = get_nonlinear_field(packed, 10, (uint8_t[]){15, 19, 24, 23, 22, 18, 6, 10, 14, 3, 2});
+  card->ParitySupported = false;
+  return true;
+}
+
+bool Pack_2804W(/*in*/hidproxcard_t* card, /*out*/hidproxmessage_t* packed){
+  memset(packed, 0, sizeof(hidproxmessage_t));
+  if (card->FacilityCode > 0x0FF) return false; // Can't encode FC.
+  if (card->CardNumber > 0x7FFF) return false; // Can't encode CN.
+  packed->Length = 28;
+  set_linear_field(packed, card->FacilityCode, 4, 8);
+  set_linear_field(packed, card->CardNumber, 12, 15);
+  if (card->ParitySupported){
+    set_bit_by_position(packed, 
+      oddparity32(get_nonlinear_field(packed, 16, (uint8_t[]){4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19, 20, 22, 23, 25, 26}))
+      , 2);
+    set_bit_by_position(packed, 
+      evenparity32(get_linear_field(packed, 1, 13))
+      , 0);
+    set_bit_by_position(packed, 
+      oddparity32(get_linear_field(packed, 0, 27))
+      , 27);
+  }
+  return add_HID_header(packed);
+}
+bool Unpack_2804W(/*in*/hidproxmessage_t* packed, /*out*/hidproxcard_t* card){
+  memset(card, 0, sizeof(hidproxcard_t));
+  if (packed->Length != 28) return false; // Wrong length? Stop here.
+  card->FacilityCode = get_linear_field(packed, 4, 8);
+  card->CardNumber = get_linear_field(packed, 12, 15);
+  card->ParitySupported = true;
+  card->ParityValid = 
+    (get_bit_by_position(packed, 0) == evenparity32(get_linear_field(packed, 1, 13))) &&
+    (get_bit_by_position(packed, 2) == oddparity32(get_nonlinear_field(packed, 16, (uint8_t[]){4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19, 20, 22, 23, 25, 26}))) &&
+    (get_bit_by_position(packed, 27) == oddparity32(get_linear_field(packed, 0, 27)));
+  return true;
+}
+
+bool Pack_ATSW30(/*in*/hidproxcard_t* card, /*out*/hidproxmessage_t* packed){
+  memset(packed, 0, sizeof(hidproxmessage_t));
+  if (card->FacilityCode > 0xFFF) return false; // Can't encode FC.
+  if (card->CardNumber > 0xFFFF) return false; // Can't encode CN.
+  packed->Length = 30;
+  set_linear_field(packed, card->FacilityCode, 1, 12);
+  set_linear_field(packed, card->CardNumber, 13, 16);
+  if (card->ParitySupported){
+    set_bit_by_position(packed, 
+      evenparity32(get_linear_field(packed, 1, 12))
+      , 0);
+    set_bit_by_position(packed, 
+      oddparity32(get_linear_field(packed, 13, 16))
+      , 29);
+  }
+  return add_HID_header(packed);
+}
+bool Unpack_ATSW30(/*in*/hidproxmessage_t* packed, /*out*/hidproxcard_t* card){
+  memset(card, 0, sizeof(hidproxcard_t));
+  if (packed->Length != 30) return false; // Wrong length? Stop here.
+  card->FacilityCode = get_linear_field(packed, 1, 12);
+  card->CardNumber = get_linear_field(packed, 13, 16);
+  card->ParitySupported = true;
+  card->ParityValid = 
+    (get_bit_by_position(packed, 0) == evenparity32(get_linear_field(packed, 1, 12))) &&
+    (get_bit_by_position(packed, 29) == oddparity32(get_linear_field(packed, 13, 16)));
+  return true;
+}
+bool Pack_ADT31(/*in*/hidproxcard_t* card, /*out*/hidproxmessage_t* packed){
+  memset(packed, 0, sizeof(hidproxmessage_t));
+  if (card->FacilityCode > 0x0F) return false; // Can't encode FC.
+  if (card->CardNumber > 0x7FFFFF) return false; // Can't encode CN.
+  packed->Length = 31;
+  set_linear_field(packed, card->FacilityCode, 1, 4);
+  set_linear_field(packed, card->CardNumber, 5, 23);
+  // Parity not known, but 4 bits are unused.
+  return add_HID_header(packed);
+}
+bool Unpack_ADT31(/*in*/hidproxmessage_t* packed, /*out*/hidproxcard_t* card){
+  memset(card, 0, sizeof(hidproxcard_t));
+  if (packed->Length != 31) return false; // Wrong length? Stop here.
+  card->FacilityCode = get_linear_field(packed, 1, 4);
+  card->CardNumber = get_linear_field(packed, 5, 23);
+  card->ParitySupported = false;
+  return true;
+}
+
+bool Pack_D10202(/*in*/hidproxcard_t* card, /*out*/hidproxmessage_t* packed){
+  memset(packed, 0, sizeof(hidproxmessage_t));
+  if (card->FacilityCode > 0x007F) return false; // Can't encode FC.
+  if (card->CardNumber > 0x00FFFFFF) return false; // Can't encode CN.
+  
+  packed->Length = 33; // Set number of bits
+  set_linear_field(packed, card->FacilityCode, 1, 7);
+  set_linear_field(packed, card->CardNumber, 8, 24);
+  
+  if (card->ParitySupported){
+    set_bit_by_position(packed, evenparity32(get_linear_field(packed, 1, 16)), 0);
+    set_bit_by_position(packed, oddparity32(get_linear_field(packed, 16, 16)), 32);
+  }
+  return add_HID_header(packed);
+}
+bool Unpack_D10202(/*in*/hidproxmessage_t* packed, /*out*/hidproxcard_t* card){
+  memset(card, 0, sizeof(hidproxcard_t));
+  if (packed->Length != 33) return false; // Wrong length? Stop here.
+  
+  card->CardNumber = get_linear_field(packed, 8, 24);
+  card->FacilityCode = get_linear_field(packed, 1, 7);
+  card->ParitySupported = true;
+  card->ParityValid =
+    (get_bit_by_position(packed, 0) == evenparity32(get_linear_field(packed, 1, 16))) &&
+    (get_bit_by_position(packed, 32) == oddparity32(get_linear_field(packed, 16, 16)));
+  return true;
+}
+
+
+bool Pack_H10306(/*in*/hidproxcard_t* card, /*out*/hidproxmessage_t* packed){
+  memset(packed, 0, sizeof(hidproxmessage_t));
+  if (card->FacilityCode > 0xFFFF) return false; // Can't encode FC.
+  if (card->CardNumber > 0xFFFF) return false; // Can't encode CN.
+  
+  packed->Length = 34; // Set number of bits
+  packed->bot |= (card->CardNumber & 0xFFFF) << 1;
+  packed->bot |= (card->FacilityCode & 0x7FFF) << 17;
+  packed->mid |= (card->FacilityCode & 0x8000) >> 15;
+  if (card->ParitySupported){
+    packed->mid |= (evenparity32((packed->mid & 0x00000001) ^ (packed->bot & 0xFFFE0000)) & 1) << 1;
+    packed->bot |= ( oddparity32(packed->bot & 0x0001FFFE) & 1);
+  }
+  return add_HID_header(packed);
+}
+bool Unpack_H10306(/*in*/hidproxmessage_t* packed, /*out*/hidproxcard_t* card){
+  memset(card, 0, sizeof(hidproxcard_t));
+  if (packed->Length != 34) return false; // Wrong length? Stop here.
+  
+  card->CardNumber = (packed->bot >> 1) & 0xFFFF;
+  card->FacilityCode = ((packed->mid & 1) << 15) | ((packed->bot >> 17) & 0xFF);
+  card->ParitySupported = true;
+  card->ParityValid =
+    ((evenparity32((packed->mid & 0x00000001) ^ (packed->bot & 0xFFFE0000)) & 1) == ((packed->mid >> 1) & 1)) &&
+    ((oddparity32(packed->bot & 0x0001FFFE) & 1) == ((packed->bot & 1)));
+  return true;
+}
+bool Pack_N1002(/*in*/hidproxcard_t* card, /*out*/hidproxmessage_t* packed){
+  memset(packed, 0, sizeof(hidproxmessage_t));
+  if (card->FacilityCode > 0xFF) return false; // Can't encode FC.
+  if (card->CardNumber > 0xFFFF) return false; // Can't encode CN.
+  
+  packed->Length = 34; // Set number of bits
+  set_linear_field(packed, card->FacilityCode, 9, 8);
+  set_linear_field(packed, card->CardNumber, 17, 16);
+  return add_HID_header(packed);
+}
+bool Unpack_N1002(/*in*/hidproxmessage_t* packed, /*out*/hidproxcard_t* card){
+  memset(card, 0, sizeof(hidproxcard_t));
+  if (packed->Length != 34) return false; // Wrong length? Stop here.
+  
+  card->CardNumber = get_linear_field(packed, 17, 16);
+  card->FacilityCode = get_linear_field(packed, 9, 8);
+  card->ParitySupported = false;
+  return true;
+}
+
+
+bool Pack_C1k35s(/*in*/hidproxcard_t* card, /*out*/hidproxmessage_t* packed){
+  memset(packed, 0, sizeof(hidproxmessage_t));
+  if (card->FacilityCode > 0xFFF) return false; // Can't encode FC.
+  if (card->CardNumber > 0xFFFFF) return false; // Can't encode CN.
+  
+  packed->Length = 35; // Set number of bits
+  packed->bot |= (card->CardNumber & 0x000FFFFF) << 1;
+  packed->bot |= (card->FacilityCode & 0x000007FF) << 21;
+  packed->mid |= (card->FacilityCode & 0x00000800) >> 11;
+  if (card->ParitySupported){
+    packed->mid |= (evenparity32((packed->mid & 0x00000001) ^ (packed->bot & 0xB6DB6DB6)) & 1) << 1;
+    packed->bot |= ( oddparity32((packed->mid & 0x00000003) ^ (packed->bot & 0x6DB6DB6C)) & 1);
+    packed->mid |= ( oddparity32((packed->mid & 0x00000003) ^ (packed->bot & 0xFFFFFFFF)) & 1) << 2;
+  }
+  return add_HID_header(packed);
+}
+bool Unpack_C1k35s(/*in*/hidproxmessage_t* packed, /*out*/hidproxcard_t* card){
+  memset(card, 0, sizeof(hidproxcard_t));
+  if (packed->Length != 35) return false; // Wrong length? Stop here.
+  
+  card->CardNumber = (packed->bot >> 1) & 0x000FFFFF;
+  card->FacilityCode = ((packed->mid & 1) << 11) | ((packed->bot >> 21));
+  card->ParitySupported = true;
+  card->ParityValid =
+    (evenparity32((packed->mid & 0x00000001) ^ (packed->bot & 0xB6DB6DB6)) == ((packed->mid >> 1) & 1)) &&
+    ( oddparity32((packed->mid & 0x00000003) ^ (packed->bot & 0x6DB6DB6C)) == ((packed->bot >> 0) & 1)) &&
+    ( oddparity32((packed->mid & 0x00000003) ^ (packed->bot & 0xFFFFFFFF)) == ((packed->mid >> 2) & 1));
+  return true;
+}
+
+bool Pack_H10320(/*in*/hidproxcard_t* card, /*out*/hidproxmessage_t* packed){
+  memset(packed, 0, sizeof(hidproxmessage_t));
+  if (card->FacilityCode > 0) return false; // Can't encode FC. (none in this format)
+  if (card->CardNumber > 99999999) return false; // Can't encode CN.
+  
+  packed->Length = 36; // Set number of bits
+  // This card is BCD-encoded rather than binary. Set the 4-bit groups independently.
+  set_linear_field(packed, (card->CardNumber / 10000000) % 10, 0, 4);
+  set_linear_field(packed, (card->CardNumber / 1000000) % 10, 4, 4);
+  set_linear_field(packed, (card->CardNumber / 100000) % 10, 8, 4);
+  set_linear_field(packed, (card->CardNumber / 10000) % 10, 12, 4);
+  set_linear_field(packed, (card->CardNumber / 1000) % 10, 16, 4);
+  set_linear_field(packed, (card->CardNumber / 100) % 10, 20, 4);
+  set_linear_field(packed, (card->CardNumber / 10) % 10, 24, 4);
+  set_linear_field(packed, (card->CardNumber / 1) % 10, 28, 4);
+  if (card->ParitySupported){
+    set_bit_by_position(packed, evenparity32(
+      get_nonlinear_field(packed, 8, (uint8_t[]){0, 4, 8, 12, 16, 20, 24, 28})
+    ), 32);
+    set_bit_by_position(packed, oddparity32(
+      get_nonlinear_field(packed, 8, (uint8_t[]){1, 5, 9, 13, 17, 21, 25, 29})
+    ), 33);
+    set_bit_by_position(packed, evenparity32(
+      get_nonlinear_field(packed, 8, (uint8_t[]){2, 6, 10, 14, 18, 22, 28, 30})
+    ), 34);
+    set_bit_by_position(packed, evenparity32(
+      get_nonlinear_field(packed, 8, (uint8_t[]){3, 7, 11, 15, 19, 23, 29, 31})
+    ), 35);
+  }
+  return add_HID_header(packed);
+}
+bool Unpack_H10320(/*in*/hidproxmessage_t* packed, /*out*/hidproxcard_t* card){
+  memset(card, 0, sizeof(hidproxcard_t));
+  if (packed->Length != 36) return false; // Wrong length? Stop here.
+  // This card is BCD-encoded rather than binary. Get the 4-bit groups independently.
+  card->CardNumber += get_linear_field(packed, 0, 4) * 10000000;
+  card->CardNumber += get_linear_field(packed, 4, 4) * 1000000;
+  card->CardNumber += get_linear_field(packed, 8, 4) * 100000;
+  card->CardNumber += get_linear_field(packed, 12, 4) * 10000;
+  card->CardNumber += get_linear_field(packed, 16, 4) * 1000;
+  card->CardNumber += get_linear_field(packed, 20, 4) * 100;
+  card->CardNumber += get_linear_field(packed, 24, 4) * 10;
+  card->CardNumber += get_linear_field(packed, 28, 4);
+  card->ParitySupported = true;
+  card->ParityValid =
+    (get_bit_by_position(packed, 32) == evenparity32(get_nonlinear_field(packed, 8, (uint8_t[]){0, 4, 8, 12, 16, 20, 24, 28}))) &&
+    (get_bit_by_position(packed, 33) ==  oddparity32(get_nonlinear_field(packed, 8, (uint8_t[]){1, 5, 9, 13, 17, 21, 25, 29}))) &&
+    (get_bit_by_position(packed, 34) == evenparity32(get_nonlinear_field(packed, 8, (uint8_t[]){2, 6, 10, 14, 18, 22, 28, 30}))) &&
+    (get_bit_by_position(packed, 35) == evenparity32(get_nonlinear_field(packed, 8, (uint8_t[]){3, 7, 11, 15, 19, 23, 29, 31})));
+  return true;
+}
+
+
+bool Pack_H10302(/*in*/hidproxcard_t* card, /*out*/hidproxmessage_t* packed){
+  memset(packed, 0, sizeof(hidproxmessage_t));
+  if (card->FacilityCode > 0) return false; // Can't encode FC. (none in this format)
+  if (card->CardNumber > 0x00000007FFFFFFFF) return false; // Can't encode CN.
+  
+  packed->Length = 37; // Set number of bits
+  set_linear_field(packed, card->CardNumber, 1, 35);
+  if (card->ParitySupported){
+    set_bit_by_position(packed,
+      evenparity32(get_linear_field(packed, 1, 18))
+    , 0);
+    set_bit_by_position(packed, 
+      oddparity32(get_linear_field(packed, 18, 18))
+    , 36);
+  }
+  return add_HID_header(packed);
+}
+bool Unpack_H10302(/*in*/hidproxmessage_t* packed, /*out*/hidproxcard_t* card){
+  memset(card, 0, sizeof(hidproxcard_t));
+  if (packed->Length != 37) return false; // Wrong length? Stop here.
+  
+  card->CardNumber = get_linear_field(packed, 1, 35);
+  card->ParitySupported = true;
+  card->ParityValid =
+    (get_bit_by_position(packed, 0) == evenparity32(get_linear_field(packed, 1, 18))) &&
+    (get_bit_by_position(packed, 36) == oddparity32(get_linear_field(packed, 18, 18)));
+    
+  return true;
+}
+
+bool Pack_H10304(/*in*/hidproxcard_t* card, /*out*/hidproxmessage_t* packed){
+  memset(packed, 0, sizeof(hidproxmessage_t));
+  if (card->FacilityCode > 0x0000FFFF) return false; // Can't encode FC.
+  if (card->CardNumber > 0x0007FFFF) return false; // Can't encode CN.
+  
+  packed->Length = 37; // Set number of bits
+  packed->bot |= (card->CardNumber & 0x0007FFFF) << 1;
+  packed->bot |= (card->FacilityCode & 0x00000FFF) << 20;
+  packed->mid |= (card->FacilityCode & 0x0000F000) >> 12;
+  if (card->ParitySupported){
+    packed->mid |= (evenparity32((packed->mid & 0x0000000F) ^ (packed->bot & 0xFFFC0000)) & 1) << 4;
+    packed->bot |= ( oddparity32(packed->bot & 0x0007FFFE) & 1);
+  }
+  return add_HID_header(packed);
+}
+bool Unpack_H10304(/*in*/hidproxmessage_t* packed, /*out*/hidproxcard_t* card){
+  memset(card, 0, sizeof(hidproxcard_t));
+  if (packed->Length != 37) return false; // Wrong length? Stop here.
+  
+  card->CardNumber = (packed->bot >> 1) & 0x0007FFFF;
+  card->FacilityCode = ((packed->mid & 0xF) << 12) | ((packed->bot >> 20));
+  card->ParitySupported = true;
+  card->ParityValid =
+    (evenparity32((packed->mid & 0x0000000F) ^ (packed->bot & 0xFFFC0000)) == ((packed->mid >> 4) & 1)) &&
+    (oddparity32( packed->bot & 0x0007FFFE) == (packed->bot & 1));
+  return true;
+}
+
+
+bool Pack_P10001(/*in*/hidproxcard_t* card, /*out*/hidproxmessage_t* packed){
+  memset(packed, 0, sizeof(hidproxmessage_t));
+  if (card->FacilityCode > 0xFFF) return false; // Can't encode FC.
+  if (card->CardNumber > 0xFFFF) return false; // Can't encode CN.
+  
+  packed->Length = 40; // Set number of bits
+  set_linear_field(packed, 0xF, 0, 4);
+  set_linear_field(packed, card->FacilityCode, 4, 12);
+  set_linear_field(packed, card->CardNumber, 16, 16);
+  
+  if (card->ParitySupported){
+    set_linear_field(packed, 
+      get_linear_field(packed, 0, 8) ^
+      get_linear_field(packed, 8, 8) ^
+      get_linear_field(packed, 16, 8) ^
+      get_linear_field(packed, 24, 8)
+    , 32, 8);
+  }
+  return add_HID_header(packed);
+}
+bool Unpack_P10001(/*in*/hidproxmessage_t* packed, /*out*/hidproxcard_t* card){
+  memset(card, 0, sizeof(hidproxcard_t));
+  if (packed->Length != 40) return false; // Wrong length? Stop here.
+  
+  card->CardNumber = get_linear_field(packed, 16, 16);
+  card->FacilityCode = get_linear_field(packed, 4, 12);
+  card->ParitySupported = true;
+  card->ParityValid = (
+    get_linear_field(packed, 0, 8) ^
+    get_linear_field(packed, 8, 8) ^
+    get_linear_field(packed, 16, 8) ^
+    get_linear_field(packed, 24, 8)
+  ) == get_linear_field(packed, 32, 8);
+  return true;
+}
+
+
+bool Pack_C1k48s(/*in*/hidproxcard_t* card, /*out*/hidproxmessage_t* packed){
+  memset(packed, 0, sizeof(hidproxmessage_t));
+  if (card->FacilityCode > 0x003FFFFF) return false; // Can't encode FC.
+  if (card->CardNumber > 0x007FFFFF) return false; // Can't encode CN.
+  
+  packed->Length = 48; // Set number of bits
+  packed->bot |= (card->CardNumber & 0x007FFFFF) << 1;
+  packed->bot |= (card->FacilityCode & 0x000000FF) << 24;
+  packed->mid |= (card->FacilityCode & 0x003FFF00) >> 8;
+  if (card->ParitySupported){
+    packed->mid |= (evenparity32((packed->mid & 0x00001B6D) ^ (packed->bot & 0xB6DB6DB6)) & 1) << 14;
+    packed->bot |= ( oddparity32((packed->mid & 0x000036DB) ^ (packed->bot & 0x6DB6DB6C)) & 1);
+    packed->mid |= ( oddparity32((packed->mid & 0x00007FFF) ^ (packed->bot & 0xFFFFFFFF)) & 1) << 15;
+  }
+  return add_HID_header(packed);
+}
+bool Unpack_C1k48s(/*in*/hidproxmessage_t* packed, /*out*/hidproxcard_t* card){
+  memset(card, 0, sizeof(hidproxcard_t));
+  if (packed->Length != 48) return false; // Wrong length? Stop here.
+  
+  card->CardNumber = (packed->bot >> 1) & 0x007FFFFF;
+  card->FacilityCode = ((packed->mid & 0x00003FFF) << 8) | ((packed->bot >> 24));
+  card->ParitySupported = true;
+  card->ParityValid =
+    (evenparity32((packed->mid & 0x00001B6D) ^ (packed->bot & 0xB6DB6DB6)) == ((packed->mid >> 14) & 1)) &&
+    ( oddparity32((packed->mid & 0x000036DB) ^ (packed->bot & 0x6DB6DB6C)) == ((packed->bot >> 0) & 1)) &&
+    ( oddparity32((packed->mid & 0x00007FFF) ^ (packed->bot & 0xFFFFFFFF)) == ((packed->mid >> 15) & 1));
+  return true;
+}
+
+static const hidcardformat_t FormatTable[] = {
+    {"H10301", Pack_H10301, Unpack_H10301, "HID H10301 26-bit"}, // imported from old pack/unpack
+    {"Tecom27", Pack_Tecom27, Unpack_Tecom27, "Tecom 27-bit"}, // from cardinfo.barkweb.com.au
+    {"2804W", Pack_2804W, Unpack_2804W, "2804 Wiegand"}, // from cardinfo.barkweb.com.au
+    {"ATSW30", Pack_ATSW30, Unpack_ATSW30, "ATS Wiegand 30-bit"}, // from cardinfo.barkweb.com.au
+    {"ADT31", Pack_ADT31, Unpack_ADT31, "HID ADT 31-bit"}, // from cardinfo.barkweb.com.au
+    {"D10202", Pack_D10202, Unpack_D10202, "HID D10202 33-bit"}, // from cardinfo.barkweb.com.au
+    {"H10306", Pack_H10306, Unpack_H10306, "HID H10306 34-bit"}, // imported from old pack/unpack
+    {"N1002", Pack_N1002, Unpack_N1002, "HID N1002 34-bit"}, // from cardinfo.barkweb.com.au
+    {"C1k35s", Pack_C1k35s, Unpack_C1k35s, "HID Corporate 1000 35-bit standard layout"}, // imported from old pack/unpack
+    {"H10320", Pack_H10320, Unpack_H10320, "HID H10320 36-bit BCD, Card num only"}, // from Proxmark forums
+    {"H10302", Pack_H10302, Unpack_H10302, "HID H10302 37-bit huge, Card num only"}, // from Proxmark forums
+    {"H10304", Pack_H10304, Unpack_H10304, "HID H10304 37-bit"}, // imported from old pack/unpack
+    {"P10001", Pack_P10001, Unpack_P10001, "HID P10001 Honeywell 40-bit"}, // from cardinfo.barkweb.com.au
+    {"C1k48s", Pack_C1k48s, Unpack_C1k48s, "HID Corporate 1000 48-bit standard layout"}, // imported from old pack/unpack
+    {NULL, NULL, NULL, NULL} // Must null terminate array
+};
+
+void HIDListFormats(){
+  if (FormatTable[0].Name == NULL)
+    return;
+  int i = 0;
+  PrintAndLog("%-10s %s", "Name", "Description");
+  PrintAndLog("------------------------------------------------------------");
+  while (FormatTable[i].Name)
+  {
+    PrintAndLog("%-10s %s", FormatTable[i].Name, FormatTable[i].Descrp);
+    ++i;
+  }
+  PrintAndLog("");
+  return;
+}
+
+hidcardformat_t HIDGetCardFormat(int idx){
+  return FormatTable[idx];
+}
+
+int HIDFindCardFormat(const char *format)
+{
+  if (FormatTable[0].Name == NULL) 
+    return -1;
+  int i = 0;
+  while (FormatTable[i].Name && strcmp(FormatTable[i].Name, format))
+  {
+    ++i;
+  }
+
+       if (FormatTable[i].Name) {
+               return i;
+       } else {
+    return -1;
+       }
+}
+
+bool HIDPack(/* in */int FormatIndex, /* in */hidproxcard_t* card, /* out */hidproxmessage_t* packed){
+  memset(packed, 0, sizeof(hidproxmessage_t));
+  if (FormatIndex < 0 || FormatIndex >= (sizeof(FormatTable) / sizeof(FormatTable[0]))) return false;
+  return FormatTable[FormatIndex].Pack(card, packed);
+}
+
+bool HIDTryUnpack(/* in */hidproxmessage_t* packed){
+  if (FormatTable[0].Name == NULL) 
+    return false;
+    
+  bool result = false;
+  int i = 0;
+  hidproxcard_t card;
+  memset(&card, 0, sizeof(hidproxcard_t));
+  while (FormatTable[i].Name)
+  {
+    if (FormatTable[i].Unpack(packed, &card)){
+      result = true;
+      PrintAndLog("%-16s FC: %u, Card %"PRIu64", Parity %s", 
+        FormatTable[i].Name, 
+        card.FacilityCode, 
+        card.CardNumber, 
+        (card.ParitySupported) ? ((card.ParityValid) ? "valid" : "invalid") : "n/a"
+      );
+    }
+    ++i;
+  }
+  return result;
+}
diff --git a/client/hidcardformats.h b/client/hidcardformats.h
new file mode 100644 (file)
index 0000000..8ff887f
--- /dev/null
@@ -0,0 +1,32 @@
+//-----------------------------------------------------------------------------
+// Copyright (C) 2018 grauerfuchs
+//
+// 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.
+//-----------------------------------------------------------------------------
+// HID card format packing/unpacking routines
+//-----------------------------------------------------------------------------
+
+#ifndef HIDCARDFORMATS_H__
+#define HIDCARDFORMATS_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "hidcardformatutils.h"
+
+// Structure for defined HID card formats available for packing/unpacking
+typedef struct hidcardformat_s{
+  const char* Name;
+  bool (*Pack)(/*in*/hidproxcard_t* card, /*out*/hidproxmessage_t* packed);
+  bool (*Unpack)(/*in*/hidproxmessage_t* packed, /*out*/hidproxcard_t* card);
+  const char* Descrp;
+} hidcardformat_t;
+
+void HIDListFormats();
+int HIDFindCardFormat(const char *format);
+hidcardformat_t HIDGetCardFormat(int idx);
+bool HIDPack(/* in */int FormatIndex, /* in */hidproxcard_t* card, /* out */hidproxmessage_t* packed);
+bool HIDTryUnpack(/* in */hidproxmessage_t* packed);
+
+#endif
diff --git a/client/hidcardformatutils.c b/client/hidcardformatutils.c
new file mode 100644 (file)
index 0000000..d7c159c
--- /dev/null
@@ -0,0 +1,172 @@
+//-----------------------------------------------------------------------------
+// Copyright (C) 2018 grauerfuchs
+//
+// 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.
+//-----------------------------------------------------------------------------
+// HID card format packing/unpacking support functions
+//-----------------------------------------------------------------------------
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include "hidcardformatutils.h"
+#include "ui.h"
+
+bool get_bit_by_position(/* in */hidproxmessage_t* data, /* in */uint8_t pos){
+  if (pos >= data->Length) return false;
+  pos = (data->Length - pos) - 1; // invert ordering; Indexing goes from 0 to 1. Subtract 1 for weight of bit.
+  bool result = false;
+  if (pos > 95) 
+    result = false;
+  else if (pos > 63)
+    result = (data->top >> (pos - 64)) & 1;
+  else if (pos > 31)
+    result = (data->mid >> (pos - 32)) & 1;
+  else
+    result = (data->bot >> pos) & 1;
+  return result;
+}
+bool set_bit_by_position(/* inout */hidproxmessage_t* data, /* in */bool value, /* in */uint8_t pos){
+  if (pos >= data->Length) return false;
+  pos = (data->Length - pos) - 1; // invert ordering; Indexing goes from 0 to 1. Subtract 1 for weight of bit.
+  if (pos > 95) {
+    return false;
+  } else if (pos > 63) {
+    if (value)
+      data->top |= (1 << (pos - 64));
+    else
+      data->top &= ~(1 << (pos - 64));
+    return true;
+  } else if (pos > 31) {
+    if (value)
+      data->mid |= (1 << (pos - 32));
+    else
+      data->mid &= ~(1 << (pos - 32));
+    return true;
+  } else {
+    if (value)
+      data->bot |= (1 << pos);
+    else
+      data->bot &= ~(1 << pos);
+    return true;
+  }
+}
+/**
+ * Safeguard the data by doing a manual deep copy
+ * 
+ * At the time of the initial writing, the struct does not contain pointers. That doesn't
+ * mean it won't eventually contain one, however. To prevent memory leaks and erroneous
+ * aliasing, perform the copy function manually instead. Hence, this function.
+ * 
+ * If the definition of the hid_proxmessage struct changes, this function must also
+ * be updated to match.
+ */
+void proxmessage_datacopy(/*in*/hidproxmessage_t* src, /*out*/hidproxmessage_t* dest){
+  dest->bot = src->bot;
+  dest->mid = src->mid;
+  dest->top = src->top;
+  dest->Length = src->Length;
+}
+/**
+ *
+ * Yes, this is horribly inefficient for linear data. 
+ * The current code is a temporary measure to have a working function in place
+ * until all the bugs shaken from the block/chunk version of the code.
+ *
+ */
+uint64_t get_linear_field(/* in */hidproxmessage_t* data, uint8_t firstBit, uint8_t length){
+  uint64_t result = 0;
+  for (uint8_t i = 0; i < length; i++ ) {
+    result = (result << 1) | get_bit_by_position(data, firstBit + i);
+  }
+  return result;
+}
+bool set_linear_field(/* inout */hidproxmessage_t* data, uint64_t value, uint8_t firstBit, uint8_t length){
+  hidproxmessage_t tmpdata;
+  proxmessage_datacopy(data, &tmpdata);
+  bool result = true;
+  for (int i = 0; i < length; i++){
+    result &= set_bit_by_position(&tmpdata, (value >> ((length - i) - 1)) & 1, firstBit + i);
+  }
+  if (result) proxmessage_datacopy(&tmpdata, data);
+  return result;
+}
+
+uint64_t get_nonlinear_field(/* in */hidproxmessage_t* data, uint8_t numBits, uint8_t* bits){
+  uint64_t result = 0;
+  for (int i = 0; i < numBits; i++){
+    result = (result << 1) | (get_bit_by_position(data, *(bits+i)) & 1);
+  }
+  return result;
+}
+bool set_nonlinear_field(/* inout */hidproxmessage_t* data, uint64_t value, uint8_t numBits, uint8_t* bits){
+  hidproxmessage_t tmpdata;
+  proxmessage_datacopy(data, &tmpdata);
+  bool result = true;
+  for (int i = 0; i < numBits; i++){
+    result &= set_bit_by_position(&tmpdata, (value >> ((numBits - i) - 1)) & 1, *(bits + i));
+  }
+  if (result) proxmessage_datacopy(&tmpdata, data);
+  return result;
+}
+
+uint8_t get_length_from_header(/* inout */hidproxmessage_t* data) {
+  uint8_t len = 0;
+       
+  uint32_t hFmt; // for calculating card length
+  if ((data->top & 0x000FFFFF) > 0) { // > 64 bits
+    hFmt = data->top & 0x000FFFFF;
+    len = 64;
+  } else if ((data->mid & 0xFFFFFFC0) > 0) { // < 63-38 bits
+    hFmt = data->mid & 0xFFFFFFC0;
+    len = 32;
+  } else if ((data->mid & 0x00000020) == 0) { // 37 bits
+    hFmt = 0;
+    len = 37;
+  } else if ((data->mid & 0x0000001F) > 0){ // 36-32 bits
+    hFmt = data->mid & 0x0000001F;
+    len = 32;
+  } else { // <32 bits
+    hFmt = data->bot;
+    len = 0;
+  }
+
+  while (hFmt > 1) {
+    hFmt >>= 1;
+    len++;
+  }
+  return len;
+}
+
+hidproxmessage_t initialize_proxmessage_object(uint32_t top, uint32_t mid, uint32_t bot){
+  struct hidproxmessage_s result;
+  memset(&result, 0, sizeof(hidproxmessage_t));
+  result.top = top;
+  result.mid = mid;
+  result.bot = bot;
+  result.Length = get_length_from_header(&result);
+  return result;
+}
+bool add_HID_header(/* inout */hidproxmessage_t* data){
+  if (data->Length > 84 || data->Length == 0) return false; // Invalid value
+
+  if (data->Length >= 64){
+    data->top |= 1 << (data->Length - 64); // leading 1: start bit
+    data->top |= 0x09e00000; // Extended-length header
+  } else if (data->Length > 37){
+    data->mid |= 1 << (data->Length - 32); // leading 1: start bit
+    data->top |= 0x09e00000; // Extended-length header
+  } else if (data->Length == 37){
+    // No header bits added to 37-bit cards
+  } else if (data->Length >= 32){
+    data->mid |= 0x20; // Bit 37; standard header
+    data->mid |= 1 << (data->Length - 32); // leading 1: start bit
+  } else {
+    data->mid |= 0x20; // Bit 37; standard header
+    data->bot |= 1 << data->Length; // leading 1: start bit
+  }
+  return true;
+}
\ No newline at end of file
diff --git a/client/hidcardformatutils.h b/client/hidcardformatutils.h
new file mode 100644 (file)
index 0000000..afb76f1
--- /dev/null
@@ -0,0 +1,47 @@
+//-----------------------------------------------------------------------------
+// Copyright (C) 2018 grauerfuchs
+//
+// 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.
+//-----------------------------------------------------------------------------
+// HID card format packing/unpacking support functions
+//-----------------------------------------------------------------------------
+
+#ifndef HIDCARDFORMATUTILS_H__
+#define HIDCARDFORMATUTILS_H__
+
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+// Structure for packed HID messages
+// Always align lowest value (last transmitted) bit to ordinal position 0 (lowest valued bit bottom)
+typedef struct hidproxmessage_s{
+  uint8_t Length; // Number of encoded bits in prox message (excluding headers and preamble)
+  uint32_t top; // Bits in x<<64 positions
+  uint32_t mid; // Bits in x<<32 positions
+  uint32_t bot; // Lowest ordinal positions
+} hidproxmessage_t;
+
+// Structure for unpacked HID prox cards
+typedef struct hidproxcard_s{
+  uint32_t FacilityCode;
+  uint64_t CardNumber;
+  uint8_t IssueLevel;
+  bool ParitySupported; // Only valid for responses
+  bool ParityValid; // Only valid for responses
+} hidproxcard_t;
+
+bool get_bit_by_position(/* in */hidproxmessage_t* data, /* in */uint8_t pos);
+bool set_bit_by_position(/* inout */hidproxmessage_t* data, /* in */bool value, /* in */uint8_t pos);
+
+uint64_t get_linear_field(/* in */hidproxmessage_t* data, /* in */uint8_t firstBit, /* in */uint8_t length);
+bool set_linear_field(/* inout */hidproxmessage_t* data, /* in */uint64_t value, /* in */uint8_t firstBit, /* in */uint8_t length);
+
+uint64_t get_nonlinear_field(/* in */hidproxmessage_t* data, /* in */uint8_t numBits, /* in */uint8_t* bits);
+bool set_nonlinear_field(/* inout */hidproxmessage_t* data, /* in */uint64_t value, /* in */uint8_t numBits, /* in */uint8_t* bits);
+
+hidproxmessage_t initialize_proxmessage_object(/* in */uint32_t top, /* in */uint32_t mid, /* in */uint32_t bot);
+bool add_HID_header(/* inout */hidproxmessage_t* data);
+#endif
Impressum, Datenschutz