Merge pull request #9 from RfidResearchGroup/master

Update
This commit is contained in:
mwalker33 2019-09-22 14:42:58 +10:00 committed by GitHub
commit a1eb992fa8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
56 changed files with 2032 additions and 607 deletions

View file

@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file.
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
## [unreleased][unreleased]
- Add `wiegand list/encode/decode` - wiegand format manipulation. Adapted to fit here. (@grauerfuchs)
- Add `lf t55xx protect` - sets password and enables password protection on t55x7 tag (@iceman1001)
- Chg `lf t55xx wipe` - now accepts user provided configuration block (@iceman1001)
- Chg proxmark3-flasher is now merged into proxmark3 client. Add pm3-flash (@doegox)

View file

@ -376,14 +376,15 @@ test_script:
ExecTest "hf mf offline text" "hf mf" {bash -lc "cd ~/client;./proxmark3 -c 'hf mf'"} "at_enc"
ExecTest "hf mf hardnested" "hf mf hardnested" {bash -lc "cd ~/client;./proxmark3 -c 'hf mf hardnested t 1 000000000000'"} "found:"
ExecTest "hf mf iclass" "hf mf iclass" {bash -lc "cd ~/client;./proxmark3 -c 'hf iclass loclass t'"} "verified ok"
#proxmark crypto tests
ExecTest "emv test" "emv test" {bash -lc "cd ~/client;./proxmark3 -c 'emv test'"} "Test?s? ? OK"
# Long tests:
# ExecTest "hf mf hardnested" "hf mf hardnested" {bash -lc "cd ~/client;./proxmark3 -c 'hf mf hardnested t 1 000000000000'"} "found:"
# ExecTest "hf mf iclass" "hf mf iclass" {bash -lc "cd ~/client;./proxmark3 -c 'hf iclass loclass t l'"} "verified ok"
# ExecTest "emv test" "emv test" {bash -lc "cd ~/client;./proxmark3 -c 'emv test -i -l'"} "Test?s? ? OK"
# Short tests:
ExecTest "hf mf iclass" "hf mf iclass" {bash -lc "cd ~/client;./proxmark3 -c 'hf iclass loclass t'"} "OK!"
ExecTest "emv test" "emv test" {bash -lc "cd ~/client;./proxmark3 -c 'emv test -i'"} "Test?s? ? OK"
if ($global:TestsPassed) {

View file

@ -208,13 +208,13 @@ void MeasureAntennaTuning(void) {
uint16_t MeasureAntennaTuningHfData(void) {
uint16_t volt = 0; // in mV
volt = (MAX_ADC_HF_VOLTAGE * AvgAdc(ADC_CHAN_HF)) >> 10;
uint16_t avg = AvgAdc(ADC_CHAN_HF);
volt = (MAX_ADC_HF_VOLTAGE * avg) >> 10;
bool use_high = (volt > MAX_ADC_HF_VOLTAGE - 300);
if (!use_high) {
volt = (MAX_ADC_HF_VOLTAGE * AvgAdc(ADC_CHAN_HF)) >> 10;
} else {
if (use_high) {
volt = (MAX_ADC_HF_VOLTAGE_RDV40 * AvgAdc(ADC_CHAN_HF_RDV40)) >> 10;
// volt = (MAX_ADC_HF_VOLTAGE * AvgAdc(ADC_CHAN_HF)) >> 10;
}
return volt;
}
@ -343,7 +343,7 @@ void SendStatus(void) {
Flashmem_print_info();
#endif
reply_old(CMD_ACK, 1, 0, 0, 0, 0);
reply_ng(CMD_STATUS, PM3_SUCCESS, NULL, 0);
}
void SendCapabilities(void) {
@ -730,10 +730,6 @@ static void PacketReceived(PacketCommandNG *packet) {
CmdIOdemodFSK(packet->oldarg[0], &high, &low, 1);
break;
}
case CMD_LF_IO_CLONE: {
CopyIOtoT55x7(packet->oldarg[0], packet->oldarg[1]);
break;
}
case CMD_LF_EM410X_DEMOD: {
uint32_t high;
uint64_t low;
@ -769,17 +765,6 @@ static void PacketReceived(PacketCommandNG *packet) {
SimulateTagLowFrequencyBidir(packet->oldarg[0], packet->oldarg[1]);
break;
}
case CMD_LF_INDALA_CLONE: {
CopyIndala64toT55x7(packet->data.asDwords[0], packet->data.asDwords[1]);
break;
}
case CMD_LF_INDALA224_CLONE: {
CopyIndala224toT55x7(
packet->data.asDwords[0], packet->data.asDwords[1], packet->data.asDwords[2], packet->data.asDwords[3],
packet->data.asDwords[4], packet->data.asDwords[5], packet->data.asDwords[6]
);
break;
}
case CMD_LF_T55XX_READBL: {
struct p {
uint32_t password;
@ -861,7 +846,7 @@ static void PacketReceived(PacketCommandNG *packet) {
bool Q5;
uint8_t blocks[8];
} PACKED;
struct p *payload = (struct p*)packet->data.asBytes;
struct p *payload = (struct p *)packet->data.asBytes;
CopyVikingtoT55xx(payload->blocks, payload->Q5);
break;
}
@ -1251,22 +1236,22 @@ static void PacketReceived(PacketCommandNG *packet) {
break;
}
case CMD_HF_ICLASS_READBL: {
/*
struct p {
uint8_t blockno;
} PACKED;
struct p *payload = (struct p *)packet->data.asBytes;
*/
iClass_ReadBlk( packet->data.asBytes[0] );
/*
struct p {
uint8_t blockno;
} PACKED;
struct p *payload = (struct p *)packet->data.asBytes;
*/
iClass_ReadBlk(packet->data.asBytes[0]);
break;
}
case CMD_HF_ICLASS_AUTH: { //check
/*
struct p {
uint8_t mac[4];
} PACKED;
struct p *payload = (struct p *)packet->data.asBytes;
*/
/*
struct p {
uint8_t mac[4];
} PACKED;
struct p *payload = (struct p *)packet->data.asBytes;
*/
iClass_Authentication(packet->data.asBytes);
break;
}
@ -1680,7 +1665,9 @@ static void PacketReceived(PacketCommandNG *packet) {
break;
}
case CMD_FLASHMEM_SET_SPIBAUDRATE: {
FlashmemSetSpiBaudrate(packet->oldarg[0]);
if (packet->length != sizeof(uint32_t))
break;
FlashmemSetSpiBaudrate(packet->data.asDwords[0]);
break;
}
case CMD_FLASHMEM_WRITE: {

View file

@ -2044,8 +2044,7 @@ bool GetIso14443aAnswerFromTag_Thinfilm(uint8_t *receivedResponse, uint8_t *rec
}
}
// timeout already in ms + 10ms guard time
if (GetTickCount() - receive_timer > 1160)
if (GetTickCount() - receive_timer > 100)
break;
}
*received_len = Demod.len;

View file

@ -918,7 +918,7 @@ void CmdHIDsimTAGEx(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT, boo
*/
// special start of frame marker containing invalid Manchester bit sequences
uint8_t bits[8+8*2+84*2] = { 0, 0, 0, 1, 1, 1, 0, 1 };
uint8_t bits[8 + 8 * 2 + 84 * 2] = { 0, 0, 0, 1, 1, 1, 0, 1 };
uint8_t bitlen = 0;
uint16_t n = 8;
@ -928,9 +928,9 @@ void CmdHIDsimTAGEx(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT, boo
DbpString("Tags can only have 84 bits.");
return;
}
bitlen = 8+8*2+84*2;
bitlen = 8 + 8 * 2 + 84 * 2;
hi2 |= 0x9E00000; // 9E: long format identifier
manchesterEncodeUint32(hi2, 16+12, bits, &n);
manchesterEncodeUint32(hi2, 16 + 12, bits, &n);
manchesterEncodeUint32(hi, 32, bits, &n);
manchesterEncodeUint32(lo, 32, bits, &n);
} else {
@ -939,7 +939,7 @@ void CmdHIDsimTAGEx(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT, boo
DbpString("[!] tags can only have 44 bits. - USE lf simfsk for larger tags");
return;
}
bitlen = 8+44*2;
bitlen = 8 + 44 * 2;
manchesterEncodeUint32(hi, 12, bits, &n);
manchesterEncodeUint32(lo, 32, bits, &n);
}
@ -1712,7 +1712,7 @@ void T55xxWriteBlock(uint8_t *data) {
c->flags &= (0xff ^ 0x40); // Called for a write, so ensure it is clear/0
LED_A_ON();
T55xx_SendCMD(c->data, c->pwd, c->flags | (c->blockno << 9)) ; //, false);
T55xx_SendCMD(c->data, c->pwd, c->flags | (c->blockno << 9));
// Perform write (nominal is 5.6 ms for T55x7 and 18ms for E5550,
// so wait a little more)
@ -1744,7 +1744,6 @@ void T55xxWriteBlock(uint8_t *data) {
// turn field off
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
// cmd_send(CMD_ACK,0,0,0,0,0);
reply_ng(CMD_LF_T55XX_WRITEBL, PM3_SUCCESS, NULL, 0);
LED_A_OFF();
}
@ -2037,46 +2036,6 @@ void CopyHIDtoT55x7(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT) {
LED_D_OFF();
}
void CopyIOtoT55x7(uint32_t hi, uint32_t lo) {
uint32_t data[] = {T55x7_BITRATE_RF_64 | T55x7_MODULATION_FSK2a | (2 << T55x7_MAXBLOCK_SHIFT), hi, lo};
//TODO add selection of chip for Q5 or T55x7
// data[0] = T5555_SET_BITRATE(64) | T5555_MODULATION_FSK2 | T5555_INVERT_OUTPUT | 2 << T5555_MAXBLOCK_SHIFT;
LED_D_ON();
// Program the data blocks for supplied ID
// and the block 0 config
WriteT55xx(data, 0, 3);
LED_D_OFF();
}
// Clone Indala 64-bit tag by UID to T55x7
void CopyIndala64toT55x7(uint32_t hi, uint32_t lo) {
//Program the 2 data blocks for supplied 64bit UID
// and the Config for Indala 64 format (RF/32;PSK1 with RF/2;Maxblock=2)
uint32_t data[] = { T55x7_BITRATE_RF_32 | T55x7_MODULATION_PSK1 | (2 << T55x7_MAXBLOCK_SHIFT), hi, lo};
//TODO add selection of chip for Q5 or T55x7
// data[0] = T5555_SET_BITRATE(32 | T5555_MODULATION_PSK1 | 2 << T5555_MAXBLOCK_SHIFT;
LED_D_ON();
WriteT55xx(data, 0, 3);
//Alternative config for Indala (Extended mode;RF/32;PSK1 with RF/2;Maxblock=2;Inverse data)
// T5567WriteBlock(0x603E1042,0);
LED_D_OFF();
}
// Clone Indala 224-bit tag by UID to T55x7
void CopyIndala224toT55x7(uint32_t uid1, uint32_t uid2, uint32_t uid3, uint32_t uid4, uint32_t uid5, uint32_t uid6, uint32_t uid7) {
//Program the 7 data blocks for supplied 224bit UID
uint32_t data[] = {0, uid1, uid2, uid3, uid4, uid5, uid6, uid7};
// and the block 0 for Indala224 format
//Config for Indala (RF/32;PSK2 with RF/2;Maxblock=7)
data[0] = T55x7_BITRATE_RF_32 | T55x7_MODULATION_PSK2 | (7 << T55x7_MAXBLOCK_SHIFT);
//TODO add selection of chip for Q5 or T55x7
// data[0] = T5555_SET_BITRATE(32 | T5555_MODULATION_PSK2 | 7 << T5555_MAXBLOCK_SHIFT;
LED_D_ON();
WriteT55xx(data, 0, 8);
//Alternative config for Indala (Extended mode;RF/32;PSK1 with RF/2;Maxblock=7;Inverse data)
// T5567WriteBlock(0x603E10E2,0);
LED_D_OFF();
}
// clone viking tag to T55xx
void CopyVikingtoT55xx(uint8_t *blocks, uint8_t Q5) {
@ -2085,7 +2044,7 @@ void CopyVikingtoT55xx(uint8_t *blocks, uint8_t Q5) {
data[0] = T5555_SET_BITRATE(32) | T5555_MODULATION_MANCHESTER | 2 << T5555_MAXBLOCK_SHIFT;
data[1] = bytes_to_num(blocks, 4);
data[2] = bytes_to_num(blocks +4, 4);
data[2] = bytes_to_num(blocks + 4, 4);
// Program the data blocks for supplied ID and the block 0 config
WriteT55xx(data, 0, 3);

View file

@ -42,12 +42,9 @@ void CmdHIDdemodFSK(int findone, uint32_t *high, uint32_t *low, int ledcontrol);
void CmdAWIDdemodFSK(int findone, uint32_t *high, uint32_t *low, int ledcontrol); // Realtime demodulation mode for AWID26
void CmdEM410xdemod(int findone, uint32_t *high, uint64_t *low, int ledcontrol);
void CmdIOdemodFSK(int findone, uint32_t *high, uint32_t *low, int ledcontrol);
void CopyIOtoT55x7(uint32_t hi, uint32_t lo); // Clone an ioProx card to T5557/T5567
void CopyHIDtoT55x7(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT); // Clone an HID card to T5557/T5567
void CopyVikingtoT55xx(uint8_t *blocks, uint8_t Q5);
void WriteEM410x(uint32_t card, uint32_t id_hi, uint32_t id_lo);
void CopyIndala64toT55x7(uint32_t hi, uint32_t lo); // Clone Indala 64-bit tag by UID to T55x7
void CopyIndala224toT55x7(uint32_t uid1, uint32_t uid2, uint32_t uid3, uint32_t uid4, uint32_t uid5, uint32_t uid6, uint32_t uid7); // Clone Indala 224-bit tag by UID to T55x7
void T55xxResetRead(uint8_t flags);
//id T55xxWriteBlock(uint32_t data, uint8_t blockno, uint32_t pwd, uint8_t flags);
void T55xxWriteBlock(uint8_t *data);

View file

@ -1977,11 +1977,6 @@ void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain) {
}
void MifareCIdent() {
#define GEN_1A 1
#define GEN_1B 2
#define GEN_2 4
#define GEN_UNFUSED 5
// variables
uint8_t isGen = 0;
uint8_t rec[1] = {0x00};
@ -1997,16 +1992,13 @@ void MifareCIdent() {
// Generation 1 test
ReaderTransmitBitsPar(wupC1, 7, NULL, NULL);
if (ReaderReceive(rec, recpar) || (rec[0] != 0x0a)) {
if (ReaderReceive(rec, recpar) && (rec[0] == 0x0a)) {
ReaderTransmit(wupC2, sizeof(wupC2), NULL);
if (!ReaderReceive(rec, recpar) || (rec[0] != 0x0a)) {
isGen = GEN_1B;
isGen = MAGIC_GEN_1B;
goto OUT;
};
isGen = GEN_1A;
isGen = MAGIC_GEN_1A;
goto OUT;
}
@ -2017,20 +2009,19 @@ void MifareCIdent() {
int res = iso14443a_select_card(uid, NULL, &cuid, true, 0, true);
if (res == 2) {
Dbprintf("cident AA55C396 == %08X", cuid);
if (cuid == 0xAA55C396) {
isGen = GEN_UNFUSED;
isGen = MAGIC_GEN_UNFUSED;
goto OUT;
}
ReaderTransmit(rats, sizeof(rats), NULL);
res = ReaderReceive(buf, par);
if (memcmp(buf, "\x09\x78\x00\x91\x02\xDA\xBC\x19\x10\xF0\x05", 11) == 0) {
isGen = GEN_2;
isGen = MAGIC_GEN_2;
goto OUT;
}
if (memcmp(buf, "\x0D\x78\x00\x71\x02\x88\x49\xA1\x30\x20\x15\x06\x08\x56\x3D", 15) == 0) {
isGen = GEN_2;
isGen = MAGIC_GEN_2;
}
};

View file

@ -230,6 +230,7 @@ CMDSRCS = crapto1/crapto1.c \
cmdflashmemspiffs.c \
cmdsmartcard.c \
cmdusart.c \
cmdwiegand.c \
cmdparser.c \
cmdmain.c \
pm3_binlib.c \
@ -238,7 +239,9 @@ CMDSRCS = crapto1/crapto1.c \
pm3_bitlib.c \
cmdcrc.c \
bucketsort.c \
flash.c
flash.c \
wiegand_formats.c \
wiegand_formatutils.c
cpu_arch = $(shell uname -m)
ifneq ($(findstring 86, $(cpu_arch)), )

View file

@ -1676,6 +1676,8 @@ static int CmdLoad(const char *Cmd) {
int len = 0;
len = strlen(Cmd);
if (len == 0) return PM3_EFILE;
if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE;
memcpy(filename, Cmd, len);

View file

@ -117,7 +117,7 @@ static int CmdFlashmemSpiBaudrate(const char *Cmd) {
usage_flashmem_spibaud();
return PM3_EINVARG;
}
SendCommandMIX(CMD_FLASHMEM_SET_SPIBAUDRATE, baudrate, 0, 0, NULL, 0);
SendCommandNG(CMD_FLASHMEM_SET_SPIBAUDRATE, (uint8_t*)&baudrate, sizeof(uint32_t));
return PM3_SUCCESS;
}

View file

@ -229,10 +229,11 @@ static int usage_hf_iclass_sniff(void) {
return PM3_SUCCESS;
}
static int usage_hf_iclass_loclass(void) {
PrintAndLogEx(NORMAL, "Usage: hf iclass loclass [options]");
PrintAndLogEx(NORMAL, "Usage: hf iclass loclass [h] [t [l]] [f <filename>]");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h Show this help");
PrintAndLogEx(NORMAL, " t Perform self-test");
PrintAndLogEx(NORMAL, " t l Perform self-test, including long ones");
PrintAndLogEx(NORMAL, " f <filename> Bruteforce iclass dumpfile");
PrintAndLogEx(NORMAL, " An iclass dumpfile is assumed to consist of an arbitrary number of");
PrintAndLogEx(NORMAL, " malicious CSNs, and their protocol responses");
@ -1831,10 +1832,11 @@ static int CmdHFiClass_loclass(const char *Cmd) {
return PM3_EFILE;
}
} else if (opt == 't') {
char opt2 = tolower(param_getchar(Cmd, 1));
int errors = testCipherUtils();
errors += testMAC();
errors += doKeyTests(0);
errors += testElite();
errors += testElite(opt2=='l');
if (errors) PrintAndLogEx(ERR, "There were errors!!!");
return PM3_ESOFT;
}

View file

@ -502,7 +502,7 @@ static int CmdStatus(const char *Cmd) {
clearCommandBuffer();
PacketResponseNG resp;
SendCommandNG(CMD_STATUS, NULL, 0);
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000))
if (WaitForResponseTimeout(CMD_STATUS, &resp, 2000) == false)
PrintAndLogEx(WARNING, "Status command failed. Communication speed test timed out");
return PM3_SUCCESS;
}

View file

@ -26,6 +26,7 @@
#include "cmdlf.h" // lf read
#include "protocols.h" // for T55xx config register definitions
#include "util_posix.h"
#include "cmdlft55xx.h" // verifywrite
static int CmdHelp(const char *Cmd);
/*
@ -414,6 +415,7 @@ static int CmdAWIDClone(const char *Cmd) {
PrintAndLogEx(INFO, "Preparing to clone AWID %u to T55x7 with FC: %u, CN: %u", fmtlen, fc, cn);
print_blocks(blocks, 4);
uint8_t res = 0;
PacketResponseNG resp;
// fast push mode
@ -437,7 +439,20 @@ static int CmdAWIDClone(const char *Cmd) {
PrintAndLogEx(ERR, "Error occurred, device did not respond during write operation.");
return PM3_ETIMEOUT;
}
if (i == 0) {
SetConfigWithBlock0(blocks[0]);
if (t55xxAquireAndCompareBlock0(false, 0, blocks[0], false))
continue;
}
if (t55xxVerifyWrite(i, 0, false, false, 0, 0xFF, blocks[i]) == false)
res++;
}
if (res == 0)
PrintAndLogEx(SUCCESS, "Success writing to tag");
return PM3_SUCCESS;
}

View file

@ -821,6 +821,12 @@ int EM4x50Read(const char *Cmd, bool verbose) {
uint8_t bits[MAX_GRAPH_TRACE_LEN] = {0};
size_t size = getFromGraphBuf(bits);
if (size < 4000) {
if (verbose || g_debugMode) PrintAndLogEx(ERR, "Error: EM4x50 - Too little data in Graphbuffer");
return PM3_ESOFT;
}
computeSignalProperties(bits, size);
signal_t *sp = getSignalProperties();

View file

@ -24,6 +24,7 @@
#include "crc16.h" // for checksum crc-16_ccitt
#include "protocols.h" // for T55xx config register definitions
#include "lfdemod.h" // parityTest
#include "cmdlft55xx.h" // verifywrite
/*
FDX-B ISO11784/85 demod (aka animal tag) BIPHASE, inverted, rf/32, with preamble of 00000000001 (128bits)
@ -296,6 +297,7 @@ static int CmdFdxClone(const char *Cmd) {
PrintAndLogEx(INFO, "Preparing to clone FDX-B to T55x7 with animal ID: %04u-%"PRIu64, countryid, animalid);
print_blocks(blocks, 5);
uint8_t res = 0;
PacketResponseNG resp;
// fast push mode
@ -318,7 +320,20 @@ static int CmdFdxClone(const char *Cmd) {
PrintAndLogEx(ERR, "Error occurred, device did not respond during write operation.");
return PM3_ETIMEOUT;
}
if (i == 0) {
SetConfigWithBlock0(blocks[0]);
if (t55xxAquireAndCompareBlock0(false, 0, blocks[0], false))
continue;
}
if (t55xxVerifyWrite(i, 0, false, false, 0, 0xFF, blocks[i]) == false)
res++;
}
if (res == 0)
PrintAndLogEx(SUCCESS, "Success writing to tag");
return PM3_SUCCESS;
}

View file

@ -21,6 +21,7 @@
#include "cmdlf.h"
#include "protocols.h" // for T55xx config register definitions
#include "lfdemod.h" // parityTest
#include "cmdlft55xx.h" // verifywrite
static int CmdHelp(const char *Cmd);
@ -183,6 +184,7 @@ static int CmdGuardClone(const char *Cmd) {
PrintAndLogEx(INFO, "Preparing to clone Guardall to T55x7 with Facility Code: %u, Card Number: %u", facilitycode, cardnumber);
print_blocks(blocks, 4);
uint8_t res = 0;
PacketResponseNG resp;
// fast push mode
@ -205,7 +207,20 @@ static int CmdGuardClone(const char *Cmd) {
PrintAndLogEx(ERR, "Error occurred, device did not respond during write operation.");
return PM3_ETIMEOUT;
}
if (i == 0) {
SetConfigWithBlock0(blocks[0]);
if (t55xxAquireAndCompareBlock0(false, 0, blocks[0], false))
continue;
}
if (t55xxVerifyWrite(i, 0, false, false, 0, 0xFF, blocks[i]) == false)
res++;
}
if (res == 0)
PrintAndLogEx(SUCCESS, "Success writing to tag");
return PM3_SUCCESS;
}

View file

@ -5,7 +5,17 @@
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// Low frequency HID commands
// Low frequency HID commands (known)
//
// Useful resources:
// RF interface, programming a T55x7 clone, 26-bit HID H10301 encoding:
// http://www.proxmark.org/files/Documents/125%20kHz%20-%20HID/HID_format_example.pdf
//
// "Understanding Card Data Formats"
// https://www.hidglobal.com/sites/default/files/hid-understanding_card_data_formats-wp-en.pdf
//
// "What Format Do You Need?"
// https://www.hidglobal.com/sites/default/files/resource_files/hid-prox-br-en.pdf
//-----------------------------------------------------------------------------
#include "cmdlfhid.h"
@ -25,40 +35,24 @@
#include "cmdlf.h" // lf_read
#include "util_posix.h"
#include "lfdemod.h"
#include "wiegand_formats.h"
#ifndef BITS
# define BITS 96
#endif
static int CmdHelp(const char *Cmd);
/*
static int usage_lf_hid_read(void) {
static int usage_lf_hid_watch(void) {
PrintAndLogEx(NORMAL, "Enables HID compatible reader mode printing details.");
PrintAndLogEx(NORMAL, "By default, values are printed and logged until the button is pressed or another USB command is issued.");
PrintAndLogEx(NORMAL, "If the [1] option is provided, reader mode is exited after reading a single HID card.");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf hid read [h] [1]");
PrintAndLogEx(NORMAL, "Usage: lf hid watch [h]");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : This help");
PrintAndLogEx(NORMAL, " 1 : (optional) stop after reading a single card");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf hid read");
PrintAndLogEx(NORMAL, " lf hid read 1");
return PM3_SUCCESS;
}
*/
static int usage_lf_hid_wiegand(void) {
PrintAndLogEx(NORMAL, "This command converts facility code/card number to Wiegand code");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf hid wiegand [h] [OEM] [FC] [CN]");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h - This help");
PrintAndLogEx(NORMAL, " OEM - OEM number / site code");
PrintAndLogEx(NORMAL, " FC - facility code");
PrintAndLogEx(NORMAL, " CN - card number");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf hid wiegand 0 101 2001");
PrintAndLogEx(NORMAL, " lf hid watch");
return PM3_SUCCESS;
}
static int usage_lf_hid_sim(void) {
@ -91,19 +85,21 @@ static int usage_lf_hid_brute(void) {
PrintAndLogEx(NORMAL, "This is a attack against reader. if cardnumber is given, it starts with it and goes up / down one step");
PrintAndLogEx(NORMAL, "if cardnumber is not given, it starts with 1 and goes up to 65535");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf hid brute [h] [v] a <format> f <facility-code> c <cardnumber> d <delay>");
PrintAndLogEx(NORMAL, "Usage: lf hid brute [h] [v] w <format> [<field> (decimal)>] {...}");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : This help");
PrintAndLogEx(NORMAL, " a <format> : 26|33|34|35|37|40|44|84");
PrintAndLogEx(NORMAL, " f <facility-code> : 8-bit value HID facility code");
PrintAndLogEx(NORMAL, " c <cardnumber> : (optional) cardnumber to start with, max 65535");
PrintAndLogEx(NORMAL, " w <format> : see `wiegand list` for available formats");
PrintAndLogEx(NORMAL, " f <facility-code> : facility code");
PrintAndLogEx(NORMAL, " c <cardnumber> : card number to start with");
PrintAndLogEx(NORMAL, " i <issuelevel> : issue level");
PrintAndLogEx(NORMAL, " o <oem> : OEM code");
PrintAndLogEx(NORMAL, " d <delay> : delay betweens attempts in ms. Default 1000ms");
PrintAndLogEx(NORMAL, " v : verbose logging, show all tries");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf hid brute a 26 f 224");
PrintAndLogEx(NORMAL, " lf hid brute a 26 f 21 d 2000");
PrintAndLogEx(NORMAL, " lf hid brute v a 26 f 21 c 200 d 2000");
PrintAndLogEx(NORMAL, " lf hid brute w H10301 f 224");
PrintAndLogEx(NORMAL, " lf hid brute w H10301 f 21 d 2000");
PrintAndLogEx(NORMAL, " lf hid brute v w H10301 f 21 c 200 d 2000");
return PM3_SUCCESS;
}
@ -118,17 +114,33 @@ static int sendPing(void) {
return PM3_ETIMEOUT;
return PM3_SUCCESS;
}
static int sendTry(uint8_t fmtlen, uint32_t fc, uint32_t cn, uint32_t delay, uint8_t *bits, bool verbose) {
static int sendTry(uint8_t format_idx, wiegand_card_t *card, uint32_t delay, bool verbose) {
wiegand_message_t packed;
memset(&packed, 0, sizeof(wiegand_message_t));
if (HIDPack(format_idx, card, &packed) == false) {
PrintAndLogEx(WARNING, "The card data could not be encoded in the selected format.");
return PM3_ESOFT;
}
// this should be optional.
if (verbose)
PrintAndLogEx(INFO, "Trying FC: %u; CN: %u", fc, cn);
PrintAndLogEx(INFO, "Trying FC: %u; CN: %u; Issue level: %u; OEM: %u", card->FacilityCode, card->CardNumber, card->IssueLevel, card->OEM);
calcWiegand(fmtlen, fc, cn, bits, 0);
lf_hidsim_t payload;
payload.hi2 = packed.Top;
payload.hi = packed.Mid;
payload.lo = packed.Bot;
clearCommandBuffer();
SendCommandMIX(CMD_LF_HID_SIMULATE, bytebits_to_byte(bits, 32), bytebits_to_byte(bits + 32, 32), 0, NULL, 0);
SendCommandNG(CMD_LF_HID_SIMULATE, (uint8_t *)&payload, sizeof(payload));
/*
PacketResponseNG resp;
WaitForResponse(CMD_LF_HID_SIMULATE, &resp);
if (resp.status == PM3_EOPABORTED)
return resp.status;
*/
msleep(delay);
return sendPing();
}
@ -248,18 +260,18 @@ static int CmdHIDRead(const char *Cmd) {
lf_read(true, 12000);
return CmdHIDDemod(Cmd);
}
/*
// this read loops on device side.
// uses the demod in lfops.c
static int CmdHIDRead_device(const char *Cmd) {
static int CmdHIDWatch(const char *Cmd) {
if (Cmd[0] == 'h' || Cmd[0] == 'H') return usage_lf_hid_read();
uint8_t findone = (Cmd[0] == '1') ? 1 : 0;
uint8_t ctmp = tolower(param_getchar(Cmd, 0));
if ( strlen(Cmd) == 0 || ctmp == 'h') return usage_lf_hid_watch();
clearCommandBuffer();
SendCommandMIX(CMD_LF_HID_DEMOD, findone, 0, 0, NULL, 0);
SendCommandMIX(CMD_LF_HID_DEMOD, 0, 0, 0, NULL, 0);
return PM3_SUCCESS;
}
*/
static int CmdHIDSim(const char *Cmd) {
lf_hidsim_t payload;
payload.longFMT = 0;
@ -309,8 +321,8 @@ static int CmdHIDClone(const char *Cmd) {
uint32_t hi2 = 0, hi = 0, lo = 0;
uint32_t n = 0, i = 0;
uint8_t ctmp = param_getchar(Cmd, 0);
if (strlen(Cmd) == 0 || ctmp == 'H' || ctmp == 'h') return usage_lf_hid_clone();
uint8_t ctmp = tolower(param_getchar(Cmd, 0));
if (strlen(Cmd) == 0 || ctmp == 'h') return usage_lf_hid_clone();
uint8_t longid[1] = {0};
if (strchr(Cmd, 'l') != 0) {
i++;
@ -338,202 +350,9 @@ static int CmdHIDClone(const char *Cmd) {
}
/*
// struct to handle wiegand
typedef struct {
uint8_t FormatLen;
uint8_t SiteCode;
uint8_t FacilityCode;
uint8_t CardNumber;
uint8_t *Wiegand;
size_t Wiegand_n;
} wiegand_t;
*/
static void addHIDMarker(uint8_t fmtlen, uint8_t *out) {
// temp array
uint8_t arr[BITS];
memset(arr, 0, BITS);
// copy inpu
uint8_t pos = sizeof(arr) - fmtlen;
memcpy(arr + pos, out, fmtlen);
switch (fmtlen) {
case 26: {
// start sentinel, BITS-bit 27 = 1
arr[BITS - 27] = 1;
// fmt smaller than 37 used, bit37 = 1
arr[BITS - 38] = 1;
memcpy(out, arr, BITS);
break;
}
case 34:
// start sentinel, BITS-bit 27 = 1
arr[BITS - 35] = 1;
// fmt smaller than 37 used, bit37 = 1
arr[BITS - 38] = 1;
memcpy(out, arr, BITS);
break;
default:
break;
}
}
// static void getParity34(uint32_t *hi, uint32_t *lo){
// uint32_t result = 0;
// int i;
// // even parity
// for (i = 7;i >= 0;i--)
// result ^= (*hi >> i) & i;
// for (i = 31;i >= 24;i--)
// result ^= (*lo >> i) & 1;
// *hi |= result << 2;
// // odd parity bit
// result = 0;
// for (i = 23;i >= 1;i--)
// result ^= (*lo >> i) & 1;
// *lo |= !result;
// }
// static void getParity37H(uint32_t *hi, uint32_t *lo){
// uint32_t result = 0;
// int i;
// // even parity
// for (i = 4;i >= 0;i--)
// result ^= (*hi >> i) & 1;
// for (i = 31;i >= 20;i--)
// result ^= (*lo >> i) & 1;
// *hi |= result << 4;
// // odd parity
// result = 0;
// for (i = 19;i >= 1;i--)
// result ^= (*lo >> i) & 1;
// *lo |= result;
// }
//static void calc26(uint16_t fc, uint32_t cardno, uint8_t *out){
static void calc26(uint16_t fc, uint32_t cardno, uint8_t *out) {
uint8_t wiegand[24];
num_to_bytebits(fc, 8, wiegand);
num_to_bytebits(cardno, 16, wiegand + 8);
wiegand_add_parity(out, wiegand, sizeof(wiegand));
}
// static void calc33(uint16_t fc, uint32_t cardno, uint8_t *out){
// }
static void calc34(uint16_t fc, uint32_t cardno, uint8_t *out) {
uint8_t wiegand[32];
num_to_bytebits(fc, 16, wiegand);
num_to_bytebits(cardno, 16, wiegand + 16);
wiegand_add_parity(out, wiegand, sizeof(wiegand));
}
// static void calc35(uint16_t fc, uint32_t cardno, uint8_t *out){
// *lo = ((cardno & 0xFFFFF) << 1) | fc << 21;
// *hi = (1 << 5) | ((fc >> 11) & 1);
// }
static void calc36(uint8_t oem, uint16_t fc, uint32_t cardno, uint8_t *out) {
// FC 1 - 16 - 16 bit
// cardno 17 - 33 - 16 bit
// oem 34 - 35 - 2 bit
// Odd Parity 0th bit 1-18
// Even Parity 36th bit 19-35
uint8_t wiegand[34];
num_to_bytebits(fc, 16, wiegand);
num_to_bytebits(cardno & 0xFFFF, 16, wiegand + 16);
num_to_bytebits(oem, 2, wiegand + 32);
wiegand_add_parity_swapped(out, wiegand, sizeof(wiegand));
}
static void calc37S(uint16_t fc, uint32_t cardno, uint8_t *out) {
// FC 2 - 17 - 16 bit
// cardno 18 - 36 - 19 bit
// Even P1 1 - 19
// Odd P37 19 - 36
uint8_t wiegand[35];
num_to_bytebits(fc, 16, wiegand);
num_to_bytebits(cardno, 19, wiegand + 16);
wiegand_add_parity(out, wiegand, sizeof(wiegand));
}
static void calc37H(uint64_t cardno, uint8_t *out) {
// SC NONE
// cardno 1-35 34 bits
// Even Parity 0th bit 1-18
// Odd Parity 36th bit 19-35
uint8_t wiegand[37];
num_to_bytebits((uint32_t)(cardno >> 32), 2, wiegand);
num_to_bytebits((uint32_t)(cardno >> 0), 32, wiegand + 2);
wiegand_add_parity(out, wiegand, sizeof(wiegand));
PrintAndLogEx(NORMAL, "%x %x\n", (uint32_t)(cardno >> 32), (uint32_t)cardno);
}
// static void calc40(uint64_t cardno, uint8_t *out){
// cardno = (cardno & 0xFFFFFFFFFF);
// *lo = ((cardno & 0xFFFFFFFF) << 1 );
// *hi = (cardno >> 31);
// }
void calcWiegand(uint8_t fmtlen, uint16_t fc, uint64_t cardno, uint8_t *bits, uint8_t oem) {
uint32_t cn32 = (cardno & 0xFFFFFFFF);
switch (fmtlen) {
case 26:
calc26(fc, cn32, bits);
break;
// case 33 : calc33(fc, cn32, bits); break;
case 34:
calc34(fc, cn32, bits);
break;
// case 35 : calc35(fc, cn32, bits); break;
case 36:
calc36(oem, fc, cn32, bits);
break;
case 37:
calc37S(fc, cn32, bits);
break;
case 38:
calc37H(cardno, bits);
break;
// case 40 : calc40(cardno, bits); break;
// case 44 : { break; }
// case 84 : { break; }
default:
break;
}
}
static int CmdHIDWiegand(const char *Cmd) {
uint32_t oem = 0, fc = 0;
uint64_t cardnum = 0;
uint8_t bits[BITS] = {0};
uint8_t *bs = bits;
uint8_t ctmp = tolower(param_getchar(Cmd, 0));
if (strlen(Cmd) < 3 || ctmp == 'h') return usage_lf_hid_wiegand();
oem = param_get8(Cmd, 0);
fc = param_get32ex(Cmd, 1, 0, 10);
cardnum = param_get64ex(Cmd, 2, 0, 10);
uint8_t fmtlen[] = {26, 33, 34, 35, 36, 37, 38, 40};
PrintAndLogEx(NORMAL, "HID | OEM | FC | CN | Wiegand | HID Formatted");
PrintAndLogEx(NORMAL, "----+-----+------+---------+-----------+--------------------");
for (uint8_t i = 0; i < ARRAYLEN(fmtlen); i++) {
memset(bits, 0x00, sizeof(bits));
calcWiegand(fmtlen[i], fc, cardnum, bs, oem);
PrintAndLogEx(NORMAL, "ice:: %s \n", sprint_bin(bs, fmtlen[i]));
uint64_t wiegand = (uint64_t)bytebits_to_byte(bs, 32) << 32 | bytebits_to_byte(bs + 32, 32);
addHIDMarker(fmtlen[i], bs);
PrintAndLogEx(NORMAL, "ice:: %s\n", sprint_bin(bs, BITS));
uint64_t blocks = (uint64_t)bytebits_to_byte(bs + 32, 32) << 32 | bytebits_to_byte(bs + 64, 32);
uint8_t shifts = 64 - fmtlen[i];
wiegand >>= shifts;
PrintAndLogEx(NORMAL, " %u | %03u | %03u | %" PRIu64 " | %" PRIX64 " | %" PRIX64,
PrintAndLogEx(NORMAL, " %u | %03u | %03u | %" PRIu64 " | %" PRIX64 " | %" PRIX64,
fmtlen[i],
oem,
fc,
@ -543,26 +362,33 @@ static int CmdHIDWiegand(const char *Cmd) {
);
}
PrintAndLogEx(NORMAL, "----+-----+-----+-------+-----------+--------------------");
return PM3_SUCCESS;
}
*/
static int CmdHIDBrute(const char *Cmd) {
bool errors = false, verbose = false;
uint32_t fc = 0, cn = 0, delay = 1000;
uint8_t fmtlen = 0;
uint8_t bits[96];
memset(bits, 0, sizeof(bits));
uint32_t delay = 1000;
uint8_t cmdp = 0;
int format_idx = -1;
char format[16] = {0};
wiegand_card_t data;
memset(&data, 0, sizeof(wiegand_card_t));
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h':
return usage_lf_hid_brute();
case 'f':
fc = param_get32ex(Cmd, cmdp + 1, 0, 10);
if (!fc)
case 'w':
param_getstr(Cmd, cmdp + 1, format, sizeof(format));
format_idx = HIDFindCardFormat(format);
if (format_idx == -1) {
PrintAndLogEx(WARNING, "Unknown format: %s", format);
errors = true;
}
cmdp += 2;
break;
case 'c':
data.CardNumber = param_get32ex(Cmd, cmdp + 1, 0, 10);
cmdp += 2;
break;
case 'd':
@ -570,24 +396,17 @@ static int CmdHIDBrute(const char *Cmd) {
delay = param_get32ex(Cmd, cmdp + 1, 1000, 10);
cmdp += 2;
break;
case 'c':
cn = param_get32ex(Cmd, cmdp + 1, 0, 10);
// truncate cardnumber.
cn &= 0xFFFF;
case 'f':
data.FacilityCode = param_get32ex(Cmd, cmdp + 1, 0, 10);
cmdp += 2;
break;
case 'a':
fmtlen = param_get8(Cmd, cmdp + 1);
case 'i':
data.IssueLevel = param_get32ex(Cmd, cmdp + 1, 0, 10);
cmdp += 2;
break;
case 'o':
data.OEM = param_get32ex(Cmd, cmdp + 1, 0, 10);
cmdp += 2;
bool is_ftm_ok = false;
uint8_t ftms[] = {26, 33, 34, 35, 37};
for (uint8_t i = 0; i < ARRAYLEN(ftms); i++) {
if (ftms[i] == fmtlen) {
is_ftm_ok = true;
}
}
// negated
errors = !is_ftm_ok;
break;
case 'v':
verbose = true;
@ -599,15 +418,11 @@ static int CmdHIDBrute(const char *Cmd) {
break;
}
}
if (fc == 0) errors = true;
if (errors) return usage_lf_hid_brute();
PrintAndLogEx(INFO, "Brute-forcing HID reader");
PrintAndLogEx(INFO, "Press pm3-button to abort simulation or run another command");
uint16_t up = cn;
uint16_t down = cn;
// main loop
for (;;) {
@ -622,13 +437,16 @@ static int CmdHIDBrute(const char *Cmd) {
}
// Do one up
if (up < 0xFFFF)
if (sendTry(fmtlen, fc, up++, delay, bits, verbose) != PM3_SUCCESS) return PM3_ESOFT;
if (data.CardNumber < 0xFFFF) {
data.CardNumber++;
if (sendTry(format_idx, &data, delay, verbose) != PM3_SUCCESS) return PM3_ESOFT;
}
// Do one down (if cardnumber is given)
if (cn > 1)
if (down > 1)
if (sendTry(fmtlen, fc, --down, delay, bits, verbose) != PM3_SUCCESS) return PM3_ESOFT;
if (data.CardNumber > 1) {
data.CardNumber--;
if (sendTry(format_idx, &data, delay, verbose) != PM3_SUCCESS) return PM3_ESOFT;
}
}
return PM3_SUCCESS;
}
@ -639,8 +457,8 @@ static command_t CommandTable[] = {
{"read", CmdHIDRead, IfPm3Lf, "attempt to read and extract tag data"},
{"clone", CmdHIDClone, IfPm3Lf, "clone HID to T55x7"},
{"sim", CmdHIDSim, IfPm3Lf, "simulate HID tag"},
{"wiegand", CmdHIDWiegand, AlwaysAvailable, "convert facility code/card number to Wiegand code"},
{"brute", CmdHIDBrute, IfPm3Lf, "bruteforce card number against reader"},
{"watch", CmdHIDWatch, IfPm3Lf, "continuously watch for cards. Reader mode"},
{NULL, NULL, NULL, NULL}
};

View file

@ -25,6 +25,8 @@
#include "lfdemod.h" // parityTest, bitbytes_to_byte
#include "cmddata.h"
#include "cmdlf.h" // lf_read
#include "protocols.h" // t55 defines
#include "cmdlft55xx.h" // verifywrite
static int CmdHelp(const char *Cmd);
@ -439,10 +441,12 @@ static int CmdIndalaSim(const char *Cmd) {
return PM3_SUCCESS;
}
// iceman - needs refactoring
static int CmdIndalaClone(const char *Cmd) {
bool isLongUid = false;
uint32_t blocks[8] = {0};
uint8_t max = 0;
uint8_t data[7 * 4];
int datalen = 0;
@ -466,27 +470,77 @@ static int CmdIndalaClone(const char *Cmd) {
CLIGetHexWithReturn(2, data, &datalen);
CLIParserFree();
/*
//TODO add selection of chip for Q5 or T55x7
// data[0] = T5555_SET_BITRATE(32 | T5555_MODULATION_PSK2 | 7 << T5555_MAXBLOCK_SHIFT;
//Alternative config for Indala (Extended mode;RF/32;PSK1 with RF/2;Maxblock=7;Inverse data)
// T5567WriteBlock(0x603E10E2,0);
// data[0] = T5555_SET_BITRATE(32 | T5555_MODULATION_PSK1 | 2 << T5555_MAXBLOCK_SHIFT;
//Alternative config for Indala (Extended mode;RF/32;PSK1 with RF/2;Maxblock=2;Inverse data)
// T5567WriteBlock(0x603E1042,0);
*/
if (isLongUid) {
// config for Indala (RF/32;PSK2 with RF/2;Maxblock=7)
PrintAndLogEx(INFO, "Preparing to clone Indala 224bit tag with RawID %s", sprint_hex(data, datalen));
uint32_t datawords[7] = {0};
datawords[0] = bytes_to_num(data, 4);
datawords[1] = bytes_to_num(data + 4, 4);
datawords[2] = bytes_to_num(data + 8, 4);
datawords[3] = bytes_to_num(data + 12, 4);
datawords[4] = bytes_to_num(data + 16, 4);
datawords[5] = bytes_to_num(data + 20, 4);
datawords[6] = bytes_to_num(data + 24, 4);
clearCommandBuffer();
SendCommandOLD(CMD_LF_INDALA224_CLONE, 0, 0, 0, datawords, sizeof(datawords));
blocks[0] = T55x7_BITRATE_RF_32 | T55x7_MODULATION_PSK2 | (7 << T55x7_MAXBLOCK_SHIFT);
blocks[1] = bytes_to_num(data, 4);
blocks[2] = bytes_to_num(data + 4, 4);
blocks[3] = bytes_to_num(data + 8, 4);
blocks[4] = bytes_to_num(data + 12, 4);
blocks[5] = bytes_to_num(data + 16, 4);
blocks[6] = bytes_to_num(data + 20, 4);
blocks[7] = bytes_to_num(data + 24, 4);
max = 8;
} else {
// config for Indala 64 format (RF/32;PSK1 with RF/2;Maxblock=2)
PrintAndLogEx(INFO, "Preparing to clone Indala 64bit tag with RawID %s", sprint_hex(data, datalen));
uint32_t datawords[2] = {0};
datawords[0] = bytes_to_num(data, 4);
datawords[1] = bytes_to_num(data + 4, 4);
clearCommandBuffer();
SendCommandOLD(CMD_LF_INDALA_CLONE, 0, 0, 0, datawords, sizeof(datawords));
blocks[0] = T55x7_BITRATE_RF_32 | T55x7_MODULATION_PSK1 | (2 << T55x7_MAXBLOCK_SHIFT);
blocks[1] = bytes_to_num(data, 4);
blocks[2] = bytes_to_num(data + 4, 4);
max = 3;
}
print_blocks(blocks, max);
uint8_t res = 0;
PacketResponseNG resp;
// fast push mode
conn.block_after_ACK = true;
for (uint8_t i = 0; i < max; i++) {
if (i == max - 1) {
// Disable fast mode on last packet
conn.block_after_ACK = false;
}
clearCommandBuffer();
t55xx_write_block_t ng;
ng.data = blocks[i];
ng.pwd = 0;
ng.blockno = i;
ng.flags = 0;
SendCommandNG(CMD_LF_T55XX_WRITEBL, (uint8_t *)&ng, sizeof(ng));
if (!WaitForResponseTimeout(CMD_LF_T55XX_WRITEBL, &resp, T55XX_WRITE_TIMEOUT)) {
PrintAndLogEx(ERR, "Error occurred, device did not respond during write operation.");
return PM3_ETIMEOUT;
}
if (i == 0) {
SetConfigWithBlock0(blocks[0]);
if (t55xxAquireAndCompareBlock0(false, 0, blocks[0], false))
continue;
}
if (t55xxVerifyWrite(i, 0, false, false, 0, 0xFF, blocks[i]) == false)
res++;
}
if (res == 0)
PrintAndLogEx(SUCCESS, "Success writing to tag");
return PM3_SUCCESS;
}

View file

@ -24,6 +24,7 @@
#include "lfdemod.h" // parityTest, bitbytes_to_byte
#include "protocols.h" // for T55xx config register definitions
#include "cmddata.h"
#include "cmdlft55xx.h" // verifywrite
static int CmdHelp(const char *Cmd);
/*
@ -243,7 +244,6 @@ static int CmdIOProxSim(const char *Cmd) {
static int CmdIOProxClone(const char *Cmd) {
uint32_t blocks[3] = {T55x7_MODULATION_FSK2a | T55x7_BITRATE_RF_64 | 2 << T55x7_MAXBLOCK_SHIFT, 0, 0};
uint16_t cn = 0;
uint8_t version = 0, fc = 0;
uint8_t bits[64];
@ -268,7 +268,9 @@ static int CmdIOProxClone(const char *Cmd) {
return PM3_ESOFT;
}
if (param_getchar(Cmd, 3) == 'Q' || param_getchar(Cmd, 3) == 'q')
uint32_t blocks[3] = {T55x7_MODULATION_FSK2a | T55x7_BITRATE_RF_64 | 2 << T55x7_MAXBLOCK_SHIFT, 0, 0};
if (tolower(param_getchar(Cmd, 3) == 'q'))
blocks[0] = T5555_MODULATION_FSK2 | T5555_INVERT_OUTPUT | T5555_SET_BITRATE(64) | 2 << T5555_MAXBLOCK_SHIFT;
blocks[1] = bytebits_to_byte(bits, 32);
@ -277,8 +279,42 @@ static int CmdIOProxClone(const char *Cmd) {
PrintAndLogEx(INFO, "Preparing to clone IOProx to T55x7 with Version: %u FC: %u, CN: %u", version, fc, cn);
print_blocks(blocks, 3);
clearCommandBuffer();
SendCommandMIX(CMD_LF_IO_CLONE, blocks[1], blocks[2], 0, NULL, 0);
uint8_t res = 0;
PacketResponseNG resp;
// fast push mode
conn.block_after_ACK = true;
for (uint8_t i = 0; i < 3; i++) {
if (i == 2) {
// Disable fast mode on last packet
conn.block_after_ACK = false;
}
clearCommandBuffer();
t55xx_write_block_t ng;
ng.data = blocks[i];
ng.pwd = 0;
ng.blockno = i;
ng.flags = 0;
SendCommandNG(CMD_LF_T55XX_WRITEBL, (uint8_t *)&ng, sizeof(ng));
if (!WaitForResponseTimeout(CMD_LF_T55XX_WRITEBL, &resp, T55XX_WRITE_TIMEOUT)) {
PrintAndLogEx(ERR, "Error occurred, device did not respond during write operation.");
return PM3_ETIMEOUT;
}
if (i == 0) {
SetConfigWithBlock0(blocks[0]);
if (t55xxAquireAndCompareBlock0(false, 0, blocks[0], false))
continue;
}
if (t55xxVerifyWrite(i, 0, false, false, 0, 0xFF, blocks[i]) == false)
res++;
}
if (res == 0)
PrintAndLogEx(SUCCESS, "Success writing to tag");
return PM3_SUCCESS;
}

View file

@ -24,6 +24,7 @@
#include "cmdlf.h"
#include "protocols.h" // for T55xx config register definitions
#include "lfdemod.h" // parityTest
#include "cmdlft55xx.h" // verifywrite
static int CmdHelp(const char *Cmd);
@ -170,6 +171,7 @@ static int CmdJablotronClone(const char *Cmd) {
PrintAndLogEx(INFO, "Preparing to clone Jablotron to T55x7 with FullCode: %"PRIx64, fullcode);
print_blocks(blocks, 3);
uint8_t res = 0;
PacketResponseNG resp;
// fast push mode
@ -192,7 +194,20 @@ static int CmdJablotronClone(const char *Cmd) {
PrintAndLogEx(ERR, "Error occurred, device did not respond during write operation.");
return PM3_ETIMEOUT;
}
if (i == 0) {
SetConfigWithBlock0(blocks[0]);
if (t55xxAquireAndCompareBlock0(false, 0, blocks[0], false))
continue;
}
if (t55xxVerifyWrite(i, 0, false, false, 0, 0xFF, blocks[i]) == false)
res++;
}
if (res == 0)
PrintAndLogEx(SUCCESS, "Success writing to tag");
return PM3_SUCCESS;
}

View file

@ -22,6 +22,7 @@
#include "cmdlf.h"
#include "protocols.h" // for T55xx config register definitions
#include "lfdemod.h" // preamble test
#include "cmdlft55xx.h" // verifywrite
static int CmdHelp(const char *Cmd);
@ -159,6 +160,7 @@ static int CmdKeriClone(const char *Cmd) {
blocks[2] = data & 0xFFFFFFFF;
print_blocks(blocks, 3);
uint8_t res = 0;
PacketResponseNG resp;
// fast push mode
@ -181,8 +183,20 @@ static int CmdKeriClone(const char *Cmd) {
PrintAndLogEx(ERR, "Error occurred, device did not respond during write operation.");
return PM3_ETIMEOUT;
}
if (i == 0) {
SetConfigWithBlock0(blocks[0]);
if (t55xxAquireAndCompareBlock0(false, 0, blocks[0], false))
continue;
}
if (t55xxVerifyWrite(i, 0, false, false, 0, 0xFF, blocks[i]) == false)
res++;
}
if (res == 0)
PrintAndLogEx(SUCCESS, "Success writing to tag");
return PM3_SUCCESS;
}

View file

@ -9,20 +9,6 @@
#include "cmdlfnedap.h"
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include "cmdparser.h" // command_t
#include "comms.h"
#include "crc16.h"
#include "cmdlft55xx.h"
#include "ui.h"
#include "cmddata.h"
#include "cmdlf.h"
#include "lfdemod.h"
#define FIXED_71 0x71
#define FIXED_40 0x40
#define UNKNOWN_A 0x00
@ -469,6 +455,7 @@ int CmdLFNedapClone(const char *Cmd) {
PrintAndLogEx(SUCCESS, "Preparing to clone NEDAP to T55x7");
print_blocks(blocks, max);
uint8_t res = 0;
PacketResponseNG resp;
// fast push mode
@ -490,10 +477,24 @@ int CmdLFNedapClone(const char *Cmd) {
PrintAndLogEx(ERR, "Error occurred, device did not respond during write operation.");
return PM3_ETIMEOUT;
}
if (i == 0) {
SetConfigWithBlock0(blocks[0]);
if (t55xxAquireAndCompareBlock0(false, 0, blocks[0], false))
continue;
}
if (t55xxVerifyWrite(i, 0, false, false, 0, 0xFF, blocks[i]) == false)
res++;
}
if (res == 0)
PrintAndLogEx(SUCCESS, "Success writing to tag");
else {
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "The block 0 was changed (eXtended) which can be hard to detect.");
PrintAndLogEx(INFO, " Configure it manually " _YELLOW_("`lf t55xx config b 64 d BI i 1 o 32`"));
}
PrintAndLogEx(NORMAL, "\n");
PrintAndLogEx(INFO, "The block 0 was changed (eXtended) which can be hard to detect.");
PrintAndLogEx(INFO, " Configure it manually " _YELLOW_("`lf t55xx config b 64 d BI i 1 o 32`"));
return PM3_SUCCESS;
}

View file

@ -11,6 +11,19 @@
#include "common.h"
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include "cmdparser.h" // command_t
#include "comms.h"
#include "crc16.h"
#include "cmdlft55xx.h" // verifywrite
#include "ui.h"
#include "cmddata.h"
#include "cmdlf.h"
#include "lfdemod.h"
int CmdLFNedap(const char *Cmd);
int demodNedap(void);

View file

@ -177,16 +177,17 @@ static int CmdNoralsyClone(const char *Cmd) {
return PM3_ETIMEOUT;
}
// write block0, needs a detect.
if (i == 0)
t55xxAquireAndDetect(false, 0, blocks[i], false);
if (i == 0) {
SetConfigWithBlock0(blocks[0]);
if (t55xxAquireAndCompareBlock0(false, 0, blocks[0], false))
continue;
}
if (t55xxVerifyWrite(i, 0, false, false, 0, 0xFF, blocks[i]) == false)
res++;
}
if ( res == 0 )
if (res == 0)
PrintAndLogEx(SUCCESS, "Success writing to tag");
return PM3_SUCCESS;

View file

@ -144,19 +144,18 @@ static int CmdPrescoClone(const char *Cmd) {
return PM3_ETIMEOUT;
}
// write block0, needs a detect.
if (i == 0) {
printf("enter detect ");
bool ok = t55xxAquireAndDetect(false, 0, blocks[i], false);
printf(" b0 = '%c' \n", (ok) ? 'Y':'N');
SetConfigWithBlock0(blocks[0]);
if (t55xxAquireAndCompareBlock0(false, 0, blocks[0], false))
continue;
}
if (t55xxVerifyWrite(i, 0, false, false, 0, 0xFF, blocks[i]) == false) {
if (t55xxVerifyWrite(i, 0, false, false, 0, 0xFF, blocks[i]) == false)
res++;
printf(" i = %d \n", i);
}
}
if ( res == 0 )
if (res == 0)
PrintAndLogEx(SUCCESS, "Success writing to tag");
return PM3_SUCCESS;

View file

@ -254,16 +254,18 @@ static int CmdPyramidClone(const char *Cmd) {
return PM3_ETIMEOUT;
}
// write block0, needs a detect.
if (i == 0)
t55xxAquireAndDetect(false, 0, blocks[i], false);
if (i == 0) {
SetConfigWithBlock0(blocks[0]);
if (t55xxAquireAndCompareBlock0(false, 0, blocks[0], false))
continue;
}
if (t55xxVerifyWrite(i, 0, false, false, 0, 0xFF, blocks[i]) == false)
res++;
}
if ( res == 0 )
if (res == 0)
PrintAndLogEx(SUCCESS, "Success writing to tag");
return PM3_SUCCESS;

View file

@ -52,7 +52,7 @@ t55xx_conf_block_t config = {
.Q5 = false,
.usepwd = false,
.downlink_mode = refFixedBit
};
};
t55xx_conf_block_t Get_t55xx_Config() {
return config;
@ -338,7 +338,7 @@ static int usage_t55xx_protect() {
static int CmdHelp(const char *Cmd);
static bool t55xxProtect(bool lock, bool usepwd, uint8_t override, uint32_t password, uint8_t downlink_mode, uint32_t new_password ) {
static bool t55xxProtect(bool lock, bool usepwd, uint8_t override, uint32_t password, uint8_t downlink_mode, uint32_t new_password) {
PrintAndLogEx(INFO, "Checking current configuration");
@ -354,7 +354,7 @@ static bool t55xxProtect(bool lock, bool usepwd, uint8_t override, uint32_t pass
if (GetT55xxBlockData(&block0) == false)
return false;
bool isPwdBitAlreadySet = (block0 >> (32-28) & 1);
bool isPwdBitAlreadySet = (block0 >> (32 - 28) & 1);
if (isPwdBitAlreadySet) {
PrintAndLogEx(INFO, "PWD bit is already set");
usepwd = true;
@ -368,7 +368,7 @@ static bool t55xxProtect(bool lock, bool usepwd, uint8_t override, uint32_t pass
}
// write new password
if ( t55xxWrite(T55x7_PWD_BLOCK, T55x7_PAGE0, usepwd, testmode, password, downlink_mode, new_password ) != PM3_SUCCESS ) {
if (t55xxWrite(T55x7_PWD_BLOCK, T55x7_PAGE0, usepwd, testmode, password, downlink_mode, new_password) != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Failed to write new password");
return false;
} else {
@ -386,7 +386,7 @@ static bool t55xxProtect(bool lock, bool usepwd, uint8_t override, uint32_t pass
}
// write config
if ( t55xxWrite(T55x7_CONFIGURATION_BLOCK, T55x7_PAGE0, usepwd, testmode, curr_password, downlink_mode, block0 ) != PM3_SUCCESS ) {
if (t55xxWrite(T55x7_CONFIGURATION_BLOCK, T55x7_PAGE0, usepwd, testmode, curr_password, downlink_mode, block0) != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Failed to write modified configuration block %08X", block0);
return false;
} else {
@ -405,21 +405,48 @@ static bool t55xxProtect(bool lock, bool usepwd, uint8_t override, uint32_t pass
}
}
bool t55xxAquireAndCompareBlock0(bool usepwd, uint32_t password, uint32_t known_block0, bool verbose) {
if (verbose)
PrintAndLogEx(INFO, "Block0 write detected, running `detect` to see if validation is possible");
for (uint8_t m = 0; m < 4; m++) {
if (AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password, m) == false) {
continue;
}
if (DecodeT55xxBlock() == false) {
continue;
}
for (uint16_t i = 0; DemodBufferLen - 32; i++) {
uint32_t tmp = PackBits(i, 32, DemodBuffer);
if (tmp == known_block0) {
config.offset = i;
config.downlink_mode = m;
return true;
}
}
}
return false;
}
bool t55xxAquireAndDetect(bool usepwd, uint32_t password, uint32_t known_block0, bool verbose) {
if (verbose)
PrintAndLogEx(INFO, "Block0 write detected, running `detect` to see if validation is possible");
for ( uint8_t m = 0; m < 4; m++) {
for (uint8_t m = 0; m < 4; m++) {
if (AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password, m) == false)
continue;
if (tryDetectModulationEx(m, verbose, known_block0) == false)
continue;
config.downlink_mode = m;
return true;
}
return false;
return false;
}
bool t55xxVerifyWrite(uint8_t block, bool page1, bool usepwd, uint8_t override, uint32_t password, uint8_t downlink_mode, uint32_t data) {
@ -435,7 +462,7 @@ bool t55xxVerifyWrite(uint8_t block, bool page1, bool usepwd, uint8_t override,
if (GetT55xxBlockData(&read_data) == false)
return false;
} else if ( res == PM3_EWRONGANSVER) {
} else if (res == PM3_EWRONGANSVER) {
// could't decode. Lets see if this was a block 0 write and try read/detect it auto.
// this messes up with ppls config..
@ -491,6 +518,39 @@ void printT5xxHeader(uint8_t page) {
PrintAndLogEx(SUCCESS, "----+----------+----------------------------------+-------");
}
void SetConfigWithBlock0(uint32_t block0) {
SetConfigWithBlock0Ex(block0, 0, false);
}
void SetConfigWithBlock0Ex(uint32_t block0, uint8_t offset, bool Q5) {
// T55x7
uint32_t extend = (block0 >> (32 - 15)) & 0x01;
uint32_t dbr;
if (extend)
dbr = (block0 >> (32 - 14)) & 0x3F;
else
dbr = (block0 >> (32 - 14)) & 0x07;
uint32_t datamod = (block0 >> (32 - 20)) & 0x1F;
bool pwd = (bool)((block0 >> (32 - 28)) & 0x01);
bool sst = (bool)((block0 >> (32 - 29)) & 0x01);
bool inv = (bool)((block0 >> (32 - 31)) & 0x01);
config.modulation = datamod;
config.bitrate = dbr;
// FSK1a, FSK2a
if (datamod == DEMOD_FSK1a || datamod == DEMOD_FSK2a || datamod == DEMOD_BIa)
config.inverted = 1;
else
config.inverted = inv;
config.Q5 = Q5;
config.ST = sst;
config.usepwd = pwd;
config.offset = offset;
config.block0 = block0;
}
static int CmdT55xxSetConfig(const char *Cmd) {
// No args
@ -619,32 +679,8 @@ static int CmdT55xxSetConfig(const char *Cmd) {
//Validations
if (errors) return usage_t55xx_config();
if ( gotconf ) {
// Q5
// T55x7
uint32_t extend = (block0 >> (32 - 15)) & 0x01;
uint32_t dbr;
if (extend)
dbr = (block0 >> (32 - 14)) & 0x3F;
else
dbr = (block0 >> (32 - 14)) & 0x07;
uint32_t datamod = (block0 >> (32 - 20)) & 0x1F;
bool pwd = (bool)((block0 >> (32 - 28)) & 0x01);
bool sst = (bool)((block0 >> (32 - 29)) & 0x01);
bool inv = (bool)((block0 >> (32 - 31)) & 0x01);
config.modulation = datamod;
config.bitrate = dbr;
config.inverted = inv;
config.Q5 = 0;
config.ST = sst;
config.usepwd = pwd;
config.offset = 0;
config.block0 = block0;
if (gotconf) {
SetConfigWithBlock0Ex(block0, config.offset, config.Q5);
} else {
config.block0 = 0;
}
@ -893,7 +929,7 @@ static int CmdT55xxDetect(const char *Cmd) {
if (useGB == false) {
if ( try_all_dl_modes ) {
if (try_all_dl_modes) {
for (uint8_t m = downlink_mode; m < 4; m++) {
if (AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password, m) == false)
@ -1116,7 +1152,7 @@ bool tryDetectModulationEx(uint8_t downlink_mode, bool print_config, uint32_t wa
wanted = (wanted_conf == tests[i].block0);
retval = testKnownConfigBlock(tests[i].block0);
if (retval || wanted ) {
if (retval || wanted) {
PrintAndLogEx(NORMAL, "--[%d]--------------- << selected this", i + 1);
config.modulation = tests[i].modulation;
config.bitrate = tests[i].bitrate;
@ -1131,7 +1167,7 @@ bool tryDetectModulationEx(uint8_t downlink_mode, bool print_config, uint32_t wa
}
if (print_config)
printConfiguration(tests[i]);
printConfiguration(tests[i]);
}
}
return retval;
@ -1391,7 +1427,7 @@ int printConfiguration(t55xx_conf_block_t b) {
PrintAndLogEx(NORMAL, " Offset : %d", b.offset);
PrintAndLogEx(NORMAL, " Seq. Term. : %s", (b.ST) ? _GREEN_("Yes") : "No");
PrintAndLogEx(NORMAL, " Block0 : 0x%08X", b.block0);
PrintAndLogEx(NORMAL, " Downlink Mode : %s", GetDownlinkModeStr (b.downlink_mode));
PrintAndLogEx(NORMAL, " Downlink Mode : %s", GetDownlinkModeStr(b.downlink_mode));
PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS;
}
@ -1514,7 +1550,7 @@ static int CmdT55xxWriteBlock(const char *Cmd) {
PrintAndLogEx(INFO, "Writing page %d block: %02d data: 0x%08X %s", page1, block, data, (usepwd) ? pwdStr : "");
if ( t55xxWrite(block, page1, usepwd, testMode, password, downlink_mode, data) != PM3_SUCCESS ) {
if (t55xxWrite(block, page1, usepwd, testMode, password, downlink_mode, data) != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Write failed");
return PM3_ESOFT;
}
@ -2165,23 +2201,22 @@ char *GetModulationStr(uint32_t id, bool xmode) {
return buf;
}
char *GetDownlinkModeStr (uint8_t downlink_mode)
{
char *GetDownlinkModeStr(uint8_t downlink_mode) {
static char buf[30];
char *retStr = buf;
switch (downlink_mode) {
case T55XX_DLMODE_FIXED :
snprintf(retStr, sizeof(buf),"default/fixed bit length");
snprintf(retStr, sizeof(buf), "default/fixed bit length");
break;
case T55XX_DLMODE_LLR :
snprintf(retStr, sizeof(buf),"long leading reference");
snprintf(retStr, sizeof(buf), "long leading reference");
break;
case T55XX_DLMODE_LEADING_ZERO :
snprintf(retStr, sizeof(buf),"leading zero reference");
snprintf(retStr, sizeof(buf), "leading zero reference");
break;
case T55XX_DLMODE_1OF4 :
snprintf(retStr, sizeof(buf),"1 of 4 coding reference");
snprintf(retStr, sizeof(buf), "1 of 4 coding reference");
break;
default:
snprintf(retStr, sizeof(buf), _RED_("(Unknown)"));
@ -2392,7 +2427,7 @@ static int CmdT55xxWipe(const char *Cmd) {
if (errors) return usage_t55xx_wipe();
PrintAndLogEx(INFO, "\nBegin wiping %s", (Q5)? "Q5 / T5555 tag" : "T55x7 tag");
PrintAndLogEx(INFO, "\nBegin wiping %s", (Q5) ? "Q5 / T5555 tag" : "T55x7 tag");
// default config blocks.
if (gotconf == false) {
@ -2579,7 +2614,7 @@ static int CmdT55xxChkPwds(const char *Cmd) {
continue;
}
found = tryDetectModulation(dl_mode,T55XX_PrintConfig);
found = tryDetectModulation(dl_mode, T55XX_PrintConfig);
if (found) {
PrintAndLogEx(SUCCESS, "Found valid password: [ " _GREEN_("%08X") " ]", curr_password);
dl_mode = 4; // Exit other downlink mode checks
@ -2697,7 +2732,7 @@ uint8_t tryOnePassword(uint32_t password, uint8_t downlink_mode) {
// if (getSignalProperties()->isnoise == false) {
// } else {
if (tryDetectModulation(dl_mode,T55XX_PrintConfig)) {
if (tryDetectModulation(dl_mode, T55XX_PrintConfig)) {
return 1 + (dl_mode << 1);
}
// }
@ -2957,7 +2992,7 @@ static int CmdT55xxDetectPage1(const char *Cmd) {
cmdp++;
break;
case 'r':
//ICEMAN STRANGE
//ICEMAN STRANGE
downlink_mode = param_get8ex(Cmd, cmdp + 1, 0, 10);
if (downlink_mode == 4)
try_all_dl_modes = true;
@ -3146,7 +3181,7 @@ static int CmdT55xxProtect(const char *Cmd) {
cmdp += 2;
break;
case 'r':
//ICEMAN STRANGE
//ICEMAN STRANGE
downlink_mode = param_get8ex(Cmd, cmdp + 1, 0, 10);
if (downlink_mode > 3)
downlink_mode = 0;
@ -3170,7 +3205,7 @@ static int CmdT55xxProtect(const char *Cmd) {
return PM3_ESOFT;
// lock
if ( t55xxProtect(true, usepwd, override, password, downlink_mode, new_password) == false ) {
if (t55xxProtect(true, usepwd, override, password, downlink_mode, new_password) == false) {
PrintAndLogEx(WARNING, "Command failed. Did you run `lf t55xx detect` before?");
return PM3_ESOFT;
}

View file

@ -131,6 +131,9 @@ void Set_t55xx_Config(t55xx_conf_block_t conf);
int CmdLFT55XX(const char *Cmd);
void SetConfigWithBlock0(uint32_t block0);
void SetConfigWithBlock0Ex(uint32_t block0, uint8_t offset, bool Q5);
char *GetPskCfStr(uint32_t id, bool q5);
char *GetBitRateStr(uint32_t id, bool xmode);
char *GetSaferStr(uint32_t id);
@ -138,13 +141,14 @@ char *GetQ5ModulationStr(uint32_t id);
char *GetModulationStr(uint32_t id, bool xmode);
char *GetModelStrFromCID(uint32_t cid);
char *GetSelectedModulationStr(uint8_t id);
char *GetDownlinkModeStr (uint8_t dlmode);
char *GetDownlinkModeStr(uint8_t dlmode);
void printT5xxHeader(uint8_t page);
void printT55xxBlock(uint8_t blockNum);
int printConfiguration(t55xx_conf_block_t b);
bool t55xxAquireAndCompareBlock0(bool usepwd, uint32_t password, uint32_t known_block0, bool verbose);
bool t55xxAquireAndDetect(bool usepwd, uint32_t password, uint32_t known_block0, bool verbose);
bool t55xxVerifyWrite( uint8_t block, bool page1, bool usepwd, uint8_t override, uint32_t password, uint8_t downlink_mode, uint32_t data);
bool t55xxVerifyWrite(uint8_t block, bool page1, bool usepwd, uint8_t override, uint32_t password, uint8_t downlink_mode, uint32_t data);
int T55xxReadBlock(uint8_t block, bool page1, bool usepwd, uint8_t override, uint32_t password, uint8_t downlink_mode);
int T55xxReadBlockEx(uint8_t block, bool page1, bool usepwd, uint8_t override, uint32_t password, uint8_t downlink_mode, bool verbose);

View file

@ -97,7 +97,7 @@ static int CmdVikingClone(const char *Cmd) {
clearCommandBuffer();
SendCommandNG(CMD_LF_VIKING_CLONE, (uint8_t*)&payload, sizeof(payload));
SendCommandNG(CMD_LF_VIKING_CLONE, (uint8_t *)&payload, sizeof(payload));
PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_LF_VIKING_CLONE, &resp, T55XX_WRITE_TIMEOUT)) {
PrintAndLogEx(ERR, "Error occurred, device did not respond during write operation.");

View file

@ -191,15 +191,17 @@ static int CmdVisa2kClone(const char *Cmd) {
return PM3_ETIMEOUT;
}
// write block0, needs a detect.
if (i == 0)
t55xxAquireAndDetect(false, 0, blocks[i], false);
if (i == 0) {
SetConfigWithBlock0(blocks[0]);
if (t55xxAquireAndCompareBlock0(false, 0, blocks[0], false))
continue;
}
if (t55xxVerifyWrite(i, 0, false, false, 0, 0xFF, blocks[i]) == false)
res++;
}
if ( res == 0 )
if (res == 0)
PrintAndLogEx(SUCCESS, "Success writing to tag");
return PM3_SUCCESS;

View file

@ -32,6 +32,7 @@
#include "cmdflashmem.h" // rdv40 flashmem commands
#include "cmdsmartcard.h" // rdv40 smart card ISO7816 commands
#include "cmdusart.h" // rdv40 FPC USART commands
#include "cmdwiegand.h" // wiegand commands
#include "ui.h"
#include "util_posix.h"
@ -98,11 +99,12 @@ static command_t CommandTable[] = {
{"mem", CmdFlashMem, IfPm3Flash, "{ Flash Memory manipulation... }"},
{"msleep", CmdMsleep, AlwaysAvailable, "Add a pause in milliseconds"},
{"rem", CmdRem, AlwaysAvailable, "Add text to row in log file"},
{"reveng", CmdRev, AlwaysAvailable, "{ Crc calculations from the RevEng software }"},
{"reveng", CmdRev, AlwaysAvailable, "{ CRC calculations from RevEng software }"},
{"sc", CmdSmartcard, IfPm3Smartcard, "{ Smart card ISO7816 commands... }"},
{"script", CmdScript, AlwaysAvailable, "{ Scripting commands }"},
{"trace", CmdTrace, AlwaysAvailable, "{ Trace manipulation... }"},
{"usart", CmdUsart, IfPm3FpcUsartFromUsb, "{ USART commands... }"},
{"wiegand", CmdWiegand, AlwaysAvailable, "{ Wiegand format manipulation... }"},
{"quit", CmdQuit, AlwaysAvailable, ""},
{"exit", CmdQuit, AlwaysAvailable, "Exit program"},
{NULL, NULL, NULL, NULL}

205
client/cmdwiegand.c Normal file
View file

@ -0,0 +1,205 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2018 iceman <iceman at iuse.se>
//
// 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.
//-----------------------------------------------------------------------------
// Trace commands
//-----------------------------------------------------------------------------
#include "cmdwiegand.h"
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include "cmdparser.h" // command_t
#include "comms.h"
#include "pm3_cmd.h"
#include "protocols.h"
#include "parity.h" // oddparity
#include "cmdhflist.h" // annotations
#include "wiegand_formats.h"
#include "wiegand_formatutils.h"
#include "util.h"
static int CmdHelp(const char *Cmd);
static int usage_wiegand_list() {
PrintAndLogEx(NORMAL, "List available wiegand formats");
return PM3_SUCCESS;
}
static int usage_wiegand_encode() {
PrintAndLogEx(NORMAL, "Encode wiegand formatted number to raw hex");
PrintAndLogEx(NORMAL, "Usage: wiegand encode [w <format>] [<field> <value (decimal)>] {...}");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " w <format> see `wiegand list` for available formats");
PrintAndLogEx(NORMAL, " c <value> card number");
PrintAndLogEx(NORMAL, " f <value> facility code");
PrintAndLogEx(NORMAL, " i <value> issue Level");
PrintAndLogEx(NORMAL, " o <value> OEM code");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "samples:");
PrintAndLogEx(NORMAL, " wiegand encode w H10301 f 101 c 1337");
return PM3_SUCCESS;
}
static int usage_wiegand_decode() {
PrintAndLogEx(NORMAL, "Decode raw hex to wiegand format");
PrintAndLogEx(NORMAL, "Usage: wiegand decode [id] <p>");
PrintAndLogEx(NORMAL, " p ignore invalid parity");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Samples:");
PrintAndLogEx(NORMAL, " wiegand decode 2006f623ae");
return PM3_SUCCESS;
}
void PrintTagId(wiegand_message_t *packed) {
if (packed->Top != 0) {
PrintAndLogEx(SUCCESS, "Card ID: %X%08X%08X",
(uint32_t)packed->Top,
(uint32_t)packed->Mid,
(uint32_t)packed->Bot)
;
} else {
PrintAndLogEx(SUCCESS, "Card ID: %X%08X",
(uint32_t)packed->Mid,
(uint32_t)packed->Bot)
;
}
}
int CmdWiegandList(const char *Cmd) {
bool errors = false;
char cmdp = 0;
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h':
return usage_wiegand_list();
default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
break;
}
}
HIDListFormats();
return PM3_SUCCESS;
}
int CmdWiegandEncode(const char *Cmd) {
int format_idx = -1;
char format[16] = {0};
wiegand_card_t data;
memset(&data, 0, sizeof(wiegand_card_t));
bool errors = false;
char cmdp = 0;
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h':
return usage_wiegand_encode();
case 'w':
param_getstr(Cmd, cmdp + 1, format, sizeof(format));
format_idx = HIDFindCardFormat(format);
if (format_idx == -1) {
PrintAndLogEx(WARNING, "Unknown format: %s", format);
errors = true;
}
cmdp += 2;
break;
case 'i':
data.IssueLevel = param_get32ex(Cmd, cmdp + 1, 0, 10);
cmdp += 2;
break;
case 'f':
data.FacilityCode = param_get32ex(Cmd, cmdp + 1, 0, 10);
cmdp += 2;
break;
case 'c':
data.CardNumber = param_get64ex(Cmd, cmdp + 1, 0, 10);
cmdp += 2;
break;
case 'o':
data.OEM = param_get32ex(Cmd, cmdp + 1, 0, 10);
cmdp += 2;
break;
default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
break;
}
}
if (errors || cmdp == 0) return usage_wiegand_encode();
wiegand_message_t packed;
memset(&packed, 0, sizeof(wiegand_message_t));
if (HIDPack(format_idx, &data, &packed) == false) {
PrintAndLogEx(WARNING, "The card data could not be encoded in the selected format.");
return PM3_ESOFT;
}
PrintTagId(&packed);
return PM3_SUCCESS;
}
int CmdWiegandDecode(const char *Cmd) {
uint32_t top = 0, mid = 0, bot = 0;
bool ignore_parity = false, gothex = false;
bool errors = false;
char cmdp = 0;
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
uint32_t strlen = param_getlength(Cmd, cmdp);
strlen++; // null termin
if (strlen > 2) {
char *s = calloc(strlen, sizeof(uint8_t));
param_getstr(Cmd, cmdp, s, strlen);
hexstring_to_u96(&top, &mid, &bot, s);
free(s);
gothex = true;
cmdp++;
continue;
}
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h':
return usage_wiegand_decode();
case 'p':
ignore_parity = true;
cmdp++;
break;
default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
break;
}
}
if (gothex == false)
errors = true;
if (errors || cmdp < 1) return usage_wiegand_decode();
wiegand_message_t packed = initialize_message_object(top, mid, bot);
HIDTryUnpack(&packed, ignore_parity);
return PM3_SUCCESS;
}
static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"},
{"list", CmdWiegandList, AlwaysAvailable, "List available wiegand formats"},
{"encode", CmdWiegandEncode, AlwaysAvailable, "Convert "},
{"decode", CmdWiegandDecode, AlwaysAvailable, "Convert raw hex to wiegand format"},
{NULL, NULL, NULL, NULL}
};
static int CmdHelp(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
CmdsHelp(CommandTable);
return PM3_SUCCESS;
}
int CmdWiegand(const char *Cmd) {
clearCommandBuffer();
return CmdsParse(CommandTable, Cmd);
}

20
client/cmdwiegand.h Normal file
View file

@ -0,0 +1,20 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2019 iceman <iceman at iuse.se>
//
// 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.
//-----------------------------------------------------------------------------
// Trace commands
//-----------------------------------------------------------------------------
#ifndef CMDWIEGAND_H__
#define CMDWIEGAND_H__
#include "common.h"
int CmdWiegand(const char *Cmd);
int CmdWiegandList(const char *Cmd);
int CmdWiegandEncode(const char *Cmd);
int CmdWiegandDecode(const char *Cmd);
#endif

View file

@ -1714,8 +1714,23 @@ static int CmdEMVList(const char *Cmd) {
}
static int CmdEMVTest(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
return ExecuteCryptoTests(true);
CLIParserInit("emv test",
"Executes tests\n",
"Usage:\n\temv test [l]\n");
void *argtable[] = {
arg_param_begin,
arg_lit0("iI", "ignore", "ignore timing tests for VM"),
arg_lit0("lL", "long", "run long tests too"),
arg_param_end
};
CLIExecWithReturn(Cmd, argtable, true);
bool ignoreTimeTest = arg_get_lit(1);
bool runSlowTests = arg_get_lit(2);
CLIParserFree();
return ExecuteCryptoTests(true, ignoreTimeTest, runSlowTests);
}
static int CmdEMVRoca(const char *Cmd) {

View file

@ -301,8 +301,9 @@ close_pub:
return ret;
}
int exec_crypto_test(bool verbose) {
unsigned int keylengths[] = {1024, 1152, 1408, 1984, 2048, 3072, 4096};
int exec_crypto_test(bool verbose, bool include_slow_tests) {
unsigned int keylengths[] = {1024, 2048};
unsigned int extra_keylengths[] = {1152, 1408, 1984, 3072, 4096};
int i;
int ret;
fprintf(stdout, "\n");
@ -322,6 +323,15 @@ int exec_crypto_test(bool verbose) {
return ret;
}
}
if (include_slow_tests) {
for (i = 0; i < ARRAYLEN(extra_keylengths); i++) {
unsigned int kl = extra_keylengths[i];
ret = test_genkey(kl, message, kl / 8, verbose);
if (ret) {
fprintf(stderr, "Crypto generate key[%u] test: failed\n", kl);
return ret;
}
}
}
return 0;
}

View file

@ -17,5 +17,5 @@
#define __CRYPTO_TEST_H
#include <stdbool.h>
int exec_crypto_test(bool verbose);
int exec_crypto_test(bool verbose, bool include_slow_tests);
#endif

View file

@ -33,7 +33,7 @@
#include "crypto/libpcrypto.h"
#include "emv/emv_roca.h"
int ExecuteCryptoTests(bool verbose) {
int ExecuteCryptoTests(bool verbose, bool ignore_time, bool include_slow_tests) {
int res;
bool TestFail = false;
@ -56,7 +56,7 @@ int ExecuteCryptoTests(bool verbose) {
if (res) TestFail = true;
res = mbedtls_entropy_self_test(verbose);
if (res) TestFail = true;
if (res && !ignore_time) TestFail = true;
// retry for CI (when resources too low)
for (int i = 0; i < 3; i++) {
@ -65,7 +65,7 @@ int ExecuteCryptoTests(bool verbose) {
break;
PrintAndLogEx(WARNING, "Repeat timing test %d", i + 1);
}
if (res) TestFail = true;
if (res && !ignore_time) TestFail = true;
res = mbedtls_ctr_drbg_self_test(verbose);
if (res) TestFail = true;
@ -94,7 +94,7 @@ int ExecuteCryptoTests(bool verbose) {
res = exec_cda_test(verbose);
if (res) TestFail = true;
res = exec_crypto_test(verbose);
res = exec_crypto_test(verbose, include_slow_tests);
if (res) TestFail = true;
res = roca_self_test();

View file

@ -12,5 +12,5 @@
#define __CRYPTOTEST_H
#include <stdbool.h>
int ExecuteCryptoTests(bool verbose);
int ExecuteCryptoTests(bool verbose, bool ignore_time, bool include_slow_tests);
#endif

View file

@ -37,6 +37,7 @@
// Name: Yubico U2F Root CA Serial 457200631
// Issued: 2014-08-01
// https://github.com/Yubico/developers.yubico.com/tree/master/static/U2F
// https://fido-mds-parser.appspot.com/?url=https://mds.fidoalliance.org/metadata/7DwVE5vbRQysYTJrf95b3a
#define YUBICO_CA \
"-----BEGIN CERTIFICATE-----\r\n" \
"MIIDHjCCAgagAwIBAgIEG0BT9zANBgkqhkiG9w0BAQsFADAuMSwwKgYDVQQDEyNZ\r\n" \
@ -75,6 +76,83 @@
"jQGd7rwSZuE5RWUPVygYhUstQO9zNUOs\r\n" \
"-----END CERTIFICATE-----\r\n"
// FEITIAN U2F
// https://fido-mds-parser.appspot.com/?url=https://mds.fidoalliance.org/metadata/eS7v8sum4jxp7kgLQ5Qqcg
#define FEITIAN_U2F_CA \
"-----BEGIN CERTIFICATE-----\r\n" \
"MIIBfjCCASWgAwIBAgIBATAKBggqhkjOPQQDAjAXMRUwEwYDVQQDDAxGVCBGSURP\r\n" \
"IDAyMDAwIBcNMTYwNTAxMDAwMDAwWhgPMjA1MDA1MDEwMDAwMDBaMBcxFTATBgNV\r\n" \
"BAMMDEZUIEZJRE8gMDIwMDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABNBmrRqV\r\n" \
"OxztTJVN19vtdqcL7tKQeol2nnM2/yYgvksZnr50SKbVgIEkzHQVOu80LVEE3lVh\r\n" \
"eO1HjggxAlT6o4WjYDBeMB0GA1UdDgQWBBRJFWQt1bvG3jM6XgmV/IcjNtO/CzAf\r\n" \
"BgNVHSMEGDAWgBRJFWQt1bvG3jM6XgmV/IcjNtO/CzAMBgNVHRMEBTADAQH/MA4G\r\n" \
"A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAgNHADBEAiAwfPqgIWIUB+QBBaVGsdHy\r\n" \
"0s5RMxlkzpSX/zSyTZmUpQIgB2wJ6nZRM8oX/nA43Rh6SJovM2XwCCH//+LirBAb\r\n" \
"B0M=\r\n" \
"-----END CERTIFICATE-----\r\n"
// FEITIAN FIDO2
#define FEITIAN_FIDO2_CA \
"-----BEGIN CERTIFICATE-----\r\n" \
"MIIB2DCCAX6gAwIBAgIQGBUrQbdDrm20FZnDsX2CBTAKBggqhkjOPQQDAjBLMQsw\r\n" \
"CQYDVQQGEwJVUzEdMBsGA1UECgwURmVpdGlhbiBUZWNobm9sb2dpZXMxHTAbBgNV\r\n" \
"BAMMFEZlaXRpYW4gRklETyBSb290IENBMCAXDTE4MDQwMTAwMDAwMFoYDzIwNDgw\r\n" \
"MzMxMjM1OTU5WjBLMQswCQYDVQQGEwJVUzEdMBsGA1UECgwURmVpdGlhbiBUZWNo\r\n" \
"bm9sb2dpZXMxHTAbBgNVBAMMFEZlaXRpYW4gRklETyBSb290IENBMFkwEwYHKoZI\r\n" \
"zj0CAQYIKoZIzj0DAQcDQgAEsFYEEhiJuqqnMgQjSiivBjV7DGCTf4XBBH/B7uvZ\r\n" \
"sKxXShF0L8uDISWUvcExixRs6gB3oldSrjox6L8T94NOzqNCMEAwHQYDVR0OBBYE\r\n" \
"FEu9hyYRrRyJzwRYvnDSCIxrFiO3MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/\r\n" \
"BAQDAgEGMAoGCCqGSM49BAMCA0gAMEUCIDHSb2mbNDAUNXvpPU0oWKeNye0fQ2l9\r\n" \
"D01AR2+sLZdhAiEAo3wz684IFMVsCCRmuJqxH6FQRESNqezuo1E+KkGxWuM=\r\n" \
"-----END CERTIFICATE-----\r\n"
// https://hypersecu.com/support/downloads
// HyperFIDO U2F Security Key Attestation CA
// Issuer: CN=FT FIDO 0100
#define HYPERFIDO_U2F_1_CA \
"-----BEGIN CERTIFICATE-----\r\n" \
"MIIBjTCCATOgAwIBAgIBATAKBggqhkjOPQQDAjAXMRUwEwYDVQQDEwxGVCBGSURP\r\n" \
"IDAxMDAwHhcNMTQwNzAxMTUzNjI2WhcNNDQwNzAzMTUzNjI2WjAXMRUwEwYDVQQD\r\n" \
"EwxGVCBGSURPIDAxMDAwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASxdLxJx8ol\r\n" \
"S3DS5cIHzunPF0gg69d+o8ZVCMJtpRtlfBzGuVL4YhaXk2SC2gptPTgmpZCV2vbN\r\n" \
"fAPi5gOF0vbZo3AwbjAdBgNVHQ4EFgQUXt4jWlYDgwhaPU+EqLmeM9LoPRMwPwYD\r\n" \
"VR0jBDgwNoAUXt4jWlYDgwhaPU+EqLmeM9LoPROhG6QZMBcxFTATBgNVBAMTDEZU\r\n" \
"IEZJRE8gMDEwMIIBATAMBgNVHRMEBTADAQH/MAoGCCqGSM49BAMCA0gAMEUCIQC2\r\n" \
"D9o9cconKTo8+4GZPyZBJ3amc8F0/kzyidX9dhrAIAIgM9ocs5BW/JfmshVP9Mb+\r\n" \
"Joa/kgX4dWbZxrk0ioTfJZg=\r\n" \
"-----END CERTIFICATE-----\r\n"
// Issuer: CN= HYPERFIDO 0200
#define HYPERFIDO_U2F_2_CA \
"-----BEGIN CERTIFICATE-----\r\n" \
"MIIBxzCCAWygAwIBAgICEAswCgYIKoZIzj0EAwIwOjELMAkGA1UEBhMCQ0ExEjAQ\r\n" \
"BgNVBAoMCUhZUEVSU0VDVTEXMBUGA1UEAwwOSFlQRVJGSURPIDAyMDAwIBcNMTgw\r\n" \
"MTAxMDAwMDAwWhgPMjA0NzEyMzEyMzU5NTlaMDoxCzAJBgNVBAYTAkNBMRIwEAYD\r\n" \
"VQQKDAlIWVBFUlNFQ1UxFzAVBgNVBAMMDkhZUEVSRklETyAwMjAwMFkwEwYHKoZI\r\n" \
"zj0CAQYIKoZIzj0DAQcDQgAErKUI1G0S7a6IOLlmHipLlBuxTYjsEESQvzQh3dB7\r\n" \
"dvxxWWm7kWL91rq6S7ayZG0gZPR+zYqdFzwAYDcG4+aX66NgMF4wHQYDVR0OBBYE\r\n" \
"FLZYcfMMwkQAGbt3ryzZFPFypmsIMB8GA1UdIwQYMBaAFLZYcfMMwkQAGbt3ryzZ\r\n" \
"FPFypmsIMAwGA1UdEwQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMC\r\n" \
"A0kAMEYCIQCG2/ppMGt7pkcRie5YIohS3uDPIrmiRcTjqDclKVWg0gIhANcPNDZH\r\n" \
"E2/zZ+uB5ThG9OZus+xSb4knkrbAyXKX2zm/\r\n" \
"-----END CERTIFICATE-----\r\n"
// NXP
// https://fido-mds-parser.appspot.com/?url=https://mds.fidoalliance.org/metadata/JKP5CiDehdMMPwtG5i7to5
#define NXP_U2F_CA \
"-----BEGIN CERTIFICATE-----\r\n" \
"MIIBjzCCATWgAwIBAgIJASNFZ4mrze8BMAoGCCqGSM49BAMCMCgxJjAkBgNVBAMM\r\n" \
"HU5YUCBTZW1pY29uZHVjdG9yIFUyRiBSb290IENBMB4XDTE1MTIxNjE2MDUxMFoX\r\n" \
"DTI1MTIxMzE2MDUxMFowGjEYMBYGA1UEAwwPTlhQIEZJRE8gVTJGIHYwMFkwEwYH\r\n" \
"KoZIzj0CAQYIKoZIzj0DAQcDQgAExbuQcVAAX7IPwqVVVX/ni3Ch3Zzo04WkSsr5\r\n" \
"nHXpEarB+sd846FAi/o3a7oF1+u/oV65syguDD/0FaUGuUgTpKNWMFQwDAYDVR0T\r\n" \
"AQH/BAIwADAOBgNVHQ8BAf8EBAMCB4AwHwYDVR0jBBgwFoAUpaNTDgOg8hGDmawL\r\n" \
"bDydVSoNNPgwEwYLKwYBBAGC5RwCAQEEBAMCBDAwCgYIKoZIzj0EAwIDSAAwRQIh\r\n" \
"AJlr23jig2LxRM1PpgMAQXnZJy/HnkRB9O8KD0o2oK/mAiBG5EK1S3yVHdkkVGTJ\r\n" \
"Q12ffuK8Op7Nx89cszCr0WyIhQ==\r\n" \
"-----END CERTIFICATE-----\r\n"
/* Concatenation of all additional CA certificates in PEM format if available */
const char additional_ca_pem[] = GLOBALSIGN_CA YUBICO_CA SOLOKEY_CA;
const char additional_ca_pem[] = GLOBALSIGN_CA YUBICO_CA SOLOKEY_CA \
FEITIAN_U2F_CA FEITIAN_FIDO2_CA HYPERFIDO_U2F_1_CA HYPERFIDO_U2F_2_CA NXP_U2F_CA;
const size_t additional_ca_pem_len = sizeof(additional_ca_pem);

View file

@ -69,6 +69,40 @@ int fileExists(const char *filename) {
return result == 0;
}
/**
* @brief checks if path is file.
* @param filename
* @return
*/
bool is_regular_file(const char *filename) {
#ifdef _WIN32
struct _stat st;
_stat(filename, &st);
return S_ISREG(st.st_mode) != 0;
#else
struct stat st;
stat(filename, &st);
return S_ISREG(st.st_mode) != 0;
#endif
}
/**
* @brief checks if path is directory.
* @param filename
* @return
*/
bool is_directory(const char *filename) {
#ifdef _WIN32
struct _stat st;
_stat(filename, &st);
return S_ISDIR(st.st_mode) != 0;
#else
struct stat st;
stat(filename, &st);
return S_ISDIR(st.st_mode) != 0;
#endif
}
static char *filenamemcopy(const char *preferredName, const char *suffix) {
if (preferredName == NULL) return NULL;
if (suffix == NULL) return NULL;
@ -1012,10 +1046,20 @@ out:
}
int searchFile(char **foundpath, const char *pm3dir, const char *searchname, const char *suffix, bool silent) {
if (foundpath == NULL)
return PM3_EINVARG;
if (searchname == NULL || strlen(searchname) == 0)
return PM3_EINVARG;
if (is_directory(searchname))
return PM3_EINVARG;
char *filename = filenamemcopy(searchname, suffix);
if (filename == NULL) return PM3_EMALLOC;
if (filename == NULL || strlen(filename) == 0)
return PM3_EMALLOC;
int res = searchFinalFile(foundpath, pm3dir, filename, silent);
if (res != PM3_SUCCESS) {
if ((res == PM3_EFILE) && (!silent))

View file

@ -637,7 +637,7 @@ static int _testHash1() {
return 0;
}
int testElite() {
int testElite(bool slowtests) {
PrintAndLogEx(INFO, "Testing iClass Elite functinality...");
PrintAndLogEx(INFO, "Testing hash2");
uint8_t k_cus[8] = {0x5B, 0x7C, 0x62, 0xC4, 0x91, 0xC1, 0x1B, 0x39};
@ -669,6 +669,7 @@ int testElite() {
errors += _testHash1();
PrintAndLogEx(INFO, "Testing key diversification ...");
errors += _test_iclass_key_permutation();
errors += _testBruteforce();
if (slowtests)
errors += _testBruteforce();
return errors;
}

View file

@ -124,7 +124,7 @@ int calculateMasterKey(uint8_t first16bytes[], uint64_t master_key[]);
* @brief Test function
* @return
*/
int testElite(void);
int testElite(bool slowtests);
/**
Here are some pretty optimal values that can be used to recover necessary data in only

View file

@ -1033,16 +1033,16 @@ void detect_classic_magic(void) {
}
switch (isGeneration) {
case 1:
case MAGIC_GEN_1A:
PrintAndLogEx(SUCCESS, "Answers to magic commands (GEN 1a): " _GREEN_("YES"));
break;
case 2:
case MAGIC_GEN_1B:
PrintAndLogEx(SUCCESS, "Answers to magic commands (GEN 1b): " _GREEN_("YES"));
break;
case 4:
case MAGIC_GEN_2:
PrintAndLogEx(SUCCESS, "Answers to magic commands (GEN 2 / CUID): " _GREEN_("YES"));
break;
case 5:
case MAGIC_GEN_UNFUSED:
PrintAndLogEx(SUCCESS, "Answers to magic commands (Write Once / FUID): " _GREEN_("YES"));
break;
default:

View file

@ -930,7 +930,7 @@ static int l_T55xx_readblock(lua_State *L) {
return returnToLuaWithError(L, "Failed to read config block");
}
if (!tryDetectModulation(0,true)) { // Default to prev. behaviour (default dl mode and print config)
if (!tryDetectModulation(0, true)) { // Default to prev. behaviour (default dl mode and print config)
PrintAndLogEx(NORMAL, "Safety Check: Could not detect if PWD bit is set in config block. Exits.");
return 0;
} else {
@ -1006,7 +1006,7 @@ static int l_T55xx_detect(lua_State *L) {
}
}
isok = tryDetectModulation(0,true); // Default to prev. behaviour (default dl mode and print config)
isok = tryDetectModulation(0, true); // Default to prev. behaviour (default dl mode and print config)
if (isok == false) {
return returnToLuaWithError(L, "Could not detect modulation automatically. Try setting it manually with \'lf t55xx config\'");
}

View file

@ -390,7 +390,7 @@ void print_blocks(uint32_t *data, size_t len) {
PrintAndLogEx(ERR, "..empty data");
} else {
for (uint8_t i = 0; i < len; i++)
PrintAndLogEx(SUCCESS, " %02d | 0x%08X", i, data[i]);
PrintAndLogEx(SUCCESS, " %02d | %08X", i, data[i]);
}
}
@ -878,3 +878,20 @@ char *strmcopy(const char *buf) {
}
return str;
}
/**
* Converts a hex string to component "hi2", "hi" and "lo" 32-bit integers, one nibble
* at a time.
*
* Returns the number of nibbles (4 bits) entered.
*/
int hexstring_to_u96(uint32_t *hi2, uint32_t *hi, uint32_t *lo, const char *str) {
int n = 0, i = 0;
while (sscanf(&str[i++], "%1x", &n) == 1) {
*hi2 = (*hi2 << 4) | (*hi >> 28);
*hi = (*hi << 4) | (*lo >> 28);
*lo = (*lo << 4) | (n & 0xf);
}
return i - 1;
}

View file

@ -98,4 +98,5 @@ void clean_ascii(unsigned char *buf, size_t len);
void strcleanrn(char *buf, size_t len);
void strcreplace(char *buf, size_t len, char from, char to);
char *strmcopy(const char *buf);
int hexstring_to_u96(uint32_t *hi2, uint32_t *hi, uint32_t *lo, const char *str);
#endif

715
client/wiegand_formats.c Normal file
View file

@ -0,0 +1,715 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2018 grauerfuchs
//
// 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.
//-----------------------------------------------------------------------------
// HID card format packing/unpacking routines
//-----------------------------------------------------------------------------
#include "wiegand_formats.h"
bool Pack_H10301(wiegand_card_t *card, wiegand_message_t *packed) {
memset(packed, 0, sizeof(wiegand_message_t));
if (card->FacilityCode > 0xFF) return false; // Can't encode FC.
if (card->CardNumber > 0xFFFF) return false; // Can't encode CN.
if (card->IssueLevel > 0) return false; // Not used in this format
if (card->OEM > 0) return false; // Not used in this format
packed->Length = 26; // Set number of bits
packed->Bot |= (card->CardNumber & 0xFFFF) << 1;
packed->Bot |= (card->FacilityCode & 0xFF) << 17;
packed->Bot |= oddparity32((packed->Bot >> 1) & 0xFFF) & 1;
packed->Bot |= (evenparity32((packed->Bot >> 13) & 0xFFF) & 1) << 25;
return add_HID_header(packed);
}
bool Unpack_H10301(wiegand_message_t *packed, wiegand_card_t *card) {
memset(card, 0, sizeof(wiegand_card_t));
if (packed->Length != 26) return false; // Wrong length? Stop here.
card->CardNumber = (packed->Bot >> 1) & 0xFFFF;
card->FacilityCode = (packed->Bot >> 17) & 0xFF;
card->ParityValid =
(oddparity32((packed->Bot >> 1) & 0xFFF) == (packed->Bot & 1)) &&
((evenparity32((packed->Bot >> 13) & 0xFFF) & 1) == ((packed->Bot >> 25) & 1));
return true;
}
bool Pack_Tecom27(wiegand_card_t *card, wiegand_message_t *packed) {
memset(packed, 0, sizeof(wiegand_message_t));
if (card->FacilityCode > 0x7FF) return false; // Can't encode FC.
if (card->CardNumber > 0xFFFF) return false; // Can't encode CN.
if (card->IssueLevel > 0) return false; // Not used in this format
if (card->OEM > 0) return false; // Not used in this format
packed->Length = 27;
set_nonlinear_field(packed, card->FacilityCode, 10, (uint8_t[]) {15, 19, 24, 23, 22, 18, 6, 10, 14, 3, 2});
set_nonlinear_field(packed, card->CardNumber, 16, (uint8_t[]) {0, 1, 13, 12, 9, 26, 20, 16, 17, 21, 25, 7, 8, 11, 4, 5});
return add_HID_header(packed);
}
bool Unpack_Tecom27(wiegand_message_t *packed, wiegand_card_t *card) {
memset(card, 0, sizeof(wiegand_card_t));
if (packed->Length != 27) return false; // Wrong length? Stop here.
card->CardNumber = get_nonlinear_field(packed, 16, (uint8_t[]) {0, 1, 13, 12, 9, 26, 20, 16, 17, 21, 25, 7, 8, 11, 4, 5});
card->FacilityCode = get_nonlinear_field(packed, 10, (uint8_t[]) {15, 19, 24, 23, 22, 18, 6, 10, 14, 3, 2});
return true;
}
bool Pack_2804W(wiegand_card_t *card, wiegand_message_t *packed) {
memset(packed, 0, sizeof(wiegand_message_t));
if (card->FacilityCode > 0x0FF) return false; // Can't encode FC.
if (card->CardNumber > 0x7FFF) return false; // Can't encode CN.
if (card->IssueLevel > 0) return false; // Not used in this format
if (card->OEM > 0) return false; // Not used in this format
packed->Length = 28;
set_linear_field(packed, card->FacilityCode, 4, 8);
set_linear_field(packed, card->CardNumber, 12, 15);
set_bit_by_position(packed,
oddparity32(get_nonlinear_field(packed, 16, (uint8_t[]) {4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19, 20, 22, 23, 25, 26}))
, 2);
set_bit_by_position(packed,
evenparity32(get_linear_field(packed, 1, 13))
, 0);
set_bit_by_position(packed,
oddparity32(get_linear_field(packed, 0, 27))
, 27);
return add_HID_header(packed);
}
bool Unpack_2804W(wiegand_message_t *packed, wiegand_card_t *card) {
memset(card, 0, sizeof(wiegand_card_t));
if (packed->Length != 28) return false; // Wrong length? Stop here.
card->FacilityCode = get_linear_field(packed, 4, 8);
card->CardNumber = get_linear_field(packed, 12, 15);
card->ParityValid =
(get_bit_by_position(packed, 0) == evenparity32(get_linear_field(packed, 1, 13))) &&
(get_bit_by_position(packed, 2) == oddparity32(get_nonlinear_field(packed, 16, (uint8_t[]) {4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19, 20, 22, 23, 25, 26}))) &&
(get_bit_by_position(packed, 27) == oddparity32(get_linear_field(packed, 0, 27)));
return true;
}
bool Pack_ATSW30(wiegand_card_t *card, wiegand_message_t *packed) {
memset(packed, 0, sizeof(wiegand_message_t));
if (card->FacilityCode > 0xFFF) return false; // Can't encode FC.
if (card->CardNumber > 0xFFFF) return false; // Can't encode CN.
if (card->IssueLevel > 0) return false; // Not used in this format
if (card->OEM > 0) return false; // Not used in this format
packed->Length = 30;
set_linear_field(packed, card->FacilityCode, 1, 12);
set_linear_field(packed, card->CardNumber, 13, 16);
set_bit_by_position(packed,
evenparity32(get_linear_field(packed, 1, 12))
, 0);
set_bit_by_position(packed,
oddparity32(get_linear_field(packed, 13, 16))
, 29);
return add_HID_header(packed);
}
bool Unpack_ATSW30(wiegand_message_t *packed, wiegand_card_t *card) {
memset(card, 0, sizeof(wiegand_card_t));
if (packed->Length != 30) return false; // Wrong length? Stop here.
card->FacilityCode = get_linear_field(packed, 1, 12);
card->CardNumber = get_linear_field(packed, 13, 16);
card->ParityValid =
(get_bit_by_position(packed, 0) == evenparity32(get_linear_field(packed, 1, 12))) &&
(get_bit_by_position(packed, 29) == oddparity32(get_linear_field(packed, 13, 16)));
return true;
}
bool Pack_ADT31(wiegand_card_t *card, wiegand_message_t *packed) {
memset(packed, 0, sizeof(wiegand_message_t));
if (card->FacilityCode > 0x0F) return false; // Can't encode FC.
if (card->CardNumber > 0x7FFFFF) return false; // Can't encode CN.
if (card->IssueLevel > 0) return false; // Not used in this format
if (card->OEM > 0) return false; // Not used in this format
packed->Length = 31;
set_linear_field(packed, card->FacilityCode, 1, 4);
set_linear_field(packed, card->CardNumber, 5, 23);
// Parity not known, but 4 bits are unused.
return add_HID_header(packed);
}
bool Unpack_ADT31(wiegand_message_t *packed, wiegand_card_t *card) {
memset(card, 0, sizeof(wiegand_card_t));
if (packed->Length != 31) return false; // Wrong length? Stop here.
card->FacilityCode = get_linear_field(packed, 1, 4);
card->CardNumber = get_linear_field(packed, 5, 23);
return true;
}
bool Pack_Kastle(wiegand_card_t *card, wiegand_message_t *packed) {
memset(packed, 0, sizeof(wiegand_message_t));
if (card->FacilityCode > 0x00FF) return false; // Can't encode FC.
if (card->CardNumber > 0x0000FFFF) return false; // Can't encode CN.
if (card->IssueLevel > 0x001F) return false; // IL is only 5 bits.
if (card->OEM > 0) return false; // Not used in this format
packed->Length = 32; // Set number of bits
set_bit_by_position(packed, 1, 1); // Always 1
set_linear_field(packed, card->IssueLevel, 2, 5);
set_linear_field(packed, card->FacilityCode, 7, 8);
set_linear_field(packed, card->CardNumber, 15, 16);
set_bit_by_position(packed, evenparity32(get_linear_field(packed, 1, 16)), 0);
set_bit_by_position(packed, oddparity32(get_linear_field(packed, 14, 17)), 31);
return add_HID_header(packed);
}
bool Unpack_Kastle(wiegand_message_t *packed, wiegand_card_t *card) {
memset(card, 0, sizeof(wiegand_card_t));
if (packed->Length != 32) return false; // Wrong length? Stop here.
if (get_bit_by_position(packed, 1) != 1) return false; // Always 1 in this format
card->IssueLevel = get_linear_field(packed, 2, 5);
card->FacilityCode = get_linear_field(packed, 7, 8);
card->CardNumber = get_linear_field(packed, 15, 16);
card->ParityValid =
(get_bit_by_position(packed, 0) == evenparity32(get_linear_field(packed, 1, 16))) &&
(get_bit_by_position(packed, 31) == oddparity32(get_linear_field(packed, 14, 17)));
return true;
}
bool Pack_D10202(wiegand_card_t *card, wiegand_message_t *packed) {
memset(packed, 0, sizeof(wiegand_message_t));
if (card->FacilityCode > 0x007F) return false; // Can't encode FC.
if (card->CardNumber > 0x00FFFFFF) return false; // Can't encode CN.
if (card->IssueLevel > 0) return false; // Not used in this format
if (card->OEM > 0) return false; // Not used in this format
packed->Length = 33; // Set number of bits
set_linear_field(packed, card->FacilityCode, 1, 7);
set_linear_field(packed, card->CardNumber, 8, 24);
set_bit_by_position(packed, evenparity32(get_linear_field(packed, 1, 16)), 0);
set_bit_by_position(packed, oddparity32(get_linear_field(packed, 16, 16)), 32);
return add_HID_header(packed);
}
bool Unpack_D10202(wiegand_message_t *packed, wiegand_card_t *card) {
memset(card, 0, sizeof(wiegand_card_t));
if (packed->Length != 33) return false; // Wrong length? Stop here.
card->CardNumber = get_linear_field(packed, 8, 24);
card->FacilityCode = get_linear_field(packed, 1, 7);
card->ParityValid =
(get_bit_by_position(packed, 0) == evenparity32(get_linear_field(packed, 1, 16))) &&
(get_bit_by_position(packed, 32) == oddparity32(get_linear_field(packed, 16, 16)));
return true;
}
bool Pack_H10306(wiegand_card_t *card, wiegand_message_t *packed) {
memset(packed, 0, sizeof(wiegand_message_t));
if (card->FacilityCode > 0xFFFF) return false; // Can't encode FC.
if (card->CardNumber > 0xFFFF) return false; // Can't encode CN.
if (card->IssueLevel > 0) return false; // Not used in this format
if (card->OEM > 0) return false; // Not used in this format
packed->Length = 34; // Set number of bits
packed->Bot |= (card->CardNumber & 0xFFFF) << 1;
packed->Bot |= (card->FacilityCode & 0x7FFF) << 17;
packed->Mid |= (card->FacilityCode & 0x8000) >> 15;
packed->Mid |= (evenparity32((packed->Mid & 0x00000001) ^ (packed->Bot & 0xFFFE0000)) & 1) << 1;
packed->Bot |= (oddparity32(packed->Bot & 0x0001FFFE) & 1);
return add_HID_header(packed);
}
bool Unpack_H10306(wiegand_message_t *packed, wiegand_card_t *card) {
memset(card, 0, sizeof(wiegand_card_t));
if (packed->Length != 34) return false; // Wrong length? Stop here.
card->CardNumber = (packed->Bot >> 1) & 0xFFFF;
card->FacilityCode = ((packed->Mid & 1) << 15) | ((packed->Bot >> 17) & 0xFF);
card->ParityValid =
((evenparity32((packed->Mid & 0x00000001) ^ (packed->Bot & 0xFFFE0000)) & 1) == ((packed->Mid >> 1) & 1)) &&
((oddparity32(packed->Bot & 0x0001FFFE) & 1) == ((packed->Bot & 1)));
return true;
}
bool Pack_N10002(wiegand_card_t *card, wiegand_message_t *packed) {
memset(packed, 0, sizeof(wiegand_message_t));
if (card->FacilityCode > 0xFF) return false; // Can't encode FC.
if (card->CardNumber > 0xFFFF) return false; // Can't encode CN.
if (card->IssueLevel > 0) return false; // Not used in this format
if (card->OEM > 0) return false; // Not used in this format
packed->Length = 34; // Set number of bits
set_linear_field(packed, card->FacilityCode, 9, 8);
set_linear_field(packed, card->CardNumber, 17, 16);
return add_HID_header(packed);
}
bool Unpack_N10002(wiegand_message_t *packed, wiegand_card_t *card) {
memset(card, 0, sizeof(wiegand_card_t));
if (packed->Length != 34) return false; // Wrong length? Stop here.
card->CardNumber = get_linear_field(packed, 17, 16);
card->FacilityCode = get_linear_field(packed, 9, 8);
return true;
}
bool Pack_C1k35s(wiegand_card_t *card, wiegand_message_t *packed) {
memset(packed, 0, sizeof(wiegand_message_t));
if (card->FacilityCode > 0xFFF) return false; // Can't encode FC.
if (card->CardNumber > 0xFFFFF) return false; // Can't encode CN.
if (card->IssueLevel > 0) return false; // Not used in this format
if (card->OEM > 0) return false; // Not used in this format
packed->Length = 35; // Set number of bits
packed->Bot |= (card->CardNumber & 0x000FFFFF) << 1;
packed->Bot |= (card->FacilityCode & 0x000007FF) << 21;
packed->Mid |= (card->FacilityCode & 0x00000800) >> 11;
packed->Mid |= (evenparity32((packed->Mid & 0x00000001) ^ (packed->Bot & 0xB6DB6DB6)) & 1) << 1;
packed->Bot |= (oddparity32((packed->Mid & 0x00000003) ^ (packed->Bot & 0x6DB6DB6C)) & 1);
packed->Mid |= (oddparity32((packed->Mid & 0x00000003) ^ (packed->Bot & 0xFFFFFFFF)) & 1) << 2;
return add_HID_header(packed);
}
bool Unpack_C1k35s(wiegand_message_t *packed, wiegand_card_t *card) {
memset(card, 0, sizeof(wiegand_card_t));
if (packed->Length != 35) return false; // Wrong length? Stop here.
card->CardNumber = (packed->Bot >> 1) & 0x000FFFFF;
card->FacilityCode = ((packed->Mid & 1) << 11) | ((packed->Bot >> 21));
card->ParityValid =
(evenparity32((packed->Mid & 0x00000001) ^ (packed->Bot & 0xB6DB6DB6)) == ((packed->Mid >> 1) & 1)) &&
(oddparity32((packed->Mid & 0x00000003) ^ (packed->Bot & 0x6DB6DB6C)) == ((packed->Bot >> 0) & 1)) &&
(oddparity32((packed->Mid & 0x00000003) ^ (packed->Bot & 0xFFFFFFFF)) == ((packed->Mid >> 2) & 1));
return true;
}
bool Pack_H10320(wiegand_card_t *card, wiegand_message_t *packed) {
memset(packed, 0, sizeof(wiegand_message_t));
if (card->FacilityCode > 0) return false; // Can't encode FC. (none in this format)
if (card->CardNumber > 99999999) return false; // Can't encode CN.
if (card->IssueLevel > 0) return false; // Not used in this format
if (card->OEM > 0) return false; // Not used in this format
packed->Length = 36; // Set number of bits
// This card is BCD-encoded rather than binary. Set the 4-bit groups independently.
for (uint32_t idx = 0; idx < 8; idx++) {
set_linear_field(packed, (uint64_t)(card->CardNumber / pow(10, 7 - idx)) % 10, idx * 4, 4);
}
set_bit_by_position(packed, evenparity32(
get_nonlinear_field(packed, 8, (uint8_t[]) {0, 4, 8, 12, 16, 20, 24, 28})
), 32);
set_bit_by_position(packed, oddparity32(
get_nonlinear_field(packed, 8, (uint8_t[]) {1, 5, 9, 13, 17, 21, 25, 29})
), 33);
set_bit_by_position(packed, evenparity32(
get_nonlinear_field(packed, 8, (uint8_t[]) {2, 6, 10, 14, 18, 22, 28, 30})
), 34);
set_bit_by_position(packed, evenparity32(
get_nonlinear_field(packed, 8, (uint8_t[]) {3, 7, 11, 15, 19, 23, 29, 31})
), 35);
return add_HID_header(packed);
}
bool Unpack_H10320(wiegand_message_t *packed, wiegand_card_t *card) {
memset(card, 0, sizeof(wiegand_card_t));
if (packed->Length != 36) return false; // Wrong length? Stop here.
// This card is BCD-encoded rather than binary. Get the 4-bit groups independently.
for (uint32_t idx = 0; idx < 8; idx++) {
uint64_t val = get_linear_field(packed, idx * 4, 4);
if (val > 9) {
// Violation of BCD; Zero and exit.
card->CardNumber = 0;
return false;
} else {
card->CardNumber += val * pow(10, 7 - idx);
}
}
card->ParityValid =
(get_bit_by_position(packed, 32) == evenparity32(get_nonlinear_field(packed, 8, (uint8_t[]) {0, 4, 8, 12, 16, 20, 24, 28}))) &&
(get_bit_by_position(packed, 33) == oddparity32(get_nonlinear_field(packed, 8, (uint8_t[]) {1, 5, 9, 13, 17, 21, 25, 29}))) &&
(get_bit_by_position(packed, 34) == evenparity32(get_nonlinear_field(packed, 8, (uint8_t[]) {2, 6, 10, 14, 18, 22, 28, 30}))) &&
(get_bit_by_position(packed, 35) == evenparity32(get_nonlinear_field(packed, 8, (uint8_t[]) {3, 7, 11, 15, 19, 23, 29, 31})));
return true;
}
bool Pack_S12906(wiegand_card_t *card, wiegand_message_t *packed) {
memset(packed, 0, sizeof(wiegand_message_t));
if (card->FacilityCode > 0xFF) return false; // Can't encode FC.
if (card->IssueLevel > 0x03) return false; // Can't encode IL.
if (card->CardNumber > 0x00FFFFFF) return false; // Can't encode CN.
if (card->OEM > 0) return false; // Not used in this format
packed->Length = 36; // Set number of bits
set_linear_field(packed, card->FacilityCode, 1, 8);
set_linear_field(packed, card->IssueLevel, 9, 2);
set_linear_field(packed, card->CardNumber, 11, 24);
set_bit_by_position(packed, oddparity32(get_linear_field(packed, 1, 17)), 0);
set_bit_by_position(packed, oddparity32(get_linear_field(packed, 17, 18)), 35);
return add_HID_header(packed);
}
bool Unpack_S12906(wiegand_message_t *packed, wiegand_card_t *card) {
memset(card, 0, sizeof(wiegand_card_t));
if (packed->Length != 36) return false; // Wrong length? Stop here.
card->FacilityCode = get_linear_field(packed, 1, 8);
card->IssueLevel = get_linear_field(packed, 9, 2);
card->CardNumber = get_linear_field(packed, 11, 24);
card->ParityValid =
(get_bit_by_position(packed, 0) == oddparity32(get_linear_field(packed, 1, 17))) &&
(get_bit_by_position(packed, 35) == oddparity32(get_linear_field(packed, 17, 18)));
return true;
}
bool Pack_Sie36(wiegand_card_t *card, wiegand_message_t *packed) {
memset(packed, 0, sizeof(wiegand_message_t));
if (card->FacilityCode > 0x0003FFFF) return false; // Can't encode FC.
if (card->CardNumber > 0x0000FFFF) return false; // Can't encode CN.
if (card->IssueLevel > 0) return false; // Not used in this format
if (card->OEM > 0) return false; // Not used in this format
packed->Length = 36; // Set number of bits
set_linear_field(packed, card->FacilityCode, 1, 18);
set_linear_field(packed, card->CardNumber, 19, 16);
set_bit_by_position(packed,
oddparity32(get_nonlinear_field(packed, 23, (uint8_t[]) {1, 3, 4, 6, 7, 9, 10, 12, 13, 15, 16, 18, 19, 21, 22, 24, 25, 27, 28, 30, 31, 33, 34}))
, 0);
set_bit_by_position(packed,
evenparity32(get_nonlinear_field(packed, 23, (uint8_t[]) {1, 2, 4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19, 20, 22, 23, 25, 26, 28, 29, 31, 32, 34}))
, 35);
return add_HID_header(packed);
}
bool Unpack_Sie36(wiegand_message_t *packed, wiegand_card_t *card) {
memset(card, 0, sizeof(wiegand_card_t));
if (packed->Length != 36) return false; // Wrong length? Stop here.
card->FacilityCode = get_linear_field(packed, 1, 18);
card->CardNumber = get_linear_field(packed, 19, 16);
card->ParityValid =
(get_bit_by_position(packed, 0) == oddparity32(get_nonlinear_field(packed, 23, (uint8_t[]) {1, 3, 4, 6, 7, 9, 10, 12, 13, 15, 16, 18, 19, 21, 22, 24, 25, 27, 28, 30, 31, 33, 34}))) &&
(get_bit_by_position(packed, 35) == oddparity32(get_nonlinear_field(packed, 23, (uint8_t[]) {1, 2, 4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19, 20, 22, 23, 25, 26, 28, 29, 31, 32, 34})));
return true;
}
bool Pack_C15001(wiegand_card_t *card, wiegand_message_t *packed) {
memset(packed, 0, sizeof(wiegand_message_t));
if (card->FacilityCode > 0x000000FF) return false; // Can't encode FC.
if (card->CardNumber > 0x0000FFFF) return false; // Can't encode CN.
if (card->IssueLevel > 0) return false; // Not used in this format
if (card->OEM > 0x000003FF) return false; // Can't encode OEM.
packed->Length = 36; // Set number of bits
set_linear_field(packed, card->OEM, 1, 10);
set_linear_field(packed, card->FacilityCode, 11, 8);
set_linear_field(packed, card->CardNumber, 19, 16);
set_bit_by_position(packed, evenparity32(get_linear_field(packed, 1, 17)), 0);
set_bit_by_position(packed, oddparity32(get_linear_field(packed, 18, 17)), 35);
return add_HID_header(packed);
}
bool Unpack_C15001(wiegand_message_t *packed, wiegand_card_t *card) {
memset(card, 0, sizeof(wiegand_card_t));
if (packed->Length != 36) return false; // Wrong length? Stop here.
card->OEM = get_linear_field(packed, 1, 10);
card->FacilityCode = get_linear_field(packed, 11, 8);
card->CardNumber = get_linear_field(packed, 19, 16);
card->ParityValid =
(get_bit_by_position(packed, 0) == evenparity32(get_linear_field(packed, 1, 17))) &&
(get_bit_by_position(packed, 35) == oddparity32(get_linear_field(packed, 18, 17)));
return true;
}
bool Pack_H10302(wiegand_card_t *card, wiegand_message_t *packed) {
memset(packed, 0, sizeof(wiegand_message_t));
if (card->FacilityCode > 0) return false; // Can't encode FC. (none in this format)
if (card->CardNumber > 0x00000007FFFFFFFF) return false; // Can't encode CN.
if (card->IssueLevel > 0) return false; // Not used in this format
if (card->OEM > 0) return false; // Not used in this format
packed->Length = 37; // Set number of bits
set_linear_field(packed, card->CardNumber, 1, 35);
set_bit_by_position(packed, evenparity32(get_linear_field(packed, 1, 18)), 0);
set_bit_by_position(packed, oddparity32(get_linear_field(packed, 18, 18)), 36);
return add_HID_header(packed);
}
bool Unpack_H10302(wiegand_message_t *packed, wiegand_card_t *card) {
memset(card, 0, sizeof(wiegand_card_t));
if (packed->Length != 37) return false; // Wrong length? Stop here.
card->CardNumber = get_linear_field(packed, 1, 35);
card->ParityValid =
(get_bit_by_position(packed, 0) == evenparity32(get_linear_field(packed, 1, 18))) &&
(get_bit_by_position(packed, 36) == oddparity32(get_linear_field(packed, 18, 18)));
return true;
}
bool Pack_H10304(wiegand_card_t *card, wiegand_message_t *packed) {
memset(packed, 0, sizeof(wiegand_message_t));
if (card->FacilityCode > 0x0000FFFF) return false; // Can't encode FC.
if (card->CardNumber > 0x0007FFFF) return false; // Can't encode CN.
if (card->IssueLevel > 0) return false; // Not used in this format
if (card->OEM > 0) return false; // Not used in this format
packed->Length = 37; // Set number of bits
packed->Bot |= (card->CardNumber & 0x0007FFFF) << 1;
packed->Bot |= (card->FacilityCode & 0x00000FFF) << 20;
packed->Mid |= (card->FacilityCode & 0x0000F000) >> 12;
packed->Mid |= (evenparity32((packed->Mid & 0x0000000F) ^ (packed->Bot & 0xFFFC0000)) & 1) << 4;
packed->Bot |= (oddparity32(packed->Bot & 0x0007FFFE) & 1);
return add_HID_header(packed);
}
bool Unpack_H10304(wiegand_message_t *packed, wiegand_card_t *card) {
memset(card, 0, sizeof(wiegand_card_t));
if (packed->Length != 37) return false; // Wrong length? Stop here.
card->CardNumber = (packed->Bot >> 1) & 0x0007FFFF;
card->FacilityCode = ((packed->Mid & 0xF) << 12) | ((packed->Bot >> 20));
card->ParityValid =
(evenparity32((packed->Mid & 0x0000000F) ^ (packed->Bot & 0xFFFC0000)) == ((packed->Mid >> 4) & 1)) &&
(oddparity32(packed->Bot & 0x0007FFFE) == (packed->Bot & 1));
return true;
}
bool Pack_P10001(wiegand_card_t *card, wiegand_message_t *packed) {
memset(packed, 0, sizeof(wiegand_message_t));
if (card->FacilityCode > 0xFFF) return false; // Can't encode FC.
if (card->CardNumber > 0xFFFF) return false; // Can't encode CN.
if (card->IssueLevel > 0) return false; // Not used in this format
if (card->OEM > 0) return false; // Not used in this format
packed->Length = 40; // Set number of bits
set_linear_field(packed, 0xF, 0, 4);
set_linear_field(packed, card->FacilityCode, 4, 12);
set_linear_field(packed, card->CardNumber, 16, 16);
set_linear_field(packed,
get_linear_field(packed, 0, 8) ^
get_linear_field(packed, 8, 8) ^
get_linear_field(packed, 16, 8) ^
get_linear_field(packed, 24, 8)
, 32, 8);
return add_HID_header(packed);
}
bool Unpack_P10001(wiegand_message_t *packed, wiegand_card_t *card) {
memset(card, 0, sizeof(wiegand_card_t));
if (packed->Length != 40) return false; // Wrong length? Stop here.
card->CardNumber = get_linear_field(packed, 16, 16);
card->FacilityCode = get_linear_field(packed, 4, 12);
card->ParityValid = (
get_linear_field(packed, 0, 8) ^
get_linear_field(packed, 8, 8) ^
get_linear_field(packed, 16, 8) ^
get_linear_field(packed, 24, 8)
) == get_linear_field(packed, 32, 8);
return true;
}
bool Pack_C1k48s(wiegand_card_t *card, wiegand_message_t *packed) {
memset(packed, 0, sizeof(wiegand_message_t));
if (card->FacilityCode > 0x003FFFFF) return false; // Can't encode FC.
if (card->CardNumber > 0x007FFFFF) return false; // Can't encode CN.
if (card->IssueLevel > 0) return false; // Not used in this format
if (card->OEM > 0) return false; // Not used in this format
packed->Length = 48; // Set number of bits
packed->Bot |= (card->CardNumber & 0x007FFFFF) << 1;
packed->Bot |= (card->FacilityCode & 0x000000FF) << 24;
packed->Mid |= (card->FacilityCode & 0x003FFF00) >> 8;
packed->Mid |= (evenparity32((packed->Mid & 0x00001B6D) ^ (packed->Bot & 0xB6DB6DB6)) & 1) << 14;
packed->Bot |= (oddparity32((packed->Mid & 0x000036DB) ^ (packed->Bot & 0x6DB6DB6C)) & 1);
packed->Mid |= (oddparity32((packed->Mid & 0x00007FFF) ^ (packed->Bot & 0xFFFFFFFF)) & 1) << 15;
return add_HID_header(packed);
}
bool Unpack_C1k48s(wiegand_message_t *packed, wiegand_card_t *card) {
memset(card, 0, sizeof(wiegand_card_t));
if (packed->Length != 48) return false; // Wrong length? Stop here.
card->CardNumber = (packed->Bot >> 1) & 0x007FFFFF;
card->FacilityCode = ((packed->Mid & 0x00003FFF) << 8) | ((packed->Bot >> 24));
card->ParityValid =
(evenparity32((packed->Mid & 0x00001B6D) ^ (packed->Bot & 0xB6DB6DB6)) == ((packed->Mid >> 14) & 1)) &&
(oddparity32((packed->Mid & 0x000036DB) ^ (packed->Bot & 0x6DB6DB6C)) == ((packed->Bot >> 0) & 1)) &&
(oddparity32((packed->Mid & 0x00007FFF) ^ (packed->Bot & 0xFFFFFFFF)) == ((packed->Mid >> 15) & 1));
return true;
}
static const cardformat_t FormatTable[] = {
{"H10301", Pack_H10301, Unpack_H10301, "HID H10301 26-bit", {1, 1, 0, 0, 1}}, // imported from old pack/unpack
{"Tecom27", Pack_Tecom27, Unpack_Tecom27, "Tecom 27-bit", {1, 1, 0, 0, 1}}, // from cardinfo.barkweb.com.au
{"2804W", Pack_2804W, Unpack_2804W, "2804 Wiegand", {1, 1, 0, 0, 1}}, // from cardinfo.barkweb.com.au
{"ATSW30", Pack_ATSW30, Unpack_ATSW30, "ATS Wiegand 30-bit", {1, 1, 0, 0, 1}}, // from cardinfo.barkweb.com.au
{"ADT31", Pack_ADT31, Unpack_ADT31, "HID ADT 31-bit", {1, 1, 0, 0, 1}}, // from cardinfo.barkweb.com.au
{"Kastle", Pack_Kastle, Unpack_Kastle, "Kastle 32-bit", {1, 1, 1, 0, 1}}, // from @xilni; PR #23 on RfidResearchGroup/proxmark3
{"D10202", Pack_D10202, Unpack_D10202, "HID D10202 33-bit", {1, 1, 0, 0, 1}}, // from cardinfo.barkweb.com.au
{"H10306", Pack_H10306, Unpack_H10306, "HID H10306 34-bit", {1, 1, 0, 0, 1}}, // imported from old pack/unpack
{"N10002", Pack_N10002, Unpack_N10002, "HID N10002 34-bit", {1, 1, 0, 0, 1}}, // from cardinfo.barkweb.com.au
{"C1k35s", Pack_C1k35s, Unpack_C1k35s, "HID Corporate 1000 35-bit standard layout", {1, 1, 0, 0, 1}}, // imported from old pack/unpack
{"C15001", Pack_C15001, Unpack_C15001, "HID KeySpan 36-bit", {1, 1, 0, 1, 1}}, // from Proxmark forums
{"S12906", Pack_S12906, Unpack_S12906, "HID Simplex 36-bit", {1, 1, 1, 0, 1}}, // from cardinfo.barkweb.com.au
{"Sie36", Pack_Sie36, Unpack_Sie36, "HID 36-bit Siemens", {1, 1, 0, 0, 1}}, // from cardinfo.barkweb.com.au
{"H10320", Pack_H10320, Unpack_H10320, "HID H10320 36-bit BCD", {1, 0, 0, 0, 1}}, // from Proxmark forums
{"H10302", Pack_H10302, Unpack_H10302, "HID H10302 37-bit huge ID", {1, 0, 0, 0, 1}}, // from Proxmark forums
{"H10304", Pack_H10304, Unpack_H10304, "HID H10304 37-bit", {1, 1, 0, 0, 1}}, // imported from old pack/unpack
{"P10001", Pack_P10001, Unpack_P10001, "HID P10001 Honeywell 40-bit" }, // from cardinfo.barkweb.com.au
{"C1k48s", Pack_C1k48s, Unpack_C1k48s, "HID Corporate 1000 48-bit standard layout", {1, 1, 0, 0, 1}}, // imported from old pack/unpack
{NULL, NULL, NULL, NULL, {0, 0, 0, 0, 0}} // Must null terminate array
};
void HIDListFormats() {
if (FormatTable[0].Name == NULL)
return;
PrintAndLogEx(NORMAL, "%-10s %s", "Name", "Description");
PrintAndLogEx(NORMAL, "------------------------------------------------------------");
int i = 0;
while (FormatTable[i].Name) {
PrintAndLogEx(NORMAL, _YELLOW_("%-10s")" %-30s", FormatTable[i].Name, FormatTable[i].Descrp);
++i;
}
PrintAndLogEx(NORMAL, "");
return;
}
cardformat_t HIDGetCardFormat(int idx) {
return FormatTable[idx];
}
int HIDFindCardFormat(const char *format) {
if (FormatTable[0].Name == NULL)
return -1;
int i = 0;
// str_lower
while (FormatTable[i].Name && strcmp(FormatTable[i].Name, format)) {
++i;
}
if (FormatTable[i].Name)
return i;
return -1;
}
bool HIDPack(int format_idx, wiegand_card_t *card, wiegand_message_t *packed) {
memset(packed, 0, sizeof(wiegand_message_t));
if (format_idx < 0 || format_idx >= (sizeof(FormatTable) / sizeof(FormatTable[0])))
return false;
return FormatTable[format_idx].Pack(card, packed);
}
void HIDDisplayUnpackedCard(wiegand_card_t *card, const cardformat_t format) {
/*
PrintAndLogEx(SUCCESS, " Format: %s (%s)", format.Name, format.Descrp);
if (format.Fields.hasFacilityCode)
PrintAndLogEx(SUCCESS, "Facility Code: %d",card->FacilityCode);
if (format.Fields.hasCardNumber)
PrintAndLogEx(SUCCESS, " Card Number: %d",card->CardNumber);
if (format.Fields.hasIssueLevel)
PrintAndLogEx(SUCCESS, " Issue Level: %d",card->IssueLevel);
if (format.Fields.hasOEMCode)
PrintAndLogEx(SUCCESS, " OEM Code: %d",card->OEM);
if (format.Fields.hasParity)
PrintAndLogEx(SUCCESS, " Parity: %s",card->ParityValid ? "Valid" : "Invalid");
*/
char s[80] = {0};
if (format.Fields.hasFacilityCode)
snprintf(s, sizeof(s), "FC: %d", card->FacilityCode);
if (format.Fields.hasCardNumber)
snprintf(s + strlen(s), sizeof(s) - strlen(s), " CN: %" PRIu64, card->CardNumber);
if (format.Fields.hasIssueLevel)
snprintf(s + strlen(s), sizeof(s) - strlen(s), " Issue %d", card->IssueLevel);
if (format.Fields.hasOEMCode)
snprintf(s + strlen(s), sizeof(s) - strlen(s), " OEM: %d", card->OEM);
if (format.Fields.hasParity)
snprintf(s + strlen(s), sizeof(s) - strlen(s), " parity: %s", card->ParityValid ? "valid" : "invalid");
PrintAndLogEx(SUCCESS, "%s [%s - %s]", s, format.Name, format.Descrp);
}
bool HIDTryUnpack(wiegand_message_t *packed, bool ignore_parity) {
if (FormatTable[0].Name == NULL)
return false;
bool result = false;
int i = 0;
wiegand_card_t card;
memset(&card, 0, sizeof(wiegand_card_t));
while (FormatTable[i].Name) {
if (FormatTable[i].Unpack(packed, &card)) {
if (ignore_parity || !FormatTable[i].Fields.hasParity || card.ParityValid) {
result = true;
HIDDisplayUnpackedCard(&card, FormatTable[i]);
}
}
++i;
}
if (result == false) {
PrintAndLogEx(SUCCESS, "Unknown. Bit len %d", packed->Length);
}
return result;
}

48
client/wiegand_formats.h Normal file
View file

@ -0,0 +1,48 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2018 grauerfuchs
//
// 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.
//-----------------------------------------------------------------------------
// Wiegand format packing/unpacking routines
//-----------------------------------------------------------------------------
#ifndef WIEGAND_FORMATS_H__
#define WIEGAND_FORMATS_H__
#include <string.h> // memset
#include <stdbool.h>
#include <stdint.h>
#include <inttypes.h>
#include <math.h>
#include <stdio.h>
#include "cmddata.h"
#include "wiegand_formatutils.h"
#include "parity.h" // for parity
#include "ui.h"
typedef struct {
bool hasCardNumber;
bool hasFacilityCode;
bool hasIssueLevel;
bool hasOEMCode;
bool hasParity;
} cardformatdescriptor_t;
// Structure for defined Wiegand card formats available for packing/unpacking
typedef struct {
const char *Name;
bool (*Pack)(wiegand_card_t *card, wiegand_message_t *packed);
bool (*Unpack)(wiegand_message_t *packed, wiegand_card_t *card);
const char *Descrp;
cardformatdescriptor_t Fields;
} cardformat_t;
void HIDListFormats();
int HIDFindCardFormat(const char *format);
cardformat_t HIDGetCardFormat(int idx);
bool HIDPack(int FormatIndex, wiegand_card_t *card, wiegand_message_t *packed);
bool HIDTryUnpack(wiegand_message_t *packed, bool ignoreParity);
#endif

View file

@ -0,0 +1,185 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2018 grauerfuchs
//
// 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.
//-----------------------------------------------------------------------------
// Wiegand card format packing/unpacking support functions
//-----------------------------------------------------------------------------
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "wiegand_formatutils.h"
#include "ui.h"
bool get_bit_by_position(wiegand_message_t *data, uint8_t pos) {
if (pos >= data->Length) return false;
pos = (data->Length - pos) - 1; // invert ordering; Indexing goes from 0 to 1. Subtract 1 for weight of bit.
bool result = false;
if (pos > 95)
result = false;
else if (pos > 63)
result = (data->Top >> (pos - 64)) & 1;
else if (pos > 31)
result = (data->Mid >> (pos - 32)) & 1;
else
result = (data->Bot >> pos) & 1;
return result;
}
bool set_bit_by_position(wiegand_message_t *data, bool value, uint8_t pos) {
if (pos >= data->Length) return false;
pos = (data->Length - pos) - 1; // invert ordering; Indexing goes from 0 to 1. Subtract 1 for weight of bit.
if (pos > 95) {
return false;
} else if (pos > 63) {
if (value)
data->Top |= (1 << (pos - 64));
else
data->Top &= ~(1 << (pos - 64));
return true;
} else if (pos > 31) {
if (value)
data->Mid |= (1 << (pos - 32));
else
data->Mid &= ~(1 << (pos - 32));
return true;
} else {
if (value)
data->Bot |= (1 << pos);
else
data->Bot &= ~(1 << pos);
return true;
}
}
/**
* Safeguard the data by doing a manual deep copy
*
* At the time of the initial writing, the struct does not contain pointers. That doesn't
* mean it won't eventually contain one, however. To prevent memory leaks and erroneous
* aliasing, perform the copy function manually instead. Hence, this function.
*
* If the definition of the wiegand_message struct changes, this function must also
* be updated to match.
*/
void message_datacopy(wiegand_message_t *src, wiegand_message_t *dest) {
dest->Bot = src->Bot;
dest->Mid = src->Mid;
dest->Top = src->Top;
dest->Length = src->Length;
}
/**
*
* Yes, this is horribly inefficient for linear data.
* The current code is a temporary measure to have a working function in place
* until all the bugs shaken from the block/chunk version of the code.
*
*/
uint64_t get_linear_field(wiegand_message_t *data, uint8_t firstBit, uint8_t length) {
uint64_t result = 0;
for (uint8_t i = 0; i < length; i++) {
result = (result << 1) | get_bit_by_position(data, firstBit + i);
}
return result;
}
bool set_linear_field(wiegand_message_t *data, uint64_t value, uint8_t firstBit, uint8_t length) {
wiegand_message_t tmpdata;
message_datacopy(data, &tmpdata);
bool result = true;
for (int i = 0; i < length; i++) {
result &= set_bit_by_position(&tmpdata, (value >> ((length - i) - 1)) & 1, firstBit + i);
}
if (result)
message_datacopy(&tmpdata, data);
return result;
}
uint64_t get_nonlinear_field(wiegand_message_t *data, uint8_t numBits, uint8_t *bits) {
uint64_t result = 0;
for (int i = 0; i < numBits; i++) {
result = (result << 1) | (get_bit_by_position(data, *(bits + i)) & 1);
}
return result;
}
bool set_nonlinear_field(wiegand_message_t *data, uint64_t value, uint8_t numBits, uint8_t *bits) {
wiegand_message_t tmpdata;
message_datacopy(data, &tmpdata);
bool result = true;
for (int i = 0; i < numBits; i++) {
result &= set_bit_by_position(&tmpdata, (value >> ((numBits - i) - 1)) & 1, *(bits + i));
}
if (result)
message_datacopy(&tmpdata, data);
return result;
}
uint8_t get_length_from_header(wiegand_message_t *data) {
uint8_t len = 0;
uint32_t hfmt = 0; // for calculating card length
if ((data->Top & 0x000FFFFF) > 0) { // > 64 bits
hfmt = data->Top & 0x000FFFFF;
len = 64;
} else if ((data->Mid & 0xFFFFFFC0) > 0) { // < 63-38 bits
hfmt = data->Mid & 0xFFFFFFC0;
len = 32;
} else if (data->Mid && (data->Mid & 0x00000020) == 0) { // 37 bits;
hfmt = 0;
len = 37;
} else if ((data->Mid & 0x0000001F) > 0) { // 36-32 bits
printf("a\n");
hfmt = data->Mid & 0x0000001F;
len = 32;
} else if (data->Top == 0 && data->Mid == 0) { //< 32 bits
hfmt = data->Bot;
len = 0;
} else {
hfmt = data->Bot;
len = 0;
}
while (hfmt > 1) {
hfmt >>= 1;
len++;
}
return len;
}
wiegand_message_t initialize_message_object(uint32_t top, uint32_t mid, uint32_t bot) {
wiegand_message_t result;
memset(&result, 0, sizeof(wiegand_message_t));
result.Top = top;
result.Mid = mid;
result.Bot = bot;
result.Length = get_length_from_header(&result);
return result;
}
bool add_HID_header(wiegand_message_t *data) {
if (data->Length > 84 || data->Length == 0) return false; // Invalid value
if (data->Length >= 64) {
data->Top |= 1 << (data->Length - 64); // leading 1: start bit
data->Top |= 0x09e00000; // Extended-length header
} else if (data->Length > 37) {
data->Mid |= 1 << (data->Length - 32); // leading 1: start bit
data->Top |= 0x09e00000; // Extended-length header
} else if (data->Length == 37) {
// No header bits added to 37-bit cards
} else if (data->Length >= 32) {
data->Mid |= 0x20; // Bit 37; standard header
data->Mid |= 1 << (data->Length - 32); // leading 1: start bit
} else {
data->Mid |= 0x20; // Bit 37; standard header
data->Bot |= 1 << data->Length; // leading 1: start bit
}
return true;
}

View file

@ -0,0 +1,49 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2018 grauerfuchs
//
// 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.
//-----------------------------------------------------------------------------
// Weigand card format packing/unpacking support functions
//-----------------------------------------------------------------------------
#ifndef WIEGAND_FORMATUTILS_H__
#define WIEGAND_FORMATUTILS_H__
#include <stdarg.h>
#include <stdint.h>
#include <stdbool.h>
// Structure for packed wiegand messages
// Always align lowest value (last transmitted) bit to ordinal position 0 (lowest valued bit bottom)
typedef struct {
uint8_t Length; // Number of encoded bits in wiegand message (excluding headers and preamble)
uint32_t Top; // Bits in x<<64 positions
uint32_t Mid; // Bits in x<<32 positions
uint32_t Bot; // Lowest ordinal positions
} wiegand_message_t;
// Structure for unpacked wiegand card, like HID prox
typedef struct {
uint32_t FacilityCode;
uint64_t CardNumber;
uint32_t IssueLevel;
uint32_t OEM;
bool ParityValid; // Only valid for responses
} wiegand_card_t;
bool get_bit_by_position(wiegand_message_t *data, uint8_t pos);
bool set_bit_by_position(wiegand_message_t *data, bool value, uint8_t pos);
uint64_t get_linear_field(wiegand_message_t *data, uint8_t firstBit, uint8_t length);
bool set_linear_field(wiegand_message_t *data, uint64_t value, uint8_t firstBit, uint8_t length);
uint64_t get_nonlinear_field(wiegand_message_t *data, uint8_t numBits, uint8_t *bits);
bool set_nonlinear_field(wiegand_message_t *data, uint64_t value, uint8_t numBits, uint8_t *bits);
wiegand_message_t initialize_message_object(uint32_t top, uint32_t mid, uint32_t bot);
bool add_HID_header(wiegand_message_t *data);
#endif

View file

@ -9,7 +9,7 @@
|[Sim Module](#Sim-Module)|[Hitag](#Hitag)||
|[Lua Scripts](#Lua-Scripts)|||
|[Smart Card](#Smart-Card)|||
|[Wiegand convertion](#Wiegand-manipulation)|||
## Generic
^[Top](#top)
@ -62,7 +62,7 @@ Options
---
k <Key> : *Access Key as 16 hex symbols or 1 hex to select key from memory
pm3 --> hf iclass dump k AFA785A7DAB33378
m3 --> hf iclass dump k 0
```
Read iClass Block
@ -72,7 +72,7 @@ Options
b <Block> : The block number as 2 hex symbols
k <Key> : Access Key as 16 hex symbols or 1 hex to select key from memory
pm3 --> hf iclass readblk b 7 k AFA785A7DAB33378
pm3 --> hf iclass rdbl b 7 k 0
```
Write to iClass Block
@ -83,7 +83,7 @@ b <Block> : The block number as 2 hex symbols
d <data> : Set the Data to write as 16 hex symbols
k <Key> : Access Key as 16 hex symbols or 1 hex to select key from memory
pm3 --> hf iclass writeblk b 07 d 6ce099fe7e614fd0 k AFA785A7DAB33378
pm3 --> hf iclass wrbl b 07 d 6ce099fe7e614fd0 k 0
```
Print keystore
@ -107,7 +107,7 @@ pm3 --> hf iclass managekeys n 0 k AFA785A7DAB33378
Encrypt iClass Block
```
pm3 --> hf iclass encryptblk 0000000f2aa3dba8
pm3 --> hf iclass encrypt 0000000f2aa3dba8
```
Load iClass dump into memory for simulation
@ -116,7 +116,7 @@ Options
---
f <filename> : load iclass tag-dump filename
pm3 --> hf iclass eload f iclass_tagdump-db883702f8ff12e0.bin
pm3 --> hf iclass eload f hf-iclass-db883702f8ff12e0.bin
```
Simulate iClass
@ -124,6 +124,7 @@ Simulate iClass
Options
---
0 <CSN> simulate the given CSN
2 Runs part 1 of LOCLASS attack
1 simulate default CSN
3 Full simulation using emulator memory (see 'hf iclass eload')
@ -132,14 +133,14 @@ pm3 --> hf iclass sim 3
Clone iClass Legacy Sequence
```
pm3 --> hf iclass readblk b 7 k AFA785A7DAB33378
pm3 --> hf iclass writeblk b 07 d 6ce099fe7e614fd0 k AFA785A7DAB33378
pm3 --> hf iclass rdbl b 7 k 0
pm3 --> hf iclass wrbl b 7 d 6ce099fe7e614fd0 k 0
```
Simulate iClass Sequence
```
pm3 --> hf iclass dump k AFA785A7DAB33378
pm3 --> hf iclass eload f iclass_tagdump-db883702f8ff12e0.bin
pm3 --> hf iclass dump k 0
pm3 --> hf iclass eload f hf-iclass-db883702f8ff12e0.bin
pm3 --> hf iclass sim 3
```
@ -224,6 +225,14 @@ Options
pm3 --> hf mf wrbl 0 A FFFFFFFFFFFF d3a2859f6b880400c801002000000016
```
Run autopwn
```
Options
---
pm3 --> hf mf autopwn
```
Run Hardnested attack
```
Options
@ -241,8 +250,8 @@ Options
<card memory> <file name w/o `.eml`>
[card memory]: 0 = 320 bytes (Mifare Mini), 1 = 1K (default), 2 = 2K, 4 = 4K, u = UL
pm3 --> hf mf eload 353C2AA6
pm3 --> hf mf eload 1 353C2AA6
pm3 --> hf mf eload hf-mf-353C2AA6
pm3 --> hf mf eload 1 hf-mf-353C2AA6
```
Simulate Mifare
@ -268,6 +277,37 @@ pm3 --> hf mf dump
pm3 --> hf mf restore 1 u 4A6CE843 k hf-mf-A29558E4-key.bin f hf-mf-A29558E4-data.bin
```
## Wiegand manipulation
^[Top](#top)
List all available weigand formats in client
```
pm3 --> wiegand list
```
Convert Site & Facility code to Wiegand raw hex
```
Options
---
w <format> o <OEM> f <FC> c <CN> i <issuelevel>
w : wiegand format to use
o : OEM number / site code
f : facility code
c : card number
i : issue level
pm3 --> wiegand encode 0 56 150
```
Convert Site & Facility code from Wiegand raw hex to numbers
```
Options
---
p : ignore parity errors
pm3 --> wiegand decode 2006f623ae
```
## HID Prox
^[Top](#top)
@ -281,18 +321,6 @@ Demodulate HID Prox card
pm3 --> lf hid demod
```
Convert Site & Facility code to Wiegand
```
Options
---
<OEM> <FC> <CN>
OEM : OEM number / site code
FC : facility code
CN : card number
pm3 --> lf hid wiegand 0 56 150
```
Simulate Prox card
```

View file

@ -242,6 +242,14 @@ typedef struct {
uint8_t keytype;
} PACKED mfc_eload_t;
typedef struct {
uint8_t status;
uint8_t CSN[8];
uint8_t CONFIG[8];
uint8_t CC[8];
uint8_t AIA[8];
} PACKED iclass_reader_t;
// For the bootloader
#define CMD_DEVICE_INFO 0x0000
#define CMD_SETUP_WRITE 0x0001
@ -345,9 +353,6 @@ typedef struct {
#define CMD_SET_ADC_MUX 0x020F
#define CMD_LF_HID_CLONE 0x0210
#define CMD_LF_EM410X_WRITE 0x0211
#define CMD_LF_INDALA_CLONE 0x0212
// for 224 bits UID
#define CMD_LF_INDALA224_CLONE 0x0213
#define CMD_LF_T55XX_READBL 0x0214
#define CMD_LF_T55XX_WRITEBL 0x0215
#define CMD_LF_T55XX_RESET_READ 0x0216
@ -356,7 +361,6 @@ typedef struct {
#define CMD_LF_EM4X_READWORD 0x0218
#define CMD_LF_EM4X_WRITEWORD 0x0219
#define CMD_LF_IO_DEMOD 0x021A
#define CMD_LF_IO_CLONE 0x021B
#define CMD_LF_EM410X_DEMOD 0x021c
// Sampling configuration for LF reader/sniffer
#define CMD_LF_SAMPLING_SET_CONFIG 0x021d

View file

@ -205,6 +205,11 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
#define MAGIC_WIPE 0x40
#define MAGIC_SINGLE (MAGIC_WUPC | MAGIC_HALT | MAGIC_INIT | MAGIC_OFF) //0x1E
// by CMD_HF_MIFARE_CIDENT
#define MAGIC_GEN_1A 1
#define MAGIC_GEN_1B 2
#define MAGIC_GEN_2 4
#define MAGIC_GEN_UNFUSED 5
/**
06 00 = INITIATE
0E xx = SELECT ID (xx = Chip-ID)

View file

@ -3,6 +3,12 @@
PM3PATH=$(dirname "$0")
cd "$PM3PATH" || exit 1
if [ "$1" == "long" ]; then
SLOWTESTS=true
else
SLOWTESTS=false
fi
C_RED='\033[0;31m'
C_GREEN='\033[0;32m'
C_YELLOW='\033[0;33m'
@ -95,9 +101,14 @@ while true; do
printf "\n${C_BLUE}Testing HF:${C_NC}\n"
if ! CheckExecute "hf mf offline text" "./client/proxmark3 -c 'hf mf'" "at_enc"; then break; fi
if ! CheckExecute "hf mf hardnested test" "./client/proxmark3 -c 'hf mf hardnested t 1 000000000000'" "found:" "repeat" "ignore"; then break; fi
if ! CheckExecute "hf iclass test" "./client/proxmark3 -c 'hf iclass loclass t'" "verified ok"; then break; fi
if ! CheckExecute "emv test" "./client/proxmark3 -c 'emv test'" "Test(s) \[ OK"; then break; fi
if $SLOWTESTS; then
if ! CheckExecute "hf mf hardnested test" "./client/proxmark3 -c 'hf mf hardnested t 1 000000000000'" "found:" "repeat" "ignore"; then break; fi
if ! CheckExecute "hf iclass test" "./client/proxmark3 -c 'hf iclass loclass t l'" "verified ok"; then break; fi
if ! CheckExecute "emv test" "./client/proxmark3 -c 'emv test -l'" "Test(s) \[ OK"; then break; fi
else
if ! CheckExecute "hf iclass test" "./client/proxmark3 -c 'hf iclass loclass t'" "OK!"; then break; fi
if ! CheckExecute "emv test" "./client/proxmark3 -c 'emv test'" "Test(s) \[ OK"; then break; fi
fi
printf "\n${C_BLUE}Testing tools:${C_NC}\n"
# Need a decent example for mfkey32...

View file

@ -17,7 +17,7 @@ interface bcm2835gpio
# This file is meant for recent versions of Raspberry Pi
# You can check yours with:
# dd if=/proc/device-tree/soc/ranges bs=4 skip=1 count=1 2>/dev/null|xxd -p
# if it returns 20000000, use interface-raspberrypi2.cfg
# if it returns 20000000, use interface-raspberrypi.cfg
# if it returns 3F000000, you're fine
bcm2835gpio_peripheral_base 0x3F000000