| 1 | //----------------------------------------------------------------------------- |
| 2 | // |
| 3 | // This code is licensed to you under the terms of the GNU GPL, version 2 or, |
| 4 | // at your option, any later version. See the LICENSE.txt file for the text of |
| 5 | // the license. |
| 6 | //----------------------------------------------------------------------------- |
| 7 | // Low frequency Securakey tag commands |
| 8 | // ASK/Manchester, RF/40, 96 bits long (unknown cs) |
| 9 | //----------------------------------------------------------------------------- |
| 10 | |
| 11 | #include "cmdlfsecurakey.h" |
| 12 | |
| 13 | #include <string.h> |
| 14 | #include <inttypes.h> |
| 15 | #include <math.h> |
| 16 | #include "comms.h" |
| 17 | #include "ui.h" |
| 18 | #include "util.h" |
| 19 | #include "graph.h" |
| 20 | #include "cmdparser.h" |
| 21 | #include "cmddata.h" |
| 22 | #include "cmdmain.h" |
| 23 | #include "cmdlf.h" |
| 24 | #include "protocols.h" // for T55xx config register definitions |
| 25 | #include "lfdemod.h" // preamble test |
| 26 | #include "parity.h" // for wiegand parity test |
| 27 | |
| 28 | static int CmdHelp(const char *Cmd); |
| 29 | |
| 30 | // by marshmellow |
| 31 | // find Securakey preamble in already demoded data |
| 32 | int SecurakeyFind(uint8_t *dest, size_t *size) { |
| 33 | if (*size < 96) return -1; //make sure buffer has data |
| 34 | size_t startIdx = 0; |
| 35 | uint8_t preamble[] = {0,1,1,1,1,1,1,1,1,1,0,0,1}; |
| 36 | if (!preambleSearch(dest, preamble, sizeof(preamble), size, &startIdx)) |
| 37 | return -2; //preamble not found |
| 38 | if (*size != 96) return -3; //wrong demoded size |
| 39 | //return start position |
| 40 | return (int)startIdx; |
| 41 | } |
| 42 | |
| 43 | //see ASKDemod for what args are accepted |
| 44 | int CmdSecurakeyDemod(const char *Cmd) { |
| 45 | |
| 46 | //ASK / Manchester |
| 47 | bool st = false; |
| 48 | if (!ASKDemod_ext("40 0 0", false, false, 1, &st)) { |
| 49 | if (g_debugMode) PrintAndLog("DEBUG: Error - Securakey: ASK/Manchester Demod failed"); |
| 50 | return 0; |
| 51 | } |
| 52 | if (st) return 0; |
| 53 | size_t size = DemodBufferLen; |
| 54 | int ans = SecurakeyFind(DemodBuffer, &size); |
| 55 | if (ans < 0) { |
| 56 | if (g_debugMode) { |
| 57 | if (ans == -1) |
| 58 | PrintAndLog("DEBUG: Error - Securakey: too few bits found"); |
| 59 | else if (ans == -2) |
| 60 | PrintAndLog("DEBUG: Error - Securakey: preamble not found"); |
| 61 | else if (ans == -3) |
| 62 | PrintAndLog("DEBUG: Error - Securakey: Size not correct: %d", size); |
| 63 | else |
| 64 | PrintAndLog("DEBUG: Error - Securakey: ans: %d", ans); |
| 65 | } |
| 66 | return 0; |
| 67 | } |
| 68 | setDemodBuf(DemodBuffer, 96, ans); |
| 69 | setClockGrid(g_DemodClock, g_DemodStartIdx + (ans*g_DemodClock)); |
| 70 | |
| 71 | //got a good demod |
| 72 | uint32_t raw1 = bytebits_to_byte(DemodBuffer , 32); |
| 73 | uint32_t raw2 = bytebits_to_byte(DemodBuffer+32, 32); |
| 74 | uint32_t raw3 = bytebits_to_byte(DemodBuffer+64, 32); |
| 75 | |
| 76 | // 26 bit format |
| 77 | // preamble ??bitlen reserved EPx xxxxxxxy yyyyyyyy yyyyyyyOP CS? CS2? |
| 78 | // 0111111111 0 01011010 0 00000000 0 00000010 0 00110110 0 00111110 0 01100010 0 00001111 0 01100000 0 00000000 0 0000 |
| 79 | |
| 80 | // 32 bit format |
| 81 | // preamble ??bitlen reserved EPxxxxxxx xxxxxxxy yyyyyyyy yyyyyyyOP CS? CS2? |
| 82 | // 0111111111 0 01100000 0 00000000 0 10000100 0 11001010 0 01011011 0 01010110 0 00010110 0 11100000 0 00000000 0 0000 |
| 83 | |
| 84 | // x = FC? |
| 85 | // y = card # |
| 86 | // standard wiegand parities. |
| 87 | // unknown checksum 11 bits? at the end |
| 88 | uint8_t bits_no_spacer[85]; |
| 89 | memcpy(bits_no_spacer, DemodBuffer + 11, 85); |
| 90 | |
| 91 | // remove marker bits (0's every 9th digit after preamble) (pType = 3 (always 0s)) |
| 92 | size = removeParity(bits_no_spacer, 0, 9, 3, 85); |
| 93 | if ( size != 85-9 ) { |
| 94 | if (g_debugMode) PrintAndLog("DEBUG: Error removeParity: %d", size); |
| 95 | return 0; |
| 96 | } |
| 97 | |
| 98 | uint8_t bitLen = (uint8_t)bytebits_to_byte(bits_no_spacer+2, 6); |
| 99 | uint32_t fc=0, lWiegand=0, rWiegand=0; |
| 100 | if (bitLen > 40) { //securakey's max bitlen is 40 bits... |
| 101 | if (g_debugMode) PrintAndLog("DEBUG: Error bitLen too long: %u", bitLen); |
| 102 | return 0; |
| 103 | } |
| 104 | // get left 1/2 wiegand & right 1/2 wiegand (for parity test and wiegand print) |
| 105 | lWiegand = bytebits_to_byte(bits_no_spacer + 48 - bitLen, bitLen/2); |
| 106 | rWiegand = bytebits_to_byte(bits_no_spacer + 48 - bitLen + bitLen/2, bitLen/2); |
| 107 | // get FC |
| 108 | fc = bytebits_to_byte(bits_no_spacer+49-bitLen, bitLen-2-16); |
| 109 | |
| 110 | // test bitLen |
| 111 | if (bitLen != 26 && bitLen != 32) |
| 112 | PrintAndLog("***unknown securakey bitLen - share with forum***"); |
| 113 | |
| 114 | uint32_t cardid = bytebits_to_byte(bits_no_spacer+8+23, 16); |
| 115 | // test parities - evenparity32 looks to add an even parity returns 0 if already even... |
| 116 | bool parity = !evenparity32(lWiegand) && !oddparity32(rWiegand); |
| 117 | |
| 118 | PrintAndLog("Securakey Tag Found--BitLen: %u, Card ID: %u, FC: 0x%X, Raw: %08X%08X%08X", bitLen, cardid, fc, raw1 ,raw2, raw3); |
| 119 | if (bitLen <= 32) |
| 120 | PrintAndLog("Wiegand: %08X, Parity: %s", (lWiegand<<(bitLen/2)) | rWiegand, parity ? "Passed" : "Failed"); |
| 121 | PrintAndLog("\nHow the FC translates to printed FC is unknown"); |
| 122 | PrintAndLog("How the checksum is calculated is unknown"); |
| 123 | PrintAndLog("Help the community identify this format further\n by sharing your tag on the pm3 forum or with forum members"); |
| 124 | return 1; |
| 125 | } |
| 126 | |
| 127 | int CmdSecurakeyRead(const char *Cmd) { |
| 128 | lf_read(true, 8000); |
| 129 | return CmdSecurakeyDemod(Cmd); |
| 130 | } |
| 131 | |
| 132 | static command_t CommandTable[] = { |
| 133 | {"help", CmdHelp, 1, "This help"}, |
| 134 | {"demod", CmdSecurakeyDemod,1, "Attempt to read and extract tag data from the GraphBuffer"}, |
| 135 | {"read", CmdSecurakeyRead, 0, "Attempt to read and extract tag data from the antenna"}, |
| 136 | {NULL, NULL, 0, NULL} |
| 137 | }; |
| 138 | |
| 139 | int CmdLFSecurakey(const char *Cmd) { |
| 140 | clearCommandBuffer(); |
| 141 | CmdsParse(CommandTable, Cmd); |
| 142 | return 0; |
| 143 | } |
| 144 | |
| 145 | int CmdHelp(const char *Cmd) { |
| 146 | CmdsHelp(CommandTable); |
| 147 | return 0; |
| 148 | } |