diff --git a/client/Makefile b/client/Makefile index 5f5df148..f1082b2c 100644 --- a/client/Makefile +++ b/client/Makefile @@ -139,9 +139,12 @@ CMDSRCS = mifarehost.c \ cmdlft55xx.c \ cmdlfpcf7931.c \ cmdlfviking.c \ + cmdlfpac.c \ cmdlfpresco.c \ cmdlfpyramid.c \ + cmdlfsecurakey.c \ cmdlfguard.c \ + cmdlfnexwatch.c \ cmdlfnedap.c \ cmdlfjablotron.c \ cmdlfvisa2000.c \ diff --git a/client/cmddata.c b/client/cmddata.c index 00932a36..1c690547 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -1865,51 +1865,6 @@ int CmdIndalaDecode(const char *Cmd) return 1; } -int CmdPSKNexWatch(const char *Cmd) -{ - if (!PSKDemod("", false)) return 0; - - uint8_t preamble[28] = {0,0,0,0,0,1,0,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; - size_t startIdx = 0, size = DemodBufferLen; - - // sanity check. - if ( size < sizeof(preamble) + 100) return 0; - - bool invert = false; - if (!preambleSearch(DemodBuffer, preamble, sizeof(preamble), &size, &startIdx)){ - // if didn't find preamble try again inverting - if (!PSKDemod("1", false)) return 0; - - size = DemodBufferLen; - if (!preambleSearch(DemodBuffer, preamble, sizeof(preamble), &size, &startIdx)) return 0; - invert = true; - } - if (size != 128) return 0; - setDemodBuf(DemodBuffer, size, startIdx+4); - startIdx = 8+32; //4 = extra i added, 8 = preamble, 32 = reserved bits (always 0) - //get ID - uint32_t ID = 0; - for (uint8_t wordIdx=0; wordIdx<4; wordIdx++){ - for (uint8_t idx=0; idx<8; idx++){ - ID = (ID << 1) | DemodBuffer[startIdx+wordIdx+(idx*4)]; - } - } - //parity check (TBD) - - //checksum check (TBD) - - //output - PrintAndLog("NexWatch ID: %d", ID); - if (invert){ - PrintAndLog("DEBUG: Error - NexWatch had to Invert - probably NexKey"); - for (uint8_t idx=0; idx [l] -- print the data in the DemodBuffer - 'x' for hex output"}, {"pskindalademod", CmdIndalaDecode, 1, "[clock] [invert<0|1>] -- Demodulate an indala tag (PSK1) from GraphBuffer (args optional)"}, - {"psknexwatchdemod",CmdPSKNexWatch, 1, "Demodulate a NexWatch tag (nexkey, quadrakey) (PSK1) from GraphBuffer"}, {"rawdemod", CmdRawDemod, 1, "[modulation] ... -see help (h option) -- Demodulate the data in the GraphBuffer and output binary"}, {"samples", CmdSamples, 0, "[512 - 40000] -- Get raw samples for graph window (GraphBuffer)"}, {"save", CmdSave, 1, " -- Save trace (from graph window)"}, diff --git a/client/cmddata.h b/client/cmddata.h index 4ea0b3b2..f042d50e 100644 --- a/client/cmddata.h +++ b/client/cmddata.h @@ -46,7 +46,6 @@ int CmdFSKdemodPyramid(const char *Cmd); int CmdFSKrawdemod(const char *Cmd); int CmdPSK1rawDemod(const char *Cmd); int CmdPSK2rawDemod(const char *Cmd); -int CmdPSKNexWatch(const char *Cmd); int CmdPSKIdteck(const char *Cmd); int CmdGrid(const char *Cmd); int CmdGetBitStream(const char *Cmd); diff --git a/client/cmdlf.c b/client/cmdlf.c index 6e3422a4..39ea5a72 100644 --- a/client/cmdlf.c +++ b/client/cmdlf.c @@ -1196,7 +1196,12 @@ int CmdLFfind(const char *Cmd) { if (ans>0) { PrintAndLog("\nValid Presco ID Found!"); return 1; - } + } + ans=CmdPacDemod(""); + if (ans>0) { + PrintAndLog("\nValid PAC/Stanley ID Found!"); + return 1; + } // TIdemod? PrintAndLog("\nNo Known Tags Found!\n"); @@ -1273,12 +1278,15 @@ static command_t CommandTable[] = { {"io", CmdLFIO, 1, "{ IOPROX RFIDs... }"}, {"jablotron", CmdLFJablotron, 1, "{ Jablotron RFIDs... }"}, {"nedap", CmdLFNedap, 1, "{ Nedap RFIDs... }"}, + {"nexwatch", CmdLFNexWatch, 1, "{ NexWatch RFIDs... }"}, {"noralsy", CmdLFNoralsy, 1, "{ Noralsy RFIDs... }"}, + {"pac", CmdLFPac, 1, "{ PAC/Stanley RFIDs...}"}, {"pcf7931", CmdLFPCF7931, 1, "{ PCF7931 RFIDs... }"}, {"presco", CmdLFPresco, 1, "{ Presco RFIDs... }"}, {"pyramid", CmdLFPyramid, 1, "{ Farpointe/Pyramid RFIDs... }"}, {"ti", CmdLFTI, 1, "{ TI RFIDs... }"}, {"t55xx", CmdLFT55XX, 1, "{ T55xx RFIDs... }"}, + {"securakey", CmdLFSecurakey, 1, "{ Securakey RFIDs... }"}, {"viking", CmdLFViking, 1, "{ Viking RFIDs... }"}, {"visa2000", CmdLFVisa2k, 1, "{ Visa2000 RFIDs... }"}, {"config", CmdLFSetConfig, 0, "Set config for LF sampling, bit/sample, decimation, frequency"}, diff --git a/client/cmdlf.h b/client/cmdlf.h index 0bd2f6db..55856c88 100644 --- a/client/cmdlf.h +++ b/client/cmdlf.h @@ -44,6 +44,9 @@ #include "cmdlfnoralsy.h" // for NORALSY meny #include "cmdlffdx.h" // for FDX-B meny #include "cmdlfcotag.h" // for COTAG meny +#include "cmdlfnexwatch.h" //for nexwatch menu +#include "cmdlfsecurakey.h" //for securakey menu +#include "cmdlfpac.h" // for pac menu #define T55XX_WRITE_TIMEOUT 1500 diff --git a/client/cmdlfnexwatch.c b/client/cmdlfnexwatch.c new file mode 100644 index 00000000..4647699e --- /dev/null +++ b/client/cmdlfnexwatch.c @@ -0,0 +1,100 @@ +//----------------------------------------------------------------------------- +// +// 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. +//----------------------------------------------------------------------------- +// Low frequency Honeywell NexWatch tag commands +// PSK1 RF/16, RF/2, 128 bits long (known) +//----------------------------------------------------------------------------- +#include +#include +#include +#include +#include "cmdlfnexwatch.h" +#include "proxmark3.h" +#include "ui.h" +#include "util.h" +#include "graph.h" +#include "cmdparser.h" +#include "cmddata.h" +#include "cmdlf.h" +#include "lfdemod.h" + +static int CmdHelp(const char *Cmd); + +int CmdPSKNexWatch(const char *Cmd) +{ + if (!PSKDemod("", false)) return 0; + + uint8_t preamble[28] = {0,0,0,0,0,1,0,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + size_t startIdx = 0, size = DemodBufferLen; + + // sanity check. + if ( size < sizeof(preamble) + 100) return 0; + + bool invert = false; + if (!preambleSearch(DemodBuffer, preamble, sizeof(preamble), &size, &startIdx)){ + // if didn't find preamble try again inverting + if (!PSKDemod("1", false)) return 0; + + size = DemodBufferLen; + if (!preambleSearch(DemodBuffer, preamble, sizeof(preamble), &size, &startIdx)) return 0; + invert = true; + } + if (size != 128) return 0; + setDemodBuf(DemodBuffer, size, startIdx+4); + //setClockGrid(g_DemodClock, g_DemodStartIdx + ((startIdx+4)*g_DemodClock)); + startIdx = 8+32; // 8 = preamble, 32 = reserved bits (always 0) + //get ID + uint32_t ID = 0; + for (uint8_t wordIdx=0; wordIdx<4; wordIdx++){ + for (uint8_t idx=0; idx<8; idx++){ + ID = (ID << 1) | DemodBuffer[startIdx+wordIdx+(idx*4)]; + } + } + //parity check (TBD) + + //checksum check (TBD) + + //output + PrintAndLog("NexWatch ID: %d", ID); + if (invert){ + PrintAndLog("Had to Invert - probably NexKey"); + for (uint8_t idx=0; idx +#include +#include "proxmark3.h" +#include "ui.h" +#include "util.h" +#include "graph.h" +#include "cmdparser.h" +#include "cmddata.h" +#include "cmdmain.h" +#include "cmdlf.h" +#include "lfdemod.h" // preamble test + +static int CmdHelp(const char *Cmd); + +// by marshmellow +// find PAC preamble in already demoded data +int PacFind(uint8_t *dest, size_t *size) { + if (*size < 128) return -1; //make sure buffer has data + size_t startIdx = 0; + uint8_t preamble[] = {1,1,1,1,1,1,1,1,0,0,1,0,0,0,0,0,0,1,0}; + if (!preambleSearch(dest, preamble, sizeof(preamble), size, &startIdx)) + return -2; //preamble not found + if (*size != 128) return -3; //wrong demoded size + //return start position + return (int)startIdx; +} + +//see NRZDemod for what args are accepted +int CmdPacDemod(const char *Cmd) { + + //NRZ + if (!NRZrawDemod(Cmd, false)) { + if (g_debugMode) PrintAndLog("DEBUG: Error - PAC: NRZ Demod failed"); + return 0; + } + size_t size = DemodBufferLen; + int ans = PacFind(DemodBuffer, &size); + if (ans < 0) { + if (g_debugMode) { + if (ans == -1) + PrintAndLog("DEBUG: Error - PAC: too few bits found"); + else if (ans == -2) + PrintAndLog("DEBUG: Error - PAC: preamble not found"); + else if (ans == -3) + PrintAndLog("DEBUG: Error - PAC: Size not correct: %d", size); + else + PrintAndLog("DEBUG: Error - PAC: ans: %d", ans); + } + return 0; + } + setDemodBuf(DemodBuffer, 128, ans); +// setClockGrid(g_DemodClock, g_DemodStartIdx + (ans*g_DemodClock)); + + //got a good demod + uint32_t raw1 = bytebits_to_byte(DemodBuffer , 32); + uint32_t raw2 = bytebits_to_byte(DemodBuffer+32, 32); + uint32_t raw3 = bytebits_to_byte(DemodBuffer+64, 32); + uint32_t raw4 = bytebits_to_byte(DemodBuffer+96, 32); + + // preamble then appears to have marker bits of "10" CS? + // 11111111001000000 10 01001100 10 00001101 10 00001101 10 00001101 10 00001101 10 00001101 10 00001101 10 00001101 10 00001101 10 10001100 10 100000001 + // unknown checksum 9 bits at the end + + PrintAndLog("PAC/Stanley Tag Found -- Raw: %08X%08X%08X%08X", raw1 ,raw2, raw3, raw4); + PrintAndLog("\nHow the Raw ID is translated by the reader is unknown"); + return 1; +} + +int CmdPacRead(const char *Cmd) { + //lf_read(true, 4096*2 + 20); + CmdLFRead("s"); + getSamples("8192",TRUE); + return CmdPacDemod(Cmd); +} + +static command_t CommandTable[] = { + {"help", CmdHelp, 1, "This help"}, + {"demod", CmdPacDemod,1, "Attempt to read and extract tag data from the GraphBuffer"}, + {"read", CmdPacRead, 0, "Attempt to read and extract tag data from the antenna"}, + {NULL, NULL, 0, NULL} +}; + +int CmdLFPac(const char *Cmd) { + clearCommandBuffer(); + CmdsParse(CommandTable, Cmd); + return 0; +} + +int CmdHelp(const char *Cmd) { + CmdsHelp(CommandTable); + return 0; +} diff --git a/client/cmdlfpac.h b/client/cmdlfpac.h new file mode 100644 index 00000000..99b35a53 --- /dev/null +++ b/client/cmdlfpac.h @@ -0,0 +1,17 @@ +//----------------------------------------------------------------------------- +// +// 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. +//----------------------------------------------------------------------------- +// Low frequency Securakey tag commands +//----------------------------------------------------------------------------- +#ifndef CMDLFPAC_H__ +#define CMDLFPAC_H__ + +extern int CmdLFPac(const char *Cmd); +extern int CmdPacRead(const char *Cmd); +extern int CmdPacDemod(const char *Cmd); + +#endif + diff --git a/client/cmdlfsecurakey.c b/client/cmdlfsecurakey.c new file mode 100644 index 00000000..59e339a9 --- /dev/null +++ b/client/cmdlfsecurakey.c @@ -0,0 +1,148 @@ +//----------------------------------------------------------------------------- +// +// 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. +//----------------------------------------------------------------------------- +// Low frequency Securakey tag commands +// ASK/Manchester, RF/40, 96 bits long (unknown cs) +//----------------------------------------------------------------------------- +#include "cmdlfsecurakey.h" +#include +#include +#include +#include "proxmark3.h" +#include "ui.h" +#include "util.h" +#include "graph.h" +#include "cmdparser.h" +#include "cmddata.h" +#include "cmdmain.h" +#include "cmdlf.h" +#include "protocols.h" // for T55xx config register definitions +#include "lfdemod.h" // preamble test +#include "parity.h" // for wiegand parity test + +static int CmdHelp(const char *Cmd); + +// by marshmellow +// find Securakey preamble in already demoded data +int SecurakeyFind(uint8_t *dest, size_t *size) { + if (*size < 96) return -1; //make sure buffer has data + size_t startIdx = 0; + uint8_t preamble[] = {0,1,1,1,1,1,1,1,1,1,0,0,1}; + if (!preambleSearch(dest, preamble, sizeof(preamble), size, &startIdx)) + return -2; //preamble not found + if (*size != 96) return -3; //wrong demoded size + //return start position + return (int)startIdx; +} + +//see ASKDemod for what args are accepted +int CmdSecurakeyDemod(const char *Cmd) { + + //ASK / Manchester + bool st = false; + if (!ASKDemod_ext("40 0 0", false, false, 1, &st)) { + if (g_debugMode) PrintAndLog("DEBUG: Error - Securakey: ASK/Manchester Demod failed"); + return 0; + } + if (st) return 0; + size_t size = DemodBufferLen; + int ans = SecurakeyFind(DemodBuffer, &size); + if (ans < 0) { + if (g_debugMode) { + if (ans == -1) + PrintAndLog("DEBUG: Error - Securakey: too few bits found"); + else if (ans == -2) + PrintAndLog("DEBUG: Error - Securakey: preamble not found"); + else if (ans == -3) + PrintAndLog("DEBUG: Error - Securakey: Size not correct: %d", size); + else + PrintAndLog("DEBUG: Error - Securakey: ans: %d", ans); + } + return 0; + } + setDemodBuf(DemodBuffer, 96, ans); + //setClockGrid(g_DemodClock, g_DemodStartIdx + (ans*g_DemodClock)); + + //got a good demod + uint32_t raw1 = bytebits_to_byte(DemodBuffer , 32); + uint32_t raw2 = bytebits_to_byte(DemodBuffer+32, 32); + uint32_t raw3 = bytebits_to_byte(DemodBuffer+64, 32); + + // 26 bit format + // preamble ??bitlen reserved EPx xxxxxxxy yyyyyyyy yyyyyyyOP CS? CS2? + // 0111111111 0 01011010 0 00000000 0 00000010 0 00110110 0 00111110 0 01100010 0 00001111 0 01100000 0 00000000 0 0000 + + // 32 bit format + // preamble ??bitlen reserved EPxxxxxxx xxxxxxxy yyyyyyyy yyyyyyyOP CS? CS2? + // 0111111111 0 01100000 0 00000000 0 10000100 0 11001010 0 01011011 0 01010110 0 00010110 0 11100000 0 00000000 0 0000 + + // x = FC? + // y = card # + // standard wiegand parities. + // unknown checksum 11 bits? at the end + uint8_t bits_no_spacer[85]; + memcpy(bits_no_spacer, DemodBuffer + 11, 85); + + // remove marker bits (0's every 9th digit after preamble) (pType = 3 (always 0s)) + size = removeParity(bits_no_spacer, 0, 9, 3, 85); + if ( size != 85-9 ) { + if (g_debugMode) PrintAndLog("DEBUG: Error removeParity: %d", size); + return 0; + } + + uint8_t bitLen = (uint8_t)bytebits_to_byte(bits_no_spacer+2, 6); + uint32_t fc=0, lWiegand=0, rWiegand=0; + if (bitLen > 40) { //securakey's max bitlen is 40 bits... + if (g_debugMode) PrintAndLog("DEBUG: Error bitLen too long: %u", bitLen); + return 0; + } + // get left 1/2 wiegand & right 1/2 wiegand (for parity test and wiegand print) + lWiegand = bytebits_to_byte(bits_no_spacer + 48 - bitLen, bitLen/2); + rWiegand = bytebits_to_byte(bits_no_spacer + 48 - bitLen + bitLen/2, bitLen/2); + // get FC + fc = bytebits_to_byte(bits_no_spacer+49-bitLen, bitLen-2-16); + + // test bitLen + if (bitLen != 26 && bitLen != 32) + PrintAndLog("***unknown securakey bitLen - share with forum***"); + + uint32_t cardid = bytebits_to_byte(bits_no_spacer+8+23, 16); + // test parities - evenparity32 looks to add an even parity returns 0 if already even... + bool parity = !evenparity32(lWiegand) && !oddparity32(rWiegand); + + PrintAndLog("Securakey Tag Found--BitLen: %u, Card ID: %u, FC: 0x%X, Raw: %08X%08X%08X", bitLen, cardid, fc, raw1 ,raw2, raw3); + if (bitLen <= 32) + PrintAndLog("Wiegand: %08X, Parity: %s", (lWiegand<<(bitLen/2)) | rWiegand, parity ? "Passed" : "Failed"); + PrintAndLog("\nHow the FC translates to printed FC is unknown"); + PrintAndLog("How the checksum is calculated is unknown"); + PrintAndLog("Help the community identify this format further\n by sharing your tag on the pm3 forum or with forum members"); + return 1; +} + +int CmdSecurakeyRead(const char *Cmd) { + //lf_read(true, 8000); + CmdLFRead("s"); + getSamples("8000",TRUE); + return CmdSecurakeyDemod(Cmd); +} + +static command_t CommandTable[] = { + {"help", CmdHelp, 1, "This help"}, + {"demod", CmdSecurakeyDemod,1, "Attempt to read and extract tag data from the GraphBuffer"}, + {"read", CmdSecurakeyRead, 0, "Attempt to read and extract tag data from the antenna"}, + {NULL, NULL, 0, NULL} +}; + +int CmdLFSecurakey(const char *Cmd) { + clearCommandBuffer(); + CmdsParse(CommandTable, Cmd); + return 0; +} + +int CmdHelp(const char *Cmd) { + CmdsHelp(CommandTable); + return 0; +} diff --git a/client/cmdlfsecurakey.h b/client/cmdlfsecurakey.h new file mode 100644 index 00000000..f3c0cf88 --- /dev/null +++ b/client/cmdlfsecurakey.h @@ -0,0 +1,19 @@ +//----------------------------------------------------------------------------- +// +// 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. +//----------------------------------------------------------------------------- +// Low frequency Securakey tag commands +//----------------------------------------------------------------------------- +#ifndef CMDLFSECURAKEY_H__ +#define CMDLFSECURAKEY_H__ + +extern int CmdLFSecurakey(const char *Cmd); +extern int CmdSecurakeyClone(const char *Cmd); +extern int CmdSecurakeySim(const char *Cmd); +extern int CmdSecurakeyRead(const char *Cmd); +extern int CmdSecurakeyDemod(const char *Cmd); + +#endif + diff --git a/common/parity.h b/common/parity.h index 8e2f097c..fe1c2504 100644 --- a/common/parity.h +++ b/common/parity.h @@ -3,9 +3,11 @@ // at your option, any later version. See the LICENSE.txt file for the text of // the license. //----------------------------------------------------------------------------- -// Generic CRC calculation code. +// Parity functions //----------------------------------------------------------------------------- +// all functions defined in header file by purpose. Allows compiler optimizations. + #ifndef __PARITY_H #define __PARITY_H @@ -14,25 +16,42 @@ extern "C" { #endif #include +#include extern const uint8_t OddByteParity[256]; -extern const uint8_t EvenByteParity[256]; -static inline uint8_t oddparity8(uint8_t bt) -{ - return OddByteParity[bt]; + +static inline bool oddparity8(const uint8_t x) { + return OddByteParity[x]; } -static inline uint8_t evenparity8(const uint8_t bt) -{ - return EvenByteParity[bt]; + +static inline bool evenparity8(const uint8_t x) { + return !OddByteParity[x]; } -static inline uint8_t evenparity32(uint32_t x) + +static inline bool evenparity32(uint32_t x) { +#if !defined __GNUC__ x ^= x >> 16; x ^= x >> 8; - return EvenByteParity[x & 0xff]; + return evenparity8(x); +#else + return __builtin_parity(x); +#endif +} + + +static inline bool oddparity32(uint32_t x) +{ +#if !defined __GNUC__ + x ^= x >> 16; + x ^= x >> 8; + return oddparity8(x); +#else + return !__builtin_parity(x); +#endif } #ifdef __cplusplus