cmdlfpac - add decode / encode card ID

This commit is contained in:
danshuk 2020-01-01 00:12:09 +00:00
parent c87e8faefc
commit a290d18918

View file

@ -4,8 +4,8 @@
// at your option, any later version. See the LICENSE.txt file for the text of // at your option, any later version. See the LICENSE.txt file for the text of
// the license. // the license.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Low frequency Stanley/PAC tag commands // Low frequency PAC/Stanley tag commands
// NRZ, RF/32, 128 bits long (unknown cs) // NRZ, RF/32, 128 bits long
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include "cmdlfpac.h" #include "cmdlfpac.h"
@ -21,22 +21,111 @@
#include "lfdemod.h" // preamble test #include "lfdemod.h" // preamble test
#include "protocols.h" // t55xx defines #include "protocols.h" // t55xx defines
#include "cmdlft55xx.h" // clone.. #include "cmdlft55xx.h" // clone..
#include "parity.h"
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
static int usage_lf_pac_clone(void) { static int usage_lf_pac_clone(void) {
PrintAndLogEx(NORMAL, "clone a Stanley/PAC tag to a T55x7 tag."); PrintAndLogEx(NORMAL, "clone a PAC/Stanley tag to a T55x7 tag.");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf pac clone [h] [b <raw hex>]"); PrintAndLogEx(NORMAL, "Usage: lf pac clone [h] [c <card id>] [b <raw hex>]");
PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : this help"); PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, " b <raw hex> : raw hex data. 12 bytes max"); PrintAndLogEx(NORMAL, " c <card id> : 8 byte card ID");
PrintAndLogEx(NORMAL, " b <raw hex> : raw hex data. 16 bytes max");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf pac clone c CD4F5552 ");
PrintAndLogEx(NORMAL, " lf pac clone b FF2049906D8511C593155B56D5B2649F "); PrintAndLogEx(NORMAL, " lf pac clone b FF2049906D8511C593155B56D5B2649F ");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
// by danshuk
// PAC_8byte format: preamble (8 mark/idle bits), ascii STX (02), ascii '2' (32), ascii '0' (30), ascii bytes 0..7 (cardid), then xor checksum of cardid bytes
// all bytes following 8 bit preamble are one start bit (0), 7 data bits (lsb first), odd parity bit, and one stop bit (1)
static int demodbuf_to_pacid(uint8_t *src, const size_t src_size, uint8_t *dst, const size_t dst_size) {
const size_t byteLength = 10; // start bit, 7 data bits, parity bit, stop bit
const size_t startIndex = 8 + (3 * byteLength) + 1; // skip 8 bits preamble, STX, '2', '0', and first start bit
const size_t dataLength = 9;
if (startIndex + byteLength * (dataLength - 1) > src_size) {
PrintAndLogEx(DEBUG, "DEBUG: Error - PAC: Source buffer too small");
return PM3_EOVFLOW;
}
if (dataLength > dst_size) {
PrintAndLogEx(DEBUG, "DEBUG: Error - PAC: Destination buffer too small");
return PM3_EOVFLOW;
}
uint8_t checksum = 0;
for (size_t idx = 0; idx < dataLength; idx++) {
uint8_t byte = (uint8_t)bytebits_to_byteLSBF(src + startIndex + (byteLength * idx), 8);
dst[idx] = byte & 0x7F; // discard the parity bit
if (oddparity8(dst[idx]) != (byte & 0x80) >> 7) {
PrintAndLogEx(DEBUG, "DEBUG: Error - PAC: Parity check failed");
return PM3_ESOFT;
}
if (idx < dataLength - 1) checksum ^= byte;
}
if (dst[dataLength - 1] != checksum) {
PrintAndLogEx(DEBUG, "DEBUG: Error - PAC: Bad checksum - expected: %02X, actual: %02X", dst[dataLength - 1], checksum);
return PM3_ESOFT;
}
dst[dataLength - 1] = 0; // overwrite checksum byte with null terminator
return PM3_SUCCESS;
}
/*
// convert a 16 byte array of raw demod data (FF204990XX...) to 8 bytes of PAC_8byte ID
// performs no parity or checksum validation
static void pacRawToCardId(uint8_t* outCardId, const uint8_t* rawBytes) {
for (int i = 4; i < 12; i++) {
uint8_t shift = 7 - (i + 3) % 4 * 2;
size_t index = i + (i - 1) / 4;
outCardId[i - 4] = reflect8((((rawBytes[index] << 8) | (rawBytes[index + 1])) >> shift) & 0xFE);
}
}
*/
// convert 8 bytes of PAC_8byte ID to 16 byte array of raw data (FF204990XX...)
static void pacCardIdToRaw(uint8_t* outRawBytes, const char* cardId) {
uint8_t idbytes[10];
// prepend PAC_8byte card type "20"
idbytes[0] = '2';
idbytes[1] = '0';
for (size_t i = 0; i < 8; i++)
idbytes[i + 2] = toupper(cardId[i]);
// initialise array with start and stop bits
for (size_t i = 0; i < 16; i++)
outRawBytes[i] = 0x40 >> (i + 3) % 5 * 2;
outRawBytes[0] = 0xFF; // mark + stop
outRawBytes[1] = 0x20; // start + reflect8(STX)
uint8_t checksum = 0;
for (size_t i = 2; i < 13; i++) {
uint8_t shift = 7 - (i + 3) % 4 * 2;
uint8_t index = i + (i - 1) / 4;
uint16_t pattern;
if (i < 12) {
pattern = reflect8(idbytes[i - 2]);
pattern |= oddparity8(pattern);
if (i > 3) checksum ^= idbytes[i - 2];
}
else
pattern = (reflect8(checksum) & 0xFE) | oddparity8(checksum);
pattern <<= shift;
outRawBytes[index] |= pattern >> 8 & 0xFF;
outRawBytes[index + 1] |= pattern & 0xFF;
}
}
//see NRZDemod for what args are accepted //see NRZDemod for what args are accepted
static int CmdPacDemod(const char *Cmd) { static int CmdPacDemod(const char *Cmd) {
@ -68,13 +157,14 @@ static int CmdPacDemod(const char *Cmd) {
uint32_t raw3 = bytebits_to_byte(DemodBuffer + 64, 32); uint32_t raw3 = bytebits_to_byte(DemodBuffer + 64, 32);
uint32_t raw4 = bytebits_to_byte(DemodBuffer + 96, 32); uint32_t raw4 = bytebits_to_byte(DemodBuffer + 96, 32);
// preamble then appears to have marker bits of "10" CS? const size_t idLen = 9; // 8 bytes + null terminator
// 11111111001000000 10 01001100 10 00001101 10 00001101 10 00001101 10 00001101 10 00001101 10 00001101 10 00001101 10 00001101 10 10001100 10 100000001 uint8_t cardid[idLen];
// unknown checksum 9 bits at the end int retval = demodbuf_to_pacid(DemodBuffer, DemodBufferLen, cardid, sizeof(cardid));
if (retval == PM3_SUCCESS)
PrintAndLogEx(SUCCESS, "PAC/Stanley Tag Found -- Card ID: %s, Raw: %08X%08X%08X%08X", cardid, raw1, raw2, raw3, raw4);
PrintAndLogEx(SUCCESS, "PAC/Stanley Tag Found -- Raw: %08X%08X%08X%08X", raw1, raw2, raw3, raw4); return retval;
PrintAndLogEx(INFO, "How the Raw ID is translated by the reader is unknown. Share your trace file on forum");
return PM3_SUCCESS;
} }
static int CmdPacRead(const char *Cmd) { static int CmdPacRead(const char *Cmd) {
@ -93,6 +183,21 @@ static int CmdPacClone(const char *Cmd) {
switch (tolower(param_getchar(Cmd, cmdp))) { switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h': case 'h':
return usage_lf_pac_clone(); return usage_lf_pac_clone();
case 'c': {
// skip first block, 4*4 = 16 bytes left
uint8_t rawhex[16] = {0};
char cardid[9];
int res = param_getstr(Cmd, cmdp + 1, cardid, sizeof(cardid));
if (res < 8)
errors = true;
pacCardIdToRaw(rawhex, cardid);
for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) {
blocks[i] = bytes_to_num(rawhex + ((i - 1) * 4), sizeof(uint32_t));
}
cmdp += 2;
break;
}
case 'b': { case 'b': {
// skip first block, 4*4 = 16 bytes left // skip first block, 4*4 = 16 bytes left
uint8_t rawhex[16] = {0}; uint8_t rawhex[16] = {0};
@ -115,10 +220,10 @@ static int CmdPacClone(const char *Cmd) {
if (errors || cmdp == 0) return usage_lf_pac_clone(); if (errors || cmdp == 0) return usage_lf_pac_clone();
//Pac - compat mode, NRZ, data rate 40, 3 data blocks //Pac - compat mode, NRZ, data rate 32, 3 data blocks
blocks[0] = T55x7_MODULATION_DIRECT | T55x7_BITRATE_RF_40 | 4 << T55x7_MAXBLOCK_SHIFT; blocks[0] = T55x7_MODULATION_DIRECT | T55x7_BITRATE_RF_32 | 4 << T55x7_MAXBLOCK_SHIFT;
PrintAndLogEx(INFO, "Preparing to clone Securakey to T55x7 with raw hex"); PrintAndLogEx(INFO, "Preparing to clone PAC/Stanley tag to T55x7 with raw hex");
print_blocks(blocks, ARRAYLEN(blocks)); print_blocks(blocks, ARRAYLEN(blocks));
return clone_t55xx_tag(blocks, ARRAYLEN(blocks)); return clone_t55xx_tag(blocks, ARRAYLEN(blocks));
@ -133,7 +238,7 @@ static int CmdPacSim(const char *Cmd) {
static command_t CommandTable[] = { static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"}, {"help", CmdHelp, AlwaysAvailable, "This help"},
{"demod", CmdPacDemod, AlwaysAvailable, "Demodulate an PAC tag from the GraphBuffer"}, {"demod", CmdPacDemod, AlwaysAvailable, "Demodulate a PAC tag from the GraphBuffer"},
{"read", CmdPacRead, IfPm3Lf, "Attempt to read and extract tag data from the antenna"}, {"read", CmdPacRead, IfPm3Lf, "Attempt to read and extract tag data from the antenna"},
{"clone", CmdPacClone, IfPm3Lf, "clone PAC tag to T55x7"}, {"clone", CmdPacClone, IfPm3Lf, "clone PAC tag to T55x7"},
{"sim", CmdPacSim, IfPm3Lf, "simulate PAC tag"}, {"sim", CmdPacSim, IfPm3Lf, "simulate PAC tag"},