| 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 Farpoint / Pyramid tag commands |
| 8 | //----------------------------------------------------------------------------- |
| 9 | #include <string.h> |
| 10 | #include <inttypes.h> |
| 11 | #include "cmdlfpyramid.h" |
| 12 | static int CmdHelp(const char *Cmd); |
| 13 | |
| 14 | int usage_lf_pyramid_clone(void){ |
| 15 | PrintAndLog("clone a Farpointe/Pyramid tag to a T55x7 tag."); |
| 16 | PrintAndLog("The facility-code is 8-bit and the card number is 16-bit. Larger values are truncated. "); |
| 17 | PrintAndLog("Currently work only on 26bit"); |
| 18 | PrintAndLog(""); |
| 19 | PrintAndLog("Usage: lf pyramid clone <Facility-Code> <Card-Number>"); |
| 20 | PrintAndLog("Options :"); |
| 21 | PrintAndLog(" <Facility-Code> : 8-bit value facility code"); |
| 22 | PrintAndLog(" <Card Number> : 16-bit value card number"); |
| 23 | PrintAndLog(" Q5 : optional - clone to Q5 (T5555) instead of T55x7 chip"); |
| 24 | PrintAndLog(""); |
| 25 | PrintAndLog("Sample : lf pyramid clone 123 11223"); |
| 26 | return 0; |
| 27 | } |
| 28 | |
| 29 | int usage_lf_pyramid_sim(void) { |
| 30 | PrintAndLog("Enables simulation of Farpointe/Pyramid card with specified card number."); |
| 31 | PrintAndLog("Simulation runs until the button is pressed or another USB command is issued."); |
| 32 | PrintAndLog("The facility-code is 8-bit and the card number is 16-bit. Larger values are truncated."); |
| 33 | PrintAndLog("Currently work only on 26bit"); |
| 34 | PrintAndLog(""); |
| 35 | PrintAndLog("Usage: lf pyramid sim <Card-Number>"); |
| 36 | PrintAndLog("Options :"); |
| 37 | PrintAndLog(" <Facility-Code> : 8-bit value facility code"); |
| 38 | PrintAndLog(" <Card Number> : 16-bit value card number"); |
| 39 | PrintAndLog(""); |
| 40 | PrintAndLog("Sample : lf pyramid sim 123 11223"); |
| 41 | return 0; |
| 42 | } |
| 43 | |
| 44 | // Works for 26bits. |
| 45 | int GetPyramidBits(uint32_t fc, uint32_t cn, uint8_t *pyramidBits) { |
| 46 | |
| 47 | uint8_t pre[128]; |
| 48 | memset(pre, 0x00, sizeof(pre)); |
| 49 | |
| 50 | // format start bit |
| 51 | pre[79] = 1; |
| 52 | |
| 53 | // Get 26 wiegand from FacilityCode, CardNumber |
| 54 | uint8_t wiegand[24]; |
| 55 | memset(wiegand, 0x00, sizeof(wiegand)); |
| 56 | num_to_bytebits(fc, 8, wiegand); |
| 57 | num_to_bytebits(cn, 16, wiegand+8); |
| 58 | |
| 59 | // add wiegand parity bits (dest, source, len) |
| 60 | wiegand_add_parity(pre+80, wiegand, 24); |
| 61 | |
| 62 | // add paritybits (bitsource, dest, sourcelen, paritylen, parityType (odd, even,) |
| 63 | addParity(pre+8, pyramidBits+8, 102, 8, 1); |
| 64 | |
| 65 | // add checksum |
| 66 | uint8_t csBuff[13]; |
| 67 | for (uint8_t i = 0; i < 13; i++) |
| 68 | csBuff[i] = bytebits_to_byte(pyramidBits + 16 + (i*8), 8); |
| 69 | |
| 70 | uint32_t crc = CRC8Maxim(csBuff, 13); |
| 71 | num_to_bytebits(crc, 8, pyramidBits+120); |
| 72 | return 1; |
| 73 | } |
| 74 | |
| 75 | int CmdPyramidRead(const char *Cmd) { |
| 76 | CmdLFRead("s"); |
| 77 | getSamples("30000",false); |
| 78 | return CmdFSKdemodPyramid(""); |
| 79 | } |
| 80 | |
| 81 | int CmdPyramidClone(const char *Cmd) { |
| 82 | |
| 83 | char cmdp = param_getchar(Cmd, 0); |
| 84 | if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') return usage_lf_pyramid_clone(); |
| 85 | |
| 86 | uint32_t facilitycode=0, cardnumber=0, fc = 0, cn = 0; |
| 87 | uint32_t blocks[5]; |
| 88 | uint8_t i; |
| 89 | uint8_t bs[128]; |
| 90 | memset(bs, 0x00, sizeof(bs)); |
| 91 | |
| 92 | if (sscanf(Cmd, "%u %u", &fc, &cn ) != 2) return usage_lf_pyramid_clone(); |
| 93 | |
| 94 | facilitycode = (fc & 0x000000FF); |
| 95 | cardnumber = (cn & 0x0000FFFF); |
| 96 | |
| 97 | if ( !GetPyramidBits(facilitycode, cardnumber, bs)) { |
| 98 | PrintAndLog("Error with tag bitstream generation."); |
| 99 | return 1; |
| 100 | } |
| 101 | |
| 102 | //Pyramid - compat mode, FSK2a, data rate 50, 4 data blocks |
| 103 | blocks[0] = T55x7_MODULATION_FSK2a | T55x7_BITRATE_RF_50 | 4<<T55x7_MAXBLOCK_SHIFT; |
| 104 | |
| 105 | if (param_getchar(Cmd, 3) == 'Q' || param_getchar(Cmd, 3) == 'q') |
| 106 | //t5555 (Q5) BITRATE = (RF-2)/2 (iceman) |
| 107 | blocks[0] = T5555_MODULATION_FSK2 | T5555_INVERT_OUTPUT | 50<<T5555_BITRATE_SHIFT | 4<<T5555_MAXBLOCK_SHIFT; |
| 108 | |
| 109 | blocks[1] = bytebits_to_byte(bs,32); |
| 110 | blocks[2] = bytebits_to_byte(bs+32,32); |
| 111 | blocks[3] = bytebits_to_byte(bs+64,32); |
| 112 | blocks[4] = bytebits_to_byte(bs+96,32); |
| 113 | |
| 114 | PrintAndLog("Preparing to clone Farpointe/Pyramid to T55x7 with Facility Code: %u, Card Number: %u", facilitycode, cardnumber); |
| 115 | PrintAndLog("Blk | Data "); |
| 116 | PrintAndLog("----+------------"); |
| 117 | for ( i = 0; i<5; ++i ) |
| 118 | PrintAndLog(" %02d | %08" PRIx32, i, blocks[i]); |
| 119 | |
| 120 | UsbCommand resp; |
| 121 | UsbCommand c = {CMD_T55XX_WRITE_BLOCK, {0,0,0}}; |
| 122 | |
| 123 | for ( i = 0; i<5; ++i ) { |
| 124 | c.arg[0] = blocks[i]; |
| 125 | c.arg[1] = i; |
| 126 | clearCommandBuffer(); |
| 127 | SendCommand(&c); |
| 128 | if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)){ |
| 129 | PrintAndLog("Error occurred, device did not respond during write operation."); |
| 130 | return -1; |
| 131 | } |
| 132 | } |
| 133 | return 0; |
| 134 | } |
| 135 | |
| 136 | int CmdPyramidSim(const char *Cmd) { |
| 137 | |
| 138 | char cmdp = param_getchar(Cmd, 0); |
| 139 | if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') return usage_lf_pyramid_sim(); |
| 140 | |
| 141 | uint32_t facilitycode = 0, cardnumber = 0, fc = 0, cn = 0; |
| 142 | |
| 143 | uint8_t bs[128]; |
| 144 | size_t size = sizeof(bs); |
| 145 | memset(bs, 0x00, size); |
| 146 | |
| 147 | // Pyramid uses: fcHigh: 10, fcLow: 8, clk: 50, invert: 0 |
| 148 | uint64_t arg1, arg2; |
| 149 | arg1 = (10 << 8) + 8; |
| 150 | arg2 = 50 | 0; |
| 151 | |
| 152 | if (sscanf(Cmd, "%u %u", &fc, &cn ) != 2) return usage_lf_pyramid_sim(); |
| 153 | |
| 154 | facilitycode = (fc & 0x000000FF); |
| 155 | cardnumber = (cn & 0x0000FFFF); |
| 156 | |
| 157 | if ( !GetPyramidBits(facilitycode, cardnumber, bs)) { |
| 158 | PrintAndLog("Error with tag bitstream generation."); |
| 159 | return 1; |
| 160 | } |
| 161 | |
| 162 | PrintAndLog("Simulating Farpointe/Pyramid - Facility Code: %u, CardNumber: %u", facilitycode, cardnumber ); |
| 163 | |
| 164 | UsbCommand c = {CMD_FSK_SIM_TAG, {arg1, arg2, size}}; |
| 165 | memcpy(c.d.asBytes, bs, size); |
| 166 | clearCommandBuffer(); |
| 167 | SendCommand(&c); |
| 168 | return 0; |
| 169 | } |
| 170 | |
| 171 | static command_t CommandTable[] = { |
| 172 | {"help", CmdHelp, 1, "This help"}, |
| 173 | {"read", CmdPyramidRead, 0, "Attempt to read and extract tag data"}, |
| 174 | {"clone", CmdPyramidClone, 0, "<Facility-Code> <Card Number> clone pyramid tag"}, |
| 175 | {"sim", CmdPyramidSim, 0, "<Facility-Code> <Card Number> simulate pyramid tag"}, |
| 176 | {NULL, NULL, 0, NULL} |
| 177 | }; |
| 178 | |
| 179 | int CmdLFPyramid(const char *Cmd) { |
| 180 | clearCommandBuffer(); |
| 181 | CmdsParse(CommandTable, Cmd); |
| 182 | return 0; |
| 183 | } |
| 184 | |
| 185 | int CmdHelp(const char *Cmd) { |
| 186 | CmdsHelp(CommandTable); |
| 187 | return 0; |
| 188 | } |