mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2026-05-12 11:18:11 -07:00
client: unify wiegand input handling
Extract the reusable Wiegand normalization and packing flow into wiegand_formatutils and move existing callers onto that shared path. This rebuilds the feat-wiegand branch as one focused commit against upstream/master instead of trying to preserve the original commit chain. Key changes: - add shared helpers for plain binary, raw HID, new PACS, and formatted Wiegand input - centralize binary rendering used by cmdwiegand and PACS decode output - update lf hid sim/clone to resolve one input mode through the shared Wiegand layer and enforce the LF packed transport limit explicitly - update hf mf encodehid to accept bin/raw/new/formatted Wiegand input through the same normalization path - preserve legacy raw HID transport behavior while clarifying the packed-HID vs LF transport limits in error reporting - add offline regression coverage for the new PACS decode output and add interactive online targets for LF HID Wiegand and MIFARE encodehid Validation performed: - make client - bash -n tools/pm3_tests.sh - bash -n tools/pm3_online_tests.sh - ./tools/pm3_online_tests.sh -h - ./client/proxmark3 -c 'wiegand encode -w H10301 --fc 31 --cn 337' - ./client/proxmark3 -c 'wiegand encode -w H10301 --fc 31 --cn 337 --new' - ./client/proxmark3 -c 'wiegand decode --new 068F80A8C0'
This commit is contained in:
+93
-50
@@ -10045,18 +10045,49 @@ static int CmdHF14AMfValue(const char *Cmd) {
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int hfmf_encodehid_pack_block5(const char *binstr, uint8_t *block) {
|
||||
if (binstr == NULL || block == NULL) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
char bits_with_sentinel[121] = {0};
|
||||
size_t binlen = strlen(binstr);
|
||||
|
||||
if (binlen == 0 || (binlen + 1) > 120) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
bits_with_sentinel[0] = '1';
|
||||
memcpy(bits_with_sentinel + 1, binstr, binlen + 1);
|
||||
|
||||
size_t hexlen = 0;
|
||||
uint8_t hex[15] = {0};
|
||||
binstr_2_bytes(hex, &hexlen, bits_with_sentinel);
|
||||
if (hexlen == 0 || hexlen > (MFBLOCK_SIZE - 1)) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
memset(block + 1, 0x00, MFBLOCK_SIZE - 1);
|
||||
memcpy(block + 1 + ((MFBLOCK_SIZE - 1) - hexlen), hex, hexlen);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdHFMFHidEncode(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf mf encodehid",
|
||||
"Encode binary wiegand to card\n"
|
||||
"Use either --bin or --wiegand/--fc/--cn",
|
||||
"Encode HID/Wiegand data to a MIFARE Classic card\n"
|
||||
"Use one of --bin, --raw, --new, or --wiegand/--fc/--cn",
|
||||
"hf mf encodehid --bin 10001111100000001010100011 -> FC 31 CN 337 (H10301)\n"
|
||||
"hf mf encodehid --raw 063E02A3\n"
|
||||
"hf mf encodehid --new 068F80A8C0\n"
|
||||
"hf mf encodehid -w H10301 --fc 31 --cn 337\n"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str0(NULL, "bin", "<bin>", "Binary string i.e 0001001001"),
|
||||
arg_str0(NULL, "raw", "<hex>", "HID raw hex with sentinel bit already present"),
|
||||
arg_str0(NULL, "new", "<hex>", "new ASN.1 PACS hex from `wiegand encode --new`"),
|
||||
arg_u64_0(NULL, "fc", "<dec>", "facility code"),
|
||||
arg_u64_0(NULL, "cn", "<dec>", "card number"),
|
||||
arg_str0("w", "wiegand", "<format>", "see " _YELLOW_("`wiegand list`") " for available formats"),
|
||||
@@ -10068,31 +10099,59 @@ static int CmdHFMFHidEncode(const char *Cmd) {
|
||||
uint8_t bin[121] = {0};
|
||||
int bin_len = sizeof(bin) - 1; // CLIGetStrWithReturn does not guarantee string to be null-terminated
|
||||
CLIGetStrWithReturn(ctx, 1, bin, &bin_len);
|
||||
bin[bin_len] = '\0';
|
||||
|
||||
uint8_t raw[15] = {0};
|
||||
int raw_len = 0;
|
||||
int res = CLIParamHexToBuf(arg_get_str(ctx, 2), raw, sizeof(raw), &raw_len);
|
||||
|
||||
uint8_t new_pacs[13] = {0};
|
||||
int new_pacs_len = 0;
|
||||
res |= CLIParamHexToBuf(arg_get_str(ctx, 3), new_pacs, sizeof(new_pacs), &new_pacs_len);
|
||||
|
||||
wiegand_card_t card;
|
||||
memset(&card, 0, sizeof(wiegand_card_t));
|
||||
card.FacilityCode = arg_get_u32_def(ctx, 2, 0);
|
||||
card.CardNumber = arg_get_u32_def(ctx, 3, 0);
|
||||
card.FacilityCode = arg_get_u32_def(ctx, 4, 0);
|
||||
card.CardNumber = arg_get_u32_def(ctx, 5, 0);
|
||||
|
||||
char format[16] = {0};
|
||||
int format_len = 0;
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 4), (uint8_t *)format, sizeof(format), &format_len);
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 6), (uint8_t *)format, sizeof(format), &format_len);
|
||||
|
||||
bool verbose = arg_get_lit(ctx, 5);
|
||||
bool verbose = arg_get_lit(ctx, 7);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
// santity checks
|
||||
if (bin_len > 120) {
|
||||
if (res) {
|
||||
PrintAndLogEx(ERR, "Error parsing hex input");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (bin_len > 119) {
|
||||
PrintAndLogEx(ERR, "Binary wiegand string must be less than 120 bits");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (bin_len == 0 && card.FacilityCode == 0 && card.CardNumber == 0) {
|
||||
PrintAndLogEx(ERR, "Must provide either --cn/--fc or --bin");
|
||||
int input_modes = 0;
|
||||
input_modes += (bin_len > 0);
|
||||
input_modes += (raw_len > 0);
|
||||
input_modes += (new_pacs_len > 0);
|
||||
input_modes += (format_len > 0 || card.FacilityCode != 0 || card.CardNumber != 0);
|
||||
if (input_modes != 1) {
|
||||
PrintAndLogEx(ERR, "Use exactly one of `--bin`, `--raw`, `--new`, or `--wiegand/--fc/--cn`");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
uint8_t blocks[] = {
|
||||
if (format_len > 0 && card.FacilityCode == 0 && card.CardNumber == 0) {
|
||||
PrintAndLogEx(ERR, "`--wiegand` requires `--fc` or `--cn`");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (format_len == 0 && (card.FacilityCode != 0 || card.CardNumber != 0)) {
|
||||
PrintAndLogEx(ERR, "`--fc` and `--cn` require `--wiegand`");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
uint8_t card_blocks[] = {
|
||||
0x1B, 0x01, 0x4D, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0x78, 0x77, 0x88, 0xC1, 0x89, 0xEC, 0xA9, 0x7F, 0x8C, 0x2A,
|
||||
@@ -10102,65 +10161,49 @@ static int CmdHFMFHidEncode(const char *Cmd) {
|
||||
0x48, 0x49, 0x44, 0x20, 0x49, 0x53, 0x78, 0x77, 0x88, 0xAA, 0x20, 0x47, 0x52, 0x45, 0x41, 0x54,
|
||||
};
|
||||
|
||||
wiegand_input_t input;
|
||||
memset(&input, 0, sizeof(input));
|
||||
if (bin_len) {
|
||||
char mfcbin[121] = {0};
|
||||
mfcbin[0] = '1';
|
||||
memcpy(mfcbin + 1, bin, bin_len);
|
||||
|
||||
size_t hexlen = 0;
|
||||
uint8_t hex[15] = {0};
|
||||
binstr_2_bytes(hex, &hexlen, mfcbin);
|
||||
|
||||
memcpy(blocks + (MFBLOCK_SIZE * 4) + 1 + (15 - hexlen), hex, hexlen);
|
||||
res = wiegand_set_plain_binstr((char *)bin, &input);
|
||||
} else if (raw_len) {
|
||||
res = wiegand_pack_from_raw_hid(raw, raw_len, &input);
|
||||
} else if (new_pacs_len) {
|
||||
res = wiegand_set_new_pacs_binstr(new_pacs, new_pacs_len, &input);
|
||||
} else {
|
||||
wiegand_message_t packed;
|
||||
memset(&packed, 0, sizeof(wiegand_message_t));
|
||||
|
||||
int format_idx = HIDFindCardFormat(format);
|
||||
if (format_idx == -1) {
|
||||
PrintAndLogEx(WARNING, "Unknown format: " _YELLOW_("%s"), format);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
res = wiegand_pack_from_formatted(format_idx, &card, false, &input);
|
||||
}
|
||||
if (res != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "Failed to encode HID input");
|
||||
return res;
|
||||
}
|
||||
|
||||
if (HIDPack(format_idx, &card, &packed, false) == false) {
|
||||
PrintAndLogEx(WARNING, "The card data could not be encoded in the selected format.");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
// iceman: only for formats w length smaller than 37.
|
||||
// Needs a check.
|
||||
|
||||
// increase length to allow setting bit just above real data
|
||||
packed.Length++;
|
||||
// Set sentinel bit
|
||||
set_bit_by_position(&packed, true, 0);
|
||||
|
||||
#ifdef HOST_LITTLE_ENDIAN
|
||||
packed.Mid = BSWAP_32(packed.Mid);
|
||||
packed.Bot = BSWAP_32(packed.Bot);
|
||||
#endif
|
||||
|
||||
memcpy(blocks + (MFBLOCK_SIZE * 4) + 8, &packed.Mid, sizeof(packed.Mid));
|
||||
memcpy(blocks + (MFBLOCK_SIZE * 4) + 12, &packed.Bot, sizeof(packed.Bot));
|
||||
if (hfmf_encodehid_pack_block5(input.binstr, card_blocks + (MFBLOCK_SIZE * 4)) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "Encoded Wiegand payload is too large to fit in the MIFARE payload");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
uint8_t empty[MIFARE_KEY_SIZE] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
bool res = true;
|
||||
for (uint8_t i = 0; i < (sizeof(blocks) / MFBLOCK_SIZE); i++) {
|
||||
bool write_ok = true;
|
||||
for (uint8_t i = 0; i < (sizeof(card_blocks) / MFBLOCK_SIZE); i++) {
|
||||
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "Writing %u - %s", (i + 1), sprint_hex_inrow(blocks + (i * MFBLOCK_SIZE), MFBLOCK_SIZE));
|
||||
PrintAndLogEx(INFO, "Writing %u - %s", (i + 1), sprint_hex_inrow(card_blocks + (i * MFBLOCK_SIZE), MFBLOCK_SIZE));
|
||||
}
|
||||
|
||||
if (mf_write_block((i + 1), MF_KEY_A, empty, blocks + (i * MFBLOCK_SIZE)) == PM3_EFAILED) {
|
||||
if (mf_write_block((i + 1), MF_KEY_B, empty, blocks + (i * MFBLOCK_SIZE)) == PM3_EFAILED) {
|
||||
if (mf_write_block((i + 1), MF_KEY_A, empty, card_blocks + (i * MFBLOCK_SIZE)) == PM3_EFAILED) {
|
||||
if (mf_write_block((i + 1), MF_KEY_B, empty, card_blocks + (i * MFBLOCK_SIZE)) == PM3_EFAILED) {
|
||||
PrintAndLogEx(WARNING, "failed writing block %d using default empty key", (i + 1));
|
||||
res = false;
|
||||
write_ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (res == false) {
|
||||
if (write_ok == false) {
|
||||
PrintAndLogEx(WARNING, "Make sure card is wiped before running this command");
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
|
||||
+146
-120
@@ -44,14 +44,75 @@
|
||||
#include "wiegand_formats.h"
|
||||
#include "wiegand_formatutils.h"
|
||||
#include "cmdlfem4x05.h" // EM defines
|
||||
#include "loclass/cipherutils.h" // bitstreamout
|
||||
|
||||
#ifndef BITS
|
||||
# define BITS 96
|
||||
#endif
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
typedef struct {
|
||||
char format[16];
|
||||
int format_len;
|
||||
wiegand_card_t card;
|
||||
uint8_t raw[12];
|
||||
int raw_len;
|
||||
uint8_t bin[97];
|
||||
int bin_len;
|
||||
uint8_t new_pacs[13];
|
||||
int new_pacs_len;
|
||||
} lf_hid_cli_input_t;
|
||||
|
||||
static int lf_hid_validate_packed_transport(const wiegand_input_t *input, const char *command_name) {
|
||||
if (input->packed_valid == false) {
|
||||
PrintAndLogEx(ERR, "Credential encoded successfully, but %" PRIuMAX "-bit Wiegand data cannot be represented as a packed HID credential", (uintmax_t)input->bin_len);
|
||||
PrintAndLogEx(ERR, "Packed HID encoding supports up to 84 Wiegand bits");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
// Raw HID input already arrives in transport form and intentionally bypasses the
|
||||
// packed Wiegand length check that applies to bin/new/formatted inputs.
|
||||
if (input->packed.Length == 0) {
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
if (input->packed.Length > 37) {
|
||||
PrintAndLogEx(ERR, "%s supports only packed credentials up to 37 bits", command_name);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int lf_hid_resolve_input(const lf_hid_cli_input_t *cli, wiegand_input_t *input, int *format_idx) {
|
||||
int input_modes = 0;
|
||||
input_modes += (cli->raw_len > 0);
|
||||
input_modes += (cli->bin_len > 0);
|
||||
input_modes += (cli->new_pacs_len > 0);
|
||||
input_modes += (cli->format_len > 0 || cli->card.FacilityCode != 0 || cli->card.CardNumber != 0 || cli->card.IssueLevel != 0 || cli->card.OEM != 0);
|
||||
if (input_modes != 1) {
|
||||
PrintAndLogEx(ERR, "Use exactly one of `--raw`, `--bin`, `--new`, or `--wiegand/--fc/--cn`");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
*format_idx = -1;
|
||||
if (cli->raw_len == 0 && cli->bin_len == 0 && cli->new_pacs_len == 0) {
|
||||
*format_idx = HIDFindCardFormat(cli->format);
|
||||
}
|
||||
|
||||
if (*format_idx == -1 && cli->raw_len == 0 && cli->bin_len == 0 && cli->new_pacs_len == 0) {
|
||||
PrintAndLogEx(WARNING, "Unknown format: " _YELLOW_("%s"), cli->format);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (cli->raw_len) {
|
||||
return wiegand_pack_from_raw_hid(cli->raw, cli->raw_len, input);
|
||||
}
|
||||
if (cli->bin_len) {
|
||||
return wiegand_pack_from_plain_bin((char *)cli->bin, input);
|
||||
}
|
||||
if (cli->new_pacs_len) {
|
||||
return wiegand_pack_from_new_pacs(cli->new_pacs, cli->new_pacs_len, input);
|
||||
}
|
||||
return wiegand_pack_from_formatted(*format_idx, (wiegand_card_t *)&cli->card, true, input);
|
||||
}
|
||||
|
||||
// sending three times. Didn't seem to break the previous sim?
|
||||
static int sendPing(void) {
|
||||
SendCommandNG(CMD_BREAK_LOOP, NULL, 0);
|
||||
@@ -252,9 +313,9 @@ static int CmdHIDSim(const char *Cmd) {
|
||||
"Enables simulation of HID card with card number.\n"
|
||||
"Simulation runs until the button is pressed or another USB command is issued.",
|
||||
"lf hid sim -r 2006ec0c86 -> HID 10301 26 bit\n"
|
||||
"lf hid sim --bin 10001111100000001010100011\n"
|
||||
"lf hid sim --new 068F80A8C0\n"
|
||||
"lf hid sim -r 2e0ec00c87 -> HID Corporate 35 bit\n"
|
||||
"lf hid sim -r 01f0760643c3 -> HID P10001 40 bit\n"
|
||||
"lf hid sim -r 01400076000c86 -> HID Corporate 48 bit\n"
|
||||
"lf hid sim -w H10301 --fc 118 --cn 1603 -> HID 10301 26 bit\n"
|
||||
);
|
||||
|
||||
@@ -266,61 +327,62 @@ static int CmdHIDSim(const char *Cmd) {
|
||||
arg_u64_0("i", NULL, "<dec>", "issue level"),
|
||||
arg_u64_0("o", "oem", "<dec>", "OEM code"),
|
||||
arg_str0("r", "raw", "<hex>", "raw bytes"),
|
||||
arg_str0(NULL, "bin", "<bin>", "Binary string i.e 0001001001"),
|
||||
arg_str0(NULL, "new", "<hex>", "new ASN.1 PACS hex from `wiegand encode --new`"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
char format[16] = {0};
|
||||
int format_len = 0;
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)format, sizeof(format), &format_len);
|
||||
|
||||
wiegand_card_t card;
|
||||
memset(&card, 0, sizeof(wiegand_card_t));
|
||||
card.FacilityCode = arg_get_u32_def(ctx, 2, 0);
|
||||
card.CardNumber = arg_get_u32_def(ctx, 3, 0);
|
||||
card.IssueLevel = arg_get_u32_def(ctx, 4, 0);
|
||||
card.OEM = arg_get_u32_def(ctx, 5, 0);
|
||||
|
||||
int raw_len = 0;
|
||||
char raw[40] = {0};
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 6), (uint8_t *)raw, sizeof(raw), &raw_len);
|
||||
lf_hid_cli_input_t cli;
|
||||
memset(&cli, 0, sizeof(cli));
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)cli.format, sizeof(cli.format), &cli.format_len);
|
||||
cli.card.FacilityCode = arg_get_u32_def(ctx, 2, 0);
|
||||
cli.card.CardNumber = arg_get_u32_def(ctx, 3, 0);
|
||||
cli.card.IssueLevel = arg_get_u32_def(ctx, 4, 0);
|
||||
cli.card.OEM = arg_get_u32_def(ctx, 5, 0);
|
||||
int res = CLIParamHexToBuf(arg_get_str(ctx, 6), cli.raw, sizeof(cli.raw), &cli.raw_len);
|
||||
cli.bin_len = sizeof(cli.bin) - 1;
|
||||
CLIGetStrWithReturn(ctx, 7, cli.bin, &cli.bin_len);
|
||||
cli.bin[cli.bin_len] = '\0';
|
||||
res |= CLIParamHexToBuf(arg_get_str(ctx, 8), cli.new_pacs, sizeof(cli.new_pacs), &cli.new_pacs_len);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
wiegand_message_t packed;
|
||||
memset(&packed, 0, sizeof(wiegand_message_t));
|
||||
|
||||
// format validation
|
||||
int format_idx = HIDFindCardFormat(format);
|
||||
if (format_idx == -1 && raw_len == 0) {
|
||||
PrintAndLogEx(WARNING, "Unknown format: " _YELLOW_("%s"), format);
|
||||
if (res) {
|
||||
PrintAndLogEx(ERR, "Error parsing hex input");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (raw_len) {
|
||||
uint32_t top = 0, mid = 0, bot = 0;
|
||||
hexstring_to_u96(&top, &mid, &bot, raw);
|
||||
packed.Top = top;
|
||||
packed.Mid = mid;
|
||||
packed.Bot = bot;
|
||||
} else {
|
||||
if (HIDPack(format_idx, &card, &packed, true) == false) {
|
||||
PrintAndLogEx(WARNING, "The card data could not be encoded in the selected format.");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
if (cli.bin_len > 96) {
|
||||
PrintAndLogEx(ERR, "Binary wiegand string must be less than 97 bits");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (raw_len == 0) {
|
||||
wiegand_input_t input;
|
||||
memset(&input, 0, sizeof(input));
|
||||
int format_idx = -1;
|
||||
res = lf_hid_resolve_input(&cli, &input, &format_idx);
|
||||
if (res != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "Failed to encode HID input");
|
||||
return res;
|
||||
}
|
||||
|
||||
res = lf_hid_validate_packed_transport(&input, "LF HID simulation");
|
||||
if (res != PM3_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
|
||||
if (cli.raw_len == 0) {
|
||||
PrintAndLogEx(INFO, "Simulating HID tag");
|
||||
HIDTryUnpack(&packed);
|
||||
HIDTryUnpack(&input.packed);
|
||||
} else {
|
||||
PrintAndLogEx(INFO, "Simulating HID tag using raw " _GREEN_("%s"), raw);
|
||||
PrintAndLogEx(INFO, "Simulating HID tag using raw " _GREEN_("%s"), sprint_hex_inrow(cli.raw, cli.raw_len));
|
||||
}
|
||||
|
||||
lf_hidsim_t payload;
|
||||
payload.hi2 = packed.Top;
|
||||
payload.hi = packed.Mid;
|
||||
payload.lo = packed.Bot;
|
||||
payload.longFMT = (packed.Mid > 0xFFF);
|
||||
payload.hi2 = input.packed.Top;
|
||||
payload.hi = input.packed.Mid;
|
||||
payload.lo = input.packed.Bot;
|
||||
payload.longFMT = (input.packed.Mid > 0xFFF);
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_LF_HID_SIMULATE, (uint8_t *)&payload, sizeof(payload));
|
||||
@@ -334,6 +396,8 @@ static int CmdHIDClone(const char *Cmd) {
|
||||
"clone a HID Prox tag to a T55x7, Q5/T5555 or EM4305/4469 tag.\n"
|
||||
"Tag must be on the antenna when issuing this command.",
|
||||
"lf hid clone -r 2006ec0c86 -> write raw value for T55x7 tag (HID 10301 26 bit)\n"
|
||||
"lf hid clone --bin 10001111100000001010100011 -> write binary HID payload for T55x7 tag\n"
|
||||
"lf hid clone --new 068F80A8C0 -> write PACS-encoded HID payload for T55x7 tag\n"
|
||||
"lf hid clone -r 2e0ec00c87 -> write raw value for T55x7 tag (HID Corporate 35 bit)\n"
|
||||
"lf hid clone -r 01f0760643c3 -> write raw value for T55x7 tag (HID P10001 40 bit)\n"
|
||||
"lf hid clone -r 01400076000c86 -> write raw value for T55x7 tag (HID Corporate 48 bit)\n"
|
||||
@@ -353,33 +417,27 @@ static int CmdHIDClone(const char *Cmd) {
|
||||
arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
|
||||
arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
|
||||
arg_str0(NULL, "bin", "<bin>", "Binary string i.e 0001001001"),
|
||||
arg_str0(NULL, "new", "<hex>", "new ASN.1 PACS hex from `wiegand encode --new`"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
char format[16] = {0};
|
||||
int format_len = 0;
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)format, sizeof(format), &format_len);
|
||||
|
||||
wiegand_card_t card;
|
||||
memset(&card, 0, sizeof(wiegand_card_t));
|
||||
card.FacilityCode = arg_get_u32_def(ctx, 2, 0);
|
||||
card.CardNumber = arg_get_u32_def(ctx, 3, 0);
|
||||
card.IssueLevel = arg_get_u32_def(ctx, 4, 0);
|
||||
card.OEM = arg_get_u32_def(ctx, 5, 0);
|
||||
|
||||
int raw_len = 0;
|
||||
char raw[40] = {0};
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 6), (uint8_t *)raw, sizeof(raw), &raw_len);
|
||||
lf_hid_cli_input_t cli;
|
||||
memset(&cli, 0, sizeof(cli));
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)cli.format, sizeof(cli.format), &cli.format_len);
|
||||
cli.card.FacilityCode = arg_get_u32_def(ctx, 2, 0);
|
||||
cli.card.CardNumber = arg_get_u32_def(ctx, 3, 0);
|
||||
cli.card.IssueLevel = arg_get_u32_def(ctx, 4, 0);
|
||||
cli.card.OEM = arg_get_u32_def(ctx, 5, 0);
|
||||
int res = CLIParamHexToBuf(arg_get_str(ctx, 6), cli.raw, sizeof(cli.raw), &cli.raw_len);
|
||||
|
||||
bool q5 = arg_get_lit(ctx, 7);
|
||||
bool em = arg_get_lit(ctx, 8);
|
||||
|
||||
// t5577 can do 6 blocks with 32bits == 192 bits, HID is manchester encoded and doubles in length.
|
||||
// With parity, manchester and preamble we have about 3 blocks to play with. Ie: 96 bits
|
||||
uint8_t bin[97] = {0};
|
||||
int bin_len = sizeof(bin) - 1; // CLIGetStrWithReturn does not guarantee string to be null-terminated
|
||||
CLIGetStrWithReturn(ctx, 9, bin, &bin_len);
|
||||
cli.bin_len = sizeof(cli.bin) - 1;
|
||||
CLIGetStrWithReturn(ctx, 9, cli.bin, &cli.bin_len);
|
||||
cli.bin[cli.bin_len] = '\0';
|
||||
res |= CLIParamHexToBuf(arg_get_str(ctx, 10), cli.new_pacs, sizeof(cli.new_pacs), &cli.new_pacs_len);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (q5 && em) {
|
||||
@@ -387,59 +445,23 @@ static int CmdHIDClone(const char *Cmd) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (bin_len > 96) {
|
||||
PrintAndLogEx(ERR, "Binary wiegand string must be less than 96 bits");
|
||||
if (res) {
|
||||
PrintAndLogEx(ERR, "Error parsing hex input");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
wiegand_message_t packed;
|
||||
memset(&packed, 0, sizeof(wiegand_message_t));
|
||||
|
||||
// format validation
|
||||
int format_idx = HIDFindCardFormat(format);
|
||||
if (format_idx == -1 && raw_len == 0) {
|
||||
PrintAndLogEx(WARNING, "Unknown format: " _YELLOW_("%s"), format);
|
||||
return PM3_EINVARG;
|
||||
wiegand_input_t input;
|
||||
memset(&input, 0, sizeof(input));
|
||||
int format_idx = -1;
|
||||
res = lf_hid_resolve_input(&cli, &input, &format_idx);
|
||||
if (res != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "Failed to encode HID input");
|
||||
return res;
|
||||
}
|
||||
|
||||
uint32_t top = 0, mid = 0, bot = 0;
|
||||
if (raw_len) {
|
||||
hexstring_to_u96(&top, &mid, &bot, raw);
|
||||
packed.Top = top;
|
||||
packed.Mid = mid;
|
||||
packed.Bot = bot;
|
||||
} else if (bin_len) {
|
||||
|
||||
uint8_t hex[12];
|
||||
memset(hex, 0, sizeof(hex));
|
||||
BitstreamOut_t bout = {hex, 0, 0 };
|
||||
|
||||
for (int i = 0; i < 96 - bin_len - 1; i++) {
|
||||
pushBit(&bout, 0);
|
||||
}
|
||||
// add binary sentinel bit.
|
||||
pushBit(&bout, 1);
|
||||
|
||||
// convert binary string to hex bytes
|
||||
for (int i = 0; i < bin_len; i++) {
|
||||
char c = bin[i];
|
||||
if (c == '1')
|
||||
pushBit(&bout, 1);
|
||||
else if (c == '0')
|
||||
pushBit(&bout, 0);
|
||||
}
|
||||
|
||||
packed.Length = bin_len;
|
||||
packed.Top = bytes_to_num(hex, 4);
|
||||
packed.Mid = bytes_to_num(hex + 4, 4);
|
||||
packed.Bot = bytes_to_num(hex + 8, 4);
|
||||
add_HID_header(&packed);
|
||||
|
||||
} else {
|
||||
if (HIDPack(format_idx, &card, &packed, true) == false) {
|
||||
PrintAndLogEx(WARNING, "The card data could not be encoded in the selected format.");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
res = lf_hid_validate_packed_transport(&input, "LF HID clone");
|
||||
if (res != PM3_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
|
||||
char cardtype[16] = {"T55x7"};
|
||||
@@ -454,18 +476,22 @@ static int CmdHIDClone(const char *Cmd) {
|
||||
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
|
||||
}
|
||||
|
||||
if (raw_len == 0) {
|
||||
if (cli.raw_len == 0) {
|
||||
PrintAndLogEx(INFO, "Preparing to clone HID tag");
|
||||
HIDUnpack(format_idx, &packed);
|
||||
if (format_idx >= 0) {
|
||||
HIDUnpack(format_idx, &input.packed);
|
||||
} else {
|
||||
HIDTryUnpack(&input.packed);
|
||||
}
|
||||
} else {
|
||||
PrintAndLogEx(INFO, "Preparing to clone HID tag using raw " _YELLOW_("%s"), raw);
|
||||
PrintAndLogEx(INFO, "Preparing to clone HID tag using raw " _YELLOW_("%s"), sprint_hex_inrow(cli.raw, cli.raw_len));
|
||||
}
|
||||
|
||||
lf_hidsim_t payload;
|
||||
payload.hi2 = packed.Top;
|
||||
payload.hi = packed.Mid;
|
||||
payload.lo = packed.Bot;
|
||||
payload.longFMT = (packed.Mid > 0xFFF);
|
||||
payload.hi2 = input.packed.Top;
|
||||
payload.hi = input.packed.Mid;
|
||||
payload.lo = input.packed.Bot;
|
||||
payload.longFMT = (input.packed.Mid > 0xFFF);
|
||||
payload.Q5 = q5;
|
||||
payload.EM = em;
|
||||
|
||||
|
||||
@@ -40,20 +40,16 @@ static int CmdHelp(const char *Cmd);
|
||||
#define PACS_MAX_WIEGAND_BITS 96
|
||||
#define WIEGAND_MAX_ENCODED_BITS (PACS_MAX_WIEGAND_BITS + 8)
|
||||
|
||||
static void wiegand_packed_to_binstr(const wiegand_message_t *packed, char *binstr) {
|
||||
for (uint8_t i = 0; i < packed->Length; i++) {
|
||||
binstr[i] = get_bit_by_position((wiegand_message_t *)packed, i) ? '1' : '0';
|
||||
}
|
||||
binstr[packed->Length] = '\0';
|
||||
}
|
||||
|
||||
static int wiegand_print_new_pacs_verbose(const wiegand_message_t *packed, const uint8_t *pacs, size_t pacs_len) {
|
||||
char binstr[PACS_MAX_WIEGAND_BITS + 1] = {0};
|
||||
char rawbin[WIEGAND_MAX_ENCODED_BITS + 1] = {0};
|
||||
uint8_t raw[(WIEGAND_MAX_ENCODED_BITS + 7) / 8] = {0};
|
||||
size_t raw_len = 0;
|
||||
|
||||
wiegand_packed_to_binstr(packed, binstr);
|
||||
if (wiegand_message_to_binstr(packed, binstr, sizeof(binstr)) == false) {
|
||||
PrintAndLogEx(ERR, "Failed to render Wiegand payload");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
rawbin[0] = '1';
|
||||
memcpy(rawbin + 1, binstr, packed->Length);
|
||||
binstr_2_bytes(raw, &raw_len, rawbin);
|
||||
@@ -83,7 +79,10 @@ static int wiegand_encode_new_pacs(const wiegand_message_t *packed, bool verbose
|
||||
uint8_t pad = padded_bits - packed->Length;
|
||||
|
||||
char binstr[PACS_MAX_WIEGAND_BITS + 1] = {0};
|
||||
wiegand_packed_to_binstr(packed, binstr);
|
||||
if (wiegand_message_to_binstr(packed, binstr, sizeof(binstr)) == false) {
|
||||
PrintAndLogEx(ERR, "Failed to render Wiegand payload");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
memset(binstr + packed->Length, '0', pad);
|
||||
binstr[padded_bits] = '\0';
|
||||
|
||||
|
||||
@@ -1805,21 +1805,21 @@ int HIDDumpPACSBits(const uint8_t *const data, const uint8_t length, bool verbos
|
||||
}
|
||||
|
||||
uint8_t n = length - 1;
|
||||
uint8_t pad = data[0];
|
||||
char *binstr = (char *)calloc((length * 8) + 1, sizeof(uint8_t));
|
||||
if (binstr == NULL) {
|
||||
PrintAndLogEx(WARNING, "Failed to allocate memory");
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
bytes_2_binstr(binstr, data + 1, n);
|
||||
if (wiegand_new_pacs_to_binstr(data, length, binstr, (length * 8) + 1) == false) {
|
||||
PrintAndLogEx(ERR, "Invalid PACS value");
|
||||
free(binstr);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
// PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "------------------------- " _CYAN_("Wiegand") " ---------------------------");
|
||||
PrintAndLogEx(SUCCESS, "PACS............. " _GREEN_("%s"), sprint_hex_inrow(data, length));
|
||||
PrintAndLogEx(DEBUG, "padded bin....... " _GREEN_("%s") " ( %zu )", binstr, strlen(binstr));
|
||||
|
||||
binstr[strlen(binstr) - pad] = '\0';
|
||||
PrintAndLogEx(DEBUG, "bin.............. " _GREEN_("%s") " ( %zu )", binstr, strlen(binstr));
|
||||
|
||||
size_t hexlen = 0;
|
||||
|
||||
@@ -20,7 +20,11 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "commonutil.h"
|
||||
#include "loclass/cipherutils.h"
|
||||
#include "wiegand_formats.h"
|
||||
#include "wiegand_formatutils.h"
|
||||
#include "util.h"
|
||||
#include "ui.h"
|
||||
|
||||
uint8_t get_bit_by_position(const wiegand_message_t *data, uint8_t pos) {
|
||||
@@ -215,3 +219,211 @@ bool add_HID_header(wiegand_message_t *data) {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wiegand_message_to_binstr(const wiegand_message_t *packed, char *binstr, size_t binstr_size) {
|
||||
if (packed == NULL || binstr == NULL || binstr_size <= packed->Length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < packed->Length; i++) {
|
||||
binstr[i] = get_bit_by_position(packed, i) ? '1' : '0';
|
||||
}
|
||||
binstr[packed->Length] = '\0';
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wiegand_raw_to_binstr(const uint8_t *raw, size_t raw_len, char *binstr, size_t binstr_size) {
|
||||
if (raw == NULL || binstr == NULL || raw_len == 0 || binstr_size == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t raw_bit_len = raw_len * 8;
|
||||
if (binstr_size <= raw_bit_len) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bytes_2_binstr(binstr, raw, raw_len);
|
||||
|
||||
char *sentinel = strchr(binstr, '1');
|
||||
if (sentinel == NULL || sentinel[1] == '\0') {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t payload_len = strlen(sentinel + 1);
|
||||
if (binstr_size <= payload_len) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memmove(binstr, sentinel + 1, payload_len + 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wiegand_new_pacs_to_binstr(const uint8_t *pacs, size_t pacs_len, char *binstr, size_t binstr_size) {
|
||||
if (pacs == NULL || binstr == NULL || pacs_len < 2 || pacs[0] > 0x07) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t payload_len = pacs_len - 1;
|
||||
size_t padded_bits = payload_len * 8;
|
||||
if (binstr_size <= padded_bits) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bytes_2_binstr(binstr, pacs + 1, payload_len);
|
||||
|
||||
size_t trimmed_len = strlen(binstr);
|
||||
if (pacs[0] >= trimmed_len) {
|
||||
return false;
|
||||
}
|
||||
|
||||
binstr[trimmed_len - pacs[0]] = '\0';
|
||||
return true;
|
||||
}
|
||||
|
||||
int wiegand_pack_bin_with_hid_header(const char *binstr, wiegand_message_t *packed) {
|
||||
size_t bin_len = strlen(binstr);
|
||||
if (packed == NULL || bin_len == 0 || bin_len > 84) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
uint8_t hex[12] = {0};
|
||||
BitstreamOut_t bout = {hex, 0, 0};
|
||||
|
||||
for (size_t i = 0; i < (96 - bin_len - 1); i++) {
|
||||
pushBit(&bout, 0);
|
||||
}
|
||||
|
||||
pushBit(&bout, 1);
|
||||
|
||||
for (size_t i = 0; i < bin_len; i++) {
|
||||
char c = binstr[i];
|
||||
if (c == '1') {
|
||||
pushBit(&bout, 1);
|
||||
} else if (c == '0') {
|
||||
pushBit(&bout, 0);
|
||||
} else {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
}
|
||||
|
||||
packed->Length = (uint8_t)bin_len;
|
||||
packed->Top = bytes_to_num(hex, 4);
|
||||
packed->Mid = bytes_to_num(hex + 4, 4);
|
||||
packed->Bot = bytes_to_num(hex + 8, 4);
|
||||
|
||||
return add_HID_header(packed) ? PM3_SUCCESS : PM3_EINVARG;
|
||||
}
|
||||
|
||||
int wiegand_set_plain_binstr(const char *binstr, wiegand_input_t *input) {
|
||||
size_t bin_len = strlen(binstr);
|
||||
if (input == NULL || bin_len == 0 || bin_len >= sizeof(input->binstr)) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
memset(input, 0, sizeof(*input));
|
||||
for (size_t i = 0; i < bin_len; i++) {
|
||||
if (binstr[i] != '0' && binstr[i] != '1') {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(input->binstr, binstr, bin_len + 1);
|
||||
input->bin_len = bin_len;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int wiegand_set_new_pacs_binstr(const uint8_t *pacs, size_t pacs_len, wiegand_input_t *input) {
|
||||
if (input == NULL) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
memset(input, 0, sizeof(*input));
|
||||
if (wiegand_new_pacs_to_binstr(pacs, pacs_len, input->binstr, sizeof(input->binstr)) == false) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
input->bin_len = strlen(input->binstr);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int wiegand_pack_formatted(int format_idx, wiegand_card_t *card, bool preamble, wiegand_message_t *packed) {
|
||||
if (HIDPack(format_idx, card, packed, preamble) == false) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int wiegand_pack_from_plain_bin(const char *binstr, wiegand_input_t *input) {
|
||||
int res = wiegand_set_plain_binstr(binstr, input);
|
||||
if (res != PM3_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
|
||||
if (input->bin_len > 84) {
|
||||
input->packed_valid = false;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
res = wiegand_pack_bin_with_hid_header(input->binstr, &input->packed);
|
||||
input->packed_valid = (res == PM3_SUCCESS);
|
||||
return res;
|
||||
}
|
||||
|
||||
int wiegand_pack_from_new_pacs(const uint8_t *pacs, size_t pacs_len, wiegand_input_t *input) {
|
||||
int res = wiegand_set_new_pacs_binstr(pacs, pacs_len, input);
|
||||
if (res != PM3_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
|
||||
if (input->bin_len > 84) {
|
||||
input->packed_valid = false;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
res = wiegand_pack_bin_with_hid_header(input->binstr, &input->packed);
|
||||
input->packed_valid = (res == PM3_SUCCESS);
|
||||
return res;
|
||||
}
|
||||
|
||||
int wiegand_pack_from_formatted(int format_idx, wiegand_card_t *card, bool preamble, wiegand_input_t *input) {
|
||||
memset(input, 0, sizeof(*input));
|
||||
int res = wiegand_pack_formatted(format_idx, card, preamble, &input->packed);
|
||||
if (res != PM3_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
input->packed_valid = true;
|
||||
if (wiegand_message_to_binstr(&input->packed, input->binstr, sizeof(input->binstr)) == false) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
input->bin_len = strlen(input->binstr);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int wiegand_pack_from_raw_hid(const uint8_t *raw, size_t raw_len, wiegand_input_t *input) {
|
||||
if (raw == NULL || input == NULL || raw_len == 0) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
uint8_t aligned[12] = {0};
|
||||
memset(input, 0, sizeof(*input));
|
||||
|
||||
if (wiegand_raw_to_binstr(raw, raw_len, input->binstr, sizeof(input->binstr)) == false) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
input->bin_len = strlen(input->binstr);
|
||||
if (input->bin_len > 96) {
|
||||
input->packed_valid = false;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
if (raw_len > sizeof(aligned)) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
memcpy(aligned + (sizeof(aligned) - raw_len), raw, raw_len);
|
||||
input->packed = initialize_message_object(bytes_to_num(aligned, 4), bytes_to_num(aligned + 4, 4), bytes_to_num(aligned + 8, 4), 0);
|
||||
// Raw HID input preserves legacy behavior: transport words are populated, but
|
||||
// packed Wiegand length is left unset because this path does not repack data.
|
||||
input->packed_valid = true;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
// Structure for packed wiegand messages
|
||||
// Always align lowest value (last transmitted) bit to ordinal position 0 (lowest valued bit bottom)
|
||||
@@ -41,6 +42,13 @@ typedef struct {
|
||||
bool ParityValid; // Only valid for responses
|
||||
} wiegand_card_t;
|
||||
|
||||
typedef struct {
|
||||
size_t bin_len;
|
||||
char binstr[145];
|
||||
bool packed_valid;
|
||||
wiegand_message_t packed;
|
||||
} wiegand_input_t;
|
||||
|
||||
uint8_t get_bit_by_position(const wiegand_message_t *data, uint8_t pos);
|
||||
bool set_bit_by_position(wiegand_message_t *data, bool value, uint8_t pos);
|
||||
|
||||
@@ -54,5 +62,16 @@ wiegand_message_t initialize_message_object(uint32_t top, uint32_t mid, uint32_t
|
||||
|
||||
uint8_t get_length_from_header(const wiegand_message_t *data);
|
||||
bool add_HID_header(wiegand_message_t *data);
|
||||
bool wiegand_message_to_binstr(const wiegand_message_t *packed, char *binstr, size_t binstr_size);
|
||||
bool wiegand_raw_to_binstr(const uint8_t *raw, size_t raw_len, char *binstr, size_t binstr_size);
|
||||
bool wiegand_new_pacs_to_binstr(const uint8_t *pacs, size_t pacs_len, char *binstr, size_t binstr_size);
|
||||
int wiegand_set_plain_binstr(const char *binstr, wiegand_input_t *input);
|
||||
int wiegand_set_new_pacs_binstr(const uint8_t *pacs, size_t pacs_len, wiegand_input_t *input);
|
||||
int wiegand_pack_bin_with_hid_header(const char *binstr, wiegand_message_t *packed);
|
||||
int wiegand_pack_formatted(int format_idx, wiegand_card_t *card, bool preamble, wiegand_message_t *packed);
|
||||
int wiegand_pack_from_new_pacs(const uint8_t *pacs, size_t pacs_len, wiegand_input_t *input);
|
||||
int wiegand_pack_from_plain_bin(const char *binstr, wiegand_input_t *input);
|
||||
int wiegand_pack_from_formatted(int format_idx, wiegand_card_t *card, bool preamble, wiegand_input_t *input);
|
||||
int wiegand_pack_from_raw_hid(const uint8_t *raw, size_t raw_len, wiegand_input_t *input);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -9,6 +9,8 @@ cd "$PM3PATH" || exit 1
|
||||
|
||||
TESTALL=false
|
||||
TESTDESFIREVALUE=false
|
||||
TESTHIDWIEGAND=false
|
||||
TESTMFHIDENCODE=false
|
||||
|
||||
# https://medium.com/@Drew_Stokes/bash-argument-parsing-54f3b81a6a8f
|
||||
PARAMS=""
|
||||
@@ -16,9 +18,11 @@ while (( "$#" )); do
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
echo """
|
||||
Usage: $0 [--pm3bin /path/to/pm3] [desfire_value]
|
||||
Usage: $0 [--pm3bin /path/to/pm3] [desfire_value|hid_wiegand|mf_hid_encode]
|
||||
--pm3bin ...: Specify path to pm3 binary to test
|
||||
desfire_value: Test DESFire value operations with card
|
||||
hid_wiegand: Test LF HID simulate/clone Wiegand flows
|
||||
mf_hid_encode: Test MIFARE Classic HID encoding flows
|
||||
You must specify a test target - no default 'all' for online tests
|
||||
"""
|
||||
exit 0
|
||||
@@ -37,6 +41,16 @@ Usage: $0 [--pm3bin /path/to/pm3] [desfire_value]
|
||||
TESTDESFIREVALUE=true
|
||||
shift
|
||||
;;
|
||||
hid_wiegand)
|
||||
TESTALL=false
|
||||
TESTHIDWIEGAND=true
|
||||
shift
|
||||
;;
|
||||
mf_hid_encode)
|
||||
TESTALL=false
|
||||
TESTMFHIDENCODE=true
|
||||
shift
|
||||
;;
|
||||
-*|--*=) # unsupported flags
|
||||
echo "Error: Unsupported flag $1" >&2
|
||||
exit 1
|
||||
@@ -95,6 +109,13 @@ function CheckExecute() {
|
||||
return 1
|
||||
}
|
||||
|
||||
function WaitForEnter() {
|
||||
echo ""
|
||||
echo "$1"
|
||||
echo "Press Enter when ready, or Ctrl-C to abort."
|
||||
read -r
|
||||
}
|
||||
|
||||
echo -e "${C_BLUE}Iceman Proxmark3 online test tool${C_NC}"
|
||||
echo ""
|
||||
echo "work directory: $(pwd)"
|
||||
@@ -108,7 +129,7 @@ if command -v git >/dev/null && git rev-parse --is-inside-work-tree >/dev/null 2
|
||||
fi
|
||||
|
||||
# Check that user specified a test
|
||||
if [ "$TESTDESFIREVALUE" = false ]; then
|
||||
if [ "$TESTDESFIREVALUE" = false ] && [ "$TESTHIDWIEGAND" = false ] && [ "$TESTMFHIDENCODE" = false ]; then
|
||||
echo "Error: You must specify a test target. Use -h for help."
|
||||
exit 1
|
||||
fi
|
||||
@@ -138,6 +159,32 @@ while true; do
|
||||
if ! CheckExecute "card cleanup" "$PM3BIN -c 'hf mfdes selectapp --aid 000000; hf mfdes auth -n 0 -t 2tdea -k 00000000000000000000000000000000 --kdf none; hf mfdes deleteapp --aid 123456'" "application.*deleted"; then break; fi
|
||||
echo " card value operation tests completed successfully!"
|
||||
fi
|
||||
|
||||
if $TESTHIDWIEGAND; then
|
||||
echo -e "\n${C_BLUE}Testing LF HID Wiegand flows${C_NC} ${PM3BIN:=./pm3}"
|
||||
if ! CheckFileExist "pm3 exists" "$PM3BIN"; then break; fi
|
||||
|
||||
if ! CheckExecute "lf hid sim 26-bit bin" "$PM3BIN -c 'lf hid sim --bin 10001111100000001010100011'" "Simulating HID tag"; then break; fi
|
||||
if ! CheckExecute "lf hid sim raw oversize" "$PM3BIN -c 'lf hid sim -r 01400076000c86' 2>&1" "LF HID simulation supports only packed credentials up to 37 bits"; then break; fi
|
||||
if ! CheckExecute "lf hid sim bin oversize" "PAT=\$(printf '01%.0s' {1..48}); $PM3BIN -c \"lf hid sim --bin \$PAT\" 2>&1" "LF HID simulation supports only packed credentials up to 37 bits"; then break; fi
|
||||
if ! CheckExecute "lf hid sim new oversize" "$PM3BIN -c 'lf hid sim --new 0000A4550148AB' 2>&1" "LF HID simulation supports only packed credentials up to 37 bits"; then break; fi
|
||||
|
||||
WaitForEnter "PLACE A REWRITABLE T55xx TAG ON THE PM3 NOW"
|
||||
if ! CheckExecute "lf hid clone 26-bit bin" "$PM3BIN -c 'lf hid clone --bin 10001111100000001010100011'" "Done!"; then break; fi
|
||||
if ! CheckExecute "lf hid clone raw oversize" "$PM3BIN -c 'lf hid clone -r 01400076000c86' 2>&1" "LF HID clone supports only packed credentials up to 37 bits"; then break; fi
|
||||
if ! CheckExecute "lf hid clone bin oversize" "PAT=\$(printf '01%.0s' {1..48}); $PM3BIN -c \"lf hid clone --bin \$PAT\" 2>&1" "LF HID clone supports only packed credentials up to 37 bits"; then break; fi
|
||||
if ! CheckExecute "lf hid clone new oversize" "$PM3BIN -c 'lf hid clone --new 0000A4550148AB' 2>&1" "LF HID clone supports only packed credentials up to 37 bits"; then break; fi
|
||||
fi
|
||||
|
||||
if $TESTMFHIDENCODE; then
|
||||
echo -e "\n${C_BLUE}Testing MIFARE Classic HID encoding${C_NC} ${PM3BIN:=./pm3}"
|
||||
if ! CheckFileExist "pm3 exists" "$PM3BIN"; then break; fi
|
||||
|
||||
WaitForEnter "PLACE A BLANK MIFARE CLASSIC 1K CARD ON THE PM3 NOW"
|
||||
if ! CheckExecute "hf mf encodehid bin" "$PM3BIN -c 'hf mf encodehid --bin 10001111100000001010100011; hf mf rdbl --blk 5 -k FFFFFFFFFFFF'" "023E02A3"; then break; fi
|
||||
if ! CheckExecute "hf mf encodehid raw" "$PM3BIN -c 'hf mf encodehid --raw 023E02A3; hf mf rdbl --blk 5 -k FFFFFFFFFFFF'" "023E02A3"; then break; fi
|
||||
if ! CheckExecute "hf mf encodehid new" "$PM3BIN -c 'hf mf encodehid --new 068F80A8C0; hf mf rdbl --blk 5 -k FFFFFFFFFFFF'" "023E02A3"; then break; fi
|
||||
fi
|
||||
|
||||
echo -e "\n------------------------------------------------------------"
|
||||
echo -e "Tests [ ${C_GREEN}OK${C_NC} ] ${C_OK}\n"
|
||||
@@ -145,4 +192,4 @@ while true; do
|
||||
done
|
||||
echo -e "\n------------------------------------------------------------"
|
||||
echo -e "\nTests [ ${C_RED}FAIL${C_NC} ] ${C_FAIL}\n"
|
||||
exit 1
|
||||
exit 1
|
||||
|
||||
@@ -490,6 +490,7 @@ while true; do
|
||||
if ! CheckExecute "wiegand decode test - raw" "$CLIENTBIN -c 'wiegand decode --raw 2006F623AE'" "FC: 123 CN: 4567 parity \( ok \)"; then break; fi
|
||||
if ! CheckExecute "wiegand decode test - bin over 96-bit" "PAT=\$(printf '01%.0s' {1..49}); $CLIENTBIN -c \"wiegand decode --bin \$PAT\" 2>&1" "Binary decode supports up to 96 Wiegand bits"; then break; fi
|
||||
if ! CheckExecute "wiegand decode test - new" "$CLIENTBIN -c 'wiegand decode --new 06BD88EB80'" "FC: 123 CN: 4567 parity \( ok \)"; then break; fi
|
||||
if ! CheckExecute "wiegand decode test - new no padded bin" "if ! $CLIENTBIN -c 'wiegand decode --new 06BD88EB80' 2>&1 | grep -q 'padded bin'; then echo OK; fi" "OK"; then break; fi
|
||||
if ! CheckExecute "wiegand decode test - new 96-bit" "$CLIENTBIN -c 'wiegand decode --new 00555555555555555555555555'" "hex\\.{14} 555555555555555555555555"; then break; fi
|
||||
if ! CheckExecute "wiegand decode test - new 48-bit" "$CLIENTBIN -c 'wiegand decode --new 0000A4550148AB'" "C1k48s.*FC: 42069 CN: 42069 parity \( ok \)"; then break; fi
|
||||
if ! CheckExecute "wiegand Verkada40 encode test 1" "$CLIENTBIN -c 'wiegand encode -w Verkada40 --fc 50 --cn 1001'" "86400007D3"; then break; fi
|
||||
|
||||
Reference in New Issue
Block a user