1 //-----------------------------------------------------------------------------
4 // This code is licensed to you under the terms of the GNU GPL, version 2 or,
5 // at your option, any later version. See the LICENSE.txt file for the text of
7 //-----------------------------------------------------------------------------
8 // Low frequency Farpoint G Prox II / Pyramid tag commands
9 // Biphase, rf/ , 96 bits (unknown key calc + some bits)
10 //-----------------------------------------------------------------------------
11 #include "cmdlfguard.h"
16 #include "commonutil.h" // ARRAYLEN
17 #include "cmdparser.h" // command_t
22 #include "protocols.h" // for T55xx config register definitions
23 #include "lfdemod.h" // parityTest
24 #include "cmdlft55xx.h" // verifywrite
25 #include "cliparser.h"
26 #include "cmdlfem4x05.h" // EM defines
28 static int CmdHelp(const char *Cmd
);
30 // attempts to demodulate and identify a G_Prox_II verex/chubb card
31 // WARNING: if it fails during some points it will destroy the DemodBuffer data
32 // but will leave the GraphBuffer intact.
33 // if successful it will push askraw data back to demod buffer ready for emulation
34 int demodGuard(bool verbose
) {
35 (void) verbose
; // unused so far
36 //Differential Biphase
37 //get binary from ask wave
38 if (ASKbiphaseDemod(0, 64, 0, 0, false) != PM3_SUCCESS
) {
39 PrintAndLogEx(DEBUG
, "DEBUG: Error - gProxII ASKbiphaseDemod failed");
43 size_t size
= DemodBufferLen
;
45 int preambleIndex
= detectGProxII(DemodBuffer
, &size
);
46 if (preambleIndex
< 0) {
48 if (preambleIndex
== -1)
49 PrintAndLogEx(DEBUG
, "DEBUG: Error - gProxII too few bits found");
50 else if (preambleIndex
== -2)
51 PrintAndLogEx(DEBUG
, "DEBUG: Error - gProxII preamble not found");
52 else if (preambleIndex
== -3)
53 PrintAndLogEx(DEBUG
, "DEBUG: Error - gProxII size not correct: %zu", size
);
54 else if (preambleIndex
== -5)
55 PrintAndLogEx(DEBUG
, "DEBUG: Error - gProxII wrong spacerbits");
57 PrintAndLogEx(DEBUG
, "DEBUG: Error - gProxII ans: %d", preambleIndex
);
61 // got a good demod of 96 bits
63 uint8_t plain
[8] = {0x00};
65 size_t startIdx
= preambleIndex
+ 6; //start after 6 bit preamble
66 uint8_t bits_no_spacer
[90];
68 // not mess with raw DemodBuffer copy to a new sample array
69 memcpy(bits_no_spacer
, DemodBuffer
+ startIdx
, 90);
71 // remove the 18 (90/5=18) parity bits (down to 72 bits (96-6-18=72))
72 size_t len
= removeParity(bits_no_spacer
, 0, 5, 3, 90); //source, startloc, paritylen, ptype, length_to_run
74 PrintAndLogEx(DEBUG
, "DEBUG: Error - gProxII spacer removal did not produce 72 bits: %zu, start: %zu", len
, startIdx
);
78 // get key and then get all 8 bytes of payload decoded
79 xorKey
= (uint8_t)bytebits_to_byteLSBF(bits_no_spacer
, 8);
80 for (size_t idx
= 0; idx
< 8; idx
++) {
81 plain
[idx
] = ((uint8_t)bytebits_to_byteLSBF(bits_no_spacer
+ 8 + (idx
* 8), 8)) ^ xorKey
;
82 PrintAndLogEx(DEBUG
, "DEBUG: gProxII byte %zu after xor: %02x", idx
, plain
[idx
]);
85 setDemodBuff(DemodBuffer
, 96, preambleIndex
);
86 setClockGrid(g_DemodClock
, g_DemodStartIdx
+ (preambleIndex
* g_DemodClock
));
88 //plain contains 8 Bytes (64 bits) of decrypted raw tag data
89 uint8_t fmtLen
= plain
[0] >> 2;
92 //get raw 96 bits to print
93 uint32_t raw1
= bytebits_to_byte(DemodBuffer
, 32);
94 uint32_t raw2
= bytebits_to_byte(DemodBuffer
+ 32, 32);
95 uint32_t raw3
= bytebits_to_byte(DemodBuffer
+ 64, 32);
99 FC
= ((plain
[3] & 0x7F) << 7) | (plain
[4] >> 1);
100 Card
= ((plain
[4] & 1) << 19) | (plain
[5] << 11) | (plain
[6] << 3) | ((plain
[7] & 0xE0) >> 5);
103 FC
= ((plain
[3] & 0x7F) << 1) | (plain
[4] >> 7);
104 Card
= ((plain
[4] & 0x7F) << 9) | (plain
[5] << 1) | (plain
[6] >> 7);
111 PrintAndLogEx(SUCCESS
, "G-Prox-II - len: " _GREEN_("%u")" FC: " _GREEN_("%u") " Card: " _GREEN_("%u") ", Raw: %08x%08x%08x", fmtLen
, FC
, Card
, raw1
, raw2
, raw3
);
113 PrintAndLogEx(SUCCESS
, "G-Prox-II - Unknown len: " _GREEN_("%u") ", Raw: %08x%08x%08x", fmtLen
, raw1
, raw2
, raw3
);
118 static int CmdGuardDemod(const char *Cmd
) {
119 CLIParserContext
*ctx
;
120 CLIParserInit(&ctx
, "lf gproxii demod",
121 "Try to find Guardall Prox-II preamble, if found decode / descramble data",
129 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
131 return demodGuard(true);
134 static int CmdGuardReader(const char *Cmd
) {
135 CLIParserContext
*ctx
;
136 CLIParserInit(&ctx
, "lf gproxii reader",
137 "read a Guardall tag",
138 "lf gproxii reader -@ -> continuous reader mode"
143 arg_lit0("@", NULL
, "optional - continuous reader mode"),
146 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
147 bool cm
= arg_get_lit(ctx
, 1);
151 PrintAndLogEx(INFO
, "Press " _GREEN_("<Enter>") " to exit");
155 lf_read(false, 10000);
157 } while (cm
&& !kbd_enter_pressed());
162 static int CmdGuardClone(const char *Cmd
) {
163 CLIParserContext
*ctx
;
164 CLIParserInit(&ctx
, "lf gproxii clone",
165 "clone a Guardall tag to a T55x7, Q5/T5555 or EM4305/4469 tag.\n"
166 "The facility-code is 8-bit and the card number is 16-bit. Larger values are truncated.\n"
167 "Currently work only on 26bit",
168 "lf gproxii clone --fmt 26 --fc 123 --cn 1337\n"
169 "lf gproxii clone --q5 --fmt 26 --fc 123 --cn 1337 -> encode for Q5/T5555 tag\n"
170 "lf gproxii clone --em --fmt 26 --fc 123 --cn 1337 -> encode for EM4305/4469"
175 arg_u64_1(NULL
, "fmt", "<dec>", "format length 26|32|36|40"),
176 arg_u64_1(NULL
, "fc", "<dec>", "8-bit value facility code"),
177 arg_u64_1(NULL
, "cn", "<dec>", "16-bit value card number"),
178 arg_lit0(NULL
, "q5", "optional - specify writing to Q5/T5555 tag"),
179 arg_lit0(NULL
, "em", "optional - specify writing to EM4305/4469 tag"),
182 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
184 uint32_t fmtlen
= arg_get_u32_def(ctx
, 1, 0);
185 uint32_t fc
= arg_get_u32_def(ctx
, 2, 0);
186 uint32_t cn
= arg_get_u32_def(ctx
, 3, 0);
187 bool q5
= arg_get_lit(ctx
, 4);
188 bool em
= arg_get_lit(ctx
, 5);
192 PrintAndLogEx(FAILED
, "Can't specify both Q5 and EM4305 at the same time");
197 uint32_t facilitycode
= (fc
& 0x000000FF);
198 uint32_t cardnumber
= (cn
& 0x0000FFFF);
200 //GuardProxII - compat mode, ASK/Biphase, data rate 64, 3 data blocks
201 uint8_t *bs
= calloc(96, sizeof(uint8_t));
202 if (getGuardBits(fmtlen
, facilitycode
, cardnumber
, bs
) != PM3_SUCCESS
) {
203 PrintAndLogEx(ERR
, "Error with tag bitstream generation.");
208 uint32_t blocks
[4] = {T55x7_MODULATION_BIPHASE
| T55x7_BITRATE_RF_64
| 3 << T55x7_MAXBLOCK_SHIFT
, 0, 0, 0};
209 char cardtype
[16] = {"T55x7"};
212 blocks
[0] = T5555_FIXED
| T5555_MODULATION_BIPHASE
| T5555_SET_BITRATE(64) | 3 << T5555_MAXBLOCK_SHIFT
;
213 snprintf(cardtype
, sizeof(cardtype
), "Q5/T5555");
218 blocks
[0] = EM4305_GUARDPROXII_CONFIG_BLOCK
;
219 snprintf(cardtype
, sizeof(cardtype
), "EM4305/4469");
222 blocks
[1] = bytebits_to_byte(bs
, 32);
223 blocks
[2] = bytebits_to_byte(bs
+ 32, 32);
224 blocks
[3] = bytebits_to_byte(bs
+ 64, 32);
228 PrintAndLogEx(INFO
, "Preparing to clone Guardall to " _YELLOW_("%s") " with Facility Code: " _GREEN_("%u") " Card Number: " _GREEN_("%u")
233 print_blocks(blocks
, ARRAYLEN(blocks
));
237 res
= em4x05_clone_tag(blocks
, ARRAYLEN(blocks
), 0, false);
239 res
= clone_t55xx_tag(blocks
, ARRAYLEN(blocks
));
241 PrintAndLogEx(SUCCESS
, "Done");
242 PrintAndLogEx(HINT
, "Hint: try " _YELLOW_("`lf gproxii reader`") " to verify");
246 static int CmdGuardSim(const char *Cmd
) {
248 CLIParserContext
*ctx
;
249 CLIParserInit(&ctx
, "lf gproxii sim",
250 "Enables simulation of Guardall card with specified card number.\n"
251 "Simulation runs until the button is pressed or another USB command is issued.\n"
252 "The facility-code is 8-bit and the card number is 16-bit. Larger values are truncated.\n"
253 "Currently work only on 26bit",
254 "lf gproxii sim --fmt 26 --fc 123 --cn 1337\n"
259 arg_u64_1(NULL
, "fmt", "<dec>", "format length 26|32|36|40"),
260 arg_u64_1(NULL
, "fc", "<dec>", "8-bit value facility code"),
261 arg_u64_1(NULL
, "cn", "<dec>", "16-bit value card number"),
264 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
266 uint32_t fmtlen
= arg_get_u32_def(ctx
, 1, 0);
267 uint32_t fc
= arg_get_u32_def(ctx
, 2, 0);
268 uint32_t cn
= arg_get_u32_def(ctx
, 3, 0);
272 uint32_t facilitycode
= (fc
& 0x000000FF);
273 uint32_t cardnumber
= (cn
& 0x0000FFFF);
276 memset(bs
, 0x00, sizeof(bs
));
278 if (getGuardBits(fmtlen
, facilitycode
, cardnumber
, bs
) != PM3_SUCCESS
) {
279 PrintAndLogEx(ERR
, "Error with tag bitstream generation.");
283 PrintAndLogEx(SUCCESS
, "Simulating Guardall Prox - Facility Code: " _YELLOW_("%u") " CardNumber: " _YELLOW_("%u")
288 // Guard uses: clk: 64, invert: 0, encoding: 2 (ASK Biphase)
289 lf_asksim_t
*payload
= calloc(1, sizeof(lf_asksim_t
) + sizeof(bs
));
290 payload
->encoding
= 2;
292 payload
->separator
= 0;
294 memcpy(payload
->data
, bs
, sizeof(bs
));
296 clearCommandBuffer();
297 SendCommandNG(CMD_LF_ASK_SIMULATE
, (uint8_t *)payload
, sizeof(lf_asksim_t
) + sizeof(bs
));
300 PacketResponseNG resp
;
301 WaitForResponse(CMD_LF_ASK_SIMULATE
, &resp
);
303 PrintAndLogEx(INFO
, "Done");
304 if (resp
.status
!= PM3_EOPABORTED
)
309 static command_t CommandTable
[] = {
310 {"help", CmdHelp
, AlwaysAvailable
, "this help"},
311 {"demod", CmdGuardDemod
, AlwaysAvailable
, "demodulate a G Prox II tag from the GraphBuffer"},
312 {"reader", CmdGuardReader
, IfPm3Lf
, "attempt to read and extract tag data"},
313 {"clone", CmdGuardClone
, IfPm3Lf
, "clone Guardall tag to T55x7 or Q5/T5555"},
314 {"sim", CmdGuardSim
, IfPm3Lf
, "simulate Guardall tag"},
315 {NULL
, NULL
, NULL
, NULL
}
318 static int CmdHelp(const char *Cmd
) {
319 (void)Cmd
; // Cmd is not used so far
320 CmdsHelp(CommandTable
);
324 int CmdLFGuard(const char *Cmd
) {
325 clearCommandBuffer();
326 return CmdsParse(CommandTable
, Cmd
);
329 // demod gProxIIDemod
330 // error returns as -x
331 // success returns start position in bitstream
332 // Bitstream must contain previously askrawdemod and biphasedemoded data
333 int detectGProxII(uint8_t *bits
, size_t *size
) {
336 uint8_t preamble
[] = {1, 1, 1, 1, 1, 0};
339 if (*size
< sizeof(preamble
)) return -1;
341 if (!preambleSearch(bits
, preamble
, sizeof(preamble
), size
, &startIdx
))
342 return -2; //preamble not found
344 //gProxII should be 96 bits
345 if (*size
!= 96) return -3;
347 //check first 6 spacer bits to verify format
348 if (!bits
[startIdx
+ 5] && !bits
[startIdx
+ 10] && !bits
[startIdx
+ 15] && !bits
[startIdx
+ 20] && !bits
[startIdx
+ 25] && !bits
[startIdx
+ 30]) {
349 //confirmed proper separator bits found
350 //return start position
351 return (int) startIdx
;
353 return -5; //spacer bits not found - not a valid gproxII
357 int getGuardBits(uint8_t fmtlen
, uint32_t fc
, uint32_t cn
, uint8_t *guardBits
) {
359 uint8_t xorKey
= 0x66;
362 uint8_t rawbytes
[12];
363 memset(pre
, 0x00, sizeof(pre
));
364 memset(rawbytes
, 0x00, sizeof(rawbytes
));
366 // add format length (decimal)
369 rawbytes
[1] = (32 << 2);
374 rawbytes
[1] = (36 << 2);
375 // Get wiegand from FacilityCode 14bits, CardNumber 20bits
377 memset(wiegand
, 0x00, sizeof(wiegand
));
378 num_to_bytebits(fc
, 14, wiegand
);
379 num_to_bytebits(cn
, 20, wiegand
+ 14);
381 // add wiegand parity bits (dest, source, len)
382 wiegand_add_parity(pre
, wiegand
, 34);
386 rawbytes
[1] = (40 << 2);
391 rawbytes
[1] = (26 << 2);
392 // Get 26 wiegand from FacilityCode, CardNumber
394 memset(wiegand
, 0x00, sizeof(wiegand
));
395 num_to_bytebits(fc
, 8, wiegand
);
396 num_to_bytebits(cn
, 16, wiegand
+ 8);
398 // add wiegand parity bits (dest, source, len)
399 wiegand_add_parity(pre
, wiegand
, 24);
403 // 2bit checksum, unknown today,
404 // these two bits are the last ones of rawbyte[1], hence the LSHIFT above.
408 rawbytes
[0] = xorKey
;
413 // add wiegand to rawbytes
414 for (i
= 0; i
< 5; ++i
)
415 rawbytes
[i
+ 4] = bytebits_to_byte(pre
+ (i
* 8), 8);
417 PrintAndLogEx(DEBUG
, " WIE | %s", sprint_hex(rawbytes
, sizeof(rawbytes
)));
419 // XOR (only works on wiegand stuff)
420 for (i
= 1; i
< sizeof(rawbytes
); ++i
)
421 rawbytes
[i
] ^= xorKey
;
423 PrintAndLogEx(DEBUG
, " XOR | %s", sprint_hex(rawbytes
, sizeof(rawbytes
)));
425 // convert rawbytes to bits in pre
426 for (i
= 0; i
< sizeof(rawbytes
); ++i
)
427 num_to_bytebitsLSBF(rawbytes
[i
], 8, pre
+ (i
* 8));
429 PrintAndLogEx(DEBUG
, " Raw | %s", sprint_hex(rawbytes
, sizeof(rawbytes
)));
430 PrintAndLogEx(DEBUG
, " Raw | %s", sprint_bin(pre
, 96));
432 // add spacer bit 0 every 4 bits, starting with index 0,
433 // 12 bytes, 24 nibbles. 24+1 extra bites. 3bytes. ie 9bytes | 1byte xorkey, 8bytes rawdata (72bits, should be enough for a 40bit wiegand)
434 addParity(pre
, guardBits
+ 6, 72, 5, 3);
444 PrintAndLogEx(DEBUG
, " FIN | %s\n", sprint_bin(guardBits
, 96));