1 //-----------------------------------------------------------------------------
2 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // See LICENSE.txt for the text of the license.
15 //-----------------------------------------------------------------------------
16 // Low frequency Farpoint G Prox II / Pyramid tag commands
17 // Biphase, rf/ , 96 bits (unknown key calc + some bits)
18 //-----------------------------------------------------------------------------
19 #include "cmdlfguard.h"
24 #include "commonutil.h" // ARRAYLEN
25 #include "cmdparser.h" // command_t
30 #include "protocols.h" // for T55xx config register definitions
31 #include "lfdemod.h" // parityTest
32 #include "cmdlft55xx.h" // verifywrite
33 #include "cliparser.h"
34 #include "cmdlfem4x05.h" // EM defines
36 static int CmdHelp(const char *Cmd
);
38 static int demod_guard_raw(uint8_t *raw
, uint8_t rlen
) {
44 uint8_t bits
[96] = {0x00};
45 bytes_to_bytebits(raw
, rlen
, bits
);
47 // start after 6 bit preamble
49 uint8_t bits_no_spacer
[90];
50 memcpy(bits_no_spacer
, bits
+ start_idx
, 90);
52 // remove the 18 (90/5=18) parity bits (down to 72 bits (96-6-18=72))
53 size_t len
= removeParity(bits_no_spacer
, 0, 5, 3, 90); // source, startloc, paritylen, ptype, length_to_run
55 PrintAndLogEx(DEBUG
, "DEBUG: Error - gProxII spacer removal did not produce 72 bits: %zu, start: %zu", len
, start_idx
);
59 uint8_t plain
[8] = {0x00};
61 // get key and then get all 8 bytes of payload decoded
62 uint8_t xorKey
= (uint8_t)bytebits_to_byteLSBF(bits_no_spacer
, 8);
63 for (size_t idx
= 0; idx
< 8; idx
++) {
64 plain
[idx
] = ((uint8_t)bytebits_to_byteLSBF(bits_no_spacer
+ 8 + (idx
* 8), 8)) ^ xorKey
;
65 PrintAndLogEx(DEBUG
, "DEBUG: gProxII byte %zu after xor: %02x", idx
, plain
[idx
]);
68 // plain contains 8 Bytes (64 bits) of decrypted raw tag data
69 uint8_t fmtlen
= plain
[0] >> 2;
76 FC
= ((plain
[3] & 0x7F) << 7) | (plain
[4] >> 1);
77 Card
= ((plain
[4] & 1) << 19) | (plain
[5] << 11) | (plain
[6] << 3) | ((plain
[7] & 0xE0) >> 5);
80 FC
= ((plain
[3] & 0x7F) << 1) | (plain
[4] >> 7);
81 Card
= ((plain
[4] & 0x7F) << 9) | (plain
[5] << 1) | (plain
[6] >> 7);
89 PrintAndLogEx(SUCCESS
, "G-Prox-II - Unknown len: " _GREEN_("%u") "xor: " _GREEN_("%u")", Raw: %s", fmtlen
, xorKey
, sprint_hex_inrow(raw
, rlen
));
91 PrintAndLogEx(SUCCESS
, "G-Prox-II - Len: " _GREEN_("%u")" FC: " _GREEN_("%u") " Card: " _GREEN_("%u") "xor: " _GREEN_("%u")", Raw: %s", fmtlen
, FC
, Card
, xorKey
, sprint_hex_inrow(raw
, rlen
));
96 // attempts to demodulate and identify a G_Prox_II verex/chubb card
97 // WARNING: if it fails during some points it will destroy the g_DemodBuffer data
98 // but will leave the g_GraphBuffer intact.
99 // if successful it will push askraw data back to g_DemodBuffer ready for emulation
100 int demodGuard(bool verbose
) {
101 (void) verbose
; // unused so far
102 //Differential Biphase
103 //get binary from ask wave
104 if (ASKbiphaseDemod(0, 64, 0, 0, false) != PM3_SUCCESS
) {
105 PrintAndLogEx(DEBUG
, "DEBUG: Error - gProxII ASKbiphaseDemod failed");
109 size_t size
= g_DemodBufferLen
;
111 int preambleIndex
= detectGProxII(g_DemodBuffer
, &size
);
112 if (preambleIndex
< 0) {
114 if (preambleIndex
== -1)
115 PrintAndLogEx(DEBUG
, "DEBUG: Error - gProxII too few bits found");
116 else if (preambleIndex
== -2)
117 PrintAndLogEx(DEBUG
, "DEBUG: Error - gProxII preamble not found");
118 else if (preambleIndex
== -3)
119 PrintAndLogEx(DEBUG
, "DEBUG: Error - gProxII size not correct: %zu", size
);
120 else if (preambleIndex
== -5)
121 PrintAndLogEx(DEBUG
, "DEBUG: Error - gProxII wrong spacerbits");
123 PrintAndLogEx(DEBUG
, "DEBUG: Error - gProxII ans: %d", preambleIndex
);
127 // got a good demod of 96 bits
128 uint8_t plain
[8] = {0x00};
130 size_t startIdx
= preambleIndex
+ 6; //start after 6 bit preamble
131 uint8_t bits_no_spacer
[90];
133 // not mess with raw g_DemodBuffer copy to a new sample array
134 memcpy(bits_no_spacer
, g_DemodBuffer
+ startIdx
, 90);
136 // remove the 18 (90/5=18) parity bits (down to 72 bits (96-6-18=72))
137 size_t len
= removeParity(bits_no_spacer
, 0, 5, 3, 90); // source, startloc, paritylen, ptype, length_to_run
139 PrintAndLogEx(DEBUG
, "DEBUG: Error - gProxII spacer removal did not produce 72 bits: %zu, start: %zu", len
, startIdx
);
143 // get key and then get all 8 bytes of payload decoded
144 xorKey
= (uint8_t)bytebits_to_byteLSBF(bits_no_spacer
, 8);
145 PrintAndLogEx(DEBUG
, "DEBUG: gProxII xorKey: %u", xorKey
);
147 for (size_t idx
= 0; idx
< 8; idx
++) {
148 plain
[idx
] = ((uint8_t)bytebits_to_byteLSBF(bits_no_spacer
+ 8 + (idx
* 8), 8)) ^ xorKey
;
149 PrintAndLogEx(DEBUG
, "DEBUG: gProxII byte %zu after xor: %02x (%02x before xor)", idx
, plain
[idx
], bytebits_to_byteLSBF(bits_no_spacer
+ 8 + (idx
* 8), 8));
152 setDemodBuff(g_DemodBuffer
, 96, preambleIndex
);
153 setClockGrid(g_DemodClock
, g_DemodStartIdx
+ (preambleIndex
* g_DemodClock
));
155 //plain contains 8 Bytes (64 bits) of decrypted raw tag data
156 uint8_t fmtLen
= plain
[0] >> 2;
159 //get raw 96 bits to print
160 uint32_t raw1
= bytebits_to_byte(g_DemodBuffer
, 32);
161 uint32_t raw2
= bytebits_to_byte(g_DemodBuffer
+ 32, 32);
162 uint32_t raw3
= bytebits_to_byte(g_DemodBuffer
+ 64, 32);
163 bool unknown
= false;
166 PrintAndLogEx(DEBUG
, "DEBUG: FC 1: %x", (plain
[3] & 0x7F) << 7);
167 PrintAndLogEx(DEBUG
, "DEBUG: FC 2: %x", plain
[4] >> 1);
168 PrintAndLogEx(DEBUG
, "DEBUG: Card 1: %x", (plain
[4] & 1) << 19);
169 PrintAndLogEx(DEBUG
, "DEBUG: Card 2: %x", plain
[5] << 11);
170 PrintAndLogEx(DEBUG
, "DEBUG: Card 3: %x", plain
[6] << 3);
171 PrintAndLogEx(DEBUG
, "DEBUG: Card 4: %x", (plain
[7] & 0xE0) >> 5);
172 FC
= ((plain
[3] & 0x7F) << 7) | (plain
[4] >> 1);
173 Card
= ((plain
[4] & 1) << 19) | (plain
[5] << 11) | (plain
[6] << 3) | ((plain
[7] & 0xE0) >> 5);
176 FC
= ((plain
[3] & 0x7F) << 1) | (plain
[4] >> 7);
177 Card
= ((plain
[4] & 0x7F) << 9) | (plain
[5] << 1) | (plain
[6] >> 7);
184 PrintAndLogEx(SUCCESS
, "G-Prox-II - Unknown len: " _GREEN_("%u") " xor: " _GREEN_("%u")", Raw: %08x%08x%08x ", fmtLen
, xorKey
, raw1
, raw2
, raw3
);
186 PrintAndLogEx(SUCCESS
, "G-Prox-II - Len: " _GREEN_("%u")" FC: " _GREEN_("%u") " Card: " _GREEN_("%u") " xor: " _GREEN_("%u") ", Raw: %08x%08x%08x", fmtLen
, FC
, Card
, xorKey
, raw1
, raw2
, raw3
);
191 static int CmdGuardDemod(const char *Cmd
) {
192 CLIParserContext
*ctx
;
193 CLIParserInit(&ctx
, "lf gproxii demod",
194 "Try to find Guardall Prox-II preamble, if found decode / descramble data",
195 "lf gproxii demod -> use graphbuffer to decode\n"
196 "lf gproxii demod --raw fb8ee718ee3b8cc785c11b92 ->"
201 arg_str0("r", "raw", "<hex>", "raw bytes"),
204 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
207 uint8_t raw
[12] = {0};
208 CLIGetHexWithReturn(ctx
, 1, raw
, &raw_len
);
212 if (raw_len
!= 12 && raw_len
!= 0) {
213 PrintAndLogEx(FAILED
, "Must specify 12 bytes, got " _YELLOW_("%u"), raw_len
);
218 return demodGuard(true);
220 return demod_guard_raw(raw
, raw_len
);
223 static int CmdGuardReader(const char *Cmd
) {
224 CLIParserContext
*ctx
;
225 CLIParserInit(&ctx
, "lf gproxii reader",
226 "read a Guardall tag",
227 "lf gproxii reader -@ -> continuous reader mode"
232 arg_lit0("@", NULL
, "optional - continuous reader mode"),
235 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
236 bool cm
= arg_get_lit(ctx
, 1);
240 PrintAndLogEx(INFO
, "Press " _GREEN_("<Enter>") " to exit");
244 lf_read(false, 10000);
246 } while (cm
&& !kbd_enter_pressed());
251 static int CmdGuardClone(const char *Cmd
) {
252 CLIParserContext
*ctx
;
253 CLIParserInit(&ctx
, "lf gproxii clone",
254 "Clone a Guardall tag to a T55x7, Q5/T5555 or EM4305/4469 tag.\n"
255 "The facility-code is 8-bit and the card number is 20-bit. Larger values are truncated.\n"
256 "Currently work only on 26 | 36 bit format",
257 "lf gproxii clone --xor 141 --fmt 26 --fc 123 --cn 1337 -> encode for T55x7 tag\n"
258 "lf gproxii clone --xor 141 --fmt 26 --fc 123 --cn 1337 --q5 -> encode for Q5/T5555 tag\n"
259 "lf gproxii clone --xor 141 --fmt 26 --fc 123 --cn 1337 --em -> encode for EM4305/4469"
264 arg_u64_1(NULL
, "xor", "<dec>", "8-bit xor value (installation dependant)"),
265 arg_u64_1(NULL
, "fmt", "<dec>", "format length 26|32|36|40"),
266 arg_u64_1(NULL
, "fc", "<dec>", "8-bit value facility code"),
267 arg_u64_1(NULL
, "cn", "<dec>", "16-bit value card number"),
268 arg_lit0(NULL
, "q5", "optional - specify writing to Q5/T5555 tag"),
269 arg_lit0(NULL
, "em", "optional - specify writing to EM4305/4469 tag"),
272 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
274 uint32_t xorval
= arg_get_u32_def(ctx
, 1, 0);
275 uint32_t fmtlen
= arg_get_u32_def(ctx
, 2, 0);
276 uint32_t fc
= arg_get_u32_def(ctx
, 3, 0);
277 uint32_t cn
= arg_get_u32_def(ctx
, 4, 0);
279 bool q5
= arg_get_lit(ctx
, 5);
280 bool em
= arg_get_lit(ctx
, 6);
284 PrintAndLogEx(FAILED
, "Can't specify both Q5 and EM4305 at the same time");
289 uint32_t facilitycode
= (fc
& 0x000000FF);
290 uint32_t cardnumber
= (cn
& 0x00FFFFFF);
292 //GuardProxII - compat mode, ASK/Biphase, data rate 64, 3 data blocks
293 uint8_t *bs
= calloc(96, sizeof(uint8_t));
294 if (getGuardBits(xorval
, fmtlen
, facilitycode
, cardnumber
, bs
) != PM3_SUCCESS
) {
295 PrintAndLogEx(ERR
, "Error with tag bitstream generation.");
300 uint32_t blocks
[4] = {T55x7_MODULATION_BIPHASE
| T55x7_BITRATE_RF_64
| 3 << T55x7_MAXBLOCK_SHIFT
, 0, 0, 0};
301 char cardtype
[16] = {"T55x7"};
304 blocks
[0] = T5555_FIXED
| T5555_MODULATION_BIPHASE
| T5555_SET_BITRATE(64) | 3 << T5555_MAXBLOCK_SHIFT
;
305 snprintf(cardtype
, sizeof(cardtype
), "Q5/T5555");
310 blocks
[0] = EM4305_GUARDPROXII_CONFIG_BLOCK
;
311 snprintf(cardtype
, sizeof(cardtype
), "EM4305/4469");
314 blocks
[1] = bytebits_to_byte(bs
, 32);
315 blocks
[2] = bytebits_to_byte(bs
+ 32, 32);
316 blocks
[3] = bytebits_to_byte(bs
+ 64, 32);
320 PrintAndLogEx(INFO
, "Preparing to clone Guardall to " _YELLOW_("%s") " with Facility Code: " _GREEN_("%u") " Card Number: " _GREEN_("%u") " xorKey: " _GREEN_("%u")
326 print_blocks(blocks
, ARRAYLEN(blocks
));
330 res
= em4x05_clone_tag(blocks
, ARRAYLEN(blocks
), 0, false);
332 res
= clone_t55xx_tag(blocks
, ARRAYLEN(blocks
));
334 PrintAndLogEx(SUCCESS
, "Done");
335 PrintAndLogEx(HINT
, "Hint: try " _YELLOW_("`lf gproxii reader`") " to verify");
339 static int CmdGuardSim(const char *Cmd
) {
341 CLIParserContext
*ctx
;
342 CLIParserInit(&ctx
, "lf gproxii sim",
343 "Enables simulation of Guardall card with specified card number.\n"
344 "Simulation runs until the button is pressed or another USB command is issued.\n"
345 "The facility-code is 8-bit and the card number is 16-bit. Larger values are truncated.\n"
346 "Currently work only on 26 | 36 bit format",
347 "lf gproxii sim --xor 141 --fmt 26 --fc 123 --cn 1337\n"
352 arg_u64_1(NULL
, "xor", "<dec>", "8-bit xor value (installation dependant)"),
353 arg_u64_1(NULL
, "fmt", "<dec>", "format length 26|32|36|40"),
354 arg_u64_1(NULL
, "fc", "<dec>", "8-bit value facility code"),
355 arg_u64_1(NULL
, "cn", "<dec>", "16-bit value card number"),
358 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
360 uint32_t xorval
= arg_get_u32_def(ctx
, 1, 0);
361 uint32_t fmtlen
= arg_get_u32_def(ctx
, 2, 0);
362 uint32_t fc
= arg_get_u32_def(ctx
, 3, 0);
363 uint32_t cn
= arg_get_u32_def(ctx
, 4, 0);
367 uint32_t facilitycode
= (fc
& 0x000000FF);
368 uint32_t cardnumber
= (cn
& 0x000FFFFF);
371 memset(bs
, 0x00, sizeof(bs
));
373 if (getGuardBits(xorval
, fmtlen
, facilitycode
, cardnumber
, bs
) != PM3_SUCCESS
) {
374 PrintAndLogEx(ERR
, "Error with tag bitstream generation.");
378 PrintAndLogEx(SUCCESS
, "Simulating Guardall Prox - xorKey: " _YELLOW_("%u") " Facility Code: " _YELLOW_("%u") " CardNumber: " _YELLOW_("%u")
384 // Guard uses: clk: 64, invert: 0, encoding: 2 (ASK Biphase)
385 lf_asksim_t
*payload
= calloc(1, sizeof(lf_asksim_t
) + sizeof(bs
));
386 payload
->encoding
= 2;
388 payload
->separator
= 0;
390 memcpy(payload
->data
, bs
, sizeof(bs
));
392 clearCommandBuffer();
393 SendCommandNG(CMD_LF_ASK_SIMULATE
, (uint8_t *)payload
, sizeof(lf_asksim_t
) + sizeof(bs
));
396 PacketResponseNG resp
;
397 WaitForResponse(CMD_LF_ASK_SIMULATE
, &resp
);
399 PrintAndLogEx(INFO
, "Done!");
400 if (resp
.status
!= PM3_EOPABORTED
) {
406 static command_t CommandTable
[] = {
407 {"help", CmdHelp
, AlwaysAvailable
, "this help"},
408 {"demod", CmdGuardDemod
, AlwaysAvailable
, "demodulate a G Prox II tag from the GraphBuffer"},
409 {"reader", CmdGuardReader
, IfPm3Lf
, "attempt to read and extract tag data"},
410 {"clone", CmdGuardClone
, IfPm3Lf
, "clone Guardall tag to T55x7 or Q5/T5555"},
411 {"sim", CmdGuardSim
, IfPm3Lf
, "simulate Guardall tag"},
412 {NULL
, NULL
, NULL
, NULL
}
415 static int CmdHelp(const char *Cmd
) {
416 (void)Cmd
; // Cmd is not used so far
417 CmdsHelp(CommandTable
);
421 int CmdLFGuard(const char *Cmd
) {
422 clearCommandBuffer();
423 return CmdsParse(CommandTable
, Cmd
);
426 // demod gProxIIDemod
427 // error returns as -x
428 // success returns start position in bitstream
429 // Bitstream must contain previously askrawdemod and biphasedemoded data
430 int detectGProxII(uint8_t *bits
, size_t *size
) {
433 uint8_t preamble
[] = {1, 1, 1, 1, 1, 0};
436 if (*size
< sizeof(preamble
)) return -1;
438 // preamble not found
439 if (!preambleSearch(bits
, preamble
, sizeof(preamble
), size
, &startIdx
))
442 // gProxII should be 96 bits
443 if (*size
!= 96) return -3;
445 // check first 6 spacer bits to verify format
446 if (!bits
[startIdx
+ 5] && !bits
[startIdx
+ 10] && !bits
[startIdx
+ 15] && !bits
[startIdx
+ 20] && !bits
[startIdx
+ 25] && !bits
[startIdx
+ 30]) {
447 //confirmed proper separator bits found
448 //return start position
449 return (int) startIdx
;
452 // spacer bits not found - not a valid gproxII
457 int getGuardBits(uint8_t xorKey
, uint8_t fmtlen
, uint32_t fc
, uint32_t cn
, uint8_t *guardBits
) {
461 uint8_t rawbytes
[12];
462 memset(pre
, 0x00, sizeof(pre
));
463 memset(rawbytes
, 0x00, sizeof(rawbytes
));
465 // add format length (decimal)
468 rawbytes
[1] = (32 << 2);
472 rawbytes
[1] = (36 << 2);
473 // Get wiegand from FacilityCode 14bits, CardNumber 20bits
475 memset(wiegand
, 0x00, sizeof(wiegand
));
477 num_to_bytebits(fc
, 14, wiegand
);
478 num_to_bytebits(cn
, 20, wiegand
+ 14);
480 // add wiegand parity bits (dest, source, len)
481 wiegand_add_parity(pre
, wiegand
, 34);
485 rawbytes
[1] = (40 << 2);
490 rawbytes
[1] = (26 << 2);
491 // Get 26 wiegand from FacilityCode, CardNumber
493 memset(wiegand
, 0x00, sizeof(wiegand
));
494 num_to_bytebits(fc
, 8, wiegand
);
495 num_to_bytebits(cn
, 16, wiegand
+ 8);
497 // add wiegand parity bits (dest, source, len)
498 wiegand_add_parity(pre
, wiegand
, 24);
502 // 2bit checksum, unknown today,
503 // these two bits are the last ones of rawbyte[1], hence the LSHIFT above.
507 rawbytes
[0] = xorKey
;
512 // add wiegand to rawbytes
513 for (i
= 0; i
< 5; ++i
)
514 rawbytes
[i
+ 4] = bytebits_to_byte(pre
+ (i
* 8), 8);
516 PrintAndLogEx(DEBUG
, " WIE | %s", sprint_hex(rawbytes
, sizeof(rawbytes
)));
518 // XOR (only works on wiegand stuff)
519 for (i
= 1; i
< sizeof(rawbytes
); ++i
)
520 rawbytes
[i
] ^= xorKey
;
522 PrintAndLogEx(DEBUG
, " XOR | %s", sprint_hex(rawbytes
, sizeof(rawbytes
)));
524 // convert rawbytes to bits in pre
525 for (i
= 0; i
< sizeof(rawbytes
); ++i
)
526 num_to_bytebitsLSBF(rawbytes
[i
], 8, pre
+ (i
* 8));
528 PrintAndLogEx(DEBUG
, " Raw | %s", sprint_hex(rawbytes
, sizeof(rawbytes
)));
529 PrintAndLogEx(DEBUG
, " Raw | %s", sprint_bytebits_bin(pre
, 96));
531 // add spacer bit 0 every 4 bits, starting with index 0,
532 // 12 bytes, 24 nibbles. 24+1 extra bites. 3bytes. ie 9bytes | 1byte xorkey, 8bytes rawdata (72bits, should be enough for a 40bit wiegand)
533 addParity(pre
, guardBits
+ 6, 72, 5, 3);
543 PrintAndLogEx(DEBUG
, " FIN | %s\n", sprint_bytebits_bin(guardBits
, 96));