diff --git a/CHANGELOG.md b/CHANGELOG.md index c062f6f83..783b596c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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) diff --git a/appveyor.yml b/appveyor.yml index af725ef93..a817ff1ac 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -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) { diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 058a4709e..0ac021400 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -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; @@ -802,7 +787,7 @@ static void PacketReceived(PacketCommandNG *packet) { uint32_t password; uint8_t flags; } PACKED; - struct p *payload = (struct p *) packet->data.asBytes; + struct p *payload = (struct p *) packet->data.asBytes; T55xxWakeUp(payload->password, payload->flags); break; } @@ -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: { diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index c49d93a1f..348317a8a 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -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; diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 47c8011f8..ab0467c85 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -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,56 +2036,16 @@ 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) { - + uint32_t data[] = {T55x7_BITRATE_RF_32 | T55x7_MODULATION_MANCHESTER | (2 << T55x7_MAXBLOCK_SHIFT), 0, 0}; - if (Q5) + if (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); LED_D_OFF(); diff --git a/armsrc/lfops.h b/armsrc/lfops.h index 99d1b29eb..bf246b529 100644 --- a/armsrc/lfops.h +++ b/armsrc/lfops.h @@ -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); diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index 089a320ad..4a469e6e1 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -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; } }; diff --git a/client/Makefile b/client/Makefile index 6fee6eae8..dcbb23110 100644 --- a/client/Makefile +++ b/client/Makefile @@ -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)), ) diff --git a/client/cmddata.c b/client/cmddata.c index 792cf6a96..d1df2be65 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -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); diff --git a/client/cmdflashmem.c b/client/cmdflashmem.c index ce5b37f44..be59dc4f7 100644 --- a/client/cmdflashmem.c +++ b/client/cmdflashmem.c @@ -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; } diff --git a/client/cmdhficlass.c b/client/cmdhficlass.c index 5f8ed9fbc..691072174 100644 --- a/client/cmdhficlass.c +++ b/client/cmdhficlass.c @@ -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 ]"); 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 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; } diff --git a/client/cmdhw.c b/client/cmdhw.c index c81efda9e..c363fdc25 100644 --- a/client/cmdhw.c +++ b/client/cmdhw.c @@ -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; } diff --git a/client/cmdlfawid.c b/client/cmdlfawid.c index 2360906a4..056d95af4 100644 --- a/client/cmdlfawid.c +++ b/client/cmdlfawid.c @@ -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; } diff --git a/client/cmdlfem4x.c b/client/cmdlfem4x.c index b7948b14c..e7b1c2b06 100644 --- a/client/cmdlfem4x.c +++ b/client/cmdlfem4x.c @@ -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(); diff --git a/client/cmdlffdx.c b/client/cmdlffdx.c index 2e48918fb..85529609d 100644 --- a/client/cmdlffdx.c +++ b/client/cmdlffdx.c @@ -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; } diff --git a/client/cmdlfguard.c b/client/cmdlfguard.c index 22f7141fc..fe00d1187 100644 --- a/client/cmdlfguard.c +++ b/client/cmdlfguard.c @@ -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; } diff --git a/client/cmdlfhid.c b/client/cmdlfhid.c index d4d52fa9f..20baa6449 100644 --- a/client/cmdlfhid.c +++ b/client/cmdlfhid.c @@ -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 f c d "); + PrintAndLogEx(NORMAL, "Usage: lf hid brute [h] [v] w [ (decimal)>] {...}"); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h : This help"); - PrintAndLogEx(NORMAL, " a : 26|33|34|35|37|40|44|84"); - PrintAndLogEx(NORMAL, " f : 8-bit value HID facility code"); - PrintAndLogEx(NORMAL, " c : (optional) cardnumber to start with, max 65535"); + PrintAndLogEx(NORMAL, " w : see `wiegand list` for available formats"); + PrintAndLogEx(NORMAL, " f : facility code"); + PrintAndLogEx(NORMAL, " c : card number to start with"); + PrintAndLogEx(NORMAL, " i : issue level"); + PrintAndLogEx(NORMAL, " o : OEM code"); PrintAndLogEx(NORMAL, " d : 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} }; diff --git a/client/cmdlfindala.c b/client/cmdlfindala.c index 3fd3be59e..673ed1438 100644 --- a/client/cmdlfindala.c +++ b/client/cmdlfindala.c @@ -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; } diff --git a/client/cmdlfio.c b/client/cmdlfio.c index 87fa17b02..7b3e777c6 100644 --- a/client/cmdlfio.c +++ b/client/cmdlfio.c @@ -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; } diff --git a/client/cmdlfjablotron.c b/client/cmdlfjablotron.c index 9cc663895..13a1d6e1f 100644 --- a/client/cmdlfjablotron.c +++ b/client/cmdlfjablotron.c @@ -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; } diff --git a/client/cmdlfkeri.c b/client/cmdlfkeri.c index 384aad0b6..49d3c2a33 100644 --- a/client/cmdlfkeri.c +++ b/client/cmdlfkeri.c @@ -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; } diff --git a/client/cmdlfnedap.c b/client/cmdlfnedap.c index 3a4ebd131..b186a1354 100644 --- a/client/cmdlfnedap.c +++ b/client/cmdlfnedap.c @@ -9,20 +9,6 @@ #include "cmdlfnedap.h" -#include - -#include -#include - -#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; } diff --git a/client/cmdlfnedap.h b/client/cmdlfnedap.h index fda0e130e..74fdd30fb 100644 --- a/client/cmdlfnedap.h +++ b/client/cmdlfnedap.h @@ -11,6 +11,19 @@ #include "common.h" +#include + +#include +#include +#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); diff --git a/client/cmdlfnoralsy.c b/client/cmdlfnoralsy.c index 146c6b350..fe469720b 100644 --- a/client/cmdlfnoralsy.c +++ b/client/cmdlfnoralsy.c @@ -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; diff --git a/client/cmdlfpac.c b/client/cmdlfpac.c index 6ea0af7d6..175d56ad4 100644 --- a/client/cmdlfpac.c +++ b/client/cmdlfpac.c @@ -63,7 +63,7 @@ static int CmdPacClone(const char *Cmd) { } static int CmdPacSim(const char *Cmd) { - + // NRZ sim. PrintAndLogEx(INFO, " To be implemented, feel free to contribute!"); return PM3_SUCCESS; diff --git a/client/cmdlfpresco.c b/client/cmdlfpresco.c index a9c74d9ac..f563e2ef8 100644 --- a/client/cmdlfpresco.c +++ b/client/cmdlfpresco.c @@ -144,21 +144,20 @@ 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; } diff --git a/client/cmdlfpyramid.c b/client/cmdlfpyramid.c index d0f116bf4..216e0834e 100644 --- a/client/cmdlfpyramid.c +++ b/client/cmdlfpyramid.c @@ -254,18 +254,20 @@ 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; } diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index c49fa037d..a41cd9f40 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -44,7 +44,7 @@ //static uint8_t bit_rates[9] = {8, 16, 32, 40, 50, 64, 100, 128, 0}; // Default configuration -t55xx_conf_block_t config = { +t55xx_conf_block_t config = { .modulation = DEMOD_ASK, .inverted = false, .offset = 0x00, @@ -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; @@ -86,7 +86,7 @@ static int usage_t55xx_config() { PrintAndLogEx(NORMAL, " Q5 [0/1] - Set/reset as Q5(T5555) chip instead of T55x7"); PrintAndLogEx(NORMAL, " ST [0/1] - Set/reset Sequence Terminator on"); PrintAndLogEx(NORMAL, ""); // layout is a little differnet, so seperate until a better fix - print_usage_t55xx_downloadlink(T55XX_DLMODE_SINGLE); + print_usage_t55xx_downloadlink(T55XX_DLMODE_SINGLE); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " lf t55xx config d FSK - FSK demodulation"); @@ -331,17 +331,17 @@ static int usage_t55xx_protect() { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " lf t55xx protect n 01020304 - sets new password to 01020304"); - PrintAndLogEx(NORMAL, " lf t55xx protect p 11223344 - use pwd 11223344 to set newpwd to 00000000"); + PrintAndLogEx(NORMAL, " lf t55xx protect p 11223344 - use pwd 11223344 to set newpwd to 00000000"); PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } 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"); - + bool testmode = false; uint32_t block0 = 0; @@ -350,25 +350,25 @@ static bool t55xxProtect(bool lock, bool usepwd, uint8_t override, uint32_t pass PrintAndLogEx(WARNING, "Failed to read block0, use `p` password parameter?"); return false; } - + 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; } - // set / clear pwd bit + // set / clear pwd bit if (lock) { block0 |= 1 << 4; } else { block0 &= ~(1 << 4); } - // write new password - if ( t55xxWrite(T55x7_PWD_BLOCK, T55x7_PAGE0, usepwd, testmode, password, downlink_mode, new_password ) != PM3_SUCCESS ) { + // write new password + 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 { @@ -377,22 +377,22 @@ static bool t55xxProtect(bool lock, bool usepwd, uint8_t override, uint32_t pass // validate new password uint32_t curr_password = (isPwdBitAlreadySet) ? new_password : password; - + if (t55xxVerifyWrite(T55x7_PWD_BLOCK, T55x7_PAGE0, usepwd, override, curr_password, downlink_mode, new_password) == false) { PrintAndLogEx(WARNING, "Failed to validate the password write. aborting."); return false; } else { PrintAndLogEx(SUCCESS, "Validated new password"); } - + // 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 { PrintAndLogEx(SUCCESS, "Wrote modified configuration block"); } - + // validate new config. If all went well, card should now demand pwd, hence override = 0. override = 0; if (t55xxVerifyWrite(T55x7_CONFIGURATION_BLOCK, T55x7_PAGE0, true, override, new_password, downlink_mode, block0) == false) { @@ -405,28 +405,55 @@ 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) { uint32_t read_data = 0; - - if (downlink_mode == 0xFF) + + if (downlink_mode == 0xFF) downlink_mode = config.downlink_mode; int res = T55xxReadBlockEx(block, page1, usepwd, override, password, downlink_mode, false); @@ -435,15 +462,15 @@ bool t55xxVerifyWrite(uint8_t block, bool page1, bool usepwd, uint8_t override, if (GetT55xxBlockData(&read_data) == false) return false; - } else if ( res == PM3_EWRONGANSVER) { - - // could't decode. Lets see if this was a block 0 write and try read/detect it auto. + } 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.. if (block == 0 && page1 == false) { if (t55xxAquireAndDetect(usepwd, password, data, true) == false) return false; - + return t55xxVerifyWrite(block, page1, usepwd, 2, password, config.downlink_mode, data); } } @@ -452,7 +479,7 @@ bool t55xxVerifyWrite(uint8_t block, bool page1, bool usepwd, uint8_t override, } int t55xxWrite(uint8_t block, bool page1, bool usepwd, bool testMode, uint32_t password, uint8_t downlink_mode, uint32_t data) { - + uint8_t flags; flags = (usepwd) ? 0x1 : 0; flags |= (page1) ? 0x2 : 0; @@ -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 @@ -504,7 +564,7 @@ static int CmdT55xxSetConfig(const char *Cmd) { bool errors = false; uint32_t block0 = 0; bool gotconf = false; - + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { char tmp = tolower(param_getchar(Cmd, cmdp)); switch (tmp) { @@ -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; } @@ -892,9 +928,9 @@ static int CmdT55xxDetect(const char *Cmd) { return PM3_ESOFT; 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) continue; @@ -906,7 +942,7 @@ static int CmdT55xxDetect(const char *Cmd) { break; } } else { - + if (AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password, downlink_mode)) { found = tryDetectModulation(downlink_mode, T55XX_PrintConfig); } @@ -915,10 +951,10 @@ static int CmdT55xxDetect(const char *Cmd) { } else { found = tryDetectModulation(downlink_mode, T55XX_PrintConfig); } - + if (found == false) PrintAndLogEx(WARNING, "Could not detect modulation automatically. Try setting it manually with " _YELLOW_("\'lf t55xx config\'")); - + return PM3_SUCCESS; } @@ -1110,13 +1146,13 @@ bool tryDetectModulationEx(uint8_t downlink_mode, bool print_config, uint32_t wa if (hits > 1) { PrintAndLogEx(SUCCESS, "Found [%d] possible matches for modulation.", hits); for (int i = 0; i < hits; ++i) { - + bool wanted = false; if (wanted_conf > 0) 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; @@ -1291,14 +1327,14 @@ static bool testQ5(uint8_t mode, uint8_t *offset, int *fndBitRate, uint8_t clk) si += 3; //uint8_t ST = PackBits(si, 1, DemodBuffer); si += 1; if (maxBlk == 0) continue; - + //test modulation if (!testQ5Modulation(mode, modread)) continue; if (bitRate != clk) continue; - + *fndBitRate = convertQ5bitRate(bitRate); if (*fndBitRate < 0) continue; - + *offset = idx; return true; @@ -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,19 +1550,19 @@ 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; } if (validate) { bool isOK = t55xxVerifyWrite(block, page1, usepwd, 1, password, downlink_mode, data); - if (isOK) + if (isOK) PrintAndLogEx(SUCCESS, "Write OK, validation successful"); else PrintAndLogEx(WARNING, "Write could not validate the written data"); } - + return PM3_SUCCESS; } @@ -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) { @@ -2405,17 +2440,17 @@ static int CmdT55xxWipe(const char *Cmd) { snprintf(msg, sizeof(msg), "User provided configuration block %08X", block0); else snprintf(msg, sizeof(msg), "Default configation block %08X", block0); - + PrintAndLogEx(INFO, "%s", msg); - // Creating cmd string for write block :) + // Creating cmd string for write block :) snprintf(ptrData, sizeof(writeData), "b 0 "); if (usepwd) { snprintf(ptrData + strlen(writeData), sizeof(writeData) - strlen(writeData), "p %08x ", password); } snprintf(ptrData + strlen(writeData), sizeof(writeData) - strlen(writeData), "d %08X", block0); - + if (CmdT55xxWriteBlock(ptrData) != PM3_SUCCESS) PrintAndLogEx(WARNING, "Warning: error writing blk 0"); @@ -2428,7 +2463,7 @@ static int CmdT55xxWipe(const char *Cmd) { memset(writeData, 0x00, sizeof(writeData)); } - + // Check and rest t55xx downlink mode. if (config.downlink_mode != T55XX_DLMODE_FIXED) { // Detect found a different mode so card must support snprintf(ptrData, sizeof(writeData), "b 3 1 d 00000000"); @@ -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); } // } @@ -2956,8 +2991,8 @@ static int CmdT55xxDetectPage1(const char *Cmd) { useGB = true; cmdp++; break; - case 'r': - //ICEMAN STRANGE + case 'r': + //ICEMAN STRANGE downlink_mode = param_get8ex(Cmd, cmdp + 1, 0, 10); if (downlink_mode == 4) try_all_dl_modes = true; @@ -2992,7 +3027,7 @@ static int CmdT55xxDetectPage1(const char *Cmd) { } else { found = tryDetectP1(false); } - + if (found) { PrintAndLogEx(SUCCESS, "T55xx chip found!"); T55xx_Print_DownlinkMode(found_mode); @@ -3145,8 +3180,8 @@ static int CmdT55xxProtect(const char *Cmd) { override = 1; cmdp += 2; break; - case 'r': - //ICEMAN STRANGE + case 'r': + //ICEMAN STRANGE downlink_mode = param_get8ex(Cmd, cmdp + 1, 0, 10); if (downlink_mode > 3) downlink_mode = 0; @@ -3162,15 +3197,15 @@ static int CmdT55xxProtect(const char *Cmd) { if (gotnewpwd == false) return usage_t55xx_protect(); - + if (errors || cmdp == 0) return usage_t55xx_protect(); // sanity check. if (SanityOfflineCheck(false) != PM3_SUCCESS) 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; } diff --git a/client/cmdlft55xx.h b/client/cmdlft55xx.h index f388a39af..1b70ca9ca 100644 --- a/client/cmdlft55xx.h +++ b/client/cmdlft55xx.h @@ -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); diff --git a/client/cmdlfviking.c b/client/cmdlfviking.c index 45fe9ffb6..9bbbeaa7e 100644 --- a/client/cmdlfviking.c +++ b/client/cmdlfviking.c @@ -90,14 +90,14 @@ static int CmdVikingClone(const char *Cmd) { uint8_t blocks[8]; } PACKED payload; payload.Q5 = Q5; - + num_to_bytes(rawID, 8, &payload.blocks[0]); PrintAndLogEx(INFO, "Preparing to clone Viking tag - ID " _YELLOW_("%08X")" raw " _YELLOW_("%s"), id, sprint_hex(payload.blocks, sizeof(payload.blocks))); - + 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."); diff --git a/client/cmdlfvisa2000.c b/client/cmdlfvisa2000.c index 51cedb925..9f80a830d 100644 --- a/client/cmdlfvisa2000.c +++ b/client/cmdlfvisa2000.c @@ -169,7 +169,7 @@ static int CmdVisa2kClone(const char *Cmd) { uint8_t res = 0; PacketResponseNG resp; - + // fast push mode conn.block_after_ACK = true; for (uint8_t i = 0; i < 4; i++) { @@ -189,17 +189,19 @@ static int CmdVisa2kClone(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; + } - // write block0, needs a detect. - if (i == 0) - t55xxAquireAndDetect(false, 0, blocks[i], false); - 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; diff --git a/client/cmdmain.c b/client/cmdmain.c index eba34b2ca..4b6013d80 100644 --- a/client/cmdmain.c +++ b/client/cmdmain.c @@ -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} diff --git a/client/cmdwiegand.c b/client/cmdwiegand.c new file mode 100644 index 000000000..8c1b5e8cb --- /dev/null +++ b/client/cmdwiegand.c @@ -0,0 +1,205 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2018 iceman +// +// 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 +#include +#include +#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 ] [ ] {...}"); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " w see `wiegand list` for available formats"); + PrintAndLogEx(NORMAL, " c card number"); + PrintAndLogEx(NORMAL, " f facility code"); + PrintAndLogEx(NORMAL, " i issue Level"); + PrintAndLogEx(NORMAL, " o 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]

