mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-02-22 23:24:22 +08:00
cmdlfpac - add decode / encode card ID
This commit is contained in:
parent
c87e8faefc
commit
a290d18918
1 changed files with 120 additions and 15 deletions
|
@ -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));
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, "PAC/Stanley Tag Found -- Raw: %08X%08X%08X%08X", raw1, raw2, raw3, raw4);
|
if (retval == PM3_SUCCESS)
|
||||||
PrintAndLogEx(INFO, "How the Raw ID is translated by the reader is unknown. Share your trace file on forum");
|
PrintAndLogEx(SUCCESS, "PAC/Stanley Tag Found -- Card ID: %s, Raw: %08X%08X%08X%08X", cardid, raw1, raw2, raw3, raw4);
|
||||||
return PM3_SUCCESS;
|
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
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"},
|
||||||
|
|
Loading…
Reference in a new issue