From: grauerfuchs <42082416+grauerfuchs@users.noreply.github.com> Date: Fri, 14 Sep 2018 01:30:24 +0000 (-0400) Subject: Merge branch 'master' into master X-Git-Tag: v3.1.0~14^2~2 X-Git-Url: https://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/commitdiff_plain/173ba1e1a268c1a04dd438c4e0cbe06088187703?hp=53edb044c0dfe82fd9d0a0e0d3444a51ebe358f4 Merge branch 'master' into master --- diff --git a/CHANGELOG.md b/CHANGELOG.md index ca13dc85..f10ef4e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Changed TLV parser messages to more convenient (Merlok) - Rewritten Legic Prime reader (`hf legic reader`, `write` and `fill`) - it is using xcorrelation now (AntiCat) - `hf 14a` commands works via argtable3 commandline parsing library (Merlok) +- HID LF operations on firmware updated for complete native support of long (>37 bit) HID tags (grauerfuchs) ### Fixed - Changed start sequence in Qt mode (fix: short commands hangs main Qt thread) (Merlok) @@ -53,6 +54,8 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Added to `hf emv exec` SDA, DDA, fast DDA, CDA calculations for VISA and Mastercard and some other compatible EMV cards (Merlok) - Added `hf emv test` - crypto tests for DES, AES, SHA, RSA, SDA, DDA, CDA and some other crypto functions (Merlok) - Added `hf list mf` - deciphers crypto1 stream and works with first authentication and weak nested authentications (Merlok) +- Added `lf hid encode` and `lf hid decode` commands to translate printed HID card data to and from the packed data transmitted by a prox tag (grauerfuchs) +- Added `lf hid write` command, which operates as a macro for encode followed by clone operations (grauerfuchs) ## [3.0.1][2017-06-08] @@ -230,5 +233,3 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac ### Added - iClass functionality: full simulation of iclass tags, so tags can be simulated with data (not only CSN). Not yet support for write/update, but readers don't seem to enforce update. (holiman). - iClass decryption. Proxmark can now decrypt data on an iclass tag, but requires you to have the HID decryption key locally on your computer, as this is not bundled with the sourcecode. - - diff --git a/armsrc/appmain.c b/armsrc/appmain.c index f7bcd620..e6d40abc 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -650,7 +650,7 @@ void SamyRun() StandAloneMode(); FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - int high[OPTS], low[OPTS]; + int tops[OPTS], high[OPTS], low[OPTS]; int selected = 0; int playing = 0; int cardRead = 0; @@ -684,8 +684,11 @@ void SamyRun() /* need this delay to prevent catching some weird data */ SpinDelay(500); - CmdHIDdemodFSK(1, &high[selected], &low[selected], 0); - Dbprintf("Recorded %x %x%08x", selected, high[selected], low[selected]); + CmdHIDdemodFSK(1, &tops[selected], &high[selected], &low[selected], 0); + if (tops[selected] > 0) + Dbprintf("Recorded %x %x%08x%08x", selected, tops[selected], high[selected], low[selected]); + else + Dbprintf("Recorded %x %x%08x", selected, high[selected], low[selected]); LEDsoff(); LED(selected + 1, 0); @@ -706,7 +709,10 @@ void SamyRun() LED(LED_ORANGE, 0); // record - Dbprintf("Cloning %x %x%08x", selected, high[selected], low[selected]); + if (tops[selected] > 0) + Dbprintf("Cloning %x %x%08x%08x", selected, tops[selected], high[selected], low[selected]); + else + Dbprintf("Cloning %x %x%08x", selected, high[selected], low[selected]); // wait for button to be released while(BUTTON_PRESS()) @@ -715,8 +721,11 @@ void SamyRun() /* need this delay to prevent catching some weird data */ SpinDelay(500); - CopyHIDtoT55x7(0, high[selected], low[selected], 0); - Dbprintf("Cloned %x %x%08x", selected, high[selected], low[selected]); + CopyHIDtoT55x7(tops[selected] & 0x000FFFFF, high[selected], low[selected], (tops[selected] != 0 && ((high[selected]& 0xFFFFFFC0) != 0))); + if (tops[selected] > 0) + Dbprintf("Cloned %x %x%08x%08x", selected, tops[selected], high[selected], low[selected]); + else + Dbprintf("Cloned %x %x%08x", selected, high[selected], low[selected]); LEDsoff(); LED(selected + 1, 0); @@ -749,8 +758,12 @@ void SamyRun() // wait for button to be released while(BUTTON_PRESS()) WDT_HIT(); - Dbprintf("%x %x%08x", selected, high[selected], low[selected]); - CmdHIDsimTAG(high[selected], low[selected], 0); + if (tops[selected] > 0) + Dbprintf("%x %x%08x%08x", selected, tops[selected], high[selected], low[selected]); + else + Dbprintf("%x %x%08x", selected, high[selected], low[selected]); + + CmdHIDsimTAG(tops[selected], high[selected], low[selected], 0); DbpString("Done playing"); if (BUTTON_HELD(1000) > 0) { @@ -948,10 +961,10 @@ void UsbPacketReceived(uint8_t *packet, int len) cmd_send(CMD_ACK,SnoopLF(),0,0,0,0); break; case CMD_HID_DEMOD_FSK: - CmdHIDdemodFSK(c->arg[0], 0, 0, 1); + CmdHIDdemodFSK(c->arg[0], 0, 0, 0, 1); break; case CMD_HID_SIM_TAG: - CmdHIDsimTAG(c->arg[0], c->arg[1], 1); + CmdHIDsimTAG(c->arg[0], c->arg[1], c->arg[2], 1); break; case CMD_FSK_SIM_TAG: CmdFSKsimTAG(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); diff --git a/armsrc/apps.h b/armsrc/apps.h index 542e6b90..5b981f4f 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -68,11 +68,11 @@ void AcquireTiType(void); void AcquireRawBitsTI(void); void SimulateTagLowFrequency(int period, int gap, int ledcontrol); void SimulateTagLowFrequencyBidir(int divisor, int max_bitlen); -void CmdHIDsimTAG(int hi, int lo, int ledcontrol); +void CmdHIDsimTAG(int hi2, int hi, int lo, int ledcontrol); void CmdFSKsimTAG(uint16_t arg1, uint16_t arg2, size_t size, uint8_t *BitStream); void CmdASKsimTag(uint16_t arg1, uint16_t arg2, size_t size, uint8_t *BitStream); void CmdPSKsimTag(uint16_t arg1, uint16_t arg2, size_t size, uint8_t *BitStream); -void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol); +void CmdHIDdemodFSK(int findone, int *high2, int *high, int *low, int ledcontrol); void CmdAWIDdemodFSK(int findone, int *high, int *low, int ledcontrol); // Realtime demodulation mode for AWID26 void CmdEM410xdemod(int findone, int *high, int *low, int ledcontrol); void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol); diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 911ba8da..c0134778 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -593,7 +593,7 @@ static void fcAll(uint8_t fc, int *n, uint8_t clock, uint16_t *modCnt) // prepare a waveform pattern in the buffer based on the ID given then // simulate a HID tag until the button is pressed -void CmdHIDsimTAG(int hi, int lo, int ledcontrol) +void CmdHIDsimTAG(int hi2, int hi, int lo, int ledcontrol) { int n=0, i=0; /* @@ -606,8 +606,8 @@ void CmdHIDsimTAG(int hi, int lo, int ledcontrol) nor 1 bits, they are special patterns (a = set of 12 fc8 and b = set of 10 fc10) */ - if (hi>0xFFF) { - DbpString("Tags can only have 44 bits. - USE lf simfsk for larger tags"); + if (hi2>0x0FFFFFFF) { + DbpString("Tags can only have 44 or 84 bits. - USE lf simfsk for larger tags"); return; } // set LF so we don't kill the bigbuf we are setting with simulation data. @@ -621,13 +621,35 @@ void CmdHIDsimTAG(int hi, int lo, int ledcontrol) fc(8, &n); fc(10, &n); // logical 0 WDT_HIT(); - // manchester encode bits 43 to 32 - for (i=11; i>=0; i--) { - if ((i%4)==3) fc(0,&n); - if ((hi>>i)&1) { - fc(10, &n); fc(8, &n); // low-high transition - } else { - fc(8, &n); fc(10, &n); // high-low transition + if (hi2 > 0 || hi > 0xFFF){ + // manchester encode bits 91 to 64 (91-84 are part of the header) + for (i=27; i>=0; i--) { + if ((i%4)==3) fc(0,&n); + if ((hi2>>i)&1) { + fc(10, &n); fc(8, &n); // low-high transition + } else { + fc(8, &n); fc(10, &n); // high-low transition + } + } + WDT_HIT(); + // manchester encode bits 63 to 32 + for (i=31; i>=0; i--) { + if ((i%4)==3) fc(0,&n); + if ((hi>>i)&1) { + fc(10, &n); fc(8, &n); // low-high transition + } else { + fc(8, &n); fc(10, &n); // high-low transition + } + } + } else { + // manchester encode bits 43 to 32 + for (i=11; i>=0; i--) { + if ((i%4)==3) fc(0,&n); + if ((hi>>i)&1) { + fc(10, &n); fc(8, &n); // low-high transition + } else { + fc(8, &n); fc(10, &n); // high-low transition + } } } @@ -839,7 +861,7 @@ void CmdPSKsimTag(uint16_t arg1, uint16_t arg2, size_t size, uint8_t *BitStream) } // loop to get raw HID waveform then FSK demodulate the TAG ID from it -void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol) +void CmdHIDdemodFSK(int findone, int *high2, int *high, int *low, int ledcontrol) { uint8_t *dest = BigBuf_get_addr(); //const size_t sizeOfBigBuff = BigBuf_max_traceLen(); @@ -854,7 +876,6 @@ void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol) BigBuf_Clear_keep_EM(); while(!BUTTON_PRESS() && !usb_poll_validate_length()) { - WDT_HIT(); if (ledcontrol) LED_A_ON(); @@ -865,60 +886,70 @@ void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol) idx = HIDdemodFSK(dest, &size, &hi2, &hi, &lo, &dummyIdx); if (idx>0 && lo>0 && (size==96 || size==192)){ + uint8_t bitlen = 0; + uint32_t fc = 0; + uint32_t cardnum = 0; + bool decoded = false; + // go over previously decoded manchester data and decode into usable tag ID - if (hi2 != 0){ //extra large HID tags 88/192 bits - Dbprintf("TAG ID: %x%08x%08x (%d)", - (unsigned int) hi2, (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); - }else { //standard HID tags 44/96 bits - //Dbprintf("TAG ID: %x%08x (%d)",(unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); //old print cmd - uint8_t bitlen = 0; - uint32_t fc = 0; - uint32_t cardnum = 0; - if (((hi>>5)&1) == 1){//if bit 38 is set then < 37 bit format is used - uint32_t lo2=0; - lo2=(((hi & 31) << 12) | (lo>>20)); //get bits 21-37 to check for format len bit - uint8_t idx3 = 1; - while(lo2 > 1){ //find last bit set to 1 (format len bit) - lo2=lo2 >> 1; - idx3++; - } - bitlen = idx3+19; - fc =0; - cardnum=0; - if(bitlen == 26){ - cardnum = (lo>>1)&0xFFFF; - fc = (lo>>17)&0xFF; - } - if(bitlen == 37){ - cardnum = (lo>>1)&0x7FFFF; - fc = ((hi&0xF)<<12)|(lo>>20); - } - if(bitlen == 34){ - cardnum = (lo>>1)&0xFFFF; - fc= ((hi&1)<<15)|(lo>>17); - } - if(bitlen == 35){ - cardnum = (lo>>1)&0xFFFFF; - fc = ((hi&1)<<11)|(lo>>21); - } + if ((hi2 & 0x000FFFF) != 0){ //extra large HID tags 88/192 bits + uint32_t bp = hi2 & 0x000FFFFF; + bitlen = 63; + while (bp > 0) { + bp = bp >> 1; + bitlen++; } - else { //if bit 38 is not set then 37 bit format is used - bitlen= 37; - fc =0; - cardnum=0; - if(bitlen==37){ - cardnum = (lo>>1)&0x7FFFF; - fc = ((hi&0xF)<<12)|(lo>>20); - } + } else if ((hi >> 6) > 0) { + uint32_t bp = hi; + bitlen = 31; + while (bp > 0) { + bp = bp >> 1; + bitlen++; + } + } else if (((hi >> 5) & 1) == 0) { + bitlen = 37; + } else if ((hi & 0x0000001F) > 0 ) { + uint32_t bp = (hi & 0x0000001F); + bitlen = 31; + while (bp > 0) { + bp = bp >> 1; + bitlen++; + } + } else { + uint32_t bp = lo; + bitlen = 0; + while (bp > 0) { + bp = bp >> 1; + bitlen++; } - //Dbprintf("TAG ID: %x%08x (%d)", - // (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); - Dbprintf("TAG ID: %x%08x (%d) - Format Len: %dbit - FC: %d - Card: %d", - (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF, - (unsigned int) bitlen, (unsigned int) fc, (unsigned int) cardnum); } + switch (bitlen){ + case 26: + cardnum = (lo>>1)&0xFFFF; + fc = (lo>>17)&0xFF; + decoded = true; + break; + case 35: + cardnum = (lo>>1)&0xFFFFF; + fc = ((hi&1)<<11)|(lo>>21); + decoded = true; + break; + } + + if (hi2 != 0) //extra large HID tags 88/192 bits + Dbprintf("TAG ID: %x%08x%08x (%d)", + (unsigned int) hi2, (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); + else + Dbprintf("TAG ID: %x%08x (%d)", + (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); + + if (decoded) + Dbprintf("Format Len: %dbits - FC: %d - Card: %d", + (unsigned int) bitlen, (unsigned int) fc, (unsigned int) cardnum); + if (findone){ if (ledcontrol) LED_A_OFF(); + *high2 = hi2; *high = hi; *low = lo; break; diff --git a/client/Makefile b/client/Makefile index 54a77a84..e2f3e992 100644 --- a/client/Makefile +++ b/client/Makefile @@ -162,6 +162,8 @@ CMDSRCS = $(SRC_SMARTCARD) \ cmdlfem4x.c \ cmdlffdx.c \ cmdlfgproxii.c \ + hidcardformatutils.c\ + hidcardformats.c\ cmdlfhid.c \ cmdlfhitag.c \ cmdlfio.c \ diff --git a/client/cmdlfhid.c b/client/cmdlfhid.c index 1a9c3477..38e7073c 100644 --- a/client/cmdlfhid.c +++ b/client/cmdlfhid.c @@ -28,223 +28,10 @@ #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 @@ -266,6 +53,90 @@ int hexstring_to_int96(/* out */ uint32_t* hi2,/* out */ uint32_t* hi, /* out */ return i - 1; } +void usage_encode(){ + PrintAndLog("Usage: lf hid encode [ ] {...}"); + PrintAndLog(" Fields: c: Card number"); + PrintAndLog(" f: Facility code"); + PrintAndLog(" i: Issue Level"); + PrintAndLog(" o: OEM code"); + PrintAndLog(" example: lf hid encode H10301 f 123 c 4567"); +} +void PrintProxTagId(hidproxmessage_t *packed){ + if (packed->top != 0) { + PrintAndLog("HID Prox TAG ID: %x%08x%08x", + (uint32_t)packed->top, (uint32_t)packed->mid, (uint32_t)packed->bot); + } else { + PrintAndLog("HID Prox TAG ID: %x%08x", + (uint32_t)packed->mid, (uint32_t)packed->bot); + } +} +bool Encode(/* in */ const char *Cmd, /* out */ hidproxmessage_t *packed){ + int formatIndex = -1; + char format[16]; + memset(format, 0, sizeof(format)); + if (!strcmp(Cmd, "help") || !strcmp(Cmd, "h") || !strcmp(Cmd, "list") || !strcmp(Cmd, "?")){ + usage_encode(); + return false; + } else { + param_getstr(Cmd, 0, format, sizeof(format)); + formatIndex = HIDFindCardFormat(format); + if (formatIndex == -1) { + printf("Unknown format: %s\r\n", format); + return false; + } + } + hidproxcard_t data; + memset(&data, 0, sizeof(hidproxcard_t)); + uint8_t cmdp = 1; + while(param_getchar(Cmd, cmdp) != 0x00) { + switch(param_getchar(Cmd, cmdp)) { + case 'I': + case 'i': + data.IssueLevel = param_get32ex(Cmd, cmdp+1, 0, 10); + cmdp += 2; + break; + case 'F': + case 'f': + data.FacilityCode = param_get32ex(Cmd, cmdp+1, 0, 10); + cmdp += 2; + break; + case 'C': + case 'c': + data.CardNumber = param_get64ex(Cmd, cmdp+1, 0, 10); + cmdp += 2; + break; + case 'o': + case 'O': + data.OEM = param_get32ex(Cmd, cmdp+1, 0, 10); + cmdp += 2; + break; + default: + PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + return false; + } + } + memset(packed, 0, sizeof(hidproxmessage_t)); + if (!HIDPack(formatIndex, &data, packed)) + { + PrintAndLog("The card data could not be encoded in the selected format."); + return false; + } else { + return true; + } + +} +void Write(hidproxmessage_t *packed){ + UsbCommand c; + c.d.asBytes[0] = (packed->top != 0 && ((packed->mid & 0xFFFFFFC0) != 0)) + ? 1 : 0; // Writing long format? + c.cmd = CMD_HID_CLONE_TAG; + c.arg[0] = (packed->top & 0x000FFFFF); + c.arg[1] = packed->mid; + c.arg[2] = packed->bot; + SendCommand(&c); +} + + //by marshmellow (based on existing demod + holiman's refactor) //HID Prox demod - FSK RF/50 with preamble of 00011101 (then manchester encoded) //print full HID Prox ID and some bit format details if found @@ -301,21 +172,10 @@ 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); - 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); + hidproxmessage_t packed = initialize_proxmessage_object(hi2, hi, lo); + PrintProxTagId(&packed); - if (card_info.fmtLen == 26 || card_info.fmtLen == 35 || card_info.fmtLen == 48) { - PrintAndLog("Parity: %s", card_info.parityValid ? "valid" : "invalid"); - } + bool ret = HIDTryUnpack(&packed, false); if (!ret) { PrintAndLog("Invalid or unsupported tag length."); } @@ -342,109 +202,79 @@ int CmdHIDSim(const char *Cmd) { uint32_t hi2 = 0, hi = 0, lo = 0; hexstring_to_int96(&hi2, &hi, &lo, Cmd); - if (hi >= 0x40 || hi2 != 0) { - PrintAndLog("This looks like a long tag ID. Use 'lf simfsk' for long tags. Aborting!"); - return 0; + if (hi2 != 0) { + PrintAndLog("Emulating tag with ID %x%08x%08x", hi2, hi, lo); + } else { + PrintAndLog("Emulating tag with ID %x%08x", hi, lo); } - PrintAndLog("Emulating tag with ID %x%08x", hi, lo); PrintAndLog("Press pm3-button to abort simulation"); - UsbCommand c = {CMD_HID_SIM_TAG, {hi, lo, 0}}; + UsbCommand c = {CMD_HID_SIM_TAG, {hi2, hi, lo}}; SendCommand(&c); return 0; } int CmdHIDClone(const char *Cmd) { - unsigned int hi2 = 0, hi = 0, lo = 0; - UsbCommand c; - hexstring_to_int96(&hi2, &hi, &lo, Cmd); - - if (hi >= 0x40 || hi2 != 0) { - PrintAndLog("Cloning tag with long ID %x%08x%08x", hi2, hi, lo); - c.d.asBytes[0] = 1; - } else { - PrintAndLog("Cloning tag with ID %x%08x", hi, lo); - c.d.asBytes[0] = 0; - } - - c.cmd = CMD_HID_CLONE_TAG; - c.arg[0] = hi2; - c.arg[1] = hi; - c.arg[2] = lo; - - SendCommand(&c); + unsigned int top = 0, mid = 0, bot = 0; + hexstring_to_int96(&top, &mid, &bot, Cmd); + hidproxmessage_t packed = initialize_proxmessage_object(top, mid, bot); + Write(&packed); 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 "); - PrintAndLog(" sample: lf hid pack 26 123 4567"); + PrintAndLog("Usage: lf hid decode {p}"); + PrintAndLog(" (optional) p: Ignore invalid parity"); + 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; + bool ignoreParity = false; + hexstring_to_int96(&top, &mid, &bot, Cmd); + hidproxmessage_t packed = initialize_proxmessage_object(top, mid, bot); - 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); - } 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); - } - } else { - PrintAndLog("Invalid or unsupported tag length."); - } + char opt = param_getchar(Cmd, 1); + if (opt == 'p') ignoreParity = true; + + HIDTryUnpack(&packed, ignoreParity); return 0; } - - -int CmdHIDUnpack(const char *Cmd) -{ - uint32_t hi2 = 0, hi = 0, lo = 0; - if (strlen(Cmd)<1) { - PrintAndLog("Usage: lf hid unpack "); - PrintAndLog(" sample: lf hid unpack 2006f623ae"); +int CmdHIDEncode(const char *Cmd) { + if (strlen(Cmd) == 0) { + usage_encode(); return 0; } - hexstring_to_int96(&hi2, &hi, &lo, Cmd); - - hid_info card_info; - bool ret = unpack_hid(&card_info, hi2, hi, lo); + hidproxmessage_t packed; + memset(&packed, 0, sizeof(hidproxmessage_t)); + if (Encode(Cmd, &packed)) + PrintProxTagId(&packed); + return 0; +} - 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); +int CmdHIDWrite(const char *Cmd) { + if (strlen(Cmd) == 0) { + usage_encode(); + return 0; } - PrintAndLog("Parity: %s", card_info.parityValid ? "valid" : "invalid"); - - if (!ret) { - PrintAndLog("Invalid or unsupported tag length."); + hidproxmessage_t packed; + memset(&packed, 0, sizeof(hidproxmessage_t)); + if (Encode(Cmd, &packed)){ + PrintProxTagId(&packed); + Write(&packed); } return 0; } - +int CmdHIDFormats(){ + HIDListFormats(); + 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 +282,10 @@ static command_t CommandTable[] = {"read", CmdHIDReadFSK, 0, "['1'] Realtime HID FSK Read from antenna (option '1' for one tag only)"}, {"sim", CmdHIDSim, 0, " -- HID tag simulator"}, {"clone", CmdHIDClone, 0, " -- Clone HID to T55x7 (tag must be in antenna)"}, - {"pack", CmdHIDPack, 1, " -- packs an HID ID from its length, facility code and card number"}, - {"unpack", CmdHIDUnpack, 1, " -- unpacks an HID ID to its length, facility code and card number"}, + {"decode", CmdHIDDecode, 1, " -- Try to decode an HID tag and show its contents"}, + {"encode", CmdHIDEncode, 1, " -- Encode an HID ID with the specified format and fields"}, + {"formats", CmdHIDFormats, 1, "List supported card formats"}, + {"write", CmdHIDWrite, 0, " -- Encode and write to a T55x7 tag (tag must be in antenna)"}, {NULL, NULL, 0, NULL} }; diff --git a/client/cmdlfhid.h b/client/cmdlfhid.h index 463be56f..ef907f67 100644 --- a/client/cmdlfhid.h +++ b/client/cmdlfhid.h @@ -14,37 +14,12 @@ #include #include -// 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 index 00000000..8df5bdde --- /dev/null +++ b/client/hidcardformats.c @@ -0,0 +1,580 @@ +//----------------------------------------------------------------------------- +// 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 +#include +#include +#include +#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. + if (card->IssueLevel > 0) return false; // Not used in this format + if (card->OEM > 0) return false; // Not used in this format + packed->Length = 26; // Set number of bits + packed->bot |= (card->CardNumber & 0xFFFF) << 1; + packed->bot |= (card->FacilityCode & 0xFF) << 17; + 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->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. + if (card->IssueLevel > 0) return false; // Not used in this format + if (card->OEM > 0) return false; // Not used in this format + 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}); + 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. + if (card->IssueLevel > 0) return false; // Not used in this format + if (card->OEM > 0) return false; // Not used in this format + packed->Length = 28; + set_linear_field(packed, card->FacilityCode, 4, 8); + set_linear_field(packed, card->CardNumber, 12, 15); + 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->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. + if (card->IssueLevel > 0) return false; // Not used in this format + if (card->OEM > 0) return false; // Not used in this format + packed->Length = 30; + set_linear_field(packed, card->FacilityCode, 1, 12); + set_linear_field(packed, card->CardNumber, 13, 16); + 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->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. + if (card->IssueLevel > 0) return false; // Not used in this format + if (card->OEM > 0) return false; // Not used in this format + 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); + 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. + if (card->IssueLevel > 0) return false; // Not used in this format + if (card->OEM > 0) return false; // Not used in this format + packed->Length = 33; // Set number of bits + set_linear_field(packed, card->FacilityCode, 1, 7); + set_linear_field(packed, card->CardNumber, 8, 24); + 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->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. + if (card->IssueLevel > 0) return false; // Not used in this format + if (card->OEM > 0) return false; // Not used in this format + 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; + 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->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_N10002(/*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. + if (card->IssueLevel > 0) return false; // Not used in this format + if (card->OEM > 0) return false; // Not used in this format + 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_N10002(/*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); + 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. + if (card->IssueLevel > 0) return false; // Not used in this format + if (card->OEM > 0) return false; // Not used in this format + 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; + 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->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. + if (card->IssueLevel > 0) return false; // Not used in this format + if (card->OEM > 0) return false; // Not used in this format + packed->Length = 36; // Set number of bits + // This card is BCD-encoded rather than binary. Set the 4-bit groups independently. + for (uint32_t idx = 0; idx < 8; idx++){ + set_linear_field(packed, (uint64_t)(card->CardNumber / pow(10, 7-idx)) % 10, idx * 4, 4); + } + 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. + for (uint32_t idx = 0; idx < 8; idx++){ + uint64_t val = get_linear_field(packed, idx * 4, 4); + if (val > 9){ + // Violation of BCD; Zero and exit. + card->CardNumber = 0; + return false; + } else { + card->CardNumber += val * pow(10, 7-idx); + } + } + 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_S12906(/*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->IssueLevel > 0x03) return false; // Can't encode IL. + if (card->CardNumber > 0x00FFFFFF) return false; // Can't encode CN. + if (card->OEM > 0) return false; // Not used in this format + packed->Length = 36; // Set number of bits + set_linear_field(packed, card->FacilityCode, 1, 8); + set_linear_field(packed, card->IssueLevel, 9, 2); + set_linear_field(packed, card->CardNumber, 11, 24); + set_bit_by_position(packed, + oddparity32(get_linear_field(packed, 1, 17)) + , 0); + set_bit_by_position(packed, + oddparity32(get_linear_field(packed, 17, 18)) + , 35); + return add_HID_header(packed); +} +bool Unpack_S12906(/*in*/hidproxmessage_t* packed, /*out*/hidproxcard_t* card){ + memset(card, 0, sizeof(hidproxcard_t)); + if (packed->Length != 36) return false; // Wrong length? Stop here. + card->FacilityCode = get_linear_field(packed, 1, 8); + card->IssueLevel = get_linear_field(packed, 9, 2); + card->CardNumber = get_linear_field(packed, 11, 24); + card->ParityValid = + (get_bit_by_position(packed, 0) == oddparity32(get_linear_field(packed, 1, 17))) && + (get_bit_by_position(packed, 35) == oddparity32(get_linear_field(packed, 17, 18))); + return true; +} + +bool Pack_Sie36(/*in*/hidproxcard_t* card, /*out*/hidproxmessage_t* packed){ + memset(packed, 0, sizeof(hidproxmessage_t)); + if (card->FacilityCode > 0x0003FFFF) return false; // Can't encode FC. + if (card->CardNumber > 0x0000FFFF) return false; // Can't encode CN. + if (card->IssueLevel > 0) return false; // Not used in this format + if (card->OEM > 0) return false; // Not used in this format + packed->Length = 36; // Set number of bits + set_linear_field(packed, card->FacilityCode, 1, 18); + set_linear_field(packed, card->CardNumber, 19, 16); + set_bit_by_position(packed, + oddparity32(get_nonlinear_field(packed, 23, (uint8_t[]){1, 3, 4, 6, 7, 9, 10, 12, 13, 15, 16, 18, 19, 21, 22, 24, 25, 27, 28, 30, 31, 33, 34})) + , 0); + set_bit_by_position(packed, + evenparity32(get_nonlinear_field(packed, 23, (uint8_t[]){1, 2, 4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19, 20, 22, 23, 25, 26, 28, 29, 31, 32, 34})) + , 35); + return add_HID_header(packed); +} +bool Unpack_Sie36(/*in*/hidproxmessage_t* packed, /*out*/hidproxcard_t* card){ + memset(card, 0, sizeof(hidproxcard_t)); + if (packed->Length != 36) return false; // Wrong length? Stop here. + card->FacilityCode = get_linear_field(packed, 1, 18); + card->CardNumber = get_linear_field(packed, 19, 16); + card->ParityValid = + (get_bit_by_position(packed, 0) == oddparity32(get_nonlinear_field(packed, 23, (uint8_t[]){1, 3, 4, 6, 7, 9, 10, 12, 13, 15, 16, 18, 19, 21, 22, 24, 25, 27, 28, 30, 31, 33, 34}))) && + (get_bit_by_position(packed, 35) == oddparity32(get_nonlinear_field(packed, 23, (uint8_t[]){1, 2, 4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19, 20, 22, 23, 25, 26, 28, 29, 31, 32, 34}))); + return true; +} + +bool Pack_C15001(/*in*/hidproxcard_t* card, /*out*/hidproxmessage_t* packed){ + memset(packed, 0, sizeof(hidproxmessage_t)); + if (card->FacilityCode > 0x000000FF) return false; // Can't encode FC. + if (card->CardNumber > 0x0000FFFF) return false; // Can't encode CN. + if (card->IssueLevel > 0) return false; // Not used in this format + if (card->OEM > 0x000003FF) return false; // Can't encode OEM. + packed->Length = 36; // Set number of bits + set_linear_field(packed, card->OEM, 1, 10); + set_linear_field(packed, card->FacilityCode, 11, 8); + set_linear_field(packed, card->CardNumber, 19, 16); + set_bit_by_position(packed, + evenparity32(get_linear_field(packed, 1, 17)) + , 0); + set_bit_by_position(packed, + oddparity32(get_linear_field(packed, 18, 17)) + , 35); + return add_HID_header(packed); +} +bool Unpack_C15001(/*in*/hidproxmessage_t* packed, /*out*/hidproxcard_t* card){ + memset(card, 0, sizeof(hidproxcard_t)); + if (packed->Length != 36) return false; // Wrong length? Stop here. + card->OEM = get_linear_field(packed, 1, 10); + card->FacilityCode = get_linear_field(packed, 11, 8); + card->CardNumber = get_linear_field(packed, 19, 16); + card->ParityValid = + (get_bit_by_position(packed, 0) == evenparity32(get_linear_field(packed, 1, 17))) && + (get_bit_by_position(packed, 35) == oddparity32(get_linear_field(packed, 18, 17))); + 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. + if (card->IssueLevel > 0) return false; // Not used in this format + if (card->OEM > 0) return false; // Not used in this format + packed->Length = 37; // Set number of bits + set_linear_field(packed, card->CardNumber, 1, 35); + 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->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. + if (card->IssueLevel > 0) return false; // Not used in this format + if (card->OEM > 0) return false; // Not used in this format + 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; + 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->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. + if (card->IssueLevel > 0) return false; // Not used in this format + if (card->OEM > 0) return false; // Not used in this format + 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); + 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->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. + if (card->IssueLevel > 0) return false; // Not used in this format + if (card->OEM > 0) return false; // Not used in this format + 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; + 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->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", {1, 1, 0, 0, 1}}, // imported from old pack/unpack + {"Tecom27", Pack_Tecom27, Unpack_Tecom27, "Tecom 27-bit", {1, 1, 0, 0, 1}}, // from cardinfo.barkweb.com.au + {"2804W", Pack_2804W, Unpack_2804W, "2804 Wiegand", {1, 1, 0, 0, 1}}, // from cardinfo.barkweb.com.au + {"ATSW30", Pack_ATSW30, Unpack_ATSW30, "ATS Wiegand 30-bit", {1, 1, 0, 0, 1}}, // from cardinfo.barkweb.com.au + {"ADT31", Pack_ADT31, Unpack_ADT31, "HID ADT 31-bit", {1, 1, 0, 0, 1}}, // from cardinfo.barkweb.com.au + {"D10202", Pack_D10202, Unpack_D10202, "HID D10202 33-bit", {1, 1, 0, 0, 1}}, // from cardinfo.barkweb.com.au + {"H10306", Pack_H10306, Unpack_H10306, "HID H10306 34-bit", {1, 1, 0, 0, 1}}, // imported from old pack/unpack + {"N10002", Pack_N10002, Unpack_N10002, "HID N10002 34-bit", {1, 1, 0, 0, 1}}, // from cardinfo.barkweb.com.au + {"C1k35s", Pack_C1k35s, Unpack_C1k35s, "HID Corporate 1000 35-bit standard layout", {1, 1, 0, 0, 1}}, // imported from old pack/unpack + {"C15001", Pack_C15001, Unpack_C15001, "HID KeySpan 36-bit", {1, 1, 0, 1, 1}}, // from Proxmark forums + {"S12906", Pack_S12906, Unpack_S12906, "HID Simplex 36-bit", {1, 1, 1, 0, 1}}, // from cardinfo.barkweb.com.au + {"Sie36", Pack_Sie36, Unpack_Sie36, "HID 36-bit Siemens", {1, 1, 0, 0, 1}}, // from cardinfo.barkweb.com.au + {"H10320", Pack_H10320, Unpack_H10320, "HID H10320 36-bit BCD", {1, 0, 0, 0, 1}}, // from Proxmark forums + {"H10302", Pack_H10302, Unpack_H10302, "HID H10302 37-bit huge ID", {1, 0, 0, 0, 1}}, // from Proxmark forums + {"H10304", Pack_H10304, Unpack_H10304, "HID H10304 37-bit", {1, 1, 0, 0, 1}}, // 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", {1, 1, 0, 0, 1}}, // imported from old pack/unpack + {NULL, NULL, NULL, NULL, {0, 0, 0, 0, 0}} // 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 %-30s", 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); +} + +void HIDDisplayUnpackedCard(hidproxcard_t* card, const hidcardformat_t format){ + PrintAndLog(" Format: %s (%s)", format.Name, format.Descrp); + if (format.Fields.hasFacilityCode) + PrintAndLog("Facility Code: %d",card->FacilityCode); + if (format.Fields.hasCardNumber) + PrintAndLog(" Card Number: %d",card->CardNumber); + if (format.Fields.hasIssueLevel) + PrintAndLog(" Issue Level: %d",card->IssueLevel); + if (format.Fields.hasOEMCode) + PrintAndLog(" OEM Code: %d",card->OEM); + if (format.Fields.hasParity) + PrintAndLog(" Parity: %s",card->ParityValid ? "Valid" : "Invalid"); +} + +bool HIDTryUnpack(/* in */hidproxmessage_t* packed, /* in */bool ignoreParity){ + 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)){ + if (ignoreParity || !FormatTable[i].Fields.hasParity || card.ParityValid){ + if (!result) PrintAndLog("--------------------------------------------------"); + result = true; + HIDDisplayUnpackedCard(&card, FormatTable[i]); + PrintAndLog("--------------------------------------------------"); + } + } + ++i; + } + return result; +} diff --git a/client/hidcardformats.h b/client/hidcardformats.h new file mode 100644 index 00000000..3019b823 --- /dev/null +++ b/client/hidcardformats.h @@ -0,0 +1,42 @@ +//----------------------------------------------------------------------------- +// 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 +#include +#include "hidcardformatutils.h" + + +typedef struct hidcardformatdescriptor_s{ + bool hasCardNumber; + bool hasFacilityCode; + bool hasIssueLevel; + bool hasOEMCode; + bool hasParity; +} hidcardformatdescriptor_t; + +// 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; + hidcardformatdescriptor_t Fields; +} 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, /* in */bool ignoreParity); + +#endif diff --git a/client/hidcardformatutils.c b/client/hidcardformatutils.c new file mode 100644 index 00000000..3abee223 --- /dev/null +++ b/client/hidcardformatutils.c @@ -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 +#include +#include +#include +#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 hidproxmessage 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 index 00000000..0ab2ae72 --- /dev/null +++ b/client/hidcardformatutils.h @@ -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 +#include +#include + +// 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; + uint32_t IssueLevel; + uint32_t OEM; + 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