"); + 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); +} diff --git a/client/cmdwiegand.h b/client/cmdwiegand.h new file mode 100644 index 000000000..2c6e8fb40 --- /dev/null +++ b/client/cmdwiegand.h @@ -0,0 +1,20 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2019 iceman +// +// 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 diff --git a/client/emv/cmdemv.c b/client/emv/cmdemv.c index 8656e4902..d45181060 100644 --- a/client/emv/cmdemv.c +++ b/client/emv/cmdemv.c @@ -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) { diff --git a/client/emv/test/crypto_test.c b/client/emv/test/crypto_test.c index cdf22a995..4a40952a8 100644 --- a/client/emv/test/crypto_test.c +++ b/client/emv/test/crypto_test.c @@ -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; } diff --git a/client/emv/test/crypto_test.h b/client/emv/test/crypto_test.h index 024a950d5..4b8fcf074 100644 --- a/client/emv/test/crypto_test.h +++ b/client/emv/test/crypto_test.h @@ -17,5 +17,5 @@ #define __CRYPTO_TEST_H #include -int exec_crypto_test(bool verbose); +int exec_crypto_test(bool verbose, bool include_slow_tests); #endif diff --git a/client/emv/test/cryptotest.c b/client/emv/test/cryptotest.c index 937ff7e8e..f343ebbea 100644 --- a/client/emv/test/cryptotest.c +++ b/client/emv/test/cryptotest.c @@ -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(); diff --git a/client/emv/test/cryptotest.h b/client/emv/test/cryptotest.h index 74a317e4e..579a5a66d 100644 --- a/client/emv/test/cryptotest.h +++ b/client/emv/test/cryptotest.h @@ -12,5 +12,5 @@ #define __CRYPTOTEST_H #include -int ExecuteCryptoTests(bool verbose); +int ExecuteCryptoTests(bool verbose, bool ignore_time, bool include_slow_tests); #endif diff --git a/client/fido/additional_ca.c b/client/fido/additional_ca.c index 7ea103004..1f383c741 100644 --- a/client/fido/additional_ca.c +++ b/client/fido/additional_ca.c @@ -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); diff --git a/client/fileutils.c b/client/fileutils.c index 23553d15c..6efe4c17b 100644 --- a/client/fileutils.c +++ b/client/fileutils.c @@ -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)) diff --git a/client/loclass/elite_crack.c b/client/loclass/elite_crack.c index bf9aee5b3..c7a617f6a 100644 --- a/client/loclass/elite_crack.c +++ b/client/loclass/elite_crack.c @@ -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; } diff --git a/client/loclass/elite_crack.h b/client/loclass/elite_crack.h index 819d3de47..8b357ac66 100644 --- a/client/loclass/elite_crack.h +++ b/client/loclass/elite_crack.h @@ -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 diff --git a/client/mifare/mifarehost.c b/client/mifare/mifarehost.c index 429605a4e..e4cec00c0 100644 --- a/client/mifare/mifarehost.c +++ b/client/mifare/mifarehost.c @@ -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: diff --git a/client/scripting.c b/client/scripting.c index 586ab0940..8054ff9b4 100644 --- a/client/scripting.c +++ b/client/scripting.c @@ -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\'"); } diff --git a/client/util.c b/client/util.c index 6877e8835..da1b5d0e2 100644 --- a/client/util.c +++ b/client/util.c @@ -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; +} diff --git a/client/util.h b/client/util.h index 7cfea0f8b..7d6c6460e 100644 --- a/client/util.h +++ b/client/util.h @@ -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 diff --git a/client/wiegand_formats.c b/client/wiegand_formats.c new file mode 100644 index 000000000..4e2541cbd --- /dev/null +++ b/client/wiegand_formats.c @@ -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; +} diff --git a/client/wiegand_formats.h b/client/wiegand_formats.h new file mode 100644 index 000000000..e3aca4b9c --- /dev/null +++ b/client/wiegand_formats.h @@ -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 // memset +#include +#include +#include +#include +#include +#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 diff --git a/client/wiegand_formatutils.c b/client/wiegand_formatutils.c new file mode 100644 index 000000000..a4529955d --- /dev/null +++ b/client/wiegand_formatutils.c @@ -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 +#include +#include +#include +#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; +} diff --git a/client/wiegand_formatutils.h b/client/wiegand_formatutils.h new file mode 100644 index 000000000..534bea4f3 --- /dev/null +++ b/client/wiegand_formatutils.h @@ -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 +#include +#include + +// 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 diff --git a/doc/cheatsheet.md b/doc/cheatsheet.md index 4a61ae7d2..3fc446ec8 100644 --- a/doc/cheatsheet.md +++ b/doc/cheatsheet.md @@ -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 : *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 : The block number as 2 hex symbols k : 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 : The block number as 2 hex symbols d : Set the Data to write as 16 hex symbols k : 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 : 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 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]: 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 o f c i +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 : OEM number / site code -FC : facility code -CN : card number - -pm3 --> lf hid wiegand 0 56 150 -``` - Simulate Prox card ``` diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index d79433fcf..13995a429 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -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 diff --git a/include/protocols.h b/include/protocols.h index 9b47266c3..747e4e346 100644 --- a/include/protocols.h +++ b/include/protocols.h @@ -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) diff --git a/pm3test.sh b/pm3test.sh index 8785bf8df..de9134ba1 100755 --- a/pm3test.sh +++ b/pm3test.sh @@ -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... diff --git a/tools/jtag_openocd/interface-raspberrypi2.cfg b/tools/jtag_openocd/interface-raspberrypi2.cfg index b779cd290..dc97479d5 100644 --- a/tools/jtag_openocd/interface-raspberrypi2.cfg +++ b/tools/jtag_openocd/interface-raspberrypi2.cfg @@ -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