2016-02-28 02:47:10 +08:00
|
|
|
//-----------------------------------------------------------------------------
|
2020-11-29 19:33:09 +08:00
|
|
|
// Marshmellow
|
2016-02-28 02:47:10 +08:00
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
//-----------------------------------------------------------------------------
|
2017-07-30 15:17:48 +08:00
|
|
|
// Low frequency Farpoint G Prox II / Pyramid tag commands
|
|
|
|
// Biphase, rf/ , 96 bits (unknown key calc + some bits)
|
2016-02-28 02:47:10 +08:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "cmdlfguard.h"
|
2019-08-08 22:57:33 +08:00
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <ctype.h>
|
2020-11-29 19:33:09 +08:00
|
|
|
#include "commonutil.h" // ARRAYLEN
|
2019-08-08 22:57:33 +08:00
|
|
|
#include "cmdparser.h" // command_t
|
|
|
|
#include "comms.h"
|
|
|
|
#include "ui.h"
|
|
|
|
#include "cmddata.h"
|
|
|
|
#include "cmdlf.h"
|
2020-11-29 19:33:09 +08:00
|
|
|
#include "protocols.h" // for T55xx config register definitions
|
|
|
|
#include "lfdemod.h" // parityTest
|
|
|
|
#include "cmdlft55xx.h" // verifywrite
|
|
|
|
#include "cliparser.h"
|
|
|
|
#include "cmdlfem4x05.h" // EM defines
|
2019-08-08 22:57:33 +08:00
|
|
|
|
2016-02-28 02:47:10 +08:00
|
|
|
static int CmdHelp(const char *Cmd);
|
|
|
|
|
2020-11-29 19:33:09 +08:00
|
|
|
// attempts to demodulate and identify a G_Prox_II verex/chubb card
|
|
|
|
// WARNING: if it fails during some points it will destroy the DemodBuffer data
|
2017-07-30 15:17:48 +08:00
|
|
|
// but will leave the GraphBuffer intact.
|
2020-11-29 19:33:09 +08:00
|
|
|
// if successful it will push askraw data back to demod buffer ready for emulation
|
2020-09-28 17:50:20 +08:00
|
|
|
int demodGuard(bool verbose) {
|
|
|
|
(void) verbose; // unused so far
|
2019-03-10 06:35:06 +08:00
|
|
|
//Differential Biphase
|
|
|
|
//get binary from ask wave
|
2020-09-28 17:50:20 +08:00
|
|
|
if (ASKbiphaseDemod(0, 64, 0, 0, false) != PM3_SUCCESS) {
|
2019-03-10 06:35:06 +08:00
|
|
|
PrintAndLogEx(DEBUG, "DEBUG: Error - gProxII ASKbiphaseDemod failed");
|
2019-05-22 20:57:08 +08:00
|
|
|
return PM3_ESOFT;
|
2019-03-10 06:35:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
size_t size = DemodBufferLen;
|
|
|
|
|
|
|
|
int preambleIndex = detectGProxII(DemodBuffer, &size);
|
2019-03-10 07:00:59 +08:00
|
|
|
if (preambleIndex < 0) {
|
2019-03-10 06:35:06 +08:00
|
|
|
|
|
|
|
if (preambleIndex == -1)
|
|
|
|
PrintAndLogEx(DEBUG, "DEBUG: Error - gProxII too few bits found");
|
|
|
|
else if (preambleIndex == -2)
|
|
|
|
PrintAndLogEx(DEBUG, "DEBUG: Error - gProxII preamble not found");
|
|
|
|
else if (preambleIndex == -3)
|
2019-10-06 05:56:19 +08:00
|
|
|
PrintAndLogEx(DEBUG, "DEBUG: Error - gProxII size not correct: %zu", size);
|
2019-03-10 06:35:06 +08:00
|
|
|
else if (preambleIndex == -5)
|
|
|
|
PrintAndLogEx(DEBUG, "DEBUG: Error - gProxII wrong spacerbits");
|
|
|
|
else
|
|
|
|
PrintAndLogEx(DEBUG, "DEBUG: Error - gProxII ans: %d", preambleIndex);
|
2019-05-22 20:57:08 +08:00
|
|
|
return PM3_ESOFT;
|
2019-03-10 06:35:06 +08:00
|
|
|
}
|
|
|
|
|
2020-09-10 17:44:32 +08:00
|
|
|
// got a good demod of 96 bits
|
|
|
|
|
|
|
|
uint8_t plain[8] = {0x00};
|
2019-03-10 06:35:06 +08:00
|
|
|
uint8_t xorKey = 0;
|
|
|
|
size_t startIdx = preambleIndex + 6; //start after 6 bit preamble
|
|
|
|
uint8_t bits_no_spacer[90];
|
2020-09-10 17:44:32 +08:00
|
|
|
|
|
|
|
// not mess with raw DemodBuffer copy to a new sample array
|
2019-03-10 06:35:06 +08:00
|
|
|
memcpy(bits_no_spacer, DemodBuffer + startIdx, 90);
|
2020-09-10 17:44:32 +08:00
|
|
|
|
2019-03-10 06:35:06 +08:00
|
|
|
// remove the 18 (90/5=18) parity bits (down to 72 bits (96-6-18=72))
|
|
|
|
size_t len = removeParity(bits_no_spacer, 0, 5, 3, 90); //source, startloc, paritylen, ptype, length_to_run
|
|
|
|
if (len != 72) {
|
2019-10-06 05:56:19 +08:00
|
|
|
PrintAndLogEx(DEBUG, "DEBUG: Error - gProxII spacer removal did not produce 72 bits: %zu, start: %zu", len, startIdx);
|
2019-05-22 20:57:08 +08:00
|
|
|
return PM3_ESOFT;
|
2019-03-10 06:35:06 +08:00
|
|
|
}
|
2020-09-10 17:44:32 +08:00
|
|
|
|
2019-03-10 06:35:06 +08:00
|
|
|
// get key and then get all 8 bytes of payload decoded
|
|
|
|
xorKey = (uint8_t)bytebits_to_byteLSBF(bits_no_spacer, 8);
|
|
|
|
for (size_t idx = 0; idx < 8; idx++) {
|
2020-09-10 17:44:32 +08:00
|
|
|
plain[idx] = ((uint8_t)bytebits_to_byteLSBF(bits_no_spacer + 8 + (idx * 8), 8)) ^ xorKey;
|
|
|
|
PrintAndLogEx(DEBUG, "DEBUG: gProxII byte %zu after xor: %02x", idx, plain[idx]);
|
2019-03-10 06:35:06 +08:00
|
|
|
}
|
|
|
|
|
2019-04-07 03:46:00 +08:00
|
|
|
setDemodBuff(DemodBuffer, 96, preambleIndex);
|
2019-03-10 07:00:59 +08:00
|
|
|
setClockGrid(g_DemodClock, g_DemodStartIdx + (preambleIndex * g_DemodClock));
|
2019-03-10 06:35:06 +08:00
|
|
|
|
2020-09-10 17:44:32 +08:00
|
|
|
//plain contains 8 Bytes (64 bits) of decrypted raw tag data
|
|
|
|
uint8_t fmtLen = plain[0] >> 2;
|
2019-03-10 06:35:06 +08:00
|
|
|
uint32_t FC = 0;
|
|
|
|
uint32_t Card = 0;
|
|
|
|
//get raw 96 bits to print
|
2019-03-10 07:00:59 +08:00
|
|
|
uint32_t raw1 = bytebits_to_byte(DemodBuffer, 32);
|
2019-03-10 06:35:06 +08:00
|
|
|
uint32_t raw2 = bytebits_to_byte(DemodBuffer + 32, 32);
|
|
|
|
uint32_t raw3 = bytebits_to_byte(DemodBuffer + 64, 32);
|
|
|
|
bool unknown = false;
|
2019-03-10 07:00:59 +08:00
|
|
|
switch (fmtLen) {
|
2019-03-10 06:35:06 +08:00
|
|
|
case 36:
|
2020-09-10 17:44:32 +08:00
|
|
|
FC = ((plain[3] & 0x7F) << 7) | (plain[4] >> 1);
|
|
|
|
Card = ((plain[4] & 1) << 19) | (plain[5] << 11) | (plain[6] << 3) | ((plain[7] & 0xE0) >> 5);
|
2019-03-10 06:35:06 +08:00
|
|
|
break;
|
|
|
|
case 26:
|
2020-09-10 17:44:32 +08:00
|
|
|
FC = ((plain[3] & 0x7F) << 1) | (plain[4] >> 7);
|
|
|
|
Card = ((plain[4] & 0x7F) << 9) | (plain[5] << 1) | (plain[6] >> 7);
|
2019-03-10 06:35:06 +08:00
|
|
|
break;
|
|
|
|
default :
|
|
|
|
unknown = true;
|
|
|
|
break;
|
|
|
|
}
|
2019-03-10 07:00:59 +08:00
|
|
|
if (!unknown)
|
2020-06-26 19:01:17 +08:00
|
|
|
PrintAndLogEx(SUCCESS, "G-Prox-II - len: " _GREEN_("%u")" FC: " _GREEN_("%u") " Card: " _GREEN_("%u") ", Raw: %08x%08x%08x", fmtLen, FC, Card, raw1, raw2, raw3);
|
2019-03-10 06:35:06 +08:00
|
|
|
else
|
2020-06-26 19:01:17 +08:00
|
|
|
PrintAndLogEx(SUCCESS, "G-Prox-II - Unknown len: " _GREEN_("%u") ", Raw: %08x%08x%08x", fmtLen, raw1, raw2, raw3);
|
2019-03-10 06:35:06 +08:00
|
|
|
|
2019-05-22 20:57:08 +08:00
|
|
|
return PM3_SUCCESS;
|
2017-07-30 15:17:48 +08:00
|
|
|
}
|
|
|
|
|
2020-09-28 17:50:20 +08:00
|
|
|
static int CmdGuardDemod(const char *Cmd) {
|
2020-11-29 19:33:09 +08:00
|
|
|
CLIParserContext *ctx;
|
2020-11-29 19:53:39 +08:00
|
|
|
CLIParserInit(&ctx, "lf gproxii demod",
|
|
|
|
"Try to find Guardall Prox-II preamble, if found decode / descramble data",
|
|
|
|
"lf gproxii demod"
|
2020-11-29 19:33:09 +08:00
|
|
|
);
|
|
|
|
|
|
|
|
void *argtable[] = {
|
|
|
|
arg_param_begin,
|
|
|
|
arg_param_end
|
|
|
|
};
|
|
|
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
|
|
|
CLIParserFree(ctx);
|
2020-09-28 17:50:20 +08:00
|
|
|
return demodGuard(true);
|
|
|
|
}
|
|
|
|
|
2020-11-29 19:33:09 +08:00
|
|
|
static int CmdGuardReader(const char *Cmd) {
|
|
|
|
CLIParserContext *ctx;
|
2020-11-29 19:53:39 +08:00
|
|
|
CLIParserInit(&ctx, "lf gproxii reader",
|
2020-11-29 19:33:09 +08:00
|
|
|
"read a Guardall tag",
|
2020-11-29 19:53:39 +08:00
|
|
|
"lf gproxii reader -@ -> continuous reader mode"
|
2020-11-29 19:33:09 +08:00
|
|
|
);
|
|
|
|
|
|
|
|
void *argtable[] = {
|
|
|
|
arg_param_begin,
|
|
|
|
arg_lit0("@", NULL, "optional - continuous reader mode"),
|
|
|
|
arg_param_end
|
|
|
|
};
|
|
|
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
|
|
|
bool cm = arg_get_lit(ctx, 1);
|
|
|
|
CLIParserFree(ctx);
|
|
|
|
|
|
|
|
do {
|
|
|
|
lf_read(false, 10000);
|
|
|
|
demodGuard(!cm);
|
|
|
|
} while (cm && !kbd_enter_pressed());
|
|
|
|
|
|
|
|
return PM3_SUCCESS;
|
2016-02-28 02:47:10 +08:00
|
|
|
}
|
|
|
|
|
2019-04-12 07:55:25 +08:00
|
|
|
static int CmdGuardClone(const char *Cmd) {
|
2020-11-29 19:33:09 +08:00
|
|
|
CLIParserContext *ctx;
|
2020-11-29 19:53:39 +08:00
|
|
|
CLIParserInit(&ctx, "lf gproxii clone",
|
2020-11-29 19:33:09 +08:00
|
|
|
"clone a Guardall tag to a T55x7, Q5/T5555 or EM4305/4469 tag.\n"
|
|
|
|
"The facility-code is 8-bit and the card number is 16-bit. Larger values are truncated.\n"
|
|
|
|
"Currently work only on 26bit",
|
2020-11-29 19:53:39 +08:00
|
|
|
"lf gproxii clone --fmt 26 --fc 123 --cn 1337\n"
|
|
|
|
"lf gproxii clone --q5 --fmt 26 --fc 123 --cn 1337 -> encode for Q5/T5555 tag\n"
|
|
|
|
"lf gproxii clone --em --fmt 26 --fc 123 --cn 1337 -> encode for EM4305/4469"
|
2020-11-29 19:33:09 +08:00
|
|
|
);
|
|
|
|
|
|
|
|
void *argtable[] = {
|
|
|
|
arg_param_begin,
|
|
|
|
arg_u64_1(NULL, "fmt", "<dec>", "format length 26|32|36|40"),
|
|
|
|
arg_u64_1(NULL, "fc", "<dec>", "8-bit value facility code"),
|
|
|
|
arg_u64_1(NULL, "cn", "<dec>", "16-bit value card number"),
|
|
|
|
arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
|
|
|
|
arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
|
|
|
|
arg_param_end
|
|
|
|
};
|
|
|
|
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
|
|
|
|
|
|
|
uint32_t fmtlen = arg_get_u32_def(ctx, 1, 0);
|
|
|
|
uint32_t fc = arg_get_u32_def(ctx, 2, 0);
|
|
|
|
uint32_t cn = arg_get_u32_def(ctx, 3, 0);
|
|
|
|
bool q5 = arg_get_lit(ctx, 4);
|
|
|
|
bool em = arg_get_lit(ctx, 5);
|
|
|
|
CLIParserFree(ctx);
|
|
|
|
|
|
|
|
if (q5 && em) {
|
|
|
|
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
|
|
|
|
return PM3_EINVARG;
|
|
|
|
}
|
2019-10-13 06:48:26 +08:00
|
|
|
|
2019-03-10 06:35:06 +08:00
|
|
|
fmtlen &= 0x7f;
|
2020-11-29 19:33:09 +08:00
|
|
|
uint32_t facilitycode = (fc & 0x000000FF);
|
|
|
|
uint32_t cardnumber = (cn & 0x0000FFFF);
|
2019-03-09 15:59:13 +08:00
|
|
|
|
2019-09-27 03:44:27 +08:00
|
|
|
//GuardProxII - compat mode, ASK/Biphase, data rate 64, 3 data blocks
|
|
|
|
uint8_t *bs = calloc(96, sizeof(uint8_t));
|
2019-05-22 20:57:08 +08:00
|
|
|
if (getGuardBits(fmtlen, facilitycode, cardnumber, bs) != PM3_SUCCESS) {
|
2019-07-14 06:35:18 +08:00
|
|
|
PrintAndLogEx(ERR, "Error with tag bitstream generation.");
|
2019-09-27 03:44:27 +08:00
|
|
|
free(bs);
|
2019-05-22 20:57:08 +08:00
|
|
|
return PM3_ESOFT;
|
2019-03-10 06:35:06 +08:00
|
|
|
}
|
2016-02-28 02:47:10 +08:00
|
|
|
|
2020-11-29 19:33:09 +08:00
|
|
|
uint32_t blocks[4] = {T55x7_MODULATION_BIPHASE | T55x7_BITRATE_RF_64 | 3 << T55x7_MAXBLOCK_SHIFT, 0, 0, 0};
|
|
|
|
char cardtype[16] = {"T55x7"};
|
2019-03-10 06:35:06 +08:00
|
|
|
// Q5
|
2020-11-29 19:33:09 +08:00
|
|
|
if (q5) {
|
2020-10-12 19:08:34 +08:00
|
|
|
blocks[0] = T5555_FIXED | T5555_MODULATION_BIPHASE | T5555_SET_BITRATE(64) | 3 << T5555_MAXBLOCK_SHIFT;
|
2020-11-29 19:33:09 +08:00
|
|
|
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
|
|
|
|
}
|
|
|
|
|
|
|
|
// EM4305
|
|
|
|
if (em) {
|
|
|
|
blocks[0] = EM4305_GUARDPROXII_CONFIG_BLOCK;
|
|
|
|
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
|
|
|
|
}
|
2017-08-11 17:38:54 +08:00
|
|
|
|
2019-03-10 06:35:06 +08:00
|
|
|
blocks[1] = bytebits_to_byte(bs, 32);
|
|
|
|
blocks[2] = bytebits_to_byte(bs + 32, 32);
|
|
|
|
blocks[3] = bytebits_to_byte(bs + 64, 32);
|
2016-02-28 02:47:10 +08:00
|
|
|
|
2019-09-27 03:44:27 +08:00
|
|
|
free(bs);
|
2019-10-13 06:48:26 +08:00
|
|
|
|
2020-11-29 19:33:09 +08:00
|
|
|
PrintAndLogEx(INFO, "Preparing to clone Guardall to " _YELLOW_("%s") " with Facility Code: " _GREEN_("%u") " Card Number: " _GREEN_("%u")
|
|
|
|
, cardtype
|
|
|
|
, facilitycode
|
|
|
|
, cardnumber
|
|
|
|
);
|
2019-09-27 03:44:27 +08:00
|
|
|
print_blocks(blocks, ARRAYLEN(blocks));
|
2019-09-16 17:11:54 +08:00
|
|
|
|
2020-11-29 19:33:09 +08:00
|
|
|
int res;
|
|
|
|
if (em) {
|
|
|
|
res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false);
|
|
|
|
} else {
|
|
|
|
res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
|
|
|
}
|
2020-03-11 00:06:00 +08:00
|
|
|
PrintAndLogEx(SUCCESS, "Done");
|
2020-11-29 19:53:39 +08:00
|
|
|
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf gproxii reader`") " to verify");
|
2020-03-11 00:06:00 +08:00
|
|
|
return res;
|
2016-02-28 02:47:10 +08:00
|
|
|
}
|
|
|
|
|
2019-04-12 07:55:25 +08:00
|
|
|
static int CmdGuardSim(const char *Cmd) {
|
2016-02-28 02:47:10 +08:00
|
|
|
|
2020-11-29 19:33:09 +08:00
|
|
|
CLIParserContext *ctx;
|
2020-11-29 19:53:39 +08:00
|
|
|
CLIParserInit(&ctx, "lf gproxii sim",
|
2020-11-29 19:33:09 +08:00
|
|
|
"Enables simulation of Guardall card with specified card number.\n"
|
|
|
|
"Simulation runs until the button is pressed or another USB command is issued.\n"
|
|
|
|
"The facility-code is 8-bit and the card number is 16-bit. Larger values are truncated.\n"
|
|
|
|
"Currently work only on 26bit",
|
2020-11-29 19:53:39 +08:00
|
|
|
"lf gproxii sim --fmt 26 --fc 123 --cn 1337\n"
|
2020-11-29 19:33:09 +08:00
|
|
|
);
|
|
|
|
|
|
|
|
void *argtable[] = {
|
|
|
|
arg_param_begin,
|
|
|
|
arg_u64_1(NULL, "fmt", "<dec>", "format length 26|32|36|40"),
|
|
|
|
arg_u64_1(NULL, "fc", "<dec>", "8-bit value facility code"),
|
|
|
|
arg_u64_1(NULL, "cn", "<dec>", "16-bit value card number"),
|
|
|
|
arg_param_end
|
|
|
|
};
|
|
|
|
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
|
|
|
|
|
|
|
uint32_t fmtlen = arg_get_u32_def(ctx, 1, 0);
|
|
|
|
uint32_t fc = arg_get_u32_def(ctx, 2, 0);
|
|
|
|
uint32_t cn = arg_get_u32_def(ctx, 3, 0);
|
|
|
|
CLIParserFree(ctx);
|
2016-02-28 02:47:10 +08:00
|
|
|
|
2020-11-29 19:33:09 +08:00
|
|
|
fmtlen &= 0x7F;
|
|
|
|
uint32_t facilitycode = (fc & 0x000000FF);
|
|
|
|
uint32_t cardnumber = (cn & 0x0000FFFF);
|
2016-02-28 02:47:10 +08:00
|
|
|
|
2019-03-10 06:35:06 +08:00
|
|
|
uint8_t bs[96];
|
2019-04-19 23:03:39 +08:00
|
|
|
memset(bs, 0x00, sizeof(bs));
|
2017-08-10 01:59:03 +08:00
|
|
|
|
2019-05-22 20:57:08 +08:00
|
|
|
if (getGuardBits(fmtlen, facilitycode, cardnumber, bs) != PM3_SUCCESS) {
|
2019-07-14 06:35:18 +08:00
|
|
|
PrintAndLogEx(ERR, "Error with tag bitstream generation.");
|
2019-05-22 20:57:08 +08:00
|
|
|
return PM3_ESOFT;
|
2019-03-10 06:35:06 +08:00
|
|
|
}
|
2016-02-28 02:47:10 +08:00
|
|
|
|
2020-11-29 19:33:09 +08:00
|
|
|
PrintAndLogEx(SUCCESS, "Simulating Guardall - Facility Code: " _YELLOW_("%u") " CardNumber: " _YELLOW_("%u")
|
|
|
|
, facilitycode
|
|
|
|
, cardnumber
|
|
|
|
);
|
2016-02-29 06:28:38 +08:00
|
|
|
|
2019-05-24 19:06:08 +08:00
|
|
|
// Guard uses: clk: 64, invert: 0, encoding: 2 (ASK Biphase)
|
|
|
|
lf_asksim_t *payload = calloc(1, sizeof(lf_asksim_t) + sizeof(bs));
|
|
|
|
payload->encoding = 2;
|
|
|
|
payload->invert = 0;
|
|
|
|
payload->separator = 0;
|
|
|
|
payload->clock = 64;
|
|
|
|
memcpy(payload->data, bs, sizeof(bs));
|
|
|
|
|
2019-03-10 06:35:06 +08:00
|
|
|
clearCommandBuffer();
|
2019-08-04 01:17:00 +08:00
|
|
|
SendCommandNG(CMD_LF_ASK_SIMULATE, (uint8_t *)payload, sizeof(lf_asksim_t) + sizeof(bs));
|
2019-05-24 19:06:08 +08:00
|
|
|
free(payload);
|
|
|
|
|
2019-05-09 06:08:59 +08:00
|
|
|
PacketResponseNG resp;
|
2019-08-04 01:17:00 +08:00
|
|
|
WaitForResponse(CMD_LF_ASK_SIMULATE, &resp);
|
2019-05-24 19:06:08 +08:00
|
|
|
|
|
|
|
PrintAndLogEx(INFO, "Done");
|
2019-05-10 02:20:54 +08:00
|
|
|
if (resp.status != PM3_EOPABORTED)
|
2019-05-09 06:08:59 +08:00
|
|
|
return resp.status;
|
|
|
|
return PM3_SUCCESS;
|
2016-02-28 02:47:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static command_t CommandTable[] = {
|
2019-05-02 02:48:15 +08:00
|
|
|
{"help", CmdHelp, AlwaysAvailable, "this help"},
|
|
|
|
{"demod", CmdGuardDemod, AlwaysAvailable, "demodulate a G Prox II tag from the GraphBuffer"},
|
2020-11-29 19:33:09 +08:00
|
|
|
{"reader", CmdGuardReader, IfPm3Lf, "attempt to read and extract tag data from the antenna"},
|
2020-08-28 17:14:42 +08:00
|
|
|
{"clone", CmdGuardClone, IfPm3Lf, "clone Guardall tag to T55x7 or Q5/T5555"},
|
2019-05-02 06:02:38 +08:00
|
|
|
{"sim", CmdGuardSim, IfPm3Lf, "simulate Guardall tag"},
|
2019-05-02 02:48:15 +08:00
|
|
|
{NULL, NULL, NULL, NULL}
|
2016-02-28 02:47:10 +08:00
|
|
|
};
|
|
|
|
|
2019-04-12 07:55:25 +08:00
|
|
|
static int CmdHelp(const char *Cmd) {
|
|
|
|
(void)Cmd; // Cmd is not used so far
|
|
|
|
CmdsHelp(CommandTable);
|
2019-05-22 20:57:08 +08:00
|
|
|
return PM3_SUCCESS;
|
2019-04-12 07:55:25 +08:00
|
|
|
}
|
|
|
|
|
2019-03-10 18:20:22 +08:00
|
|
|
int CmdLFGuard(const char *Cmd) {
|
2019-03-10 06:35:06 +08:00
|
|
|
clearCommandBuffer();
|
2019-04-19 06:47:51 +08:00
|
|
|
return CmdsParse(CommandTable, Cmd);
|
2016-02-28 02:47:10 +08:00
|
|
|
}
|
|
|
|
|
2019-04-12 07:55:25 +08:00
|
|
|
// demod gProxIIDemod
|
|
|
|
// error returns as -x
|
|
|
|
// success returns start position in bitstream
|
|
|
|
// Bitstream must contain previously askrawdemod and biphasedemoded data
|
|
|
|
int detectGProxII(uint8_t *bits, size_t *size) {
|
|
|
|
|
|
|
|
size_t startIdx = 0;
|
|
|
|
uint8_t preamble[] = {1, 1, 1, 1, 1, 0};
|
|
|
|
|
|
|
|
// sanity check
|
|
|
|
if (*size < sizeof(preamble)) return -1;
|
|
|
|
|
|
|
|
if (!preambleSearch(bits, preamble, sizeof(preamble), size, &startIdx))
|
|
|
|
return -2; //preamble not found
|
|
|
|
|
|
|
|
//gProxII should be 96 bits
|
|
|
|
if (*size != 96) return -3;
|
|
|
|
|
|
|
|
//check first 6 spacer bits to verify format
|
|
|
|
if (!bits[startIdx + 5] && !bits[startIdx + 10] && !bits[startIdx + 15] && !bits[startIdx + 20] && !bits[startIdx + 25] && !bits[startIdx + 30]) {
|
|
|
|
//confirmed proper separator bits found
|
|
|
|
//return start position
|
|
|
|
return (int) startIdx;
|
|
|
|
}
|
|
|
|
return -5; //spacer bits not found - not a valid gproxII
|
|
|
|
}
|
|
|
|
|
|
|
|
// Works for 26bits.
|
|
|
|
int getGuardBits(uint8_t fmtlen, uint32_t fc, uint32_t cn, uint8_t *guardBits) {
|
|
|
|
|
|
|
|
uint8_t xorKey = 0x66;
|
|
|
|
uint8_t i;
|
|
|
|
uint8_t pre[96];
|
|
|
|
uint8_t rawbytes[12];
|
|
|
|
memset(pre, 0x00, sizeof(pre));
|
|
|
|
memset(rawbytes, 0x00, sizeof(rawbytes));
|
|
|
|
|
|
|
|
// add format length (decimal)
|
|
|
|
switch (fmtlen) {
|
|
|
|
case 32: {
|
|
|
|
rawbytes[1] = (32 << 2);
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 36: {
|
|
|
|
rawbytes[1] = (36 << 2);
|
2020-09-10 17:44:32 +08:00
|
|
|
// Get wiegand from FacilityCode 14bits, CardNumber 20bits
|
|
|
|
uint8_t wiegand[36];
|
2019-04-12 07:55:25 +08:00
|
|
|
memset(wiegand, 0x00, sizeof(wiegand));
|
2020-09-10 17:44:32 +08:00
|
|
|
num_to_bytebits(fc, 14, wiegand);
|
|
|
|
num_to_bytebits(cn, 20, wiegand + 14);
|
2019-04-12 07:55:25 +08:00
|
|
|
|
|
|
|
// add wiegand parity bits (dest, source, len)
|
|
|
|
wiegand_add_parity(pre, wiegand, 34);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 40: {
|
|
|
|
rawbytes[1] = (40 << 2);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 26:
|
|
|
|
default: {
|
|
|
|
rawbytes[1] = (26 << 2);
|
|
|
|
// Get 26 wiegand from FacilityCode, CardNumber
|
|
|
|
uint8_t wiegand[24];
|
|
|
|
memset(wiegand, 0x00, sizeof(wiegand));
|
|
|
|
num_to_bytebits(fc, 8, wiegand);
|
|
|
|
num_to_bytebits(cn, 16, wiegand + 8);
|
|
|
|
|
|
|
|
// add wiegand parity bits (dest, source, len)
|
|
|
|
wiegand_add_parity(pre, wiegand, 24);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// 2bit checksum, unknown today,
|
|
|
|
// these two bits are the last ones of rawbyte[1], hence the LSHIFT above.
|
|
|
|
|
|
|
|
|
|
|
|
// xor key
|
|
|
|
rawbytes[0] = xorKey;
|
|
|
|
|
|
|
|
rawbytes[2] = 1;
|
|
|
|
rawbytes[3] = 0;
|
|
|
|
|
|
|
|
// add wiegand to rawbytes
|
2020-09-10 17:44:32 +08:00
|
|
|
for (i = 0; i < 5; ++i)
|
2019-04-12 07:55:25 +08:00
|
|
|
rawbytes[i + 4] = bytebits_to_byte(pre + (i * 8), 8);
|
|
|
|
|
2020-09-10 17:44:32 +08:00
|
|
|
PrintAndLogEx(DEBUG, " WIE | %s", sprint_hex(rawbytes, sizeof(rawbytes)));
|
2020-09-12 06:31:17 +08:00
|
|
|
|
2019-04-12 07:55:25 +08:00
|
|
|
// XOR (only works on wiegand stuff)
|
2020-09-10 17:44:32 +08:00
|
|
|
for (i = 1; i < sizeof(rawbytes); ++i)
|
2019-04-12 07:55:25 +08:00
|
|
|
rawbytes[i] ^= xorKey ;
|
|
|
|
|
2020-09-10 17:44:32 +08:00
|
|
|
PrintAndLogEx(DEBUG, " XOR | %s", sprint_hex(rawbytes, sizeof(rawbytes)));
|
2019-04-12 07:55:25 +08:00
|
|
|
|
|
|
|
// convert rawbytes to bits in pre
|
2020-09-10 17:44:32 +08:00
|
|
|
for (i = 0; i < sizeof(rawbytes); ++i)
|
2019-04-12 07:55:25 +08:00
|
|
|
num_to_bytebitsLSBF(rawbytes[i], 8, pre + (i * 8));
|
|
|
|
|
2020-09-10 17:44:32 +08:00
|
|
|
PrintAndLogEx(DEBUG, " Raw | %s", sprint_hex(rawbytes, sizeof(rawbytes)));
|
|
|
|
PrintAndLogEx(DEBUG, " Raw | %s", sprint_bin(pre, 96));
|
2019-04-12 07:55:25 +08:00
|
|
|
|
|
|
|
// add spacer bit 0 every 4 bits, starting with index 0,
|
2020-09-10 17:44:32 +08:00
|
|
|
// 12 bytes, 24 nibbles. 24+1 extra bites. 3bytes. ie 9bytes | 1byte xorkey, 8bytes rawdata (72bits, should be enough for a 40bit wiegand)
|
|
|
|
addParity(pre, guardBits + 6, 72, 5, 3);
|
2019-04-12 07:55:25 +08:00
|
|
|
|
|
|
|
// preamble
|
|
|
|
guardBits[0] = 1;
|
|
|
|
guardBits[1] = 1;
|
|
|
|
guardBits[2] = 1;
|
|
|
|
guardBits[3] = 1;
|
|
|
|
guardBits[4] = 1;
|
|
|
|
guardBits[5] = 0;
|
|
|
|
|
|
|
|
PrintAndLogEx(DEBUG, " FIN | %s\n", sprint_bin(guardBits, 96));
|
2019-05-22 20:57:08 +08:00
|
|
|
return PM3_SUCCESS;
|
2016-02-28 02:47:10 +08:00
|
|
|
}
|
2019-04-12 07:55:25 +08:00
|
|
|
|