Merge pull request #1996 from jerji/master

Add ability to simulate paradox fobs from fc and cn
This commit is contained in:
Iceman 2023-06-04 21:59:28 +02:00 committed by GitHub
commit 005fddfe6d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 143 additions and 94 deletions

View file

@ -70,7 +70,9 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
- Updated documentation for installation on macOS with MacPorts (@linuxgemini)
- Added possible Paxton id to hitag2 tag info output
- Changed `hf mf sim` - reduce 50ms threshold to 6ms for reset to idle #1974 (@net147)
- Updated `amiibo_tools.lua` with new identifiers and create a python script `update_amiibo_tools_lua.py` to automate the process in the future. (@CorySolovewicz)
- Update `amiibo_tools.lua` with new identifiers and create a python script `update_amiibo_tools_lua.py` to automate the process in the future. (@CorySolovewicz)
- Added `lf paradox sim --fc --cn` - Simulates Paradox fob from facility code and card number (jerji)
## [Nitride.4.16191][2023-01-29]
- Changed `build_all_firmwares.sh` to fit GENERIC 256kb firmware images (@doegox)

View file

@ -1680,7 +1680,7 @@ int CmdLFfind(const char *Cmd) {
goto out;
}
}
if (demodParadox(true) == PM3_SUCCESS) {
if (demodParadox(true, false) == PM3_SUCCESS) {
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Paradox ID") " found!");
if (search_cont) {
found++;

View file

@ -20,7 +20,6 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "commonutil.h" // ARRAYLEN
#include "cmdparser.h" // command_t
#include "comms.h"
@ -53,7 +52,55 @@ static const uint8_t paradox_lut[] = {
// Paradox Prox demod - FSK2a RF/50 with preamble of 00001111 (then manchester encoded)
// print full Paradox Prox ID and some bit format details if found
int demodParadox(bool verbose) {
// This function will calculate the bitstream for a paradox card and place the result in bs.
// It returns the calculated CRC from the fc and cn.
// CRC calculation by mwalker33
static uint8_t GetParadoxBits(const uint32_t fc, const uint32_t cn, unsigned int *bs) {
uint8_t manchester[13] = { 0x00 }; // check size needed
uint32_t t1;
manchester[0] = 0x0F; // preamble
manchester[1] = 0x05; // Leading zeros - Note: from this byte on, is part of the CRC calculation
manchester[2] = 0x55; // Leading zeros its 4 bits out for the CRC, so we need to move
manchester[3] = 0x55; // Leading zeros back 4 bits once we have the crc (done below)
// add FC
t1 = manchesterEncode2Bytes(fc);
manchester[4] = (t1 >> 8) & 0xFF;
manchester[5] = t1 & 0xFF;
// add cn
t1 = manchesterEncode2Bytes(cn);
manchester[6] = (t1 >> 24) & 0xFF;
manchester[7] = (t1 >> 16) & 0xFF;
manchester[8] = (t1 >> 8) & 0xFF;
manchester[9] = t1 & 0xFF;
uint8_t crc = (CRC8Maxim(manchester + 1, 9) ^ 0x6) & 0xFF;
// add crc
t1 = manchesterEncode2Bytes(crc);
manchester[10] = (t1 >> 8) & 0xFF;
manchester[11] = t1 & 0xFF;
// move left 4 bits left 4 bits - Now that we have the CRC we need to re-align the data.
for (int i = 1; i < 12; i++)
manchester[i] = (manchester[i] << 4) + (manchester[i + 1] >> 4);
// Add trailing 1010 (11)
manchester[11] |= (1 << 3);
manchester[11] |= (1 << 1);
// move into tag blocks
for (int i = 0; i < 12; i++)
bs[1 + (i / 4)] += (manchester[i] << (8 * (3 - i % 4)));
return crc;
}
int demodParadox(bool verbose, bool oldChksum) {
(void) verbose; // unused so far
//raw fsk demod no manchester decoding no start bit finding just get binary from wave
uint8_t bits[MAX_GRAPH_TRACE_LEN] = {0};
@ -134,34 +181,39 @@ int demodParadox(bool verbose) {
uint32_t fc = ((hi & 0x3) << 6) | (lo >> 26);
uint32_t cardnum = (lo >> 10) & 0xFFFF;
uint8_t chksum = (lo >> 2) & 0xFF;
if (oldChksum) {
// Calc CRC & Checksum
// 000088f0b - FC: 8 - Card: 36619 - Checksum: 05 - RAW: 0f55555559595aa559a5566a
// checksum?
uint8_t calc_chksum = 0x47;
uint8_t pos = 0;
for (uint8_t i = 0; i < 8; i++) {
uint8_t ice = rawhex[i + 1];
for (uint8_t j = 0x80; j > 0; j >>= 2) {
// Calc CRC & Checksum
// 000088f0b - FC: 8 - Card: 36619 - Checksum: 05 - RAW: 0f55555559595aa559a5566a
// checksum?
uint8_t calc_chksum = 0x47;
uint8_t pos = 0;
for (uint8_t i = 0; i < 8; i++) {
uint8_t ice = rawhex[i + 1];
for (uint8_t j = 0x80; j > 0; j >>= 2) {
if (ice & j) {
calc_chksum ^= paradox_lut[pos];
if (ice & j) {
calc_chksum ^= paradox_lut[pos];
}
pos++;
}
pos++;
}
uint32_t crc = CRC8Maxim(rawhex + 1, 8);
PrintAndLogEx(INFO, " FSK/MAN raw : %s", sprint_hex(rawhex, sizeof(rawhex)));
PrintAndLogEx(INFO, " raw : %s = (maxim crc8) %02x == %02x", sprint_hex(rawhex + 1, 8), crc,
calc_chksum);
// PrintAndLogEx(DEBUG, " OTHER sample CRC-8/MAXIM : 55 55 69 A5 55 6A 59 5A = FC");
}
uint32_t crc = CRC8Maxim(rawhex + 1, 8);
PrintAndLogEx(DEBUG, " FSK/MAN raw : %s", sprint_hex(rawhex, sizeof(rawhex)));
PrintAndLogEx(DEBUG, " raw : %s = (maxim crc8) %02x == %02x", sprint_hex(rawhex + 1, 8), crc, calc_chksum);
// PrintAndLogEx(DEBUG, " OTHER sample CRC-8/MAXIM : 55 55 69 A5 55 6A 59 5A = FC");
uint32_t rawLo = bytebits_to_byte(bits + idx + 64, 32);
uint32_t rawHi = bytebits_to_byte(bits + idx + 32, 32);
uint32_t rawHi2 = bytebits_to_byte(bits + idx, 32);
uint32_t blocks[4] = {0};
uint8_t crc = GetParadoxBits(fc, cardnum, blocks);
if (chksum != crc)
PrintAndLogEx(ERR, "CRC Error! Calculated CRC is " _GREEN_("%d") " but card CRC is " _RED_("%d") ".", crc, chksum);
PrintAndLogEx(INFO, "Paradox - ID: " _GREEN_("%x%08x") " FC: " _GREEN_("%d") " Card: " _GREEN_("%d") ", Checksum: %02x, Raw: %08x%08x%08x",
hi >> 10,
(hi & 0x3) << 26 | (lo >> 10),
@ -185,32 +237,37 @@ static int CmdParadoxDemod(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf paradox demod",
"Try to find Paradox preamble, if found decode / descramble data",
"lf paradox demod"
"lf paradox demod --old -> Display previous checksum version"
);
void *argtable[] = {
arg_param_begin,
arg_lit0(NULL, "old", "optional - Display previous checksum version"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
bool old = arg_get_lit(ctx, 1);
CLIParserFree(ctx);
return demodParadox(true);
return demodParadox(true, old);
}
static int CmdParadoxReader(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf paradox reader",
"read a Paradox tag",
"lf Paradox reader -@ -> continuous reader mode"
"lf paradox reader -@ -> continuous reader mode\n"
"lf paradox reader --old -> Display previous checksum version"
);
void *argtable[] = {
arg_param_begin,
arg_lit0("@", NULL, "optional - continuous reader mode"),
arg_lit0(NULL, "old", "optional - Display previous checksum version"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
bool cm = arg_get_lit(ctx, 1);
bool old = arg_get_lit(ctx, 2);
CLIParserFree(ctx);
if (cm) {
@ -219,7 +276,7 @@ static int CmdParadoxReader(const char *Cmd) {
do {
lf_read(false, 10000);
demodParadox(!cm);
demodParadox(!cm, old);
} while (cm && !kbd_enter_pressed());
return PM3_SUCCESS;
@ -230,7 +287,7 @@ static int CmdParadoxClone(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf paradox clone",
"clone a paradox tag to a T55x7, Q5/T5555 or EM4305/4469 tag.",
"lf paradox clone --fc 96 --cn 40426 -> encode for T55x7 tag with fc and cn\n"
"lf paradox clone --fc 96 --cn 40426 -> encode for T55x7 tag with fc and cn\n"
"lf paradox clone --raw 0f55555695596a6a9999a59a -> encode for T55x7 tag\n"
"lf paradox clone --raw 0f55555695596a6a9999a59a --q5 -> encode for Q5/T5555 tag\n"
"lf paradox clone --raw 0f55555695596a6a9999a59a --em -> encode for EM4305/4469"
@ -263,6 +320,16 @@ static int CmdParadoxClone(const char *Cmd) {
return PM3_EINVARG;
}
if ((fc || cn) && raw_len != 0) {
PrintAndLogEx(FAILED, "Can't specify both FC/CN and RAW at the same time");
return PM3_EINVARG;
}
if (fc > 999 || cn > 99999) {
PrintAndLogEx(FAILED, "FC has a max value of 999 and CN has a max value of 99999");
return PM3_EINVARG;
}
uint32_t blocks[4] = {0};
if (raw_len != 0) {
@ -275,44 +342,8 @@ static int CmdParadoxClone(const char *Cmd) {
blocks[i] = bytes_to_num(raw + ((i - 1) * 4), sizeof(uint32_t));
}
} else {
uint8_t manchester[13] = { 0x00 }; // check size needed
uint32_t t1;
manchester[0] = 0x0F; // preamble
manchester[1] = 0x05; // Leading zeros - Note: from this byte on, is part of the CRC calculation
manchester[2] = 0x55; // Leading zeros its 4 bits out for the CRC, so we need too move
manchester[3] = 0x55; // Leading zeros back 4 bits once we have the crc (done below)
// add FC
t1 = manchesterEncode2Bytes(fc);
manchester[4] = (t1 >> 8) & 0xFF;
manchester[5] = t1 & 0xFF;
// add cn
t1 = manchesterEncode2Bytes(cn);
manchester[6] = (t1 >> 24) & 0xFF;
manchester[7] = (t1 >> 16) & 0xFF;
manchester[8] = (t1 >> 8) & 0xFF;
manchester[9] = t1 & 0xFF;
uint8_t crc = (CRC8Maxim(manchester + 1, 9) ^ 0x6) & 0xFF;
// add crc
t1 = manchesterEncode2Bytes(crc);
manchester[10] = (t1 >> 8) & 0xFF;
manchester[11] = t1 & 0xFF;
// move left 4 bits left 4 bits - Now that we have the CRC we need to re-align the data.
for (int i = 1; i < 12; i++)
manchester[i] = (manchester[i] << 4) + (manchester[i + 1] >> 4);
// Add trailing 1010 (11)
manchester[11] |= (1 << 3);
manchester[11] |= (1 << 1);
// move into tag blocks
for (int i = 0; i < 12; i++)
blocks[1 + (i / 4)] += (manchester[i] << (8 * (3 - i % 4)));
//This function generates the bitstream and puts it in blocks. it returns the crc, but we don't need it here
GetParadoxBits(fc, cn, blocks);
}
// Paradox - FSK2a, data rate 50, 3 data blocks
@ -355,12 +386,15 @@ static int CmdParadoxSim(const char *Cmd) {
CLIParserInit(&ctx, "lf paradox sim",
"Enables simulation of paradox card with specified card number.\n"
"Simulation runs until the button is pressed or another USB command is issued.",
"lf paradox sim --raw 0f55555695596a6a9999a59a"
"lf paradox sim --raw 0f55555695596a6a9999a59a -> simulate tag\n"
"lf paradox sim --fc 96 --cn 40426 -> simulate tag with fc and cn\n"
);
void *argtable[] = {
arg_param_begin,
arg_str0("r", "raw", "<hex>", " raw hex data. 12 bytes"),
arg_str0("r", "raw", "<hex>", "raw hex data. 12 bytes"),
arg_u64_0(NULL, "fc", "<dec>", "facility code"),
arg_u64_0(NULL, "cn", "<dec>", "card number"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
@ -369,13 +403,32 @@ static int CmdParadoxSim(const char *Cmd) {
// skip first block, 3*4 = 12 bytes left
uint8_t raw[12] = {0};
CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
uint32_t fc = arg_get_u32_def(ctx, 2, 0);
uint32_t cn = arg_get_u32_def(ctx, 3, 0);
CLIParserFree(ctx);
if (raw_len != 12) {
PrintAndLogEx(ERR, "Data must be 12 bytes (24 HEX characters) %d", raw_len);
if ((fc || cn) && raw_len != 0) {
PrintAndLogEx(FAILED, "Can't specify both FC/CN and RAW at the same time");
return PM3_EINVARG;
}
if (fc > 999 || cn > 99999) {
PrintAndLogEx(FAILED, "FC has a max value of 999 and CN has a max value of 99999");
return PM3_EINVARG;
}
if (raw_len != 0) {
if (raw_len != 12) {
PrintAndLogEx(ERR, "Data must be 12 bytes (24 HEX characters) %d", raw_len);
return PM3_EINVARG;
}
} else {
uint32_t blocks[4] = {0};
GetParadoxBits(fc, cn, blocks);
for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) {
num_to_bytes(blocks[i], sizeof(uint32_t), raw + ((i - 1) * 4));
}
}
PrintAndLogEx(SUCCESS, "Simulating Paradox - raw " _YELLOW_("%s"), sprint_hex_inrow(raw, sizeof(raw)));
uint8_t bs[sizeof(raw) * 8];
@ -404,21 +457,8 @@ static int CmdParadoxSim(const char *Cmd) {
return PM3_SUCCESS;
}
/*
if (sscanf(Cmd, "%u %u", &fc, &cn) != 2) return usage_lf_paradox_sim();
facilitycode = (fc & 0x000000FF);
cardnumber = (cn & 0x0000FFFF);
// if ( GetParadoxBits(facilitycode, cardnumber, bs) != PM3_SUCCESS) {
// PrintAndLogEx(ERR, "Error with tag bitstream generation.");
// return 1;
// }
PrintAndLogEx(NORMAL, "Simulating Paradox - Facility Code: %u, CardNumber: %u", facilitycode, cardnumber);
*/
static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"},
{"demod", CmdParadoxDemod, AlwaysAvailable, "demodulate a Paradox FSK tag from the GraphBuffer"},

View file

@ -22,6 +22,6 @@
int CmdLFParadox(const char *Cmd);
int demodParadox(bool verbose);
int demodParadox(bool verbose, bool oldChksum);
int detectParadox(uint8_t *dest, size_t *size, int *wave_start_idx);
#endif

View file

@ -9658,13 +9658,14 @@
"command": "lf paradox demod",
"description": "Try to find Paradox preamble, if found decode / descramble data",
"notes": [
"lf paradox demod"
"lf paradox demod --old -> Display previous checksum version"
],
"offline": true,
"options": [
"-h, --help This help"
"-h, --help This help",
"--old optional - Display previous checksum version"
],
"usage": "lf paradox demod [-h]"
"usage": "lf paradox demod [-h] [--old]"
},
"lf paradox help": {
"command": "lf paradox help",
@ -9678,27 +9679,32 @@
"command": "lf paradox reader",
"description": "read a Paradox tag",
"notes": [
"lf Paradox reader -@ -> continuous reader mode"
"lf paradox reader -@ -> continuous reader mode",
"lf paradox reader --old -> Display previous checksum version"
],
"offline": false,
"options": [
"-h, --help This help",
"-@ optional - continuous reader mode"
"-@ optional - continuous reader mode",
"--old optional - Display previous checksum version"
],
"usage": "lf paradox reader [-h@]"
"usage": "lf paradox reader [-h@] [--old]"
},
"lf paradox sim": {
"command": "lf paradox sim",
"description": "Enables simulation of paradox card with specified card number. Simulation runs until the button is pressed or another USB command is issued.",
"notes": [
"lf paradox sim --raw 0f55555695596a6a9999a59a"
"lf paradox sim --raw 0f55555695596a6a9999a59a -> simulate tag",
"lf paradox sim --fc 96 --cn 40426 -> simulate tag with fc and cn"
],
"offline": false,
"options": [
"-h, --help This help",
"-r, --raw <hex> raw hex data. 12 bytes"
"-r, --raw <hex> raw hex data. 12 bytes",
"--fc <dec> facility code",
"--cn <dec> card number"
],
"usage": "lf paradox sim [-h] [-r <hex>]"
"usage": "lf paradox sim [-h] [-r <hex>] [--fc <dec>] [--cn <dec>]"
},
"lf pcf7931 config": {
"command": "lf pcf7931 config",
@ -12018,6 +12024,7 @@
"metadata": {
"commands_extracted": 755,
"extracted_by": "PM3Help2JSON v1.00",
"extracted_on": "2023-06-02T08:44:26"
"extracted_on": "2023-06-04T15:36:56"
}
}